From bfb71a3405eeefa483ae5fd3f07813f9e312ac48 Mon Sep 17 00:00:00 2001 From: SmithThe4th Date: Fri, 27 Jun 2025 09:59:38 -0400 Subject: [PATCH 001/239] [PM-22996] Failed to decrypt ciphers: TypeError: this.uriChecksum is null (#15355) --- libs/common/src/vault/models/domain/login-uri.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/common/src/vault/models/domain/login-uri.ts b/libs/common/src/vault/models/domain/login-uri.ts index b3e6fad70dd..5874d99c99d 100644 --- a/libs/common/src/vault/models/domain/login-uri.ts +++ b/libs/common/src/vault/models/domain/login-uri.ts @@ -97,8 +97,8 @@ export class LoginUri extends Domain { */ toSdkLoginUri(): SdkLoginUri { return { - uri: this.uri.toJSON(), - uriChecksum: this.uriChecksum.toJSON(), + uri: this.uri?.toJSON(), + uriChecksum: this.uriChecksum?.toJSON(), match: this.match, }; } From f7ca5b78189d17253ae4446d338fbfc2873e7339 Mon Sep 17 00:00:00 2001 From: Colton Hurst Date: Fri, 27 Jun 2025 10:28:35 -0400 Subject: [PATCH 002/239] Small Typo & Lint Fix (#15313) * Small typo and lint fix * Removes extra line --- apps/desktop/src/platform/services/desktop-settings.service.ts | 2 +- .../components/access-selector/access-selector.component.html | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/desktop/src/platform/services/desktop-settings.service.ts b/apps/desktop/src/platform/services/desktop-settings.service.ts index 37a1fe73829..e8f311e56f6 100644 --- a/apps/desktop/src/platform/services/desktop-settings.service.ts +++ b/apps/desktop/src/platform/services/desktop-settings.service.ts @@ -108,7 +108,7 @@ export class DesktopSettingsService { private readonly closeToTrayState = this.stateProvider.getGlobal(CLOSE_TO_TRAY_KEY); /** - * Tha applications setting for whether or not to close the application into the system tray. + * The applications setting for whether or not to close the application into the system tray. */ closeToTray$ = this.closeToTrayState.state$.pipe(map(Boolean)); diff --git a/apps/web/src/app/admin-console/organizations/shared/components/access-selector/access-selector.component.html b/apps/web/src/app/admin-console/organizations/shared/components/access-selector/access-selector.component.html index 088b5051fb1..e9b7ba39aa5 100644 --- a/apps/web/src/app/admin-console/organizations/shared/components/access-selector/access-selector.component.html +++ b/apps/web/src/app/admin-console/organizations/shared/components/access-selector/access-selector.component.html @@ -1,5 +1,3 @@ - -
{{ "permission" | i18n }} From 62750a06ec2739033e0a4f597afdd99af80945ea Mon Sep 17 00:00:00 2001 From: Jordan Aasen <166539328+jaasen-livefront@users.noreply.github.com> Date: Fri, 27 Jun 2025 08:16:59 -0700 Subject: [PATCH 003/239] [PM-36] - [Tech Debt] Move SearchService to libs/common/vault (#15251) * wip - migrate search service to vault * fix import --- .../autofill/popup/fido2/fido2.component.ts | 2 +- .../browser/src/background/main.background.ts | 4 ++-- .../popup/send-v2/send-v2.component.spec.ts | 2 +- .../vault-header-v2.component.spec.ts | 2 +- .../vault-popup-items.service.spec.ts | 2 +- .../services/vault-popup-items.service.ts | 2 +- apps/cli/src/commands/get.command.ts | 2 +- apps/cli/src/commands/list.command.ts | 2 +- .../service-container/service-container.ts | 2 +- .../src/tools/send/commands/get.command.ts | 2 +- .../src/tools/send/commands/list.command.ts | 2 +- apps/desktop/src/app/app.component.ts | 2 +- .../src/app/tools/send/send.component.ts | 2 +- .../app/vault/vault-items-v2.component.ts | 2 +- .../vault/app/vault/vault-items.component.ts | 2 +- .../collections/vault.component.ts | 2 +- apps/web/src/app/app.component.ts | 2 +- apps/web/src/app/tools/send/send.component.ts | 2 +- .../vault/individual-vault/vault.component.ts | 2 +- .../src/services/jslib-services.module.ts | 4 ++-- libs/angular/src/tools/send/send.component.ts | 2 +- .../vault/components/vault-items.component.ts | 2 +- .../services/vault-timeout.service.spec.ts | 2 +- .../services/vault-timeout.service.ts | 2 +- .../abstractions/search.service.ts | 6 +++--- .../src/vault/services/cipher.service.spec.ts | 2 +- .../src/vault/services/cipher.service.ts | 2 +- .../{ => vault}/services/search.service.ts | 20 +++++++++---------- .../src/services/send-items.service.spec.ts | 2 +- .../src/services/send-items.service.ts | 2 +- 30 files changed, 43 insertions(+), 43 deletions(-) rename libs/common/src/{ => vault}/abstractions/search.service.ts (82%) rename libs/common/src/{ => vault}/services/search.service.ts (96%) diff --git a/apps/browser/src/autofill/popup/fido2/fido2.component.ts b/apps/browser/src/autofill/popup/fido2/fido2.component.ts index 3107b60f475..ac38fe2f894 100644 --- a/apps/browser/src/autofill/popup/fido2/fido2.component.ts +++ b/apps/browser/src/autofill/popup/fido2/fido2.component.ts @@ -18,13 +18,13 @@ import { } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { SecureNoteType, CipherType } from "@bitwarden/common/vault/enums"; import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; import { CardView } from "@bitwarden/common/vault/models/view/card.view"; diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 2e4818a8b0c..2f423895f9f 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -22,7 +22,6 @@ import { ApiService as ApiServiceAbstraction } from "@bitwarden/common/abstracti import { AuditService as AuditServiceAbstraction } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service"; -import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service"; import { InternalOrganizationServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; import { InternalPolicyService as InternalPolicyServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; @@ -174,7 +173,6 @@ import { ApiService } from "@bitwarden/common/services/api.service"; import { AuditService } from "@bitwarden/common/services/audit.service"; import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service"; import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service"; -import { SearchService } from "@bitwarden/common/services/search.service"; import { PasswordStrengthService, PasswordStrengthServiceAbstraction, @@ -190,6 +188,7 @@ import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vau import { CipherFileUploadService as CipherFileUploadServiceAbstraction } from "@bitwarden/common/vault/abstractions/file-upload/cipher-file-upload.service"; import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; import { InternalFolderService as InternalFolderServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; +import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/vault/abstractions/search.service"; import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/vault/abstractions/totp.service"; import { VaultSettingsService as VaultSettingsServiceAbstraction } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; @@ -207,6 +206,7 @@ import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-u import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service"; import { FolderService } from "@bitwarden/common/vault/services/folder/folder.service"; import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service"; +import { SearchService } from "@bitwarden/common/vault/services/search.service"; import { TotpService } from "@bitwarden/common/vault/services/totp.service"; import { VaultSettingsService } from "@bitwarden/common/vault/services/vault-settings/vault-settings.service"; import { DefaultTaskService, TaskService } from "@bitwarden/common/vault/tasks"; diff --git a/apps/browser/src/tools/popup/send-v2/send-v2.component.spec.ts b/apps/browser/src/tools/popup/send-v2/send-v2.component.spec.ts index 6fc4793f5c0..63ede7ba357 100644 --- a/apps/browser/src/tools/popup/send-v2/send-v2.component.spec.ts +++ b/apps/browser/src/tools/popup/send-v2/send-v2.component.spec.ts @@ -6,7 +6,6 @@ import { MockProxy, mock } from "jest-mock-extended"; import { of, BehaviorSubject } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; @@ -21,6 +20,7 @@ import { SendType } from "@bitwarden/common/tools/send/enums/send-type"; import { SendView } from "@bitwarden/common/tools/send/models/view/send.view"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { ButtonModule, NoItemsModule } from "@bitwarden/components"; import { NewSendDropdownComponent, diff --git a/apps/browser/src/vault/popup/components/vault-v2/vault-header/vault-header-v2.component.spec.ts b/apps/browser/src/vault/popup/components/vault-v2/vault-header/vault-header-v2.component.spec.ts index cda055176e8..9564aeadc09 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/vault-header/vault-header-v2.component.spec.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/vault-header/vault-header-v2.component.spec.ts @@ -7,7 +7,6 @@ import { mock } from "jest-mock-extended"; import { BehaviorSubject, Subject } from "rxjs"; import { CollectionService } from "@bitwarden/admin-console/common"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; @@ -19,6 +18,7 @@ import { StateProvider } from "@bitwarden/common/platform/state"; import { SyncService } from "@bitwarden/common/platform/sync"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service"; import { PasswordRepromptService } from "@bitwarden/vault"; diff --git a/apps/browser/src/vault/popup/services/vault-popup-items.service.spec.ts b/apps/browser/src/vault/popup/services/vault-popup-items.service.spec.ts index a573f99d3c1..63cd0d90d05 100644 --- a/apps/browser/src/vault/popup/services/vault-popup-items.service.spec.ts +++ b/apps/browser/src/vault/popup/services/vault-popup-items.service.spec.ts @@ -4,7 +4,6 @@ import { mock } from "jest-mock-extended"; import { BehaviorSubject, firstValueFrom, timeout } from "rxjs"; import { CollectionService, CollectionView } from "@bitwarden/admin-console/common"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; @@ -14,6 +13,7 @@ import { SyncService } from "@bitwarden/common/platform/sync"; import { ObservableTracker, mockAccountServiceWith } from "@bitwarden/common/spec"; import { CipherId, UserId } from "@bitwarden/common/types/guid"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service"; import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherData } from "@bitwarden/common/vault/models/data/cipher.data"; diff --git a/apps/browser/src/vault/popup/services/vault-popup-items.service.ts b/apps/browser/src/vault/popup/services/vault-popup-items.service.ts index c1dd9b30c68..20bdbd2eefe 100644 --- a/apps/browser/src/vault/popup/services/vault-popup-items.service.ts +++ b/apps/browser/src/vault/popup/services/vault-popup-items.service.ts @@ -20,7 +20,6 @@ import { } from "rxjs"; import { CollectionService } from "@bitwarden/admin-console/common"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; @@ -28,6 +27,7 @@ import { Utils } from "@bitwarden/common/platform/misc/utils"; import { SyncService } from "@bitwarden/common/platform/sync"; import { CollectionId, OrganizationId, UserId } from "@bitwarden/common/types/guid"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service"; import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; diff --git a/apps/cli/src/commands/get.command.ts b/apps/cli/src/commands/get.command.ts index 28a5680da77..3b1e0de4f15 100644 --- a/apps/cli/src/commands/get.command.ts +++ b/apps/cli/src/commands/get.command.ts @@ -6,7 +6,6 @@ import { CollectionService, CollectionView } from "@bitwarden/admin-console/comm import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; @@ -30,6 +29,7 @@ import { SendType } from "@bitwarden/common/tools/send/enums/send-type"; import { CipherId, OrganizationId, UserId } 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"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service"; import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; diff --git a/apps/cli/src/commands/list.command.ts b/apps/cli/src/commands/list.command.ts index 49ec7689b20..517050728c0 100644 --- a/apps/cli/src/commands/list.command.ts +++ b/apps/cli/src/commands/list.command.ts @@ -10,7 +10,6 @@ import { } from "@bitwarden/admin-console/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; @@ -19,6 +18,7 @@ import { ListResponse as ApiListResponse } from "@bitwarden/common/models/respon import { Utils } from "@bitwarden/common/platform/misc/utils"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { CollectionResponse } from "../admin-console/models/response/collection.response"; diff --git a/apps/cli/src/service-container/service-container.ts b/apps/cli/src/service-container/service-container.ts index 099ce503fac..df019520250 100644 --- a/apps/cli/src/service-container/service-container.ts +++ b/apps/cli/src/service-container/service-container.ts @@ -132,7 +132,6 @@ import { DefaultSyncService } from "@bitwarden/common/platform/sync/internal"; import { AuditService } from "@bitwarden/common/services/audit.service"; import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service"; import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service"; -import { SearchService } from "@bitwarden/common/services/search.service"; import { PasswordStrengthService, PasswordStrengthServiceAbstraction, @@ -153,6 +152,7 @@ import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-u import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service"; import { FolderService } from "@bitwarden/common/vault/services/folder/folder.service"; import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service"; +import { SearchService } from "@bitwarden/common/vault/services/search.service"; import { TotpService } from "@bitwarden/common/vault/services/totp.service"; import { legacyPasswordGenerationServiceFactory, diff --git a/apps/cli/src/tools/send/commands/get.command.ts b/apps/cli/src/tools/send/commands/get.command.ts index 1d651c50bf0..1b3a8f6c500 100644 --- a/apps/cli/src/tools/send/commands/get.command.ts +++ b/apps/cli/src/tools/send/commands/get.command.ts @@ -4,12 +4,12 @@ import { OptionValues } from "commander"; import { firstValueFrom } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { SendView } from "@bitwarden/common/tools/send/models/view/send.view"; import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { DownloadCommand } from "../../../commands/download.command"; import { Response } from "../../../models/response"; diff --git a/apps/cli/src/tools/send/commands/list.command.ts b/apps/cli/src/tools/send/commands/list.command.ts index ab8a4dcb1c5..f611cb3f5dc 100644 --- a/apps/cli/src/tools/send/commands/list.command.ts +++ b/apps/cli/src/tools/send/commands/list.command.ts @@ -1,8 +1,8 @@ import { firstValueFrom } from "rxjs"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { Response } from "../../../models/response"; import { ListResponse } from "../../../models/response/list.response"; diff --git a/apps/desktop/src/app/app.component.ts b/apps/desktop/src/app/app.component.ts index dc1621210de..b5c34cc95a3 100644 --- a/apps/desktop/src/app/app.component.ts +++ b/apps/desktop/src/app/app.component.ts @@ -35,7 +35,6 @@ import { UserDecryptionOptionsServiceAbstraction, } from "@bitwarden/auth/common"; import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; @@ -67,6 +66,7 @@ import { SyncService } from "@bitwarden/common/platform/sync"; import { UserId } from "@bitwarden/common/types/guid"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { CipherType } from "@bitwarden/common/vault/enums"; import { DialogRef, DialogService, ToastOptions, ToastService } from "@bitwarden/components"; import { CredentialGeneratorHistoryDialogComponent } from "@bitwarden/generator-components"; diff --git a/apps/desktop/src/app/tools/send/send.component.ts b/apps/desktop/src/app/tools/send/send.component.ts index 3ca26780853..0146a5e62ea 100644 --- a/apps/desktop/src/app/tools/send/send.component.ts +++ b/apps/desktop/src/app/tools/send/send.component.ts @@ -6,7 +6,6 @@ import { FormsModule } from "@angular/forms"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { SendComponent as BaseSendComponent } from "@bitwarden/angular/tools/send/send.component"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; @@ -17,6 +16,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl import { SendView } from "@bitwarden/common/tools/send/models/view/send.view"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { DialogService, ToastService } from "@bitwarden/components"; import { invokeMenu, RendererMenuItem } from "../../../utils"; diff --git a/apps/desktop/src/vault/app/vault/vault-items-v2.component.ts b/apps/desktop/src/vault/app/vault/vault-items-v2.component.ts index 1256c9e52e8..21b857b551a 100644 --- a/apps/desktop/src/vault/app/vault/vault-items-v2.component.ts +++ b/apps/desktop/src/vault/app/vault/vault-items-v2.component.ts @@ -6,9 +6,9 @@ import { distinctUntilChanged } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { VaultItemsComponent as BaseVaultItemsComponent } from "@bitwarden/angular/vault/components/vault-items.component"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service"; import { MenuModule } from "@bitwarden/components"; diff --git a/apps/desktop/src/vault/app/vault/vault-items.component.ts b/apps/desktop/src/vault/app/vault/vault-items.component.ts index 8bf4955343d..c37a29833d9 100644 --- a/apps/desktop/src/vault/app/vault/vault-items.component.ts +++ b/apps/desktop/src/vault/app/vault/vault-items.component.ts @@ -4,9 +4,9 @@ import { Component } from "@angular/core"; import { distinctUntilChanged } from "rxjs"; import { VaultItemsComponent as BaseVaultItemsComponent } from "@bitwarden/angular/vault/components/vault-items.component"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service"; diff --git a/apps/web/src/app/admin-console/organizations/collections/vault.component.ts b/apps/web/src/app/admin-console/organizations/collections/vault.component.ts index bc0f517d1fb..8ad0f6cf499 100644 --- a/apps/web/src/app/admin-console/organizations/collections/vault.component.ts +++ b/apps/web/src/app/admin-console/organizations/collections/vault.component.ts @@ -35,7 +35,6 @@ import { import { SearchPipe } from "@bitwarden/angular/pipes/search.pipe"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; @@ -55,6 +54,7 @@ import { Utils } from "@bitwarden/common/platform/misc/utils"; import { SyncService } from "@bitwarden/common/platform/sync"; import { CipherId, CollectionId, OrganizationId, UserId } from "@bitwarden/common/types/guid"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service"; import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; diff --git a/apps/web/src/app/app.component.ts b/apps/web/src/app/app.component.ts index b9f3b8c05b7..ada73dd0059 100644 --- a/apps/web/src/app/app.component.ts +++ b/apps/web/src/app/app.component.ts @@ -9,7 +9,6 @@ import { CollectionService } from "@bitwarden/admin-console/common"; import { DeviceTrustToastService } from "@bitwarden/angular/auth/services/device-trust-toast.service.abstraction"; import { DocumentLangSetter } from "@bitwarden/angular/platform/i18n"; import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { InternalOrganizationServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; @@ -26,6 +25,7 @@ import { NotificationsService } from "@bitwarden/common/platform/notifications"; import { StateEventRunnerService } from "@bitwarden/common/platform/state"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { DialogService, ToastService } from "@bitwarden/components"; import { KeyService, BiometricStateService } from "@bitwarden/key-management"; diff --git a/apps/web/src/app/tools/send/send.component.ts b/apps/web/src/app/tools/send/send.component.ts index 3d42b3182f8..b74a3b80ee3 100644 --- a/apps/web/src/app/tools/send/send.component.ts +++ b/apps/web/src/app/tools/send/send.component.ts @@ -4,7 +4,6 @@ import { Component, NgZone, OnInit, OnDestroy } from "@angular/core"; import { lastValueFrom } from "rxjs"; import { SendComponent as BaseSendComponent } from "@bitwarden/angular/tools/send/send.component"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; @@ -16,6 +15,7 @@ import { SendView } from "@bitwarden/common/tools/send/models/view/send.view"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; import { SendId } from "@bitwarden/common/types/guid"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { DialogRef, DialogService, diff --git a/apps/web/src/app/vault/individual-vault/vault.component.ts b/apps/web/src/app/vault/individual-vault/vault.component.ts index 29ad0ead621..51d59b54369 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault.component.ts @@ -36,7 +36,6 @@ import { import { SearchPipe } from "@bitwarden/angular/pipes/search.pipe"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { getOrganizationById, @@ -60,6 +59,7 @@ import { Utils } from "@bitwarden/common/platform/misc/utils"; import { SyncService } from "@bitwarden/common/platform/sync"; import { CipherId, CollectionId, OrganizationId, UserId } from "@bitwarden/common/types/guid"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service"; import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index bec32ac1157..780604f048d 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -59,7 +59,6 @@ import { ApiService as ApiServiceAbstraction } from "@bitwarden/common/abstracti import { AuditService as AuditServiceAbstraction } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service"; -import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { InternalOrganizationServiceAbstraction, @@ -257,7 +256,6 @@ import { ApiService } from "@bitwarden/common/services/api.service"; import { AuditService } from "@bitwarden/common/services/audit.service"; import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service"; import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service"; -import { SearchService } from "@bitwarden/common/services/search.service"; import { PasswordStrengthService, PasswordStrengthServiceAbstraction, @@ -279,6 +277,7 @@ import { FolderService as FolderServiceAbstraction, InternalFolderService, } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; +import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/vault/abstractions/search.service"; import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/vault/abstractions/totp.service"; import { VaultSettingsService as VaultSettingsServiceAbstraction } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service"; import { @@ -295,6 +294,7 @@ import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-u import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service"; import { FolderService } from "@bitwarden/common/vault/services/folder/folder.service"; import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service"; +import { SearchService } from "@bitwarden/common/vault/services/search.service"; import { TotpService } from "@bitwarden/common/vault/services/totp.service"; import { VaultSettingsService } from "@bitwarden/common/vault/services/vault-settings/vault-settings.service"; import { DefaultTaskService, TaskService } from "@bitwarden/common/vault/tasks"; diff --git a/libs/angular/src/tools/send/send.component.ts b/libs/angular/src/tools/send/send.component.ts index 5dbf3686b7d..e96bdd8e31a 100644 --- a/libs/angular/src/tools/send/send.component.ts +++ b/libs/angular/src/tools/send/send.component.ts @@ -12,7 +12,6 @@ import { combineLatest, } from "rxjs"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; @@ -25,6 +24,7 @@ import { SendType } from "@bitwarden/common/tools/send/enums/send-type"; import { SendView } from "@bitwarden/common/tools/send/models/view/send.view"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { DialogService, ToastService } from "@bitwarden/components"; @Directive() diff --git a/libs/angular/src/vault/components/vault-items.component.ts b/libs/angular/src/vault/components/vault-items.component.ts index 424243fe118..cf017899774 100644 --- a/libs/angular/src/vault/components/vault-items.component.ts +++ b/libs/angular/src/vault/components/vault-items.component.ts @@ -15,11 +15,11 @@ import { takeUntil, } from "rxjs"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service"; diff --git a/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.spec.ts b/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.spec.ts index 5ce7e37778d..9963e7d24f8 100644 --- a/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.spec.ts +++ b/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.spec.ts @@ -14,7 +14,6 @@ import { LogoutReason } from "@bitwarden/auth/common"; import { BiometricsService } from "@bitwarden/key-management"; import { FakeAccountService, mockAccountServiceWith } from "../../../../spec"; -import { SearchService } from "../../../abstractions/search.service"; import { AccountInfo } from "../../../auth/abstractions/account.service"; import { AuthService } from "../../../auth/abstractions/auth.service"; import { AuthenticationStatus } from "../../../auth/enums/authentication-status"; @@ -28,6 +27,7 @@ import { StateEventRunnerService } from "../../../platform/state"; import { UserId } from "../../../types/guid"; import { CipherService } from "../../../vault/abstractions/cipher.service"; import { FolderService } from "../../../vault/abstractions/folder/folder.service.abstraction"; +import { SearchService } from "../../../vault/abstractions/search.service"; import { FakeMasterPasswordService } from "../../master-password/services/fake-master-password.service"; import { VaultTimeoutAction } from "../enums/vault-timeout-action.enum"; import { VaultTimeout, VaultTimeoutStringType } from "../types/vault-timeout.type"; diff --git a/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.ts b/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.ts index 04769567db2..b5ee6a1fc0f 100644 --- a/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.ts +++ b/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.ts @@ -12,7 +12,6 @@ import { LogoutReason } from "@bitwarden/auth/common"; // eslint-disable-next-line no-restricted-imports import { BiometricsService } from "@bitwarden/key-management"; -import { SearchService } from "../../../abstractions/search.service"; import { AccountService } from "../../../auth/abstractions/account.service"; import { AuthService } from "../../../auth/abstractions/auth.service"; import { AuthenticationStatus } from "../../../auth/enums/authentication-status"; @@ -25,6 +24,7 @@ import { StateEventRunnerService } from "../../../platform/state"; import { UserId } from "../../../types/guid"; import { CipherService } from "../../../vault/abstractions/cipher.service"; import { FolderService } from "../../../vault/abstractions/folder/folder.service.abstraction"; +import { SearchService } from "../../../vault/abstractions/search.service"; import { InternalMasterPasswordServiceAbstraction } from "../../master-password/abstractions/master-password.service.abstraction"; import { VaultTimeoutSettingsService } from "../abstractions/vault-timeout-settings.service"; import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "../abstractions/vault-timeout.service"; diff --git a/libs/common/src/abstractions/search.service.ts b/libs/common/src/vault/abstractions/search.service.ts similarity index 82% rename from libs/common/src/abstractions/search.service.ts rename to libs/common/src/vault/abstractions/search.service.ts index 2bff33bf2db..c981aa748a4 100644 --- a/libs/common/src/abstractions/search.service.ts +++ b/libs/common/src/vault/abstractions/search.service.ts @@ -2,9 +2,9 @@ // @ts-strict-ignore import { Observable } from "rxjs"; -import { SendView } from "../tools/send/models/view/send.view"; -import { IndexedEntityId, UserId } from "../types/guid"; -import { CipherView } from "../vault/models/view/cipher.view"; +import { SendView } from "../../tools/send/models/view/send.view"; +import { IndexedEntityId, UserId } from "../../types/guid"; +import { CipherView } from "../models/view/cipher.view"; export abstract class SearchService { indexedEntityId$: (userId: UserId) => Observable; diff --git a/libs/common/src/vault/services/cipher.service.spec.ts b/libs/common/src/vault/services/cipher.service.spec.ts index 1a0b1568775..2fd9b03a37e 100644 --- a/libs/common/src/vault/services/cipher.service.spec.ts +++ b/libs/common/src/vault/services/cipher.service.spec.ts @@ -10,7 +10,6 @@ import { FakeAccountService, mockAccountServiceWith } from "../../../spec/fake-a import { FakeStateProvider } from "../../../spec/fake-state-provider"; import { makeStaticByteArray, makeSymmetricCryptoKey } from "../../../spec/utils"; import { ApiService } from "../../abstractions/api.service"; -import { SearchService } from "../../abstractions/search.service"; import { AutofillSettingsService } from "../../autofill/services/autofill-settings.service"; import { DomainSettingsService } from "../../autofill/services/domain-settings.service"; import { BulkEncryptService } from "../../key-management/crypto/abstractions/bulk-encrypt.service"; @@ -29,6 +28,7 @@ import { CipherKey, OrgKey, UserKey } from "../../types/key"; import { CipherEncryptionService } from "../abstractions/cipher-encryption.service"; import { EncryptionContext } from "../abstractions/cipher.service"; import { CipherFileUploadService } from "../abstractions/file-upload/cipher-file-upload.service"; +import { SearchService } from "../abstractions/search.service"; import { FieldType } from "../enums"; import { CipherRepromptType } from "../enums/cipher-reprompt-type"; import { CipherType } from "../enums/cipher-type"; diff --git a/libs/common/src/vault/services/cipher.service.ts b/libs/common/src/vault/services/cipher.service.ts index d8d180a7c3e..b4f79b2467e 100644 --- a/libs/common/src/vault/services/cipher.service.ts +++ b/libs/common/src/vault/services/cipher.service.ts @@ -9,7 +9,6 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service" import { KeyService } from "@bitwarden/key-management"; import { ApiService } from "../../abstractions/api.service"; -import { SearchService } from "../../abstractions/search.service"; import { AccountService } from "../../auth/abstractions/account.service"; import { AutofillSettingsServiceAbstraction } from "../../autofill/services/autofill-settings.service"; import { DomainSettingsService } from "../../autofill/services/domain-settings.service"; @@ -38,6 +37,7 @@ import { EncryptionContext, } from "../abstractions/cipher.service"; import { CipherFileUploadService } from "../abstractions/file-upload/cipher-file-upload.service"; +import { SearchService } from "../abstractions/search.service"; import { FieldType } from "../enums"; import { CipherType } from "../enums/cipher-type"; import { CipherData } from "../models/data/cipher.data"; diff --git a/libs/common/src/services/search.service.ts b/libs/common/src/vault/services/search.service.ts similarity index 96% rename from libs/common/src/services/search.service.ts rename to libs/common/src/vault/services/search.service.ts index 3e6a070195a..4b7a26b6a31 100644 --- a/libs/common/src/services/search.service.ts +++ b/libs/common/src/vault/services/search.service.ts @@ -4,21 +4,21 @@ import * as lunr from "lunr"; import { Observable, firstValueFrom, map } from "rxjs"; import { Jsonify } from "type-fest"; -import { SearchService as SearchServiceAbstraction } from "../abstractions/search.service"; -import { UriMatchStrategy } from "../models/domain/domain-service"; -import { I18nService } from "../platform/abstractions/i18n.service"; -import { LogService } from "../platform/abstractions/log.service"; +import { UriMatchStrategy } from "../../models/domain/domain-service"; +import { I18nService } from "../../platform/abstractions/i18n.service"; +import { LogService } from "../../platform/abstractions/log.service"; import { SingleUserState, StateProvider, UserKeyDefinition, VAULT_SEARCH_MEMORY, -} from "../platform/state"; -import { SendView } from "../tools/send/models/view/send.view"; -import { IndexedEntityId, UserId } from "../types/guid"; -import { FieldType } from "../vault/enums"; -import { CipherType } from "../vault/enums/cipher-type"; -import { CipherView } from "../vault/models/view/cipher.view"; +} from "../../platform/state"; +import { SendView } from "../../tools/send/models/view/send.view"; +import { IndexedEntityId, UserId } from "../../types/guid"; +import { SearchService as SearchServiceAbstraction } from "../abstractions/search.service"; +import { FieldType } from "../enums"; +import { CipherType } from "../enums/cipher-type"; +import { CipherView } from "../models/view/cipher.view"; export type SerializedLunrIndex = { version: string; diff --git a/libs/tools/send/send-ui/src/services/send-items.service.spec.ts b/libs/tools/send/send-ui/src/services/send-items.service.spec.ts index 77e3725e813..cf46c909da5 100644 --- a/libs/tools/send/send-ui/src/services/send-items.service.spec.ts +++ b/libs/tools/send/send-ui/src/services/send-items.service.spec.ts @@ -2,11 +2,11 @@ import { TestBed } from "@angular/core/testing"; import { mock } from "jest-mock-extended"; import { BehaviorSubject, first, Subject } from "rxjs"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { SendView } from "@bitwarden/common/tools/send/models/view/send.view"; import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; import { UserId } from "@bitwarden/common/types/guid"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { mockAccountServiceWith } from "../../../../../common/spec"; diff --git a/libs/tools/send/send-ui/src/services/send-items.service.ts b/libs/tools/send/send-ui/src/services/send-items.service.ts index 1ade6f37f71..52e1e3d669e 100644 --- a/libs/tools/send/send-ui/src/services/send-items.service.ts +++ b/libs/tools/send/send-ui/src/services/send-items.service.ts @@ -14,11 +14,11 @@ import { tap, } from "rxjs"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { SendView } from "@bitwarden/common/tools/send/models/view/send.view"; import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; +import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; import { SendListFiltersService } from "./send-list-filters.service"; From 652f673a3c14f1c5ba451e0afed3bf2c29cb019f Mon Sep 17 00:00:00 2001 From: Brandon Treston Date: Fri, 27 Jun 2025 11:49:58 -0400 Subject: [PATCH 004/239] [PM-23086] fix My Items collection name (#15366) * fix My Items collection name * clean up --- .../services/organization-user/organization-user.service.ts | 2 +- apps/web/src/locales/en/messages.json | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/web/src/app/admin-console/organizations/members/services/organization-user/organization-user.service.ts b/apps/web/src/app/admin-console/organizations/members/services/organization-user/organization-user.service.ts index 31dfa865005..79efeebca2a 100644 --- a/apps/web/src/app/admin-console/organizations/members/services/organization-user/organization-user.service.ts +++ b/apps/web/src/app/admin-console/organizations/members/services/organization-user/organization-user.service.ts @@ -43,7 +43,7 @@ export class OrganizationUserService { ): Observable { const encryptedCollectionName$ = this.orgKey$(organization).pipe( switchMap((orgKey) => - this.encryptService.encryptString(this.i18nService.t("My Itmes"), orgKey), + this.encryptService.encryptString(this.i18nService.t("myItems"), orgKey), ), ); diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 79197f1eb06..5c9b02e5287 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -3276,6 +3276,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Get help" }, From 4e3d83147e3e4dbdaa5b78a44d47e95426bf4c60 Mon Sep 17 00:00:00 2001 From: Ketan Mehta <45426198+ketanMehtaa@users.noreply.github.com> Date: Fri, 27 Jun 2025 21:26:14 +0530 Subject: [PATCH 005/239] fixed ui name collection overlap (#15241) Co-authored-by: Daniel James Smith <2670567+djsmith85@users.noreply.github.com> --- .../components/vault-items/vault-items.component.html | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/web/src/app/vault/components/vault-items/vault-items.component.html b/apps/web/src/app/vault/components/vault-items/vault-items.component.html index 992c9c26bf3..ef928903a72 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-items.component.html +++ b/apps/web/src/app/vault/components/vault-items/vault-items.component.html @@ -22,16 +22,12 @@ bitCell bitSortable="name" [fn]="sortByName" - [class]="showExtraColumn ? 'lg:tw-w-3/5' : 'tw-w-full'" + [class]="showExtraColumn ? 'tw-w-3/5' : 'tw-w-full'" > {{ "name" | i18n }} - + {{ "name" | i18n }} From cb36b96855bb8ad05e9fc7837224336086e5ed1a Mon Sep 17 00:00:00 2001 From: Nick Krantz <125900171+nick-livefront@users.noreply.github.com> Date: Fri, 27 Jun 2025 12:55:20 -0500 Subject: [PATCH 006/239] [PM-22178] Add `WebBrowserInteractionService` (#15261) * add `WebBrowserInteractionService` and check for the extension observable * update checkForExtension to use observables rather than window timeouts * add open extension to WebBrowserInteractionService * add at-risk-passwords to `PopupPageUrls` * refactor `PopupPageUrls` to `ExtensionPageUrls` * add test for passing a page * refactor `Default` to `Index` * clean up complete/next issue using `race` * refactor page to url * continue listening for messages from the extension after subscribed * mark risk passwords a deprecated * remove takeUntilDestroyed * add back `takeUntilDestroyed` for internal `messages` * removed null filter - unneeded * add tap to send message for extension installation * add check for accepted urls to prevent any bad actors from opening the extension --- .../abstractions/content-message-handler.ts | 3 + .../content/content-message-handler.ts | 8 ++ .../browser/src/background/main.background.ts | 35 +++++- .../src/background/runtime.background.ts | 4 + .../web-browser-interaction.service.spec.ts | 111 ++++++++++++++++++ .../web-browser-interaction.service.ts | 76 ++++++++++++ .../vault/enums/extension-page-urls.enum.ts | 12 ++ libs/common/src/vault/enums/index.ts | 1 + .../src/vault/enums/vault-messages.enum.ts | 2 + 9 files changed, 250 insertions(+), 2 deletions(-) create mode 100644 apps/web/src/app/vault/services/web-browser-interaction.service.spec.ts create mode 100644 apps/web/src/app/vault/services/web-browser-interaction.service.ts create mode 100644 libs/common/src/vault/enums/extension-page-urls.enum.ts diff --git a/apps/browser/src/autofill/content/abstractions/content-message-handler.ts b/apps/browser/src/autofill/content/abstractions/content-message-handler.ts index 8231bd688c9..f413ace9432 100644 --- a/apps/browser/src/autofill/content/abstractions/content-message-handler.ts +++ b/apps/browser/src/autofill/content/abstractions/content-message-handler.ts @@ -1,3 +1,5 @@ +import { ExtensionPageUrls } from "@bitwarden/common/vault/enums"; + type ContentMessageWindowData = { command: string; lastpass?: boolean; @@ -5,6 +7,7 @@ type ContentMessageWindowData = { state?: string; data?: string; remember?: boolean; + url?: ExtensionPageUrls; }; type ContentMessageWindowEventParams = { data: ContentMessageWindowData; diff --git a/apps/browser/src/autofill/content/content-message-handler.ts b/apps/browser/src/autofill/content/content-message-handler.ts index 60f093f8c10..c57b2d959f3 100644 --- a/apps/browser/src/autofill/content/content-message-handler.ts +++ b/apps/browser/src/autofill/content/content-message-handler.ts @@ -1,3 +1,4 @@ +import { ExtensionPageUrls } from "@bitwarden/common/vault/enums"; import { VaultMessages } from "@bitwarden/common/vault/enums/vault-messages.enum"; import { @@ -18,6 +19,8 @@ const windowMessageHandlers: ContentMessageWindowEventHandlers = { duoResult: ({ data, referrer }: { data: any; referrer: string }) => handleDuoResultMessage(data, referrer), [VaultMessages.OpenAtRiskPasswords]: () => handleOpenAtRiskPasswordsMessage(), + [VaultMessages.OpenBrowserExtensionToUrl]: ({ data }) => + handleOpenBrowserExtensionToUrlMessage(data), }; /** @@ -73,10 +76,15 @@ function handleWebAuthnResultMessage(data: ContentMessageWindowData, referrer: s sendExtensionRuntimeMessage({ command, data: data.data, remember, referrer }); } +/** @deprecated use {@link handleOpenBrowserExtensionToUrlMessage} */ function handleOpenAtRiskPasswordsMessage() { sendExtensionRuntimeMessage({ command: VaultMessages.OpenAtRiskPasswords }); } +function handleOpenBrowserExtensionToUrlMessage({ url }: { url?: ExtensionPageUrls }) { + sendExtensionRuntimeMessage({ command: VaultMessages.OpenBrowserExtensionToUrl, url }); +} + /** * Handles the window message event. * diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 2f423895f9f..c6d68a9f047 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -191,6 +191,7 @@ import { InternalFolderService as InternalFolderServiceAbstraction } from "@bitw import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/vault/abstractions/search.service"; import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/vault/abstractions/totp.service"; import { VaultSettingsService as VaultSettingsServiceAbstraction } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service"; +import { ExtensionPageUrls } from "@bitwarden/common/vault/enums"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { DefaultEndUserNotificationService, @@ -1694,14 +1695,44 @@ export default class MainBackground { // Set route of the popup before attempting to open it. // If the vault is locked, this won't have an effect as the auth guards will // redirect the user to the login page. - await browserAction.setPopup({ popup: "popup/index.html#/at-risk-passwords" }); + await browserAction.setPopup({ popup: ExtensionPageUrls.AtRiskPasswords }); await this.openPopup(); } finally { // Reset the popup route to the default route so any subsequent // popup openings will not open to the at-risk-passwords page. await browserAction.setPopup({ - popup: "popup/index.html#/", + popup: ExtensionPageUrls.Index, + }); + } + } + + /** + * Opens the popup to the given page + * @default ExtensionPageUrls.Index + */ + async openTheExtensionToPage(url: ExtensionPageUrls = ExtensionPageUrls.Index) { + const isValidUrl = Object.values(ExtensionPageUrls).includes(url); + + // If a non-defined URL is provided, return early. + if (!isValidUrl) { + return; + } + + const browserAction = BrowserApi.getBrowserAction(); + + try { + // Set route of the popup before attempting to open it. + // If the vault is locked, this won't have an effect as the auth guards will + // redirect the user to the login page. + await browserAction.setPopup({ popup: url }); + + await this.openPopup(); + } finally { + // Reset the popup route to the default route so any subsequent + // popup openings will not open to the at-risk-passwords page. + await browserAction.setPopup({ + popup: ExtensionPageUrls.Index, }); } } diff --git a/apps/browser/src/background/runtime.background.ts b/apps/browser/src/background/runtime.background.ts index cca17730a22..54fb8326cfb 100644 --- a/apps/browser/src/background/runtime.background.ts +++ b/apps/browser/src/background/runtime.background.ts @@ -296,6 +296,10 @@ export default class RuntimeBackground { await this.main.openAtRisksPasswordsPage(); this.announcePopupOpen(); break; + case VaultMessages.OpenBrowserExtensionToUrl: + await this.main.openTheExtensionToPage(msg.url); + this.announcePopupOpen(); + break; case "bgUpdateContextMenu": case "editedCipher": case "addedCipher": diff --git a/apps/web/src/app/vault/services/web-browser-interaction.service.spec.ts b/apps/web/src/app/vault/services/web-browser-interaction.service.spec.ts new file mode 100644 index 00000000000..68a9ca6d099 --- /dev/null +++ b/apps/web/src/app/vault/services/web-browser-interaction.service.spec.ts @@ -0,0 +1,111 @@ +import { fakeAsync, TestBed, tick } from "@angular/core/testing"; + +import { ExtensionPageUrls } from "@bitwarden/common/vault/enums"; +import { VaultMessages } from "@bitwarden/common/vault/enums/vault-messages.enum"; + +import { WebBrowserInteractionService } from "./web-browser-interaction.service"; + +describe("WebBrowserInteractionService", () => { + let service: WebBrowserInteractionService; + const postMessage = jest.fn(); + window.postMessage = postMessage; + + const dispatchEvent = (command: string) => { + window.dispatchEvent(new MessageEvent("message", { data: { command } })); + }; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [WebBrowserInteractionService], + }); + + postMessage.mockClear(); + + service = TestBed.inject(WebBrowserInteractionService); + }); + + describe("extensionInstalled$", () => { + it("posts a message to check for the extension", () => { + service.extensionInstalled$.subscribe(); + + expect(postMessage).toHaveBeenCalledWith({ + command: VaultMessages.checkBwInstalled, + }); + }); + + it("returns false after the timeout", fakeAsync(() => { + service.extensionInstalled$.subscribe((installed) => { + expect(installed).toBe(false); + }); + + tick(1500); + })); + + it("returns true when the extension is installed", (done) => { + service.extensionInstalled$.subscribe((installed) => { + expect(installed).toBe(true); + done(); + }); + + dispatchEvent(VaultMessages.HasBwInstalled); + }); + + it("continues to listen for extension state changes after the first response", fakeAsync(() => { + const results: boolean[] = []; + + service.extensionInstalled$.subscribe((installed) => { + results.push(installed); + }); + + // initial timeout, should emit false + tick(1500); + expect(results[0]).toBe(false); + + // then emit `HasBwInstalled` + dispatchEvent(VaultMessages.HasBwInstalled); + tick(); + expect(results[1]).toBe(true); + })); + }); + + describe("openExtension", () => { + it("posts a message to open the extension", fakeAsync(() => { + service.openExtension().catch(() => {}); + + expect(postMessage).toHaveBeenCalledWith({ + command: VaultMessages.OpenBrowserExtensionToUrl, + }); + + tick(1500); + })); + + it("posts a message with the passed page", fakeAsync(() => { + service.openExtension(ExtensionPageUrls.Index).catch(() => {}); + + expect(postMessage).toHaveBeenCalledWith({ + command: VaultMessages.OpenBrowserExtensionToUrl, + url: ExtensionPageUrls.Index, + }); + + tick(1500); + })); + + it("resolves when the extension opens", async () => { + const openExtensionPromise = service.openExtension().catch(() => { + fail(); + }); + + dispatchEvent(VaultMessages.PopupOpened); + + await openExtensionPromise; + }); + + it("rejects if the extension does not open within the timeout", fakeAsync(() => { + service.openExtension().catch((error) => { + expect(error).toBe("Failed to open the extension"); + }); + + tick(1500); + })); + }); +}); diff --git a/apps/web/src/app/vault/services/web-browser-interaction.service.ts b/apps/web/src/app/vault/services/web-browser-interaction.service.ts new file mode 100644 index 00000000000..46c566140e4 --- /dev/null +++ b/apps/web/src/app/vault/services/web-browser-interaction.service.ts @@ -0,0 +1,76 @@ +import { DestroyRef, inject, Injectable } from "@angular/core"; +import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; +import { concatWith, filter, fromEvent, map, Observable, race, take, tap, timer } from "rxjs"; + +import { ExtensionPageUrls } from "@bitwarden/common/vault/enums"; +import { VaultMessages } from "@bitwarden/common/vault/enums/vault-messages.enum"; + +/** + * The amount of time in milliseconds to wait for a response from the browser extension. + * NOTE: This value isn't computed by any means, it is just a reasonable timeout for the extension to respond. + */ +const MESSAGE_RESPONSE_TIMEOUT_MS = 1500; + +@Injectable({ + providedIn: "root", +}) +export class WebBrowserInteractionService { + destroyRef = inject(DestroyRef); + + private messages$ = fromEvent(window, "message").pipe( + takeUntilDestroyed(this.destroyRef), + ); + + /** Emits the installation status of the extension. */ + extensionInstalled$ = this.checkForExtension().pipe( + concatWith( + this.messages$.pipe( + filter((event) => event.data.command === VaultMessages.HasBwInstalled), + map(() => true), + ), + ), + ); + + /** Attempts to open the extension, rejects if the extension is not installed or it fails to open. */ + openExtension = (url?: ExtensionPageUrls) => { + return new Promise((resolve, reject) => { + race( + this.messages$.pipe( + filter((event) => event.data.command === VaultMessages.PopupOpened), + map(() => true), + ), + timer(MESSAGE_RESPONSE_TIMEOUT_MS).pipe(map(() => false)), + ) + .pipe(take(1)) + .subscribe((didOpen) => { + if (!didOpen) { + return reject("Failed to open the extension"); + } + + resolve(); + }); + + window.postMessage({ command: VaultMessages.OpenBrowserExtensionToUrl, url }); + }); + }; + + /** Sends a message via the window object to check if the extension is installed */ + private checkForExtension(): Observable { + const checkForExtension$ = race( + this.messages$.pipe( + filter((event) => event.data.command === VaultMessages.HasBwInstalled), + map(() => true), + ), + timer(MESSAGE_RESPONSE_TIMEOUT_MS).pipe(map(() => false)), + ).pipe( + tap({ + subscribe: () => { + window.postMessage({ command: VaultMessages.checkBwInstalled }); + }, + }), + take(1), + ); + + return checkForExtension$; + } +} diff --git a/libs/common/src/vault/enums/extension-page-urls.enum.ts b/libs/common/src/vault/enums/extension-page-urls.enum.ts new file mode 100644 index 00000000000..95f9e0a21df --- /dev/null +++ b/libs/common/src/vault/enums/extension-page-urls.enum.ts @@ -0,0 +1,12 @@ +import { UnionOfValues } from "../types/union-of-values"; + +/** + * Available pages within the extension by their URL. + * Useful when opening a specific page within the popup. + */ +export const ExtensionPageUrls: Record = { + Index: "popup/index.html#/", + AtRiskPasswords: "popup/index.html#/at-risk-passwords", +} as const; + +export type ExtensionPageUrls = UnionOfValues; diff --git a/libs/common/src/vault/enums/index.ts b/libs/common/src/vault/enums/index.ts index d7d1d06d2b9..c996a14a81a 100644 --- a/libs/common/src/vault/enums/index.ts +++ b/libs/common/src/vault/enums/index.ts @@ -3,3 +3,4 @@ export * from "./cipher-type"; export * from "./field-type.enum"; export * from "./linked-id-type.enum"; export * from "./secure-note-type.enum"; +export * from "./extension-page-urls.enum"; diff --git a/libs/common/src/vault/enums/vault-messages.enum.ts b/libs/common/src/vault/enums/vault-messages.enum.ts index 73272564432..fe76cd72427 100644 --- a/libs/common/src/vault/enums/vault-messages.enum.ts +++ b/libs/common/src/vault/enums/vault-messages.enum.ts @@ -1,7 +1,9 @@ const VaultMessages = { HasBwInstalled: "hasBwInstalled", checkBwInstalled: "checkIfBWExtensionInstalled", + /** @deprecated use {@link OpenBrowserExtensionToUrl} */ OpenAtRiskPasswords: "openAtRiskPasswords", + OpenBrowserExtensionToUrl: "openBrowserExtensionToUrl", PopupOpened: "popupOpened", } as const; From 64f8073fdf443147b728454ea8beaddace27b8de Mon Sep 17 00:00:00 2001 From: Jared McCannon Date: Fri, 27 Jun 2025 14:13:21 -0400 Subject: [PATCH 007/239] Removed feature flag for OptimizeNestedTraverseTypescript and vnext methods related to it. (#15314) --- .../collections/utils/collection-utils.ts | 25 -------- .../collections/vault.component.ts | 19 ++---- .../vault/individual-vault/vault.component.ts | 13 +--- libs/common/src/enums/feature-flag.enum.ts | 2 - libs/common/src/vault/service-utils.spec.ts | 18 ------ libs/common/src/vault/service-utils.ts | 64 +------------------ 6 files changed, 9 insertions(+), 132 deletions(-) diff --git a/apps/web/src/app/admin-console/organizations/collections/utils/collection-utils.ts b/apps/web/src/app/admin-console/organizations/collections/utils/collection-utils.ts index f19c3f64530..95ae911bbf6 100644 --- a/apps/web/src/app/admin-console/organizations/collections/utils/collection-utils.ts +++ b/apps/web/src/app/admin-console/organizations/collections/utils/collection-utils.ts @@ -37,31 +37,6 @@ export function getNestedCollectionTree( return nodes; } -export function getNestedCollectionTree_vNext( - collections: (CollectionView | CollectionAdminView)[], -): TreeNode[] { - if (!collections) { - return []; - } - - // Collections need to be cloned because ServiceUtils.nestedTraverse actively - // modifies the names of collections. - // These changes risk affecting collections store in StateService. - const clonedCollections = collections - .sort((a, b) => a.name.localeCompare(b.name)) - .map(cloneCollection); - - const nodes: TreeNode[] = []; - clonedCollections.forEach((collection) => { - const parts = - collection.name != null - ? collection.name.replace(/^\/+|\/+$/g, "").split(NestingDelimiter) - : []; - ServiceUtils.nestedTraverse_vNext(nodes, 0, parts, collection, null, NestingDelimiter); - }); - return nodes; -} - export function getFlatCollectionTree( nodes: TreeNode[], ): CollectionAdminView[]; diff --git a/apps/web/src/app/admin-console/organizations/collections/vault.component.ts b/apps/web/src/app/admin-console/organizations/collections/vault.component.ts index 8ad0f6cf499..5846209e4c6 100644 --- a/apps/web/src/app/admin-console/organizations/collections/vault.component.ts +++ b/apps/web/src/app/admin-console/organizations/collections/vault.component.ts @@ -125,11 +125,7 @@ import { BulkCollectionsDialogResult, } from "./bulk-collections-dialog"; import { CollectionAccessRestrictedComponent } from "./collection-access-restricted.component"; -import { - getNestedCollectionTree, - getFlatCollectionTree, - getNestedCollectionTree_vNext, -} from "./utils"; +import { getNestedCollectionTree, getFlatCollectionTree } from "./utils"; import { VaultFilterModule } from "./vault-filter/vault-filter.module"; import { VaultHeaderComponent } from "./vault-header/vault-header.component"; @@ -423,16 +419,9 @@ export class VaultComponent implements OnInit, OnDestroy { }), ); - const nestedCollections$ = combineLatest([ - allCollections$, - this.configService.getFeatureFlag$(FeatureFlag.OptimizeNestedTraverseTypescript), - ]).pipe( - map( - ([collections, shouldOptimize]) => - (shouldOptimize - ? getNestedCollectionTree_vNext(collections) - : getNestedCollectionTree(collections)) as TreeNode[], - ), + const nestedCollections$ = allCollections$.pipe( + map((collections) => getNestedCollectionTree(collections)), + shareReplay({ refCount: true, bufferSize: 1 }), ); const collections$ = combineLatest([ diff --git a/apps/web/src/app/vault/individual-vault/vault.component.ts b/apps/web/src/app/vault/individual-vault/vault.component.ts index 51d59b54369..52c4bcef01b 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault.component.ts @@ -48,7 +48,6 @@ import { OrganizationBillingServiceAbstraction } from "@bitwarden/common/billing import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction"; import { EventType } from "@bitwarden/common/enums"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -85,7 +84,6 @@ import { import { getNestedCollectionTree, getFlatCollectionTree, - getNestedCollectionTree_vNext, } from "../../admin-console/organizations/collections"; import { CollectionDialogAction, @@ -331,15 +329,8 @@ export class VaultComponent implements OnInit, OnDestroy { const filter$ = this.routedVaultFilterService.filter$; const allCollections$ = this.collectionService.decryptedCollections$; - const nestedCollections$ = combineLatest([ - allCollections$, - this.configService.getFeatureFlag$(FeatureFlag.OptimizeNestedTraverseTypescript), - ]).pipe( - map(([collections, shouldOptimize]) => - shouldOptimize - ? getNestedCollectionTree_vNext(collections) - : getNestedCollectionTree(collections), - ), + const nestedCollections$ = allCollections$.pipe( + map((collections) => getNestedCollectionTree(collections)), ); this.searchText$ diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index 8322dba03c6..55c96c2334c 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -12,7 +12,6 @@ import { ServerConfig } from "../platform/abstractions/config/server-config"; export enum FeatureFlag { /* Admin Console Team */ SeparateCustomRolePermissions = "pm-19917-separate-custom-role-permissions", - OptimizeNestedTraverseTypescript = "pm-21695-optimize-nested-traverse-typescript", CreateDefaultLocation = "pm-19467-create-default-location", /* Auth */ @@ -77,7 +76,6 @@ const FALSE = false as boolean; export const DefaultFeatureFlagValue = { /* Admin Console Team */ [FeatureFlag.SeparateCustomRolePermissions]: FALSE, - [FeatureFlag.OptimizeNestedTraverseTypescript]: FALSE, [FeatureFlag.CreateDefaultLocation]: FALSE, /* Autofill */ diff --git a/libs/common/src/vault/service-utils.spec.ts b/libs/common/src/vault/service-utils.spec.ts index 619d3d72ee6..db414da76d7 100644 --- a/libs/common/src/vault/service-utils.spec.ts +++ b/libs/common/src/vault/service-utils.spec.ts @@ -36,24 +36,6 @@ describe("serviceUtils", () => { }); }); - describe("nestedTraverse_vNext", () => { - it("should traverse a tree and add a node at the correct position given a valid path", () => { - const nodeToBeAdded: FakeObject = { id: "1.2.1", name: "1.2.1" }; - const path = ["1", "1.2", "1.2.1"]; - - ServiceUtils.nestedTraverse_vNext(nodeTree, 0, path, nodeToBeAdded, null, "/"); - expect(nodeTree[0].children[1].children[0].node).toEqual(nodeToBeAdded); - }); - - it("should combine the path for missing nodes and use as the added node name given an invalid path", () => { - const nodeToBeAdded: FakeObject = { id: "blank", name: "blank" }; - const path = ["3", "3.1", "3.1.1"]; - - ServiceUtils.nestedTraverse_vNext(nodeTree, 0, path, nodeToBeAdded, null, "/"); - expect(nodeTree[2].children[0].node.name).toEqual("3.1/3.1.1"); - }); - }); - describe("getTreeNodeObject", () => { it("should return a matching node given a single tree branch and a valid id", () => { const id = "1.1.1"; diff --git a/libs/common/src/vault/service-utils.ts b/libs/common/src/vault/service-utils.ts index 9595434223f..0d863e6ad0b 100644 --- a/libs/common/src/vault/service-utils.ts +++ b/libs/common/src/vault/service-utils.ts @@ -4,64 +4,6 @@ import { ITreeNodeObject, TreeNode } from "./models/domain/tree-node"; export class ServiceUtils { - static nestedTraverse( - nodeTree: TreeNode[], - partIndex: number, - parts: string[], - obj: ITreeNodeObject, - parent: TreeNode | undefined, - delimiter: string, - ) { - if (parts.length <= partIndex) { - return; - } - - const end: boolean = partIndex === parts.length - 1; - const partName: string = parts[partIndex]; - - for (let i = 0; i < nodeTree.length; i++) { - if (nodeTree[i].node.name !== partName) { - continue; - } - if (end && nodeTree[i].node.id !== obj.id) { - // Another node exists with the same name as the node being added - nodeTree.push(new TreeNode(obj, parent, partName)); - return; - } - // Move down the tree to the next level - ServiceUtils.nestedTraverse( - nodeTree[i].children, - partIndex + 1, - parts, - obj, - nodeTree[i], - delimiter, - ); - return; - } - - // If there's no node here with the same name... - if (nodeTree.filter((n) => n.node.name === partName).length === 0) { - // And we're at the end of the path given, add the node - if (end) { - nodeTree.push(new TreeNode(obj, parent, partName)); - return; - } - // And we're not at the end of the path, combine the current name with the next name - // 1, *1.2, 1.2.1 becomes - // 1, *1.2/1.2.1 - const newPartName = partName + delimiter + parts[partIndex + 1]; - ServiceUtils.nestedTraverse( - nodeTree, - 0, - [newPartName, ...parts.slice(partIndex + 2)], - obj, - parent, - delimiter, - ); - } - } - /** * Recursively adds a node to nodeTree * @param {TreeNode[]} nodeTree - An array of TreeNodes that the node will be added to @@ -71,7 +13,7 @@ export class ServiceUtils { * @param {ITreeNodeObject} parent - The parent node of the `obj` node * @param {string} delimiter - The delimiter used to split the path string, will be used to combine the path for missing nodes */ - static nestedTraverse_vNext( + static nestedTraverse( nodeTree: TreeNode[], partIndex: number, parts: string[], @@ -104,7 +46,7 @@ export class ServiceUtils { // 1, *1.2, 1.2.1 becomes // 1, *1.2/1.2.1 const newPartName = partName + delimiter + parts[partIndex + 1]; - ServiceUtils.nestedTraverse_vNext( + ServiceUtils.nestedTraverse( nodeTree, 0, [newPartName, ...parts.slice(partIndex + 2)], @@ -114,7 +56,7 @@ export class ServiceUtils { ); } else { // There is a node here with the same name, descend into it - ServiceUtils.nestedTraverse_vNext( + ServiceUtils.nestedTraverse( matchingNodes[0].children, partIndex + 1, parts, From 7500fe32bbcfaf7d1155b626c0dadf1f61b53a83 Mon Sep 17 00:00:00 2001 From: rr-bw <102181210+rr-bw@users.noreply.github.com> Date: Fri, 27 Jun 2025 11:19:13 -0700 Subject: [PATCH 008/239] fix(auth-guard): [PM-22822] fix infinite redirect loop (#15371) --- libs/angular/src/auth/guards/auth.guard.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/angular/src/auth/guards/auth.guard.ts b/libs/angular/src/auth/guards/auth.guard.ts index a172c45d6f9..cf4f9dc2034 100644 --- a/libs/angular/src/auth/guards/auth.guard.ts +++ b/libs/angular/src/auth/guards/auth.guard.ts @@ -100,10 +100,10 @@ export const authGuard: CanActivateFn = async ( // Post- Account Recovery or Weak Password on login if ( - forceSetPasswordReason === ForceSetPasswordReason.AdminForcePasswordReset || - (forceSetPasswordReason === ForceSetPasswordReason.WeakMasterPassword && - !routerState.url.includes("update-temp-password") && - !routerState.url.includes("change-password")) + (forceSetPasswordReason === ForceSetPasswordReason.AdminForcePasswordReset || + forceSetPasswordReason === ForceSetPasswordReason.WeakMasterPassword) && + !routerState.url.includes("update-temp-password") && + !routerState.url.includes("change-password") ) { const route = isChangePasswordFlagOn ? "/change-password" : "/update-temp-password"; return router.createUrlTree([route]); From 780ce6a762e5d90a4282354e07222a712086d6c9 Mon Sep 17 00:00:00 2001 From: Colton Hurst Date: Fri, 27 Jun 2025 14:45:39 -0400 Subject: [PATCH 009/239] Add comment to desktop-settings.service.ts based on direction from platform (#15373) --- .../src/platform/services/desktop-settings.service.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/desktop/src/platform/services/desktop-settings.service.ts b/apps/desktop/src/platform/services/desktop-settings.service.ts index e8f311e56f6..c11f10646d7 100644 --- a/apps/desktop/src/platform/services/desktop-settings.service.ts +++ b/apps/desktop/src/platform/services/desktop-settings.service.ts @@ -1,3 +1,13 @@ +/* + -- Note -- + + As of June 2025, settings should only be added here if they are owned + by the platform team. Other settings should be added to the relevant service + owned by the team that owns the setting. + + More info: https://bitwarden.atlassian.net/browse/PM-23126 +*/ + import { Observable, map } from "rxjs"; import { From 029713fe28f2825c8f85e300c7661f16d2c1c3ea Mon Sep 17 00:00:00 2001 From: tangowithfoxtrot <5676771+tangowithfoxtrot@users.noreply.github.com> Date: Fri, 27 Jun 2025 12:22:49 -0700 Subject: [PATCH 010/239] allow disabling hardware acceleration with env var (#14768) --- apps/desktop/src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index 7d97805e9be..4821b018148 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -394,7 +394,7 @@ export class Main { this.desktopSettingsService.hardwareAcceleration$, ); - if (!hardwareAcceleration) { + if (!hardwareAcceleration || process.env.ELECTRON_DISABLE_GPU) { this.logService.warning("Hardware acceleration is disabled"); app.disableHardwareAcceleration(); } else if (isMacAppStore()) { From 7a1bb81c5f562094d589d09267e589d397199a74 Mon Sep 17 00:00:00 2001 From: Jason Ng Date: Fri, 27 Jun 2025 15:49:49 -0400 Subject: [PATCH 011/239] [PM-21719] update desktop to address personal items who cant assign to collections (#15369) --- apps/desktop/src/vault/app/vault/vault-v2.component.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/desktop/src/vault/app/vault/vault-v2.component.ts b/apps/desktop/src/vault/app/vault/vault-v2.component.ts index 849899bfe66..1248f32d1ac 100644 --- a/apps/desktop/src/vault/app/vault/vault-v2.component.ts +++ b/apps/desktop/src/vault/app/vault/vault-v2.component.ts @@ -482,7 +482,9 @@ export class VaultV2Component implements OnInit, OnDestroy, CopyClickListener { }); } - if (cipher.canAssignToCollections) { + const hasEditableCollections = this.allCollections.some((collection) => !collection.readOnly); + + if (cipher.canAssignToCollections && hasEditableCollections) { menu.push({ label: this.i18nService.t("assignToCollections"), click: () => From 700f54357c1212aac620916f6578e8838a08dfa6 Mon Sep 17 00:00:00 2001 From: Nick Krantz <125900171+nick-livefront@users.noreply.github.com> Date: Fri, 27 Jun 2025 16:04:51 -0500 Subject: [PATCH 012/239] [PM-20041] Marking Task as complete (#14980) * When saving a cipher, mark any associated security tasks as complete * fix test error from encryption refactor * hide security tasks that are associated with deleted ciphers (#15247) * account for deleted ciphers for atRiskPasswordDescriptions --- .../at-risk-password-callout.component.ts | 23 ++- .../at-risk-passwords.component.spec.ts | 27 +++ .../at-risk-passwords.component.ts | 17 +- .../default-cipher-form.service.spec.ts | 161 ++++++++++++++++++ .../services/default-cipher-form.service.ts | 51 +++++- 5 files changed, 268 insertions(+), 11 deletions(-) create mode 100644 libs/vault/src/cipher-form/services/default-cipher-form.service.spec.ts diff --git a/apps/browser/src/vault/popup/components/at-risk-callout/at-risk-password-callout.component.ts b/apps/browser/src/vault/popup/components/at-risk-callout/at-risk-password-callout.component.ts index 18482706272..3c3270e557c 100644 --- a/apps/browser/src/vault/popup/components/at-risk-callout/at-risk-password-callout.component.ts +++ b/apps/browser/src/vault/popup/components/at-risk-callout/at-risk-password-callout.component.ts @@ -1,10 +1,11 @@ import { CommonModule } from "@angular/common"; import { Component, inject } from "@angular/core"; import { RouterModule } from "@angular/router"; -import { map, switchMap } from "rxjs"; +import { combineLatest, map, switchMap } from "rxjs"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; +import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { SecurityTaskType, TaskService } from "@bitwarden/common/vault/tasks"; import { AnchorLinkDirective, CalloutModule } from "@bitwarden/components"; import { I18nPipe } from "@bitwarden/ui-common"; @@ -16,10 +17,26 @@ import { I18nPipe } from "@bitwarden/ui-common"; }) export class AtRiskPasswordCalloutComponent { private taskService = inject(TaskService); + private cipherService = inject(CipherService); private activeAccount$ = inject(AccountService).activeAccount$.pipe(getUserId); protected pendingTasks$ = this.activeAccount$.pipe( - switchMap((userId) => this.taskService.pendingTasks$(userId)), - map((tasks) => tasks.filter((t) => t.type === SecurityTaskType.UpdateAtRiskCredential)), + switchMap((userId) => + combineLatest([ + this.taskService.pendingTasks$(userId), + this.cipherService.cipherViews$(userId), + ]), + ), + map(([tasks, ciphers]) => + tasks.filter((t) => { + const associatedCipher = ciphers.find((c) => c.id === t.cipherId); + + return ( + t.type === SecurityTaskType.UpdateAtRiskCredential && + associatedCipher && + !associatedCipher.isDeleted + ); + }), + ), ); } diff --git a/apps/browser/src/vault/popup/components/at-risk-passwords/at-risk-passwords.component.spec.ts b/apps/browser/src/vault/popup/components/at-risk-passwords/at-risk-passwords.component.spec.ts index dae00ba6c2b..eaa10aba624 100644 --- a/apps/browser/src/vault/popup/components/at-risk-passwords/at-risk-passwords.component.spec.ts +++ b/apps/browser/src/vault/popup/components/at-risk-passwords/at-risk-passwords.component.spec.ts @@ -203,6 +203,20 @@ describe("AtRiskPasswordsComponent", () => { expect(items).toHaveLength(1); expect(items[0].name).toBe("Item 1"); }); + + it("should not show tasks associated with deleted ciphers", async () => { + mockCiphers$.next([ + { + id: "cipher", + organizationId: "org", + name: "Item 1", + isDeleted: true, + } as CipherView, + ]); + + const items = await firstValueFrom(component["atRiskItems$"]); + expect(items).toHaveLength(0); + }); }); describe("pageDescription$", () => { @@ -245,6 +259,19 @@ describe("AtRiskPasswordsComponent", () => { type: SecurityTaskType.UpdateAtRiskCredential, } as SecurityTask, ]); + mockCiphers$.next([ + { + id: "cipher", + organizationId: "org", + name: "Item 1", + } as CipherView, + { + id: "cipher2", + organizationId: "org2", + name: "Item 2", + } as CipherView, + ]); + const description = await firstValueFrom(component["pageDescription$"]); expect(description).toBe("atRiskPasswordsDescMultiOrgPlural"); }); diff --git a/apps/browser/src/vault/popup/components/at-risk-passwords/at-risk-passwords.component.ts b/apps/browser/src/vault/popup/components/at-risk-passwords/at-risk-passwords.component.ts index dc6712aa23f..1bfb65a15cc 100644 --- a/apps/browser/src/vault/popup/components/at-risk-passwords/at-risk-passwords.component.ts +++ b/apps/browser/src/vault/popup/components/at-risk-passwords/at-risk-passwords.component.ts @@ -155,32 +155,35 @@ export class AtRiskPasswordsComponent implements OnInit { (t) => t.type === SecurityTaskType.UpdateAtRiskCredential && t.cipherId != null && - ciphers[t.cipherId] != null, + ciphers[t.cipherId] != null && + !ciphers[t.cipherId].isDeleted, ) .map((t) => ciphers[t.cipherId!]), ), ); - protected pageDescription$ = this.activeUserData$.pipe( - switchMap(({ tasks, userId }) => { - const orgIds = new Set(tasks.map((t) => t.organizationId)); + protected pageDescription$ = combineLatest([this.activeUserData$, this.atRiskItems$]).pipe( + switchMap(([{ userId }, atRiskCiphers]) => { + const orgIds = new Set( + atRiskCiphers.filter((c) => c.organizationId).map((c) => c.organizationId), + ) as Set; if (orgIds.size === 1) { const [orgId] = orgIds; return this.organizationService.organizations$(userId).pipe( getOrganizationById(orgId), map((org) => this.i18nService.t( - tasks.length === 1 + atRiskCiphers.length === 1 ? "atRiskPasswordDescSingleOrg" : "atRiskPasswordsDescSingleOrgPlural", org?.name, - tasks.length, + atRiskCiphers.length, ), ), ); } - return of(this.i18nService.t("atRiskPasswordsDescMultiOrgPlural", tasks.length)); + return of(this.i18nService.t("atRiskPasswordsDescMultiOrgPlural", atRiskCiphers.length)); }), ); diff --git a/libs/vault/src/cipher-form/services/default-cipher-form.service.spec.ts b/libs/vault/src/cipher-form/services/default-cipher-form.service.spec.ts new file mode 100644 index 00000000000..3b2573b8f94 --- /dev/null +++ b/libs/vault/src/cipher-form/services/default-cipher-form.service.spec.ts @@ -0,0 +1,161 @@ +import { TestBed } from "@angular/core/testing"; +import { mock } from "jest-mock-extended"; +import { of } from "rxjs"; + +import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { UserId } from "@bitwarden/common/types/guid"; +import { + CipherService, + EncryptionContext, +} from "@bitwarden/common/vault/abstractions/cipher.service"; +import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; +import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { LoginView } from "@bitwarden/common/vault/models/view/login.view"; +import { SecurityTaskType, TaskService } from "@bitwarden/common/vault/tasks"; +import { CipherType } from "@bitwarden/sdk-internal"; + +import { CipherFormConfig } from "../abstractions/cipher-form-config.service"; + +import { DefaultCipherFormService } from "./default-cipher-form.service"; + +describe("DefaultCipherFormService", () => { + let service: DefaultCipherFormService; + let testBed: TestBed; + const cipherServiceMock = mock(); + + let markAsCompleteMock: jest.Mock; + let pendingTasks$: jest.Mock; + + beforeEach(() => { + markAsCompleteMock = jest.fn().mockResolvedValue(undefined); + pendingTasks$ = jest.fn().mockReturnValue(of([])); + cipherServiceMock.encrypt.mockResolvedValue({} as EncryptionContext); + + testBed = TestBed.configureTestingModule({ + providers: [ + { provide: CipherService, useValue: cipherServiceMock }, + { provide: TaskService, useValue: { markAsComplete: markAsCompleteMock, pendingTasks$ } }, + { + provide: AccountService, + useValue: { activeAccount$: of({ id: "user-1" as UserId } as Account) }, + }, + DefaultCipherFormService, + ], + }); + + service = testBed.inject(DefaultCipherFormService); + }); + + describe("markAssociatedTaskAsComplete", () => { + it("does not call markAsComplete when the cipher is not a login", async () => { + pendingTasks$.mockReturnValueOnce( + of([ + { + type: SecurityTaskType.UpdateAtRiskCredential, + cipherId: "cipher-1", + userId: "user-1" as UserId, + }, + ]), + ); + + const cardCipher = new CipherView(); + cardCipher.type = CipherType.Card; + cardCipher.id = "cipher-1"; + + await service.saveCipher(cardCipher, { + originalCipher: new Cipher(), + admin: false, + } as CipherFormConfig); + + expect(markAsCompleteMock).not.toHaveBeenCalled(); + }); + + it("does not call markAsComplete when there is no associated credential tasks", async () => { + pendingTasks$.mockReturnValueOnce(of([])); + + const originalCipher = new Cipher(); + originalCipher.type = CipherType.Login; + + const cipher = new CipherView(); + cipher.type = CipherType.Login; + cipher.id = "cipher-1"; + cipher.login = new LoginView(); + cipher.login.password = "password123"; + + cipherServiceMock.decrypt.mockResolvedValue({ + ...cipher, + login: { + ...cipher.login, + password: "newPassword123", + }, + } as CipherView); + + await service.saveCipher(cipher, { + originalCipher: originalCipher, + admin: false, + } as CipherFormConfig); + + expect(markAsCompleteMock).not.toHaveBeenCalled(); + }); + + it("does not call markAsComplete when the password has not changed", async () => { + pendingTasks$.mockReturnValueOnce( + of([ + { + type: SecurityTaskType.UpdateAtRiskCredential, + cipherId: "cipher-1", + userId: "user-1" as UserId, + }, + ]), + ); + + const cipher = new CipherView(); + cipher.type = CipherType.Login; + cipher.id = "cipher-1"; + cipher.login = new LoginView(); + cipher.login.password = "password123"; + + cipherServiceMock.decrypt.mockResolvedValue(cipher); + + await service.saveCipher(cipher, { + originalCipher: new Cipher(), + admin: false, + } as CipherFormConfig); + + expect(markAsCompleteMock).not.toHaveBeenCalled(); + }); + + it("calls markAsComplete when the cipher password has changed and there is an associated credential task", async () => { + pendingTasks$.mockReturnValueOnce( + of([ + { + type: SecurityTaskType.UpdateAtRiskCredential, + cipherId: "cipher-1", + userId: "user-1" as UserId, + }, + ]), + ); + + const cipher = new CipherView(); + cipher.type = CipherType.Login; + cipher.id = "cipher-1"; + cipher.login = new LoginView(); + cipher.login.password = "password123"; + + cipherServiceMock.decrypt.mockResolvedValue({ + ...cipher, + login: { + ...cipher.login, + password: "newPassword123", + }, + } as CipherView); + + await service.saveCipher(cipher, { + originalCipher: new Cipher(), + admin: false, + } as CipherFormConfig); + + expect(markAsCompleteMock).toHaveBeenCalled(); + }); + }); +}); diff --git a/libs/vault/src/cipher-form/services/default-cipher-form.service.ts b/libs/vault/src/cipher-form/services/default-cipher-form.service.ts index 99f853d4c86..5228c85c3f7 100644 --- a/libs/vault/src/cipher-form/services/default-cipher-form.service.ts +++ b/libs/vault/src/cipher-form/services/default-cipher-form.service.ts @@ -1,13 +1,16 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore import { inject, Injectable } from "@angular/core"; -import { firstValueFrom } from "rxjs"; +import { firstValueFrom, map } from "rxjs"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; +import { UserId } from "@bitwarden/common/types/guid"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { CipherType } from "@bitwarden/common/vault/enums"; import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { SecurityTaskType, TaskService } from "@bitwarden/common/vault/tasks"; import { CipherFormConfig } from "../abstractions/cipher-form-config.service"; import { CipherFormService } from "../abstractions/cipher-form.service"; @@ -20,6 +23,7 @@ function isSetEqual(a: Set, b: Set) { export class DefaultCipherFormService implements CipherFormService { private cipherService: CipherService = inject(CipherService); private accountService: AccountService = inject(AccountService); + private taskService: TaskService = inject(TaskService); async decryptCipher(cipher: Cipher): Promise { const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)); @@ -89,6 +93,8 @@ export class DefaultCipherFormService implements CipherFormService { } } + await this.markAssociatedTaskAsComplete(activeUserId, cipher, config); + // Its possible the cipher was made no longer available due to collection assignment changes // e.g. The cipher was moved to a collection that the user no longer has access to if (savedCipher == null) { @@ -97,4 +103,47 @@ export class DefaultCipherFormService implements CipherFormService { return await this.cipherService.decrypt(savedCipher, activeUserId); } + + /** + * When a cipher has an associated pending `UpdateAtRiskCredential` task + * and the password has changed, mark the task as complete. + */ + private async markAssociatedTaskAsComplete( + userId: UserId, + updatedCipher: CipherView, + config: CipherFormConfig, + ) { + const decryptedOriginalCipherCipher = await this.cipherService.decrypt( + config.originalCipher, + userId, + ); + + const associatedPendingTask = await firstValueFrom( + this.taskService + .pendingTasks$(userId) + .pipe( + map((tasks) => + tasks.find( + (task) => + task.type === SecurityTaskType.UpdateAtRiskCredential && + task.cipherId === updatedCipher.id, + ), + ), + ), + ); + + const passwordHasChanged = + updatedCipher.type === CipherType.Login && + updatedCipher.login.password && + updatedCipher.login.password !== decryptedOriginalCipherCipher?.login?.password; + + // When there is not an associated pending task or the password has not changed, + // no action needed-return early. + if (!associatedPendingTask || !passwordHasChanged) { + return; + } + + // If the cipher is a login and the password has changed, mark the associated task as complete + await this.taskService.markAsComplete(associatedPendingTask.id, userId); + } } From 031c9bc947672847b6507ac5da0ed7c8009f735b Mon Sep 17 00:00:00 2001 From: rr-bw <102181210+rr-bw@users.noreply.github.com> Date: Fri, 27 Jun 2025 15:24:12 -0700 Subject: [PATCH 013/239] fix(auth-guard): [PM-22822] remove SsoNewJitProvisionedUser case (#15376) --- libs/angular/src/auth/guards/auth.guard.spec.ts | 5 ----- libs/angular/src/auth/guards/auth.guard.ts | 10 ---------- 2 files changed, 15 deletions(-) diff --git a/libs/angular/src/auth/guards/auth.guard.spec.ts b/libs/angular/src/auth/guards/auth.guard.spec.ts index f64d6cf769d..a2e1613c6c1 100644 --- a/libs/angular/src/auth/guards/auth.guard.spec.ts +++ b/libs/angular/src/auth/guards/auth.guard.spec.ts @@ -127,7 +127,6 @@ describe("AuthGuard", () => { describe("given user is Unlocked", () => { describe("given the PM16117_SetInitialPasswordRefactor feature flag is ON", () => { const tests = [ - ForceSetPasswordReason.SsoNewJitProvisionedUser, ForceSetPasswordReason.TdeUserWithoutPasswordHasPasswordResetPermission, ForceSetPasswordReason.TdeOffboarding, ]; @@ -167,10 +166,6 @@ describe("AuthGuard", () => { describe("given the PM16117_SetInitialPasswordRefactor feature flag is OFF", () => { const tests = [ - { - reason: ForceSetPasswordReason.SsoNewJitProvisionedUser, - url: "/set-password-jit", - }, { reason: ForceSetPasswordReason.TdeUserWithoutPasswordHasPasswordResetPermission, url: "/set-password", diff --git a/libs/angular/src/auth/guards/auth.guard.ts b/libs/angular/src/auth/guards/auth.guard.ts index cf4f9dc2034..f99a91fda34 100644 --- a/libs/angular/src/auth/guards/auth.guard.ts +++ b/libs/angular/src/auth/guards/auth.guard.ts @@ -67,16 +67,6 @@ export const authGuard: CanActivateFn = async ( FeatureFlag.PM16117_ChangeExistingPasswordRefactor, ); - // User JIT provisioned into a master-password-encryption org - if ( - forceSetPasswordReason === ForceSetPasswordReason.SsoNewJitProvisionedUser && - !routerState.url.includes("set-password-jit") && - !routerState.url.includes("set-initial-password") - ) { - const route = isSetInitialPasswordFlagOn ? "/set-initial-password" : "/set-password-jit"; - return router.createUrlTree([route]); - } - // TDE org user has "manage account recovery" permission if ( forceSetPasswordReason === From 7646f3e1e7edb54f8bd0dc8a3c6de12287b9df27 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 09:57:52 +0000 Subject: [PATCH 014/239] Autosync the updated translations (#15391) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/desktop/src/locales/az/messages.json | 4 +- apps/desktop/src/locales/ca/messages.json | 2 +- apps/desktop/src/locales/es/messages.json | 36 +++++++-------- apps/desktop/src/locales/ja/messages.json | 56 +++++++++++------------ apps/desktop/src/locales/pl/messages.json | 2 +- 5 files changed, 50 insertions(+), 50 deletions(-) diff --git a/apps/desktop/src/locales/az/messages.json b/apps/desktop/src/locales/az/messages.json index 29022fc9789..e1b46ef3170 100644 --- a/apps/desktop/src/locales/az/messages.json +++ b/apps/desktop/src/locales/az/messages.json @@ -1717,10 +1717,10 @@ "message": "Hesab məhdudlaşdırıldı" }, "restrictCardTypeImport": { - "message": "Cannot import card item types" + "message": "Kart element növləri daxilə köçürülə bilmir" }, "restrictCardTypeImportDesc": { - "message": "A policy set by 1 or more organizations prevents you from importing cards to your vaults." + "message": "1 və ya daha çox təşkilat tərəfindən təyin edilən bir siyasət, kartların seyfinizə köçürülməsini əngəlləyir." }, "filePasswordAndConfirmFilePasswordDoNotMatch": { "message": "\"Fayl parolu\" və \"Fayl parolunu təsdiqlə\" uyuşmur." diff --git a/apps/desktop/src/locales/ca/messages.json b/apps/desktop/src/locales/ca/messages.json index 2ce95c78d47..fda4e073bd0 100644 --- a/apps/desktop/src/locales/ca/messages.json +++ b/apps/desktop/src/locales/ca/messages.json @@ -3746,7 +3746,7 @@ "message": "Nom de la carpeta" }, "folderHintText": { - "message": "Nest a folder by adding the parent folder's name followed by a “/”. Example: Social/Forums" + "message": "Imbriqueu una carpeta afegint el nom de la carpeta principal seguit d'una \"/\". Exemple: Social/Fòrums" }, "sendsTitleNoItems": { "message": "Send sensitive information safely", diff --git a/apps/desktop/src/locales/es/messages.json b/apps/desktop/src/locales/es/messages.json index a14ea40f0b6..78b6502bb29 100644 --- a/apps/desktop/src/locales/es/messages.json +++ b/apps/desktop/src/locales/es/messages.json @@ -226,7 +226,7 @@ "message": "Introducir la contraseña" }, "sshAgentUnlockRequired": { - "message": "Please unlock your vault to approve the SSH key request." + "message": "Por favor, desbloquea tu caja fuerte para aprobar la solicitud de clave SSH." }, "sshAgentUnlockTimeout": { "message": "SSH key request timed out." @@ -1019,7 +1019,7 @@ "message": "URL del servidor" }, "authenticationTimeout": { - "message": "Authentication timeout" + "message": "Tiempo de autenticación agotado" }, "authenticationSessionTimedOut": { "message": "The authentication session timed out. Please restart the login process." @@ -1215,7 +1215,7 @@ "message": "Timeout" }, "vaultTimeoutDesc": { - "message": "Elije cuando se agotará el tiempo de espera de tu caja fuerte y se ejecutará la acción seleccionada." + "message": "Elige cuando se agotará el tiempo de espera de tu caja fuerte y se ejecutará la acción seleccionada." }, "immediately": { "message": "Inmediatamente" @@ -1465,7 +1465,7 @@ "message": "Comprar Premium" }, "premiumPurchaseAlertV2": { - "message": "Puedes comprar el Premium desde la configuración de tu cuenta en la aplicación web de Bitwarden." + "message": "Puedes comprar el Premium desde los ajustes de tu cuenta en la aplicación web de Bitwarden." }, "premiumCurrentMember": { "message": "¡Eres un miembro Premium!" @@ -1588,7 +1588,7 @@ } }, "copySuccessful": { - "message": "Copy Successful" + "message": "Copia Exitosa" }, "errorRefreshingAccessToken": { "message": "Error de actualización del token de acceso" @@ -3176,7 +3176,7 @@ "message": "Falta el correo electrónico del usuario" }, "activeUserEmailNotFoundLoggingYouOut": { - "message": "Active user email not found. Logging you out." + "message": "Correo electrónico del usuario activo no encontrado. Cerrando sesión." }, "deviceTrusted": { "message": "Dispositivo de confianza" @@ -3600,7 +3600,7 @@ "message": "Envío de texto" }, "ssoError": { - "message": "No free ports could be found for the sso login." + "message": "No se encontraron puertos libres para el inicio de sesión sso." }, "securePasswordGenerated": { "message": "¡Contraseña segura generada! No olvides actualizar tu contraseña en el sitio web." @@ -3614,19 +3614,19 @@ "description": "This will be used as part of a larger sentence, broken up to include the generator icon. The full sentence will read 'Use the generator [GENERATOR_ICON] to create a strong unique password'" }, "biometricsStatusHelptextUnlockNeeded": { - "message": "Biometric unlock is unavailable because PIN or password unlock is required first." + "message": "El desbloqueo biométrico no está disponible porque primero es necesario desbloquear con PIN o contraseña." }, "biometricsStatusHelptextHardwareUnavailable": { - "message": "Biometric unlock is currently unavailable." + "message": "El desbloqueo biométrico no está disponible actualmente." }, "biometricsStatusHelptextAutoSetupNeeded": { - "message": "Biometric unlock is unavailable due to misconfigured system files." + "message": "El desbloqueo biométrico no está disponible por archivos del sistema mal configurados." }, "biometricsStatusHelptextManualSetupNeeded": { - "message": "Biometric unlock is unavailable due to misconfigured system files." + "message": "El desbloqueo biométrico no está disponible por archivos del sistema mal configurados." }, "biometricsStatusHelptextNotEnabledLocally": { - "message": "Biometric unlock is unavailable because it is not enabled for $EMAIL$ in the Bitwarden desktop app.", + "message": "El desbloqueo biométrico no está disponible porque no está habilitado para $EMAIL$ en la aplicación de escritorio Bitwarden.", "placeholders": { "email": { "content": "$1", @@ -3635,7 +3635,7 @@ } }, "biometricsStatusHelptextUnavailableReasonUnknown": { - "message": "Biometric unlock is currently unavailable for an unknown reason." + "message": "El desbloqueo biométrico no está disponible actualmente por una razón desconocida." }, "itemDetails": { "message": "Detalles del elemento" @@ -3644,7 +3644,7 @@ "message": "Nombre del elemento" }, "loginCredentials": { - "message": "Login credentials" + "message": "Credenciales de inicio de sesión" }, "additionalOptions": { "message": "Opciones adicionales" @@ -3774,7 +3774,7 @@ "description": "Aria label for the body content of the generator nudge" }, "newLoginNudgeTitle": { - "message": "Ahora tiempo con autocompletado" + "message": "Ahorra tiempo con el autocompletado" }, "newLoginNudgeBodyOne": { "message": "Incluír un", @@ -3856,7 +3856,7 @@ } }, "selectCollectionsToAssign": { - "message": "Select collections to assign" + "message": "Selecciona colecciones para asignar" }, "personalItemsTransferWarning": { "message": "$PERSONAL_ITEMS_COUNT$ serán transferidos permanentemente a la organización seleccionada. Ya no serás el propietario de estos elementos.", @@ -3893,10 +3893,10 @@ } }, "successfullyAssignedCollections": { - "message": "Successfully assigned collections" + "message": "Colecciones asignadas correctamente" }, "nothingSelected": { - "message": "You have not selected anything." + "message": "No has seleccionado nada." }, "itemsMovedToOrg": { "message": "Elementos movidos a $ORGNAME$", diff --git a/apps/desktop/src/locales/ja/messages.json b/apps/desktop/src/locales/ja/messages.json index f4d2123c197..ca07f36eb9e 100644 --- a/apps/desktop/src/locales/ja/messages.json +++ b/apps/desktop/src/locales/ja/messages.json @@ -24,7 +24,7 @@ "message": "ID" }, "typeNote": { - "message": "Note" + "message": "メモ" }, "typeSecureNote": { "message": "セキュアメモ" @@ -241,22 +241,22 @@ "message": "SSH エージェントとは、Bitwarden 保管庫から直接 SSH リクエストに署名できる、開発者を対象としたサービスです。" }, "sshAgentPromptBehavior": { - "message": "Ask for authorization when using SSH agent" + "message": "SSHエージェントを使用する際に認証を要求する" }, "sshAgentPromptBehaviorDesc": { - "message": "Choose how to handle SSH-agent authorization requests." + "message": "SSHエージェント認可リクエストの処理方法を選択します。" }, "sshAgentPromptBehaviorHelp": { - "message": "Remember SSH authorizations" + "message": "SSH認可を記憶する" }, "sshAgentPromptBehaviorAlways": { - "message": "Always" + "message": "常に表示する" }, "sshAgentPromptBehaviorNever": { - "message": "Never" + "message": "表示しない" }, "sshAgentPromptBehaviorRememberUntilLock": { - "message": "Remember until vault is locked" + "message": "保管庫がロックされるまで記憶する" }, "premiumRequired": { "message": "プレミアム会員専用" @@ -409,16 +409,16 @@ "message": "認証キー (TOTP)" }, "authenticatorKey": { - "message": "Authenticator key" + "message": "認証キー" }, "autofillOptions": { - "message": "Autofill options" + "message": "自動入力のオプション" }, "websiteUri": { - "message": "Website (URI)" + "message": "ウェブサイト (URI)" }, "websiteUriCount": { - "message": "Website (URI) $COUNT$", + "message": "ウェブサイト (URI) $COUNT$", "description": "Label for an input field that contains a website URI. The input field is part of a list of fields, and the count indicates the position of the field in the list.", "placeholders": { "count": { @@ -428,49 +428,49 @@ } }, "websiteAdded": { - "message": "Website added" + "message": "ウェブサイトを追加しました" }, "addWebsite": { - "message": "Add website" + "message": "ウェブサイトを追加" }, "deleteWebsite": { - "message": "Delete website" + "message": "ウェブサイトを削除" }, "owner": { - "message": "Owner" + "message": "所有者" }, "addField": { - "message": "Add field" + "message": "フィールドを追加" }, "editField": { - "message": "Edit field" + "message": "フィールドを編集" }, "permanentlyDeleteAttachmentConfirmation": { - "message": "Are you sure you want to permanently delete this attachment?" + "message": "この添付ファイルを完全に削除してもよろしいですか?" }, "fieldType": { - "message": "Field type" + "message": "フィールドの種類" }, "fieldLabel": { - "message": "Field label" + "message": "フィールドのラベル" }, "add": { - "message": "Add" + "message": "追加" }, "textHelpText": { - "message": "Use text fields for data like security questions" + "message": "秘密の質問などのデータには、テキストフィールドを使用します" }, "hiddenHelpText": { - "message": "Use hidden fields for sensitive data like a password" + "message": "パスワードのような機密データには、非表示フィールドを使用します" }, "checkBoxHelpText": { - "message": "Use checkboxes if you'd like to autofill a form's checkbox, like a remember email" + "message": "「メールアドレスを記憶する」などのフォームのチェックボックスを自動入力する場合は、チェックボックスを使用します" }, "linkedHelpText": { - "message": "Use a linked field when you are experiencing autofill issues for a specific website." + "message": "特定のウェブサイトで自動入力の問題が発生している場合は、リンクされたフィールドを使用します。" }, "linkedLabelHelpText": { - "message": "Enter the the field's html id, name, aria-label, or placeholder." + "message": "フィールドの HTML の id、name、aria-label、placeholder を入力します。" }, "folder": { "message": "フォルダー" @@ -498,7 +498,7 @@ "description": "This describes a field that is 'linked' (related) to another field." }, "cfTypeCheckbox": { - "message": "Checkbox" + "message": "チェックボックス" }, "linkedValue": { "message": "リンクされた値", @@ -695,7 +695,7 @@ "message": "最大ファイルサイズは500MBです。" }, "legacyEncryptionUnsupported": { - "message": "Legacy encryption is no longer supported. Please contact support to recover your account." + "message": "従来の暗号化はサポートされていません。アカウントを復元するにはサポートにお問い合わせください。" }, "editedFolder": { "message": "フォルダーを編集しました" diff --git a/apps/desktop/src/locales/pl/messages.json b/apps/desktop/src/locales/pl/messages.json index 0d70760eff8..df90ab92af7 100644 --- a/apps/desktop/src/locales/pl/messages.json +++ b/apps/desktop/src/locales/pl/messages.json @@ -27,7 +27,7 @@ "message": "Note" }, "typeSecureNote": { - "message": "Bezpieczna notatka" + "message": "Notatka" }, "typeSshKey": { "message": "Klucz SSH" From f0a7592036a986c97f1e02af3b0506f66e240dfd Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 09:58:02 +0000 Subject: [PATCH 015/239] Autosync the updated translations (#15390) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/browser/src/_locales/az/messages.json | 6 +- apps/browser/src/_locales/es/messages.json | 102 ++++++++++----------- apps/browser/src/_locales/pl/messages.json | 2 +- 3 files changed, 55 insertions(+), 55 deletions(-) diff --git a/apps/browser/src/_locales/az/messages.json b/apps/browser/src/_locales/az/messages.json index e189b3ba292..ddf82f37d2f 100644 --- a/apps/browser/src/_locales/az/messages.json +++ b/apps/browser/src/_locales/az/messages.json @@ -2488,10 +2488,10 @@ "message": "Bir təşkilat siyasəti, elementlərin fərdi seyfinizə köçürülməsini əngəllədi." }, "restrictCardTypeImport": { - "message": "Cannot import card item types" + "message": "Kart element növləri daxilə köçürülə bilmir" }, "restrictCardTypeImportDesc": { - "message": "A policy set by 1 or more organizations prevents you from importing cards to your vaults." + "message": "1 və ya daha çox təşkilat tərəfindən təyin edilən bir siyasət, kartların seyfinizə köçürülməsini əngəlləyir." }, "domainsTitle": { "message": "Domenlər", @@ -5072,7 +5072,7 @@ "message": "PIN ilə kilid açma təyini" }, "unlockWithBiometricSet": { - "message": "Unlock with biometrics set" + "message": "Kilidi biometriklə aç ayarı" }, "authenticating": { "message": "Kimlik doğrulama" diff --git a/apps/browser/src/_locales/es/messages.json b/apps/browser/src/_locales/es/messages.json index 89d5b928f25..250aa3430e0 100644 --- a/apps/browser/src/_locales/es/messages.json +++ b/apps/browser/src/_locales/es/messages.json @@ -1083,7 +1083,7 @@ "message": "Nueva notificación" }, "labelWithNotification": { - "message": "$LABEL$: New notification", + "message": "$LABEL$: Nueva notificación", "description": "Label for the notification with a new login suggestion.", "placeholders": { "label": { @@ -1121,7 +1121,7 @@ "description": "Button text for updating an existing login entry." }, "unlockToSave": { - "message": "Unlock to save this login", + "message": "Desbloquea para guardar este inicio de sesión", "description": "User prompt to take action in order to save the login they just entered." }, "saveLogin": { @@ -1141,7 +1141,7 @@ "description": "Message displayed when login details are successfully updated." }, "loginUpdateTaskSuccess": { - "message": "Great job! You took the steps to make you and $ORGANIZATION$ more secure.", + "message": "¡Buen trabajo! Has dado los pasos para que tú y $ORGANIZATION$ seáis más seguros.", "placeholders": { "organization": { "content": "$1" @@ -1150,7 +1150,7 @@ "description": "Shown to user after login is updated." }, "loginUpdateTaskSuccessAdditional": { - "message": "Thank you for making $ORGANIZATION$ more secure. You have $TASK_COUNT$ more passwords to update.", + "message": "Gracias por hacer $ORGANIZATION$ más seguro. Tienes $TASK_COUNT$ contraseñas más que actualizar.", "placeholders": { "organization": { "content": "$1" @@ -1162,7 +1162,7 @@ "description": "Shown to user after login is updated." }, "nextSecurityTaskAction": { - "message": "Change next password", + "message": "Cambiar siguiente contraseña", "description": "Message prompting user to undertake completion of another security task." }, "saveFailure": { @@ -1170,7 +1170,7 @@ "description": "Error message shown when the system fails to save login details." }, "saveFailureDetails": { - "message": "Oh no! We couldn't save this. Try entering the details manually.", + "message": "¡Oh no! No pudimos guardar esto. Intenta introducir los datos manualmente.", "description": "Detailed error message shown when saving login details fails." }, "enableChangedPasswordNotification": { @@ -1366,7 +1366,7 @@ "message": "Característica no disponible" }, "legacyEncryptionUnsupported": { - "message": "Legacy encryption is no longer supported. Please contact support to recover your account." + "message": "La encriptación antigua ya no está soportada. Por favor, contacta con soporte para recuperar tu cuenta." }, "premiumMembership": { "message": "Membresía Premium" @@ -1411,7 +1411,7 @@ "message": "Comprar Premium" }, "premiumPurchaseAlertV2": { - "message": "You can purchase Premium from your account settings on the Bitwarden web app." + "message": "Puedes comprar el Premium desde los ajustes de tu cuenta en la aplicación web de Bitwarden." }, "premiumCurrentMember": { "message": "¡Eres un miembro Premium!" @@ -1474,7 +1474,7 @@ } }, "dontAskAgainOnThisDeviceFor30Days": { - "message": "Don't ask again on this device for 30 days" + "message": "No volver a preguntar en este dispositivo durante 30 días" }, "selectAnotherMethod": { "message": "Selecciona otro método", @@ -1511,7 +1511,7 @@ "message": "Opciones de la autenticación en dos pasos" }, "selectTwoStepLoginMethod": { - "message": "Select two-step login method" + "message": "Selecciona un método de inicio de sesión en dos pasos" }, "recoveryCodeDesc": { "message": "¿Has perdido el acceso a todos tus métodos de autenticación en dos pasos? Utiliza tu código de recuperación para deshabilitar todos los métodos de autenticación en dos pasos de tu cuenta." @@ -1600,13 +1600,13 @@ "message": "Sugerencias de autocompletar" }, "autofillSpotlightTitle": { - "message": "Easily find autofill suggestions" + "message": "Encuentra fácilmente sugerencias de autocompletado" }, "autofillSpotlightDesc": { - "message": "Turn off your browser's autofill settings, so they don't conflict with Bitwarden." + "message": "Desactiva los ajustes de autocompletado de tu navegador para que no entren en conflicto con Bitwarden." }, "turnOffBrowserAutofill": { - "message": "Turn off $BROWSER$ autofill", + "message": "Desactivar autocompletado de $BROWSER$", "placeholders": { "browser": { "content": "$1", @@ -1615,22 +1615,22 @@ } }, "turnOffAutofill": { - "message": "Turn off autofill" + "message": "Desactivar autocompletado" }, "showInlineMenuLabel": { - "message": "Show autofill suggestions on form fields" + "message": "Mostrar sugerencias de autocompletado en campos de formulario" }, "showInlineMenuIdentitiesLabel": { - "message": "Display identities as suggestions" + "message": "Mostrar identidades como sugerencias" }, "showInlineMenuCardsLabel": { "message": "Mostrar tarjetas como sugerencias" }, "showInlineMenuOnIconSelectionLabel": { - "message": "Display suggestions when icon is selected" + "message": "Mostrar sugerencias cuando el icono esté seleccionado" }, "showInlineMenuOnFormFieldsDescAlt": { - "message": "Applies to all logged in accounts." + "message": "Se aplica a todas las cuentas a las que se haya iniciado sesión." }, "turnOffBrowserBuiltInPasswordManagerSettings": { "message": "Desactive la configuración del gestor de contraseñas del navegador para evitar conflictos." @@ -1693,13 +1693,13 @@ "message": "Abrir caja fuerte en la barra lateral" }, "commandAutofillLoginDesc": { - "message": "Autofill the last used login for the current website" + "message": "Autocompletar el último inicio de sesión usado para el sitio web actual" }, "commandAutofillCardDesc": { - "message": "Autofill the last used card for the current website" + "message": "Autocompletar la última tarjeta usada para el sitio web actual" }, "commandAutofillIdentityDesc": { - "message": "Autofill the last used identity for the current website" + "message": "Autocompletar la última identidad usada para el sitio web actual" }, "commandGeneratePasswordDesc": { "message": "Generar y copiar una nueva contraseña aleatoria al portapapeles." @@ -2491,7 +2491,7 @@ "message": "Cannot import card item types" }, "restrictCardTypeImportDesc": { - "message": "A policy set by 1 or more organizations prevents you from importing cards to your vaults." + "message": "Una política establecida en 1 o más organizaciones te impide importar tarjetas a tus cajas fuertes." }, "domainsTitle": { "message": "Dominios", @@ -2991,7 +2991,7 @@ } }, "vaultTimeoutPolicyInEffect1": { - "message": "$HOURS$ hour(s) and $MINUTES$ minute(s) maximum.", + "message": "$HOURS$ hora(s) y $MINUTES$ minuto(s) como máximo.", "placeholders": { "hours": { "content": "$1", @@ -3621,7 +3621,7 @@ "message": "Falta el correo electrónico del usuario" }, "activeUserEmailNotFoundLoggingYouOut": { - "message": "Active user email not found. Logging you out." + "message": "Correo electrónico del usuario activo no encontrado. Cerrando sesión." }, "deviceTrusted": { "message": "Dispositivo de confianza" @@ -3651,11 +3651,11 @@ "message": "Confiar con el usuario" }, "sendsTitleNoItems": { - "message": "Send sensitive information safely", + "message": "Envía información sensible de forma segura", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendsBodyNoItems": { - "message": "Share files and data securely with anyone, on any platform. Your information will remain end-to-end encrypted while limiting exposure.", + "message": "Comparte archivos y datos de forma segura con cualquiera, en cualquier plataforma. Tu información permanecerá encriptada de extremo a extremo, limitando su exposición.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "inputRequired": { @@ -3820,7 +3820,7 @@ "description": "Button text to display in overlay when the account is locked." }, "unlockAccountAria": { - "message": "Unlock your account, opens in a new window", + "message": "Desbloquea tu cuenta, se abre en una nueva ventana", "description": "Screen reader text (aria-label) for unlock account button in overlay" }, "totpCodeAria": { @@ -3828,7 +3828,7 @@ "description": "Aria label for the totp code displayed in the inline menu for autofill" }, "totpSecondsSpanAria": { - "message": "Time remaining before current TOTP expires", + "message": "Tiempo restante antes de que el TOTP actual expire", "description": "Aria label for the totp seconds displayed in the inline menu for autofill" }, "fillCredentialsFor": { @@ -3856,7 +3856,7 @@ "description": "Button text to display within inline menu when there are no matching items on a login field" }, "addNewLoginItemAria": { - "message": "Add new vault login item, opens in a new window", + "message": "Añadir nuevo elemento de inicio de sesión a la caja fuerte, se abre en una nueva ventana", "description": "Screen reader text (aria-label) for new login button within inline menu" }, "newCard": { @@ -4081,7 +4081,7 @@ "message": "No hay inicios de sesión coincidentes para este sitio" }, "searchSavePasskeyNewLogin": { - "message": "Search or save passkey as new login" + "message": "Busca o guarda la clave de acceso como nuevo inicio de sesión" }, "confirm": { "message": "Confirmar" @@ -4093,10 +4093,10 @@ "message": "Guardar clave de acceso como nuevo inicio de sesión" }, "chooseCipherForPasskeySave": { - "message": "Choose a login to save this passkey to" + "message": "Elige un inicio de sesión al que guardar esta clave de acceso" }, "chooseCipherForPasskeyAuth": { - "message": "Choose a passkey to log in with" + "message": "Elige una clave de acceso para iniciar sesión en" }, "passkeyItem": { "message": "Elemento de clave de acceso" @@ -4245,7 +4245,7 @@ "description": "Label indicating the most common import formats" }, "confirmContinueToBrowserSettingsTitle": { - "message": "Continue to browser settings?", + "message": "¿Continuar a los ajustes del navegador?", "description": "Title for dialog which asks if the user wants to proceed to a relevant browser settings page" }, "confirmContinueToHelpCenter": { @@ -4325,7 +4325,7 @@ "message": "Sugerencias de autocompletado" }, "itemSuggestions": { - "message": "Suggested items" + "message": "Elementos sugeridos" }, "autofillSuggestionsTip": { "message": "Guarda un elemento de inicio de sesión para este sitio para autocompletar" @@ -4767,7 +4767,7 @@ "message": "Solo los miembros de la organización con acceso a estas colecciones podrán ver los elementos." }, "bulkCollectionAssignmentWarning": { - "message": "You have selected $TOTAL_COUNT$ items. You cannot update $READONLY_COUNT$ of the items because you do not have edit permissions.", + "message": "Has seleccionado $TOTAL_COUNT$ elementos. No puedes actualizar $READONLY_COUNT$ de los elementos porque no tienes permisos de edición.", "placeholders": { "total_count": { "content": "$1", @@ -4865,10 +4865,10 @@ } }, "selectCollectionsToAssign": { - "message": "Select collections to assign" + "message": "Selecciona colecciones para asignar" }, "personalItemTransferWarningSingular": { - "message": "1 item will be permanently transferred to the selected organization. You will no longer own this item." + "message": "1 elemento será transferido permanentemente a la organización seleccionada. Ya no serás el propietario de este elemento." }, "personalItemsTransferWarningPlural": { "message": "$PERSONAL_ITEMS_COUNT$ items will be permanently transferred to the selected organization. You will no longer own these items.", @@ -4902,13 +4902,13 @@ } }, "successfullyAssignedCollections": { - "message": "Successfully assigned collections" + "message": "Colecciones asignadas correctamente" }, "nothingSelected": { - "message": "You have not selected anything." + "message": "No has seleccionado nada." }, "itemsMovedToOrg": { - "message": "Items moved to $ORGNAME$", + "message": "Elementos movidos a $ORGNAME$", "placeholders": { "orgname": { "content": "$1", @@ -4917,7 +4917,7 @@ } }, "itemMovedToOrg": { - "message": "Item moved to $ORGNAME$", + "message": "Elemento movido a $ORGNAME$", "placeholders": { "orgname": { "content": "$1", @@ -4961,13 +4961,13 @@ "message": "Acciones de cuenta" }, "showNumberOfAutofillSuggestions": { - "message": "Show number of login autofill suggestions on extension icon" + "message": "Mostrar número de sugerencias de autocompletado de inicios de sesión en el icono de la extensión" }, "showQuickCopyActions": { "message": "Show quick copy actions on Vault" }, "systemDefault": { - "message": "System default" + "message": "Predeterminado del sistema" }, "enterprisePolicyRequirementsApplied": { "message": "Enterprise policy requirements have been applied to this setting" @@ -5009,10 +5009,10 @@ "message": "File saved to device. Manage from your device downloads." }, "showCharacterCount": { - "message": "Show character count" + "message": "Mostrar número de caracteres" }, "hideCharacterCount": { - "message": "Hide character count" + "message": "Ocultar número de caracteres" }, "itemsInTrash": { "message": "Elementos en la papelera" @@ -5069,10 +5069,10 @@ "message": "You can customize your unlock and timeout settings to more quickly access your vault." }, "unlockPinSet": { - "message": "Unlock PIN set" + "message": "Desbloqueo con PIN establecido" }, "unlockWithBiometricSet": { - "message": "Unlock with biometrics set" + "message": "Desbloqueo con biometría establecido" }, "authenticating": { "message": "Autenticando" @@ -5309,7 +5309,7 @@ "message": "Quick and easy login" }, "quickLoginBody": { - "message": "Set up biometric unlock and autofill to log into your accounts without typing a single letter." + "message": "Configura el desbloqueo biométrico y el autocompletado para iniciar sesión en tus cuentas sin tener que escribir ni una sola letra." }, "secureUser": { "message": "Level up your logins" @@ -5318,7 +5318,7 @@ "message": "Utilice el generador para crear y guardar contraseñas fuertes y únicas para todas sus cuentas." }, "secureDevices": { - "message": "Your data, when and where you need it" + "message": "Tus datos, dónde y cuándo los necesites" }, "secureDevicesBody": { "message": "Guarda contraseñas ilimitadas a través de dispositivos ilimitados con aplicaciones móviles, de navegador y de escritorio de Bitwarden." @@ -5348,7 +5348,7 @@ "message": "Search your vault for something else" }, "newLoginNudgeTitle": { - "message": "Save time with autofill" + "message": "Ahorra tiempo con el autocompletado" }, "newLoginNudgeBodyOne": { "message": "Include a", @@ -5372,7 +5372,7 @@ "message": "With cards, easily autofill payment forms securely and accurately." }, "newIdentityNudgeTitle": { - "message": "Simplify creating accounts" + "message": "Simplifica la creación de cuentas" }, "newIdentityNudgeBody": { "message": "With identities, quickly autofill long registration or contact forms." diff --git a/apps/browser/src/_locales/pl/messages.json b/apps/browser/src/_locales/pl/messages.json index 9bb4d992b37..dba3a21d160 100644 --- a/apps/browser/src/_locales/pl/messages.json +++ b/apps/browser/src/_locales/pl/messages.json @@ -14,7 +14,7 @@ "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { - "message": "Zaloguj się lub utwórz nowe konto, aby uzyskać dostęp do Twojego bezpiecznego sejfu." + "message": "Zaloguj się lub utwórz nowe konto, aby uzyskać dostęp do bezpiecznego sejfu." }, "inviteAccepted": { "message": "Zaproszenie zostało zaakceptowane" From a05776c989f2d9839eb66bdf6715eb2b7a8c1b73 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 09:58:29 +0000 Subject: [PATCH 016/239] Autosync the updated translations (#15392) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/web/src/locales/af/messages.json | 3 +++ apps/web/src/locales/ar/messages.json | 3 +++ apps/web/src/locales/az/messages.json | 23 +++++++++++++---------- apps/web/src/locales/be/messages.json | 3 +++ apps/web/src/locales/bg/messages.json | 5 ++++- apps/web/src/locales/bn/messages.json | 3 +++ apps/web/src/locales/bs/messages.json | 3 +++ apps/web/src/locales/ca/messages.json | 5 ++++- apps/web/src/locales/cs/messages.json | 3 +++ apps/web/src/locales/cy/messages.json | 3 +++ apps/web/src/locales/da/messages.json | 3 +++ apps/web/src/locales/de/messages.json | 3 +++ apps/web/src/locales/el/messages.json | 3 +++ apps/web/src/locales/en_GB/messages.json | 3 +++ apps/web/src/locales/en_IN/messages.json | 3 +++ apps/web/src/locales/eo/messages.json | 3 +++ apps/web/src/locales/es/messages.json | 3 +++ apps/web/src/locales/et/messages.json | 3 +++ apps/web/src/locales/eu/messages.json | 3 +++ apps/web/src/locales/fa/messages.json | 3 +++ apps/web/src/locales/fi/messages.json | 3 +++ apps/web/src/locales/fil/messages.json | 3 +++ apps/web/src/locales/fr/messages.json | 3 +++ apps/web/src/locales/gl/messages.json | 3 +++ apps/web/src/locales/he/messages.json | 3 +++ apps/web/src/locales/hi/messages.json | 3 +++ apps/web/src/locales/hr/messages.json | 3 +++ apps/web/src/locales/hu/messages.json | 3 +++ apps/web/src/locales/id/messages.json | 3 +++ apps/web/src/locales/it/messages.json | 3 +++ apps/web/src/locales/ja/messages.json | 3 +++ apps/web/src/locales/ka/messages.json | 3 +++ apps/web/src/locales/km/messages.json | 3 +++ apps/web/src/locales/kn/messages.json | 3 +++ apps/web/src/locales/ko/messages.json | 3 +++ apps/web/src/locales/lv/messages.json | 3 +++ apps/web/src/locales/ml/messages.json | 3 +++ apps/web/src/locales/mr/messages.json | 3 +++ apps/web/src/locales/my/messages.json | 3 +++ apps/web/src/locales/nb/messages.json | 3 +++ apps/web/src/locales/ne/messages.json | 3 +++ apps/web/src/locales/nl/messages.json | 3 +++ apps/web/src/locales/nn/messages.json | 3 +++ apps/web/src/locales/or/messages.json | 3 +++ apps/web/src/locales/pl/messages.json | 3 +++ apps/web/src/locales/pt_BR/messages.json | 3 +++ apps/web/src/locales/pt_PT/messages.json | 3 +++ apps/web/src/locales/ro/messages.json | 3 +++ apps/web/src/locales/ru/messages.json | 3 +++ apps/web/src/locales/si/messages.json | 3 +++ apps/web/src/locales/sk/messages.json | 3 +++ apps/web/src/locales/sl/messages.json | 3 +++ apps/web/src/locales/sr_CS/messages.json | 3 +++ apps/web/src/locales/sr_CY/messages.json | 19 +++++++++++-------- apps/web/src/locales/sv/messages.json | 3 +++ apps/web/src/locales/te/messages.json | 3 +++ apps/web/src/locales/th/messages.json | 3 +++ apps/web/src/locales/tr/messages.json | 3 +++ apps/web/src/locales/uk/messages.json | 3 +++ apps/web/src/locales/vi/messages.json | 3 +++ apps/web/src/locales/zh_CN/messages.json | 9 ++++++--- apps/web/src/locales/zh_TW/messages.json | 3 +++ 62 files changed, 209 insertions(+), 23 deletions(-) diff --git a/apps/web/src/locales/af/messages.json b/apps/web/src/locales/af/messages.json index 33c8aec11af..9350bcfc0ff 100644 --- a/apps/web/src/locales/af/messages.json +++ b/apps/web/src/locales/af/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Verstekversameling" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Kry Hulp" }, diff --git a/apps/web/src/locales/ar/messages.json b/apps/web/src/locales/ar/messages.json index c96c0565eed..f8a6dc1288b 100644 --- a/apps/web/src/locales/ar/messages.json +++ b/apps/web/src/locales/ar/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "المساعدة" }, diff --git a/apps/web/src/locales/az/messages.json b/apps/web/src/locales/az/messages.json index ac1280d6ad0..062f0f35ff4 100644 --- a/apps/web/src/locales/az/messages.json +++ b/apps/web/src/locales/az/messages.json @@ -2154,16 +2154,16 @@ "message": "İki addımlı girişi qurmaq, Bitwarden hesabınızı birdəfəlik kilidləyə bilər. Geri qaytarma kodu, normal iki addımlı giriş provayderinizi artıq istifadə edə bilmədiyiniz hallarda (məs. cihazınızı itirəndə) hesabınıza müraciət etməyinizə imkan verir. Hesabınıza müraciəti itirsəniz, Bitwarden dəstəyi sizə kömək edə bilməyəcək. Geri qaytarma kodunuzu bir yerə yazmağınızı və ya çap etməyinizi və onu etibarlı bir yerdə saxlamağınızı məsləhət görürük." }, "restrictedItemTypePolicy": { - "message": "Remove card item type" + "message": "Kart element növünü sil" }, "restrictedItemTypePolicyDesc": { - "message": "Do not allow members to create card item types. Existing cards will be automatically removed." + "message": "Üzvlərin kart element növlərini yaratmasına icazə verməyin. Mövcud kartlar avtomatik silinəcək." }, "restrictCardTypeImport": { - "message": "Cannot import card item types" + "message": "Kart element növləri daxilə köçürülə bilmir" }, "restrictCardTypeImportDesc": { - "message": "A policy set by 1 or more organizations prevents you from importing cards to your vaults." + "message": "1 və ya daha çox təşkilat tərəfindən təyin edilən bir siyasət, kartların seyfinizə köçürülməsini əngəlləyir." }, "yourSingleUseRecoveryCode": { "message": "İki addımlı giriş provayderinizə müraciəti itirdiyiniz halda, iki addımlı girişi söndürmək üçün təkistifadəlik geri qaytarma kodunu istifadə edə bilərsiniz. Bitwarden tövsiyə edir ki, geri qaytarma kodunuzu bir yerə yazıb güvənli bir yerdə saxlayın." @@ -2225,7 +2225,7 @@ "message": "Sıradan çıxart" }, "orgUserDetailsNotFound": { - "message": "Member details not found." + "message": "Üzv təfsilatları tapılmadı." }, "revokeAccess": { "message": "Müraciəti ləğv et" @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "İlkin kolleksiya" }, + "myItems": { + "message": "Elementlərim" + }, "getHelp": { "message": "Kömək alın" }, @@ -5373,7 +5376,7 @@ "message": "Fövqəladə hal müraciəti rədd edildi" }, "grantorDetailsNotFound": { - "message": "Grantor details not found" + "message": "Qrant verən təfsilatları tapılmadı" }, "passwordResetFor": { "message": "$USER$ üçün parol sıfırlandı. Artıq yeni parol ilə giriş edə bilərsiniz.", @@ -5385,7 +5388,7 @@ } }, "organizationDataOwnership": { - "message": "Enforce organization data ownership" + "message": "Təşkilata data üzərində məcburi sahiblik ver" }, "personalOwnership": { "message": "Fərdi sahiblik" @@ -5779,7 +5782,7 @@ } }, "emergencyAccessLoggedOutWarning": { - "message": "Proceeding will log $NAME$ out of their current session, requiring them to log back in. Active sessions on other devices may continue to remain active for up to one hour.", + "message": "Davam etsəniz, $NAME$ üçün hazırkı seans bitəcək, təkrar giriş etməsi tələb olunacaq. Digər cihazlardakı aktiv seanslar, bir saata qədər aktiv qalmağa davam edə bilər.", "placeholders": { "name": { "content": "$1", @@ -5794,7 +5797,7 @@ "message": "Bir və ya daha çox təşkilat siyasəti, aşağıdakı tələbləri qarşılamaq üçün ana parolu tələb edir:" }, "changePasswordDelegationMasterPasswordPolicyInEffect": { - "message": "One or more organization policies require the master password to meet the following requirements:" + "message": "Bir və ya daha çox təşkilat siyasəti, aşağıdakı tələbləri qarşılamaq üçün ana parolu tələb edir:" }, "resetPasswordSuccess": { "message": "Parol sıfırlama uğurludur!" @@ -10678,7 +10681,7 @@ } }, "billingAddressRequiredToAddCredit": { - "message": "Billing address required to add credit.", + "message": "Kredit əlavə etmək üçün faktura ünvanı tələb olunur.", "description": "Error message shown when trying to add credit to a trialing organization without a billing address." } } diff --git a/apps/web/src/locales/be/messages.json b/apps/web/src/locales/be/messages.json index f0fc9db94c3..05c49e30b44 100644 --- a/apps/web/src/locales/be/messages.json +++ b/apps/web/src/locales/be/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Прадвызначаная калекцыя" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Атрымаць даведку" }, diff --git a/apps/web/src/locales/bg/messages.json b/apps/web/src/locales/bg/messages.json index e059002f5ff..d3c7604f2d7 100644 --- a/apps/web/src/locales/bg/messages.json +++ b/apps/web/src/locales/bg/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Стандартна колекция" }, + "myItems": { + "message": "Моите елементи" + }, "getHelp": { "message": "Помощ" }, @@ -5385,7 +5388,7 @@ } }, "organizationDataOwnership": { - "message": "Enforce organization data ownership" + "message": "Задължителна собственост на организационните данни" }, "personalOwnership": { "message": "Индивидуално притежание" diff --git a/apps/web/src/locales/bn/messages.json b/apps/web/src/locales/bn/messages.json index 39f883a7be6..c8539b19f79 100644 --- a/apps/web/src/locales/bn/messages.json +++ b/apps/web/src/locales/bn/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Get help" }, diff --git a/apps/web/src/locales/bs/messages.json b/apps/web/src/locales/bs/messages.json index 4bf2dd3c8c8..7c611e9ad5a 100644 --- a/apps/web/src/locales/bs/messages.json +++ b/apps/web/src/locales/bs/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Get help" }, diff --git a/apps/web/src/locales/ca/messages.json b/apps/web/src/locales/ca/messages.json index 5ba0d84fcdb..0b5d5e96988 100644 --- a/apps/web/src/locales/ca/messages.json +++ b/apps/web/src/locales/ca/messages.json @@ -502,7 +502,7 @@ "message": "Nom de la carpeta" }, "folderHintText": { - "message": "Nest a folder by adding the parent folder's name followed by a “/”. Example: Social/Forums" + "message": "Imbriqueu una carpeta afegint el nom de la carpeta principal seguit d'una \"/\". Exemple: Social/Fòrums" }, "deleteFolderPermanently": { "message": "Are you sure you want to permanently delete this folder?" @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Col·lecció per defecte" }, + "myItems": { + "message": "Els meus elements" + }, "getHelp": { "message": "Obteniu ajuda" }, diff --git a/apps/web/src/locales/cs/messages.json b/apps/web/src/locales/cs/messages.json index 5e022396a0e..8a80664c6c2 100644 --- a/apps/web/src/locales/cs/messages.json +++ b/apps/web/src/locales/cs/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Výchozí sbírka" }, + "myItems": { + "message": "Moje položky" + }, "getHelp": { "message": "Získat nápovědu" }, diff --git a/apps/web/src/locales/cy/messages.json b/apps/web/src/locales/cy/messages.json index 9e9521a6869..b8e3ccd5d25 100644 --- a/apps/web/src/locales/cy/messages.json +++ b/apps/web/src/locales/cy/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Get help" }, diff --git a/apps/web/src/locales/da/messages.json b/apps/web/src/locales/da/messages.json index 7c4f7459886..1f288af356f 100644 --- a/apps/web/src/locales/da/messages.json +++ b/apps/web/src/locales/da/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Standardsamling" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Få hjælp" }, diff --git a/apps/web/src/locales/de/messages.json b/apps/web/src/locales/de/messages.json index da3d2bd081f..c065f26f98d 100644 --- a/apps/web/src/locales/de/messages.json +++ b/apps/web/src/locales/de/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Standardsammlung" }, + "myItems": { + "message": "Meine Einträge" + }, "getHelp": { "message": "Hilfe erhalten" }, diff --git a/apps/web/src/locales/el/messages.json b/apps/web/src/locales/el/messages.json index 815c58a25ec..b8efb914a34 100644 --- a/apps/web/src/locales/el/messages.json +++ b/apps/web/src/locales/el/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Προεπιλεγμένη Συλλογή" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Ζητήστε Βοήθεια" }, diff --git a/apps/web/src/locales/en_GB/messages.json b/apps/web/src/locales/en_GB/messages.json index e3f279af8f4..bf15dd133f9 100644 --- a/apps/web/src/locales/en_GB/messages.json +++ b/apps/web/src/locales/en_GB/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Get help" }, diff --git a/apps/web/src/locales/en_IN/messages.json b/apps/web/src/locales/en_IN/messages.json index 4d5f5ff177d..d290ea148ad 100644 --- a/apps/web/src/locales/en_IN/messages.json +++ b/apps/web/src/locales/en_IN/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Get help" }, diff --git a/apps/web/src/locales/eo/messages.json b/apps/web/src/locales/eo/messages.json index 1366fc7c492..49924ab03fe 100644 --- a/apps/web/src/locales/eo/messages.json +++ b/apps/web/src/locales/eo/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Implicita kolekto" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Akiri helpon" }, diff --git a/apps/web/src/locales/es/messages.json b/apps/web/src/locales/es/messages.json index 2bc0abb9c00..253507109a8 100644 --- a/apps/web/src/locales/es/messages.json +++ b/apps/web/src/locales/es/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Colección por defecto" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Consigue ayuda" }, diff --git a/apps/web/src/locales/et/messages.json b/apps/web/src/locales/et/messages.json index c718b718d15..04b51e7c23b 100644 --- a/apps/web/src/locales/et/messages.json +++ b/apps/web/src/locales/et/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Vaikekogumik" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Klienditugi" }, diff --git a/apps/web/src/locales/eu/messages.json b/apps/web/src/locales/eu/messages.json index 1b41987012c..30f3f5488d7 100644 --- a/apps/web/src/locales/eu/messages.json +++ b/apps/web/src/locales/eu/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Bilduma lehenetsia" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Jaso laguntza" }, diff --git a/apps/web/src/locales/fa/messages.json b/apps/web/src/locales/fa/messages.json index 63ef193879a..99cdefe5695 100644 --- a/apps/web/src/locales/fa/messages.json +++ b/apps/web/src/locales/fa/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "مجموعه پیش‌فرض" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "کمک گرفتن" }, diff --git a/apps/web/src/locales/fi/messages.json b/apps/web/src/locales/fi/messages.json index 607b17d7749..9f6afee3713 100644 --- a/apps/web/src/locales/fi/messages.json +++ b/apps/web/src/locales/fi/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Oletuskokoelma" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Hanki apua" }, diff --git a/apps/web/src/locales/fil/messages.json b/apps/web/src/locales/fil/messages.json index c8689d54bbc..4794aef1d99 100644 --- a/apps/web/src/locales/fil/messages.json +++ b/apps/web/src/locales/fil/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default na koleksyon" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Humingi ng tulong" }, diff --git a/apps/web/src/locales/fr/messages.json b/apps/web/src/locales/fr/messages.json index 0ebdfaa611c..3abcdf9a999 100644 --- a/apps/web/src/locales/fr/messages.json +++ b/apps/web/src/locales/fr/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Collection par défaut" }, + "myItems": { + "message": "Mes éléments" + }, "getHelp": { "message": "Obtenir de l'aide" }, diff --git a/apps/web/src/locales/gl/messages.json b/apps/web/src/locales/gl/messages.json index ad59838cc77..9ed6e922300 100644 --- a/apps/web/src/locales/gl/messages.json +++ b/apps/web/src/locales/gl/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Get help" }, diff --git a/apps/web/src/locales/he/messages.json b/apps/web/src/locales/he/messages.json index 59f5dbc404b..e569d94437e 100644 --- a/apps/web/src/locales/he/messages.json +++ b/apps/web/src/locales/he/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "אוסף ברירת מחדל" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "קבל עזרה" }, diff --git a/apps/web/src/locales/hi/messages.json b/apps/web/src/locales/hi/messages.json index 250d68f1f0a..f6e2e491f49 100644 --- a/apps/web/src/locales/hi/messages.json +++ b/apps/web/src/locales/hi/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Get help" }, diff --git a/apps/web/src/locales/hr/messages.json b/apps/web/src/locales/hr/messages.json index d322231d2ad..ef5730fb6b6 100644 --- a/apps/web/src/locales/hr/messages.json +++ b/apps/web/src/locales/hr/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Zadana zbirka" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Potraži pomoć" }, diff --git a/apps/web/src/locales/hu/messages.json b/apps/web/src/locales/hu/messages.json index 211e99d3234..4ad900a4bae 100644 --- a/apps/web/src/locales/hu/messages.json +++ b/apps/web/src/locales/hu/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Alapértelmezett gyűjtemény" }, + "myItems": { + "message": "Saját elemek" + }, "getHelp": { "message": "Segítségkérés" }, diff --git a/apps/web/src/locales/id/messages.json b/apps/web/src/locales/id/messages.json index bb0fbad9361..fffe374b44b 100644 --- a/apps/web/src/locales/id/messages.json +++ b/apps/web/src/locales/id/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Koleksi Default" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Dapatkan Bantuan" }, diff --git a/apps/web/src/locales/it/messages.json b/apps/web/src/locales/it/messages.json index 30cd8bb6d53..a861f368366 100644 --- a/apps/web/src/locales/it/messages.json +++ b/apps/web/src/locales/it/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Raccolta predefinita" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Ottieni aiuto" }, diff --git a/apps/web/src/locales/ja/messages.json b/apps/web/src/locales/ja/messages.json index 95e2cc71644..9af2943f1da 100644 --- a/apps/web/src/locales/ja/messages.json +++ b/apps/web/src/locales/ja/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "既定のコレクション" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "ヘルプを参照する" }, diff --git a/apps/web/src/locales/ka/messages.json b/apps/web/src/locales/ka/messages.json index 4ebfca7db2c..d5ae3e1978c 100644 --- a/apps/web/src/locales/ka/messages.json +++ b/apps/web/src/locales/ka/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Get help" }, diff --git a/apps/web/src/locales/km/messages.json b/apps/web/src/locales/km/messages.json index bdcdf5ed237..f422e74a569 100644 --- a/apps/web/src/locales/km/messages.json +++ b/apps/web/src/locales/km/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Get help" }, diff --git a/apps/web/src/locales/kn/messages.json b/apps/web/src/locales/kn/messages.json index 9abfaf0329b..b400d0ca863 100644 --- a/apps/web/src/locales/kn/messages.json +++ b/apps/web/src/locales/kn/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "ಡೀಫಾಲ್ಟ್ ಸಂಗ್ರಹ" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "ಸಹಾಯ ಪಡೆ" }, diff --git a/apps/web/src/locales/ko/messages.json b/apps/web/src/locales/ko/messages.json index 8ae6e906dea..8293750eed3 100644 --- a/apps/web/src/locales/ko/messages.json +++ b/apps/web/src/locales/ko/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "기본 컬렉션" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "문의하기" }, diff --git a/apps/web/src/locales/lv/messages.json b/apps/web/src/locales/lv/messages.json index 0c738d66de2..b17131cf2ef 100644 --- a/apps/web/src/locales/lv/messages.json +++ b/apps/web/src/locales/lv/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Noklusējuma krājums" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Saņemt palīdzību" }, diff --git a/apps/web/src/locales/ml/messages.json b/apps/web/src/locales/ml/messages.json index 2b93514d5ad..ef1bb77feb4 100644 --- a/apps/web/src/locales/ml/messages.json +++ b/apps/web/src/locales/ml/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default Collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Get Help" }, diff --git a/apps/web/src/locales/mr/messages.json b/apps/web/src/locales/mr/messages.json index 338c0228fcf..97eb93dd3eb 100644 --- a/apps/web/src/locales/mr/messages.json +++ b/apps/web/src/locales/mr/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Get help" }, diff --git a/apps/web/src/locales/my/messages.json b/apps/web/src/locales/my/messages.json index bdcdf5ed237..f422e74a569 100644 --- a/apps/web/src/locales/my/messages.json +++ b/apps/web/src/locales/my/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Get help" }, diff --git a/apps/web/src/locales/nb/messages.json b/apps/web/src/locales/nb/messages.json index 7221018aca0..68cd7725bd5 100644 --- a/apps/web/src/locales/nb/messages.json +++ b/apps/web/src/locales/nb/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Standardsamling" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Få hjelp" }, diff --git a/apps/web/src/locales/ne/messages.json b/apps/web/src/locales/ne/messages.json index 4b401cd67a8..f74848f0aee 100644 --- a/apps/web/src/locales/ne/messages.json +++ b/apps/web/src/locales/ne/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Get help" }, diff --git a/apps/web/src/locales/nl/messages.json b/apps/web/src/locales/nl/messages.json index 556ef03ada0..fc2b6e9593c 100644 --- a/apps/web/src/locales/nl/messages.json +++ b/apps/web/src/locales/nl/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Standaardverzameling" }, + "myItems": { + "message": "Mijn items" + }, "getHelp": { "message": "Hulp vragen" }, diff --git a/apps/web/src/locales/nn/messages.json b/apps/web/src/locales/nn/messages.json index 0707b948a38..79700ff65e3 100644 --- a/apps/web/src/locales/nn/messages.json +++ b/apps/web/src/locales/nn/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Get help" }, diff --git a/apps/web/src/locales/or/messages.json b/apps/web/src/locales/or/messages.json index bdcdf5ed237..f422e74a569 100644 --- a/apps/web/src/locales/or/messages.json +++ b/apps/web/src/locales/or/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Get help" }, diff --git a/apps/web/src/locales/pl/messages.json b/apps/web/src/locales/pl/messages.json index b70804f2b6f..13e67f9d33c 100644 --- a/apps/web/src/locales/pl/messages.json +++ b/apps/web/src/locales/pl/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Domyślna kolekcja" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Uzyskaj pomoc" }, diff --git a/apps/web/src/locales/pt_BR/messages.json b/apps/web/src/locales/pt_BR/messages.json index dbd11b62095..da4180ee0e6 100644 --- a/apps/web/src/locales/pt_BR/messages.json +++ b/apps/web/src/locales/pt_BR/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Coleção Padrão" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Obter Ajuda" }, diff --git a/apps/web/src/locales/pt_PT/messages.json b/apps/web/src/locales/pt_PT/messages.json index 33ac3148a1c..eb06f4b7390 100644 --- a/apps/web/src/locales/pt_PT/messages.json +++ b/apps/web/src/locales/pt_PT/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Coleção predefinida" }, + "myItems": { + "message": "Os meus itens" + }, "getHelp": { "message": "Obter ajuda" }, diff --git a/apps/web/src/locales/ro/messages.json b/apps/web/src/locales/ro/messages.json index add0453a747..569faf4e9a8 100644 --- a/apps/web/src/locales/ro/messages.json +++ b/apps/web/src/locales/ro/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Colecție implicită" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Obținere ajutor" }, diff --git a/apps/web/src/locales/ru/messages.json b/apps/web/src/locales/ru/messages.json index 146c9659ce0..d57bdc8ed45 100644 --- a/apps/web/src/locales/ru/messages.json +++ b/apps/web/src/locales/ru/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Коллекция по умолчанию" }, + "myItems": { + "message": "Мои элементы" + }, "getHelp": { "message": "Получить помощь" }, diff --git a/apps/web/src/locales/si/messages.json b/apps/web/src/locales/si/messages.json index 412960c2453..80dd700f848 100644 --- a/apps/web/src/locales/si/messages.json +++ b/apps/web/src/locales/si/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Get help" }, diff --git a/apps/web/src/locales/sk/messages.json b/apps/web/src/locales/sk/messages.json index 752f088a92c..c3f204beaf3 100644 --- a/apps/web/src/locales/sk/messages.json +++ b/apps/web/src/locales/sk/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Predvolená kolekcia" }, + "myItems": { + "message": "Moje položky" + }, "getHelp": { "message": "Získať pomoc" }, diff --git a/apps/web/src/locales/sl/messages.json b/apps/web/src/locales/sl/messages.json index dca8c4d1161..5b68d7e21af 100644 --- a/apps/web/src/locales/sl/messages.json +++ b/apps/web/src/locales/sl/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Pomoč" }, diff --git a/apps/web/src/locales/sr_CS/messages.json b/apps/web/src/locales/sr_CS/messages.json index 71af7ca2062..c0681d1224f 100644 --- a/apps/web/src/locales/sr_CS/messages.json +++ b/apps/web/src/locales/sr_CS/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Get help" }, diff --git a/apps/web/src/locales/sr_CY/messages.json b/apps/web/src/locales/sr_CY/messages.json index 0f84a52f849..837b8c706b8 100644 --- a/apps/web/src/locales/sr_CY/messages.json +++ b/apps/web/src/locales/sr_CY/messages.json @@ -2154,10 +2154,10 @@ "message": "Омогућавање пријаве у два корака може вас трајно закључати са вашег Bitwarden-а налога. Код за опоравак омогућава вам приступ вашем налогу у случају да више не можете да користите свог уобичајеног добављача услуге пријављивања у два корака (нпр. ако изгубите уређај). Подршка Bitwarden-а неће вам моћи помоћи ако изгубите приступ свом налогу. Препоручујемо да запишете или одштампате код за опоравак и сачувате га на сигурном месту." }, "restrictedItemTypePolicy": { - "message": "Remove card item type" + "message": "Уклоните тип ставке картице" }, "restrictedItemTypePolicyDesc": { - "message": "Do not allow members to create card item types. Existing cards will be automatically removed." + "message": "Не дозволите члановима да креирају врсте предмета картице. Постојеће картице ће се аутоматски уклонити." }, "restrictCardTypeImport": { "message": "Не могу увозити врсте картица" @@ -2225,7 +2225,7 @@ "message": "Онемогући" }, "orgUserDetailsNotFound": { - "message": "Member details not found." + "message": "Детаљи чланова нису пронађени." }, "revokeAccess": { "message": "Опозови Приступ" @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Стандардна колекција" }, + "myItems": { + "message": "Моји предмети" + }, "getHelp": { "message": "Потражи помоћ" }, @@ -5373,7 +5376,7 @@ "message": "Одбијен хитни приступ" }, "grantorDetailsNotFound": { - "message": "Grantor details not found" + "message": "Детаљи одобравања нису пронађени" }, "passwordResetFor": { "message": "Ресетовање лозинке за $USER$. Сада се можете пријавити помоћу нове лозинке.", @@ -5385,7 +5388,7 @@ } }, "organizationDataOwnership": { - "message": "Enforce organization data ownership" + "message": "Спровести власништво података о организацији" }, "personalOwnership": { "message": "Лично власништво" @@ -5779,7 +5782,7 @@ } }, "emergencyAccessLoggedOutWarning": { - "message": "Proceeding will log $NAME$ out of their current session, requiring them to log back in. Active sessions on other devices may continue to remain active for up to one hour.", + "message": "Ако наставите, објавићете $NAME$ са тренутне сесије, захтевајући их да се поново пријаве. Активне сесије на другим уређајима могу наставити да остају активне до једног сата.", "placeholders": { "name": { "content": "$1", @@ -5794,7 +5797,7 @@ "message": "Једна или више смерница организације захтевају главну лозинку да би испуњавали следеће захтеве:" }, "changePasswordDelegationMasterPasswordPolicyInEffect": { - "message": "One or more organization policies require the master password to meet the following requirements:" + "message": "Једна или више смерница организације захтевају главну лозинку да би испуњавали следеће захтеве:" }, "resetPasswordSuccess": { "message": "Успешно ресетовање лозинке!" @@ -10678,7 +10681,7 @@ } }, "billingAddressRequiredToAddCredit": { - "message": "Billing address required to add credit.", + "message": "Адреса за наплату је потребна за додавање кредита.", "description": "Error message shown when trying to add credit to a trialing organization without a billing address." } } diff --git a/apps/web/src/locales/sv/messages.json b/apps/web/src/locales/sv/messages.json index a81335284a1..41813e5edc0 100644 --- a/apps/web/src/locales/sv/messages.json +++ b/apps/web/src/locales/sv/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Standardsamling" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Få hjälp" }, diff --git a/apps/web/src/locales/te/messages.json b/apps/web/src/locales/te/messages.json index bdcdf5ed237..f422e74a569 100644 --- a/apps/web/src/locales/te/messages.json +++ b/apps/web/src/locales/te/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Get help" }, diff --git a/apps/web/src/locales/th/messages.json b/apps/web/src/locales/th/messages.json index 48cedb1c4d5..c47c6caca85 100644 --- a/apps/web/src/locales/th/messages.json +++ b/apps/web/src/locales/th/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Get help" }, diff --git a/apps/web/src/locales/tr/messages.json b/apps/web/src/locales/tr/messages.json index af3d51faa3e..211851f8450 100644 --- a/apps/web/src/locales/tr/messages.json +++ b/apps/web/src/locales/tr/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Varsayılan koleksiyon" }, + "myItems": { + "message": "Kayıtlarım" + }, "getHelp": { "message": "Yardım al" }, diff --git a/apps/web/src/locales/uk/messages.json b/apps/web/src/locales/uk/messages.json index c67b8d62ceb..4ddcfa3c463 100644 --- a/apps/web/src/locales/uk/messages.json +++ b/apps/web/src/locales/uk/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Типова збірка" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Отримати допомогу" }, diff --git a/apps/web/src/locales/vi/messages.json b/apps/web/src/locales/vi/messages.json index 6b9cb8d0ac0..c3bbf855a38 100644 --- a/apps/web/src/locales/vi/messages.json +++ b/apps/web/src/locales/vi/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "Default collection" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "Nhận trợ giúp" }, diff --git a/apps/web/src/locales/zh_CN/messages.json b/apps/web/src/locales/zh_CN/messages.json index 55579121b4b..550d4d56bdd 100644 --- a/apps/web/src/locales/zh_CN/messages.json +++ b/apps/web/src/locales/zh_CN/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "默认集合" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "获取帮助" }, @@ -8725,13 +8728,13 @@ "message": "管理组织的集合行为" }, "limitCollectionCreationDesc": { - "message": "限制为所有者和管理员可以创建集合" + "message": "仅限所有者和管理员可以创建集合" }, "limitCollectionDeletionDesc": { - "message": "限制为所有者和管理员可以删除集合" + "message": "仅限所有者和管理员可以删除集合" }, "limitItemDeletionDescription": { - "message": "限制为具有「管理集合」权限的成员可以删项目" + "message": "仅限具有「管理集合」权限的成员可以删除项目" }, "allowAdminAccessToAllCollectionItemsDesc": { "message": "所有者和管理员可以管理所有集合和项目" diff --git a/apps/web/src/locales/zh_TW/messages.json b/apps/web/src/locales/zh_TW/messages.json index a44d7eb5f28..2193c9503ab 100644 --- a/apps/web/src/locales/zh_TW/messages.json +++ b/apps/web/src/locales/zh_TW/messages.json @@ -3275,6 +3275,9 @@ "defaultCollection": { "message": "預設集合" }, + "myItems": { + "message": "My Items" + }, "getHelp": { "message": "尋求幫助" }, From 8fec95671d1f39c863e9977542c95c80fc5957c2 Mon Sep 17 00:00:00 2001 From: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> Date: Mon, 30 Jun 2025 12:38:51 +0200 Subject: [PATCH 017/239] [PM-22090] Delete password on Windows desktop throws incorrect error (#15070) * delete password on Windows desktop throws incorrect error * delete password on Windows desktop throws incorrect error * napi documentation improvements * napi documentation update * better logging verbosity * desktop native clippy errors * unit test coverage * napi TS documentation JS language friendly * fixing merge conflicts --- .../desktop_native/core/src/password/macos.rs | 25 ++-- .../desktop_native/core/src/password/mod.rs | 2 + .../desktop_native/core/src/password/unix.rs | 9 +- .../core/src/password/windows.rs | 11 +- apps/desktop/desktop_native/napi/index.d.ts | 17 ++- apps/desktop/desktop_native/napi/src/lib.rs | 10 +- .../main-biometrics-ipc.listener.ts | 2 +- .../biometrics/main-biometrics.service.ts | 3 +- .../os-biometrics-linux.service.spec.ts | 86 +++++++++++++ .../biometrics/os-biometrics-linux.service.ts | 16 ++- .../os-biometrics-mac.service.spec.ts | 78 ++++++++++++ .../biometrics/os-biometrics-mac.service.ts | 20 ++- .../os-biometrics-windows.service.spec.ts | 115 +++++++++++++++++- .../os-biometrics-windows.service.ts | 43 ++++++- .../desktop-credential-storage-listener.ts | 10 +- 15 files changed, 407 insertions(+), 40 deletions(-) create mode 100644 apps/desktop/src/key-management/biometrics/os-biometrics-linux.service.spec.ts create mode 100644 apps/desktop/src/key-management/biometrics/os-biometrics-mac.service.spec.ts diff --git a/apps/desktop/desktop_native/core/src/password/macos.rs b/apps/desktop/desktop_native/core/src/password/macos.rs index 1af005acb4d..3075dce3b88 100644 --- a/apps/desktop/desktop_native/core/src/password/macos.rs +++ b/apps/desktop/desktop_native/core/src/password/macos.rs @@ -1,10 +1,12 @@ +use crate::password::PASSWORD_NOT_FOUND; use anyhow::Result; use security_framework::passwords::{ delete_generic_password, get_generic_password, set_generic_password, }; pub async fn get_password(service: &str, account: &str) -> Result { - let result = String::from_utf8(get_generic_password(service, account)?)?; + let password = get_generic_password(service, account).map_err(convert_error)?; + let result = String::from_utf8(password)?; Ok(result) } @@ -14,7 +16,7 @@ pub async fn set_password(service: &str, account: &str, password: &str) -> Resul } pub async fn delete_password(service: &str, account: &str) -> Result<()> { - delete_generic_password(service, account)?; + delete_generic_password(service, account).map_err(convert_error)?; Ok(()) } @@ -22,6 +24,15 @@ pub async fn is_available() -> Result { Ok(true) } +fn convert_error(e: security_framework::base::Error) -> anyhow::Error { + match e.code() { + security_framework_sys::base::errSecItemNotFound => { + anyhow::anyhow!(PASSWORD_NOT_FOUND) + } + _ => anyhow::anyhow!(e), + } +} + #[cfg(test)] mod tests { use super::*; @@ -44,10 +55,7 @@ mod tests { // Ensure password is deleted match get_password("BitwardenTest", "BitwardenTest").await { Ok(_) => panic!("Got a result"), - Err(e) => assert_eq!( - "The specified item could not be found in the keychain.", - e.to_string() - ), + Err(e) => assert_eq!(PASSWORD_NOT_FOUND, e.to_string()), } } @@ -55,10 +63,7 @@ mod tests { async fn test_error_no_password() { match get_password("Unknown", "Unknown").await { Ok(_) => panic!("Got a result"), - Err(e) => assert_eq!( - "The specified item could not be found in the keychain.", - e.to_string() - ), + Err(e) => assert_eq!(PASSWORD_NOT_FOUND, e.to_string()), } } } diff --git a/apps/desktop/desktop_native/core/src/password/mod.rs b/apps/desktop/desktop_native/core/src/password/mod.rs index 351e896c40e..93c91072dd2 100644 --- a/apps/desktop/desktop_native/core/src/password/mod.rs +++ b/apps/desktop/desktop_native/core/src/password/mod.rs @@ -1,3 +1,5 @@ +pub const PASSWORD_NOT_FOUND: &str = "Password not found."; + #[allow(clippy::module_inception)] #[cfg_attr(target_os = "linux", path = "unix.rs")] #[cfg_attr(target_os = "windows", path = "windows.rs")] diff --git a/apps/desktop/desktop_native/core/src/password/unix.rs b/apps/desktop/desktop_native/core/src/password/unix.rs index a40f4d8ed43..0b1c59e7724 100644 --- a/apps/desktop/desktop_native/core/src/password/unix.rs +++ b/apps/desktop/desktop_native/core/src/password/unix.rs @@ -1,3 +1,4 @@ +use crate::password::PASSWORD_NOT_FOUND; use anyhow::{anyhow, Result}; use oo7::dbus::{self}; use std::collections::HashMap; @@ -20,7 +21,7 @@ async fn get_password_new(service: &str, account: &str) -> Result { let secret = res.secret().await?; Ok(String::from_utf8(secret.to_vec())?) } - None => Err(anyhow!("no result")), + None => Err(anyhow!(PASSWORD_NOT_FOUND)), } } @@ -46,7 +47,7 @@ async fn get_password_legacy(service: &str, account: &str) -> Result { set_password(service, account, &secret_string).await?; Ok(secret_string) } - None => Err(anyhow!("no result")), + None => Err(anyhow!(PASSWORD_NOT_FOUND)), } } @@ -152,7 +153,7 @@ mod tests { Ok(_) => { panic!("Got a result") } - Err(e) => assert_eq!("no result", e.to_string()), + Err(e) => assert_eq!(PASSWORD_NOT_FOUND, e.to_string()), } } @@ -160,7 +161,7 @@ mod tests { async fn test_error_no_password() { match get_password("Unknown", "Unknown").await { Ok(_) => panic!("Got a result"), - Err(e) => assert_eq!("no result", e.to_string()), + Err(e) => assert_eq!(PASSWORD_NOT_FOUND, e.to_string()), } } } diff --git a/apps/desktop/desktop_native/core/src/password/windows.rs b/apps/desktop/desktop_native/core/src/password/windows.rs index f0dcc3fb1eb..ee2361a832f 100644 --- a/apps/desktop/desktop_native/core/src/password/windows.rs +++ b/apps/desktop/desktop_native/core/src/password/windows.rs @@ -1,3 +1,4 @@ +use crate::password::PASSWORD_NOT_FOUND; use anyhow::{anyhow, Result}; use widestring::{U16CString, U16String}; use windows::{ @@ -79,7 +80,9 @@ pub async fn set_password(service: &str, account: &str, password: &str) -> Resul pub async fn delete_password(service: &str, account: &str) -> Result<()> { let target_name = U16CString::from_str(target_name(service, account))?; - unsafe { CredDeleteW(PCWSTR(target_name.as_ptr()), CRED_TYPE_GENERIC, None)? }; + let result = unsafe { CredDeleteW(PCWSTR(target_name.as_ptr()), CRED_TYPE_GENERIC, None) }; + + result.map_err(|e| anyhow!(convert_error(e)))?; Ok(()) } @@ -95,7 +98,7 @@ fn target_name(service: &str, account: &str) -> String { // Convert the internal WIN32 errors to descriptive messages fn convert_error(e: windows::core::Error) -> String { if e == ERROR_NOT_FOUND.into() { - return "Password not found.".to_string(); + return PASSWORD_NOT_FOUND.to_string(); } e.to_string() } @@ -122,7 +125,7 @@ mod tests { // Ensure password is deleted match get_password("BitwardenTest", "BitwardenTest").await { Ok(_) => panic!("Got a result"), - Err(e) => assert_eq!("Password not found.", e.to_string()), + Err(e) => assert_eq!(PASSWORD_NOT_FOUND, e.to_string()), } } @@ -130,7 +133,7 @@ mod tests { async fn test_error_no_password() { match get_password("BitwardenTest", "BitwardenTest").await { Ok(_) => panic!("Got a result"), - Err(e) => assert_eq!("Password not found.", e.to_string()), + Err(e) => assert_eq!(PASSWORD_NOT_FOUND, e.to_string()), } } } diff --git a/apps/desktop/desktop_native/napi/index.d.ts b/apps/desktop/desktop_native/napi/index.d.ts index b3c6f715e98..cb9430290e3 100644 --- a/apps/desktop/desktop_native/napi/index.d.ts +++ b/apps/desktop/desktop_native/napi/index.d.ts @@ -4,18 +4,31 @@ /* auto-generated by NAPI-RS */ export declare namespace passwords { - /** Fetch the stored password from the keychain. */ + /** The error message returned when a password is not found during retrieval or deletion. */ + export const PASSWORD_NOT_FOUND: string + /** + * Fetch the stored password from the keychain. + * Throws {@link Error} with message {@link PASSWORD_NOT_FOUND} if the password does not exist. + */ export function getPassword(service: string, account: string): Promise /** Save the password to the keychain. Adds an entry if none exists otherwise updates the existing entry. */ export function setPassword(service: string, account: string, password: string): Promise - /** Delete the stored password from the keychain. */ + /** + * Delete the stored password from the keychain. + * Throws {@link Error} with message {@link PASSWORD_NOT_FOUND} if the password does not exist. + */ export function deletePassword(service: string, account: string): Promise + /** Checks if the os secure storage is available */ export function isAvailable(): Promise } export declare namespace biometrics { export function prompt(hwnd: Buffer, message: string): Promise export function available(): Promise export function setBiometricSecret(service: string, account: string, secret: string, keyMaterial: KeyMaterial | undefined | null, ivB64: string): Promise + /** + * Retrieves the biometric secret for the given service and account. + * Throws Error with message [`passwords::PASSWORD_NOT_FOUND`] if the secret does not exist. + */ export function getBiometricSecret(service: string, account: string, keyMaterial?: KeyMaterial | undefined | null): Promise /** * Derives key material from biometric data. Returns a string encoded with a diff --git a/apps/desktop/desktop_native/napi/src/lib.rs b/apps/desktop/desktop_native/napi/src/lib.rs index 079872a3b03..e538dc8d432 100644 --- a/apps/desktop/desktop_native/napi/src/lib.rs +++ b/apps/desktop/desktop_native/napi/src/lib.rs @@ -6,7 +6,12 @@ mod registry; #[napi] pub mod passwords { + /// The error message returned when a password is not found during retrieval or deletion. + #[napi] + pub const PASSWORD_NOT_FOUND: &str = desktop_core::password::PASSWORD_NOT_FOUND; + /// Fetch the stored password from the keychain. + /// Throws {@link Error} with message {@link PASSWORD_NOT_FOUND} if the password does not exist. #[napi] pub async fn get_password(service: String, account: String) -> napi::Result { desktop_core::password::get_password(&service, &account) @@ -27,6 +32,7 @@ pub mod passwords { } /// Delete the stored password from the keychain. + /// Throws {@link Error} with message {@link PASSWORD_NOT_FOUND} if the password does not exist. #[napi] pub async fn delete_password(service: String, account: String) -> napi::Result<()> { desktop_core::password::delete_password(&service, &account) @@ -34,7 +40,7 @@ pub mod passwords { .map_err(|e| napi::Error::from_reason(e.to_string())) } - // Checks if the os secure storage is available + /// Checks if the os secure storage is available #[napi] pub async fn is_available() -> napi::Result { desktop_core::password::is_available() @@ -84,6 +90,8 @@ pub mod biometrics { .map_err(|e| napi::Error::from_reason(e.to_string())) } + /// Retrieves the biometric secret for the given service and account. + /// Throws Error with message [`passwords::PASSWORD_NOT_FOUND`] if the secret does not exist. #[napi] pub async fn get_biometric_secret( service: String, diff --git a/apps/desktop/src/key-management/biometrics/main-biometrics-ipc.listener.ts b/apps/desktop/src/key-management/biometrics/main-biometrics-ipc.listener.ts index e270c4cc50f..d4ce01f53f4 100644 --- a/apps/desktop/src/key-management/biometrics/main-biometrics-ipc.listener.ts +++ b/apps/desktop/src/key-management/biometrics/main-biometrics-ipc.listener.ts @@ -55,7 +55,7 @@ export class MainBiometricsIPCListener { return; } } catch (e) { - this.logService.info(e); + this.logService.error("[Main Biometrics IPC Listener] %s failed", message.action, e); } }); } diff --git a/apps/desktop/src/key-management/biometrics/main-biometrics.service.ts b/apps/desktop/src/key-management/biometrics/main-biometrics.service.ts index a6a0e532655..1de8e3cd12d 100644 --- a/apps/desktop/src/key-management/biometrics/main-biometrics.service.ts +++ b/apps/desktop/src/key-management/biometrics/main-biometrics.service.ts @@ -40,7 +40,7 @@ export class MainBiometricsService extends DesktopBiometricsService { } else if (platform === "darwin") { // eslint-disable-next-line const OsBiometricsServiceMac = require("./os-biometrics-mac.service").default; - this.osBiometricsService = new OsBiometricsServiceMac(this.i18nService); + this.osBiometricsService = new OsBiometricsServiceMac(this.i18nService, this.logService); } else if (platform === "linux") { // eslint-disable-next-line const OsBiometricsServiceLinux = require("./os-biometrics-linux.service").default; @@ -48,6 +48,7 @@ export class MainBiometricsService extends DesktopBiometricsService { this.biometricStateService, this.encryptService, this.cryptoFunctionService, + this.logService, ); } else { throw new Error("Unsupported platform"); diff --git a/apps/desktop/src/key-management/biometrics/os-biometrics-linux.service.spec.ts b/apps/desktop/src/key-management/biometrics/os-biometrics-linux.service.spec.ts new file mode 100644 index 00000000000..64af0cc625e --- /dev/null +++ b/apps/desktop/src/key-management/biometrics/os-biometrics-linux.service.spec.ts @@ -0,0 +1,86 @@ +import { mock } from "jest-mock-extended"; + +import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service"; +import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { UserId } from "@bitwarden/common/types/guid"; +import { passwords } from "@bitwarden/desktop-napi"; +import { BiometricStateService } from "@bitwarden/key-management"; + +import OsBiometricsServiceLinux from "./os-biometrics-linux.service"; + +jest.mock("@bitwarden/desktop-napi", () => ({ + biometrics: { + setBiometricSecret: jest.fn(), + getBiometricSecret: jest.fn(), + deleteBiometricSecret: jest.fn(), + prompt: jest.fn(), + available: jest.fn(), + deriveKeyMaterial: jest.fn(), + }, + passwords: { + deletePassword: jest.fn(), + getPassword: jest.fn(), + isAvailable: jest.fn(), + PASSWORD_NOT_FOUND: "Password not found", + }, +})); + +describe("OsBiometricsServiceLinux", () => { + let service: OsBiometricsServiceLinux; + let logService: LogService; + + const mockUserId = "test-user-id" as UserId; + + beforeEach(() => { + const biometricStateService = mock(); + const encryptService = mock(); + const cryptoFunctionService = mock(); + logService = mock(); + service = new OsBiometricsServiceLinux( + biometricStateService, + encryptService, + cryptoFunctionService, + logService, + ); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe("deleteBiometricKey", () => { + const serviceName = "Bitwarden_biometric"; + const keyName = "test-user-id_user_biometric"; + + it("should delete biometric key successfully", async () => { + await service.deleteBiometricKey(mockUserId); + + expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, keyName); + }); + + it("should not throw error if key not found", async () => { + passwords.deletePassword = jest + .fn() + .mockRejectedValueOnce(new Error(passwords.PASSWORD_NOT_FOUND)); + + await service.deleteBiometricKey(mockUserId); + + expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, keyName); + expect(logService.debug).toHaveBeenCalledWith( + "[OsBiometricService] Biometric key %s not found for service %s.", + keyName, + serviceName, + ); + }); + + it("should throw error for unexpected errors", async () => { + const error = new Error("Unexpected error"); + passwords.deletePassword = jest.fn().mockRejectedValueOnce(error); + + await expect(service.deleteBiometricKey(mockUserId)).rejects.toThrow(error); + + expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, keyName); + }); + }); +}); diff --git a/apps/desktop/src/key-management/biometrics/os-biometrics-linux.service.ts b/apps/desktop/src/key-management/biometrics/os-biometrics-linux.service.ts index 8d3c8e9795f..3f13682f1b7 100644 --- a/apps/desktop/src/key-management/biometrics/os-biometrics-linux.service.ts +++ b/apps/desktop/src/key-management/biometrics/os-biometrics-linux.service.ts @@ -2,6 +2,7 @@ import { spawn } from "child_process"; import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; @@ -42,6 +43,7 @@ export default class OsBiometricsServiceLinux implements OsBiometricService { private biometricStateService: BiometricStateService, private encryptService: EncryptService, private cryptoFunctionService: CryptoFunctionService, + private logService: LogService, ) {} private _iv: string | null = null; // Use getKeyMaterial helper instead of direct access @@ -62,7 +64,19 @@ export default class OsBiometricsServiceLinux implements OsBiometricService { ); } async deleteBiometricKey(userId: UserId): Promise { - await passwords.deletePassword(SERVICE, getLookupKeyForUser(userId)); + try { + await passwords.deletePassword(SERVICE, getLookupKeyForUser(userId)); + } catch (e) { + if (e instanceof Error && e.message === passwords.PASSWORD_NOT_FOUND) { + this.logService.debug( + "[OsBiometricService] Biometric key %s not found for service %s.", + getLookupKeyForUser(userId), + SERVICE, + ); + } else { + throw e; + } + } } async getBiometricKey(userId: UserId): Promise { diff --git a/apps/desktop/src/key-management/biometrics/os-biometrics-mac.service.spec.ts b/apps/desktop/src/key-management/biometrics/os-biometrics-mac.service.spec.ts new file mode 100644 index 00000000000..6d20095d8bb --- /dev/null +++ b/apps/desktop/src/key-management/biometrics/os-biometrics-mac.service.spec.ts @@ -0,0 +1,78 @@ +import { mock } from "jest-mock-extended"; + +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { UserId } from "@bitwarden/common/types/guid"; +import { passwords } from "@bitwarden/desktop-napi"; + +import OsBiometricsServiceMac from "./os-biometrics-mac.service"; + +jest.mock("@bitwarden/desktop-napi", () => ({ + biometrics: { + setBiometricSecret: jest.fn(), + getBiometricSecret: jest.fn(), + deleteBiometricSecret: jest.fn(), + prompt: jest.fn(), + available: jest.fn(), + deriveKeyMaterial: jest.fn(), + }, + passwords: { + deletePassword: jest.fn(), + getPassword: jest.fn(), + isAvailable: jest.fn(), + PASSWORD_NOT_FOUND: "Password not found", + }, +})); + +describe("OsBiometricsServiceMac", () => { + let service: OsBiometricsServiceMac; + let i18nService: I18nService; + let logService: LogService; + + const mockUserId = "test-user-id" as UserId; + + beforeEach(() => { + i18nService = mock(); + logService = mock(); + service = new OsBiometricsServiceMac(i18nService, logService); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe("deleteBiometricKey", () => { + const serviceName = "Bitwarden_biometric"; + const keyName = "test-user-id_user_biometric"; + + it("should delete biometric key successfully", async () => { + await service.deleteBiometricKey(mockUserId); + + expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, keyName); + }); + + it("should not throw error if key not found", async () => { + passwords.deletePassword = jest + .fn() + .mockRejectedValueOnce(new Error(passwords.PASSWORD_NOT_FOUND)); + + await service.deleteBiometricKey(mockUserId); + + expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, keyName); + expect(logService.debug).toHaveBeenCalledWith( + "[OsBiometricService] Biometric key %s not found for service %s.", + keyName, + serviceName, + ); + }); + + it("should throw error for unexpected errors", async () => { + const error = new Error("Unexpected error"); + passwords.deletePassword = jest.fn().mockRejectedValueOnce(error); + + await expect(service.deleteBiometricKey(mockUserId)).rejects.toThrow(error); + + expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, keyName); + }); + }); +}); diff --git a/apps/desktop/src/key-management/biometrics/os-biometrics-mac.service.ts b/apps/desktop/src/key-management/biometrics/os-biometrics-mac.service.ts index 004495b6da9..1dc64f1bcd5 100644 --- a/apps/desktop/src/key-management/biometrics/os-biometrics-mac.service.ts +++ b/apps/desktop/src/key-management/biometrics/os-biometrics-mac.service.ts @@ -1,6 +1,7 @@ import { systemPreferences } from "electron"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { UserId } from "@bitwarden/common/types/guid"; import { passwords } from "@bitwarden/desktop-napi"; @@ -14,7 +15,10 @@ function getLookupKeyForUser(userId: UserId): string { } export default class OsBiometricsServiceMac implements OsBiometricService { - constructor(private i18nservice: I18nService) {} + constructor( + private i18nservice: I18nService, + private logService: LogService, + ) {} async supportsBiometrics(): Promise { return systemPreferences.canPromptTouchID(); @@ -52,7 +56,19 @@ export default class OsBiometricsServiceMac implements OsBiometricService { } async deleteBiometricKey(user: UserId): Promise { - return await passwords.deletePassword(SERVICE, getLookupKeyForUser(user)); + try { + return await passwords.deletePassword(SERVICE, getLookupKeyForUser(user)); + } catch (e) { + if (e instanceof Error && e.message === passwords.PASSWORD_NOT_FOUND) { + this.logService.debug( + "[OsBiometricService] Biometric key %s not found for service %s.", + getLookupKeyForUser(user), + SERVICE, + ); + } else { + throw e; + } + } } private async valueUpToDate(user: UserId, key: SymmetricCryptoKey): Promise { diff --git a/apps/desktop/src/key-management/biometrics/os-biometrics-windows.service.spec.ts b/apps/desktop/src/key-management/biometrics/os-biometrics-windows.service.spec.ts index d0fd8682f2a..674d97bf696 100644 --- a/apps/desktop/src/key-management/biometrics/os-biometrics-windows.service.spec.ts +++ b/apps/desktop/src/key-management/biometrics/os-biometrics-windows.service.spec.ts @@ -6,8 +6,11 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { UserId } from "@bitwarden/common/types/guid"; +import { passwords } from "@bitwarden/desktop-napi"; import { BiometricsStatus, BiometricStateService } from "@bitwarden/key-management"; +import { WindowMain } from "../../main/window.main"; + import OsBiometricsServiceWindows from "./os-biometrics-windows.service"; jest.mock("@bitwarden/desktop-napi", () => ({ @@ -15,28 +18,37 @@ jest.mock("@bitwarden/desktop-napi", () => ({ available: jest.fn(), setBiometricSecret: jest.fn(), getBiometricSecret: jest.fn(), - deriveKeyMaterial: jest.fn(), + deleteBiometricSecret: jest.fn(), prompt: jest.fn(), + deriveKeyMaterial: jest.fn(), }, passwords: { getPassword: jest.fn(), deletePassword: jest.fn(), + isAvailable: jest.fn(), + PASSWORD_NOT_FOUND: "Password not found", }, })); describe("OsBiometricsServiceWindows", () => { let service: OsBiometricsServiceWindows; + let i18nService: I18nService; + let windowMain: WindowMain; + let logService: LogService; let biometricStateService: BiometricStateService; + const mockUserId = "test-user-id" as UserId; + beforeEach(() => { - const i18nService = mock(); - const logService = mock(); + i18nService = mock(); + windowMain = mock(); + logService = mock(); biometricStateService = mock(); const encryptionService = mock(); const cryptoFunctionService = mock(); service = new OsBiometricsServiceWindows( i18nService, - null, + windowMain, logService, biometricStateService, encryptionService, @@ -81,7 +93,7 @@ describe("OsBiometricsServiceWindows", () => { cryptoFunctionService = mock(); service = new OsBiometricsServiceWindows( mock(), - null, + windowMain, mock(), biometricStateService, encryptionService, @@ -140,4 +152,97 @@ describe("OsBiometricsServiceWindows", () => { expect((service as any).clientKeyHalves.get(userId.toString())).toBeNull(); }); }); + + describe("deleteBiometricKey", () => { + const serviceName = "Bitwarden_biometric"; + const keyName = "test-user-id_user_biometric"; + const witnessKeyName = "test-user-id_user_biometric_witness"; + + it("should delete biometric key successfully", async () => { + await service.deleteBiometricKey(mockUserId); + + expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, keyName); + expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, witnessKeyName); + }); + + it.each([ + [false, false], + [false, true], + [true, false], + ])( + "should not throw error if key found: %s and witness key found: %s", + async (keyFound, witnessKeyFound) => { + passwords.deletePassword = jest.fn().mockImplementation((_, account) => { + if (account === keyName) { + if (!keyFound) { + throw new Error(passwords.PASSWORD_NOT_FOUND); + } + return Promise.resolve(); + } + if (account === witnessKeyName) { + if (!witnessKeyFound) { + throw new Error(passwords.PASSWORD_NOT_FOUND); + } + return Promise.resolve(); + } + throw new Error("Unexpected key"); + }); + + await service.deleteBiometricKey(mockUserId); + + expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, keyName); + expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, witnessKeyName); + if (!keyFound) { + expect(logService.debug).toHaveBeenCalledWith( + "[OsBiometricService] Biometric key %s not found for service %s.", + keyName, + serviceName, + ); + } + if (!witnessKeyFound) { + expect(logService.debug).toHaveBeenCalledWith( + "[OsBiometricService] Biometric witness key %s not found for service %s.", + witnessKeyName, + serviceName, + ); + } + }, + ); + + it("should throw error when deletePassword for key throws unexpected errors", async () => { + const error = new Error("Unexpected error"); + passwords.deletePassword = jest.fn().mockImplementation((_, account) => { + if (account === keyName) { + throw error; + } + if (account === witnessKeyName) { + return Promise.resolve(); + } + throw new Error("Unexpected key"); + }); + + await expect(service.deleteBiometricKey(mockUserId)).rejects.toThrow(error); + + expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, keyName); + expect(passwords.deletePassword).not.toHaveBeenCalledWith(serviceName, witnessKeyName); + }); + + it("should throw error when deletePassword for witness key throws unexpected errors", async () => { + const error = new Error("Unexpected error"); + passwords.deletePassword = jest.fn().mockImplementation((_, account) => { + if (account === keyName) { + return Promise.resolve(); + } + if (account === witnessKeyName) { + throw error; + } + throw new Error("Unexpected key"); + }); + + await expect(service.deleteBiometricKey(mockUserId)).rejects.toThrow(error); + + expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, keyName); + expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, witnessKeyName); + }); + }); }); diff --git a/apps/desktop/src/key-management/biometrics/os-biometrics-windows.service.ts b/apps/desktop/src/key-management/biometrics/os-biometrics-windows.service.ts index dc4f8674d7f..b1726644b0a 100644 --- a/apps/desktop/src/key-management/biometrics/os-biometrics-windows.service.ts +++ b/apps/desktop/src/key-management/biometrics/os-biometrics-windows.service.ts @@ -116,8 +116,32 @@ export default class OsBiometricsServiceWindows implements OsBiometricService { } async deleteBiometricKey(userId: UserId): Promise { - await passwords.deletePassword(SERVICE, getLookupKeyForUser(userId)); - await passwords.deletePassword(SERVICE, getLookupKeyForUser(userId) + KEY_WITNESS_SUFFIX); + try { + await passwords.deletePassword(SERVICE, getLookupKeyForUser(userId)); + } catch (e) { + if (e instanceof Error && e.message === passwords.PASSWORD_NOT_FOUND) { + this.logService.debug( + "[OsBiometricService] Biometric key %s not found for service %s.", + getLookupKeyForUser(userId), + SERVICE, + ); + } else { + throw e; + } + } + try { + await passwords.deletePassword(SERVICE, getLookupKeyForUser(userId) + KEY_WITNESS_SUFFIX); + } catch (e) { + if (e instanceof Error && e.message === passwords.PASSWORD_NOT_FOUND) { + this.logService.debug( + "[OsBiometricService] Biometric witness key %s not found for service %s.", + getLookupKeyForUser(userId) + KEY_WITNESS_SUFFIX, + SERVICE, + ); + } else { + throw e; + } + } } async authenticateBiometric(): Promise { @@ -227,8 +251,19 @@ export default class OsBiometricsServiceWindows implements OsBiometricService { storageKey + KEY_WITNESS_SUFFIX, witnessKeyMaterial, ); - } catch { - this.logService.debug("Error retrieving witness key, assuming value is not up to date."); + } catch (e) { + if (e instanceof Error && e.message === passwords.PASSWORD_NOT_FOUND) { + this.logService.debug( + "[OsBiometricService] Biometric witness key %s not found for service %s, value is not up to date.", + storageKey + KEY_WITNESS_SUFFIX, + service, + ); + } else { + this.logService.error( + "[OsBiometricService] Error retrieving witness key, assuming value is not up to date.", + e, + ); + } return false; } diff --git a/apps/desktop/src/platform/main/desktop-credential-storage-listener.ts b/apps/desktop/src/platform/main/desktop-credential-storage-listener.ts index ca4d9a2d3ca..6922911e367 100644 --- a/apps/desktop/src/platform/main/desktop-credential-storage-listener.ts +++ b/apps/desktop/src/platform/main/desktop-credential-storage-listener.ts @@ -35,13 +35,13 @@ export class DesktopCredentialStorageListener { } return val; } catch (e) { - if ( - e.message === "Password not found." || - e.message === "The specified item could not be found in the keychain." - ) { + if (e instanceof Error && e.message === passwords.PASSWORD_NOT_FOUND) { + if (message.action === "hasPassword") { + return false; + } return null; } - this.logService.info(e); + this.logService.error("[Credential Storage Listener] %s failed", message.action, e); } }); } From 043d8b353315ae01d64aa84c12d0cf8b8ed33ea5 Mon Sep 17 00:00:00 2001 From: cyprain-okeke <108260115+cyprain-okeke@users.noreply.github.com> Date: Mon, 30 Jun 2025 13:58:41 +0100 Subject: [PATCH 018/239] Dont skip payment details if triallength is zero (#15268) --- .../complete-trial-initiation.component.html | 8 ++++++-- .../complete-trial-initiation.component.ts | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/web/src/app/billing/trial-initiation/complete-trial-initiation/complete-trial-initiation.component.html b/apps/web/src/app/billing/trial-initiation/complete-trial-initiation/complete-trial-initiation.component.html index 7f093842b6a..7a1ca2cd83d 100644 --- a/apps/web/src/app/billing/trial-initiation/complete-trial-initiation/complete-trial-initiation.component.html +++ b/apps/web/src/app/billing/trial-initiation/complete-trial-initiation/complete-trial-initiation.component.html @@ -38,13 +38,17 @@ [loading]="loading && (trialPaymentOptional$ | async)" (click)="orgNameEntrySubmit()" > - {{ (trialPaymentOptional$ | async) ? ("startTrial" | i18n) : ("next" | i18n) }} + {{ + (trialPaymentOptional$ | async) && trialLength > 0 + ? ("startTrial" | i18n) + : ("next" | i18n) + }} { const isTrialPaymentOptional = await firstValueFrom(this.trialPaymentOptional$); - if (isTrialPaymentOptional) { + /** Only skip payment if the flag is on AND trialLength > 0 */ + if (isTrialPaymentOptional && this.trialLength > 0) { await this.createOrganizationOnTrial(); } else { await this.conditionallyCreateOrganization(); From 0772e5c316536c567a503d8a217c770afbdc12c8 Mon Sep 17 00:00:00 2001 From: Github Actions Date: Mon, 30 Jun 2025 13:13:00 +0000 Subject: [PATCH 019/239] Bumped client version(s) --- apps/web/package.json | 2 +- package-lock.json | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index 4dfcd58cce4..f672e44a80b 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/web-vault", - "version": "2025.6.1", + "version": "2025.7.0", "scripts": { "build:oss": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" webpack", "build:bit": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" webpack -c ../../bitwarden_license/bit-web/webpack.config.js", diff --git a/package-lock.json b/package-lock.json index c83580dd0d5..0855df67e8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -191,7 +191,7 @@ "webpack-node-externals": "3.0.0" }, "engines": { - "node": "~20", + "node": "~22", "npm": "~10" } }, @@ -235,6 +235,10 @@ }, "bin": { "bw": "build/bw.js" + }, + "engines": { + "node": "~20", + "npm": "~10" } }, "apps/cli/node_modules/define-lazy-prop": { @@ -300,7 +304,7 @@ }, "apps/web": { "name": "@bitwarden/web-vault", - "version": "2025.6.1" + "version": "2025.7.0" }, "libs/admin-console": { "name": "@bitwarden/admin-console", From 04ddea5bf3bd75400455d13bedf7760ea2b30a4c Mon Sep 17 00:00:00 2001 From: Vicki League Date: Mon, 30 Jun 2025 09:39:39 -0400 Subject: [PATCH 020/239] [CL-473] Adjust popup page max width and scroll containers (#14853) --- .../platform/popup/layout/popup-layout.mdx | 19 ++++ .../popup/layout/popup-layout.stories.ts | 100 ++++++++++++++++-- .../popup/layout/popup-page.component.html | 30 ++++-- .../popup/layout/popup-page.component.ts | 3 +- apps/browser/src/popup/scss/base.scss | 8 -- .../vault-list-items-container.component.html | 5 +- .../vault-list-items-container.component.ts | 2 + .../vault-v2/vault-v2.component.html | 10 +- .../src/stories/virtual-scrolling.mdx | 42 +++++++- libs/components/src/tw-theme.css | 2 + 10 files changed, 181 insertions(+), 40 deletions(-) diff --git a/apps/browser/src/platform/popup/layout/popup-layout.mdx b/apps/browser/src/platform/popup/layout/popup-layout.mdx index 017ee20b344..a2725350a8f 100644 --- a/apps/browser/src/platform/popup/layout/popup-layout.mdx +++ b/apps/browser/src/platform/popup/layout/popup-layout.mdx @@ -54,6 +54,9 @@ page looks nice when the extension is popped out. `false`. - `loadingText` - Custom text to be applied to the loading element for screenreaders only. Defaults to "Loading". +- `disablePadding` + - When `true`, disables the padding of the scrollable region inside of `main`. You will need to + add your own padding to the element you place inside of this area. Basic usage example: @@ -169,6 +172,22 @@ When the browser extension is popped out, the "popout" button should not be pass +## With Virtual Scroll + +If you are using a virtual scrolling container inside of the popup page, you'll want to apply the +`bitScrollLayout` directive to the `cdk-virtual-scroll-viewport` element. This tells the virtual +scroll viewport to use the popup page's scroll layout div as the scrolling container. + +See the code in the example below. + + + +### Known Virtual Scroll Issues + +See [Virtual Scrolling](?path=/docs/documentation-virtual-scrolling--docs#known-footgun) for more +information about how to structure virtual scrolling containers with layout components and avoid a +known issue with template construction. + # Other stories ## Centered Content diff --git a/apps/browser/src/platform/popup/layout/popup-layout.stories.ts b/apps/browser/src/platform/popup/layout/popup-layout.stories.ts index aecbaf673dc..894ab13dd19 100644 --- a/apps/browser/src/platform/popup/layout/popup-layout.stories.ts +++ b/apps/browser/src/platform/popup/layout/popup-layout.stories.ts @@ -1,5 +1,4 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore +import { ScrollingModule } from "@angular/cdk/scrolling"; import { CommonModule } from "@angular/common"; import { Component, importProvidersFrom } from "@angular/core"; import { RouterModule } from "@angular/router"; @@ -20,6 +19,7 @@ import { NoItemsModule, SearchModule, SectionComponent, + ScrollLayoutDirective, } from "@bitwarden/components"; import { PopupRouterCacheService } from "../view-cache/popup-router-cache.service"; @@ -39,6 +39,17 @@ import { PopupTabNavigationComponent } from "./popup-tab-navigation.component"; }) class ExtensionContainerComponent {} +@Component({ + selector: "extension-popped-container", + template: ` +
+ +
+ `, + standalone: true, +}) +class ExtensionPoppedContainerComponent {} + @Component({ selector: "vault-placeholder", template: /*html*/ ` @@ -295,6 +306,7 @@ export default { decorators: [ moduleMetadata({ imports: [ + ScrollLayoutDirective, PopupTabNavigationComponent, PopupHeaderComponent, PopupPageComponent, @@ -302,6 +314,7 @@ export default { CommonModule, RouterModule, ExtensionContainerComponent, + ExtensionPoppedContainerComponent, MockBannerComponent, MockSearchComponent, MockVaultSubpageComponent, @@ -312,6 +325,11 @@ export default { MockVaultPagePoppedComponent, NoItemsModule, VaultComponent, + ScrollingModule, + ItemModule, + SectionComponent, + IconButtonModule, + BadgeModule, ], providers: [ { @@ -495,7 +513,21 @@ export const CompactMode: Story = { const compact = canvasEl.querySelector( `#${containerId} [data-testid=popup-layout-scroll-region]`, ); + + if (!compact) { + // eslint-disable-next-line + console.error(`#${containerId} [data-testid=popup-layout-scroll-region] not found`); + return; + } + const label = canvasEl.querySelector(`#${containerId} .example-label`); + + if (!label) { + // eslint-disable-next-line + console.error(`#${containerId} .example-label not found`); + return; + } + const percentVisible = 100 - Math.round((100 * (compact.scrollHeight - compact.clientHeight)) / compact.scrollHeight); @@ -510,9 +542,9 @@ export const PoppedOut: Story = { render: (args) => ({ props: args, template: /* HTML */ ` -
+ -
+ `, }), }; @@ -560,10 +592,9 @@ export const TransparentHeader: Story = { template: /* HTML */ ` - 🤠 Custom Content - + + 🤠 Custom Content + @@ -608,3 +639,56 @@ export const WidthOptions: Story = { `, }), }; + +export const WithVirtualScrollChild: Story = { + render: (args) => ({ + props: { ...args, data: Array.from(Array(20).keys()) }, + template: /* HTML */ ` + + + + + + @defer (on immediate) { + + + + + + + + + + + + + + + + + + + + } + + + + `, + }), +}; diff --git a/apps/browser/src/platform/popup/layout/popup-page.component.html b/apps/browser/src/platform/popup/layout/popup-page.component.html index 2313b942a38..b53ef6e97eb 100644 --- a/apps/browser/src/platform/popup/layout/popup-page.component.html +++ b/apps/browser/src/platform/popup/layout/popup-page.component.html @@ -1,29 +1,39 @@
+
+
-
- -
+
- +
-
+ -
+ diff --git a/libs/components/src/stories/virtual-scrolling.mdx b/libs/components/src/stories/virtual-scrolling.mdx index 94a86090dce..ab51d9865db 100644 --- a/libs/components/src/stories/virtual-scrolling.mdx +++ b/libs/components/src/stories/virtual-scrolling.mdx @@ -16,7 +16,7 @@ We export a similar directive, `bitScrollLayout`, that integrates with `bit-layo and should be used instead of `scrollWindow`. ```html - + @@ -27,7 +27,10 @@ and should be used instead of `scrollWindow`. Due to the initialization order of Angular components and their templates, `bitScrollLayout` will error if it is used _in the same template_ as the layout component: +With `bit-layout`: + ```html + @@ -35,20 +38,43 @@ error if it is used _in the same template_ as the layout component: ``` +With `popup-page`: + +```html + + + + + + +``` + In this particular composition, the child content gets constructed before the template of -`bit-layout` and thus has no scroll container to reference. Workarounds include: +`bit-layout` (or `popup-page`) and thus has no scroll container to reference. Workarounds include: 1. Wrap the child in another component. (This tends to happen by default when the layout is integrated with a `router-outlet`.) +With `bit-layout`: + ```html ``` +With `popup-page`: + +```html + + + +``` + 2. Use a `defer` block. +With `bit-layout`: + ```html @defer (on immediate) { @@ -58,3 +84,15 @@ In this particular composition, the child content gets constructed before the te } ``` + +With `popup-page`: + +```html + + @defer (on immediate) { + + + + } + +``` diff --git a/libs/components/src/tw-theme.css b/libs/components/src/tw-theme.css index 103b90e0752..c8de973c3d1 100644 --- a/libs/components/src/tw-theme.css +++ b/libs/components/src/tw-theme.css @@ -58,6 +58,8 @@ --color-marketing-logo: 23 93 220; --tw-ring-offset-color: #ffffff; + + --tw-sm-breakpoint: 640px; } .theme_light { From a2fd4a37793dfa110b744c01fc023b7b852b02d9 Mon Sep 17 00:00:00 2001 From: Vicki League Date: Mon, 30 Jun 2025 11:03:24 -0400 Subject: [PATCH 021/239] [PM-16291] Prevent parent components from closing when esc key is pressed on select and menu (#15214) --- .../src/menu/menu-trigger-for.directive.ts | 8 ++++++++ .../components/src/select/select.component.html | 1 + libs/components/src/select/select.component.ts | 17 +++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/libs/components/src/menu/menu-trigger-for.directive.ts b/libs/components/src/menu/menu-trigger-for.directive.ts index bc174d14d23..528697600c4 100644 --- a/libs/components/src/menu/menu-trigger-for.directive.ts +++ b/libs/components/src/menu/menu-trigger-for.directive.ts @@ -1,5 +1,6 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore +import { hasModifierKey } from "@angular/cdk/keycodes"; import { Overlay, OverlayConfig, OverlayRef } from "@angular/cdk/overlay"; import { TemplatePortal } from "@angular/cdk/portal"; import { @@ -76,6 +77,13 @@ export class MenuTriggerForDirective implements OnDestroy { this.overlayRef.attach(templatePortal); this.closedEventsSub = this.getClosedEvents().subscribe((event: KeyboardEvent | undefined) => { + // Closing the menu is handled in this.destroyMenu, so we want to prevent the escape key + // from doing its normal default action, which would otherwise cause a parent component + // (like a dialog) or extension window to close + if (event?.key === "Escape" && !hasModifierKey(event)) { + event.preventDefault(); + } + if (["Tab", "Escape"].includes(event?.key)) { // Required to ensure tab order resumes correctly this.elementRef.nativeElement.focus(); diff --git a/libs/components/src/select/select.component.html b/libs/components/src/select/select.component.html index 84de9827b97..6d4c431f234 100644 --- a/libs/components/src/select/select.component.html +++ b/libs/components/src/select/select.component.html @@ -9,6 +9,7 @@ [clearable]="false" (close)="onClose()" appendTo="body" + [keyDownFn]="onKeyDown" >
diff --git a/libs/components/src/select/select.component.ts b/libs/components/src/select/select.component.ts index d2c48bf0f6e..909566bf1f8 100644 --- a/libs/components/src/select/select.component.ts +++ b/libs/components/src/select/select.component.ts @@ -1,6 +1,7 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore +import { hasModifierKey } from "@angular/cdk/keycodes"; import { Component, ContentChildren, @@ -185,4 +186,20 @@ export class SelectComponent implements BitFormFieldControl, ControlValueAcce protected onClose() { this.closed.emit(); } + + /** + * Prevent Escape key press from propagating to parent components + * (for example, parent dialog should not close when Escape is pressed in the select) + * + * @returns true to keep default key behavior; false to prevent default key behavior + * + * Needs to be arrow function to retain `this` scope. + */ + protected onKeyDown = (event: KeyboardEvent) => { + if (this.select.isOpen && event.key === "Escape" && !hasModifierKey(event)) { + event.stopPropagation(); + } + + return true; + }; } From 4bfcc9d076f812cee703d4ed473c4cb17163ebd8 Mon Sep 17 00:00:00 2001 From: SmithThe4th Date: Mon, 30 Jun 2025 11:32:19 -0400 Subject: [PATCH 022/239] [PM-23008] Error when attempting to export vault (#15397) * moved restrictedItemTypesService creation before export service is created * Fixed cliRestrictedItemTypesService arrangement --- .../service-container/service-container.ts | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/cli/src/service-container/service-container.ts b/apps/cli/src/service-container/service-container.ts index df019520250..f27c69cf47b 100644 --- a/apps/cli/src/service-container/service-container.ts +++ b/apps/cli/src/service-container/service-container.ts @@ -795,6 +795,17 @@ export class ServiceContainer { this.totpService = new TotpService(this.sdkService); + this.restrictedItemTypesService = new RestrictedItemTypesService( + this.configService, + this.accountService, + this.organizationService, + this.policyService, + ); + + this.cliRestrictedItemTypesService = new CliRestrictedItemTypesService( + this.restrictedItemTypesService, + ); + this.importApiService = new ImportApiService(this.apiService); this.importService = new ImportService( @@ -875,17 +886,6 @@ export class ServiceContainer { ); this.masterPasswordApiService = new MasterPasswordApiService(this.apiService, this.logService); - - this.restrictedItemTypesService = new RestrictedItemTypesService( - this.configService, - this.accountService, - this.organizationService, - this.policyService, - ); - - this.cliRestrictedItemTypesService = new CliRestrictedItemTypesService( - this.restrictedItemTypesService, - ); } async logout() { From 80116c7e5453f483f5a03486318e73cbd0cec633 Mon Sep 17 00:00:00 2001 From: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Date: Tue, 1 Jul 2025 02:18:56 +1000 Subject: [PATCH 023/239] Use organizations$ observable instead of class member (#15377) --- .../organizations/members/members.component.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/web/src/app/admin-console/organizations/members/members.component.ts b/apps/web/src/app/admin-console/organizations/members/members.component.ts index 633f45ae9a3..0247a8c881b 100644 --- a/apps/web/src/app/admin-console/organizations/members/members.component.ts +++ b/apps/web/src/app/admin-console/organizations/members/members.component.ts @@ -248,10 +248,13 @@ export class MembersComponent extends BaseMembersComponent const separateCustomRolePermissionsEnabled$ = this.configService.getFeatureFlag$( FeatureFlag.SeparateCustomRolePermissions, ); - this.showUserManagementControls$ = separateCustomRolePermissionsEnabled$.pipe( + this.showUserManagementControls$ = combineLatest([ + separateCustomRolePermissionsEnabled$, + organization$, + ]).pipe( map( - (separateCustomRolePermissionsEnabled) => - !separateCustomRolePermissionsEnabled || this.organization.canManageUsers, + ([separateCustomRolePermissionsEnabled, organization]) => + !separateCustomRolePermissionsEnabled || organization.canManageUsers, ), ); } From 62981a1bec37aae5bb0e9d9c489e88bc57e2e95c Mon Sep 17 00:00:00 2001 From: SmithThe4th Date: Mon, 30 Jun 2025 13:02:18 -0400 Subject: [PATCH 024/239] Migrate vault filter service from active user state to single user state (#15089) --- .../deprecated-vault-filter.service.ts | 18 +++++++++------ .../components/vault-filter.component.ts | 20 ++++++++++++++--- .../services/vault-filter.service.ts | 22 +++++++++++-------- 3 files changed, 41 insertions(+), 19 deletions(-) diff --git a/libs/angular/src/vault/abstractions/deprecated-vault-filter.service.ts b/libs/angular/src/vault/abstractions/deprecated-vault-filter.service.ts index 21528b1ddd5..9a1a31b6068 100644 --- a/libs/angular/src/vault/abstractions/deprecated-vault-filter.service.ts +++ b/libs/angular/src/vault/abstractions/deprecated-vault-filter.service.ts @@ -6,6 +6,7 @@ import { Observable } from "rxjs"; // eslint-disable-next-line no-restricted-imports import { CollectionView } from "@bitwarden/admin-console/common"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; +import { UserId } from "@bitwarden/common/types/guid"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { DynamicTreeNode } from "../vault-filter/models/dynamic-tree-node.model"; @@ -14,11 +15,14 @@ import { DynamicTreeNode } from "../vault-filter/models/dynamic-tree-node.model" * @deprecated August 30 2022: Use new VaultFilterService with observables */ export abstract class DeprecatedVaultFilterService { - buildOrganizations: () => Promise; - buildNestedFolders: (organizationId?: string) => Observable>; - buildCollections: (organizationId?: string) => Promise>; - buildCollapsedFilterNodes: () => Promise>; - storeCollapsedFilterNodes: (collapsedFilterNodes: Set) => Promise; - checkForSingleOrganizationPolicy: () => Promise; - checkForOrganizationDataOwnershipPolicy: () => Promise; + abstract buildOrganizations(): Promise; + abstract buildNestedFolders(organizationId?: string): Observable>; + abstract buildCollections(organizationId?: string): Promise>; + abstract buildCollapsedFilterNodes(userId: UserId): Promise>; + abstract storeCollapsedFilterNodes( + collapsedFilterNodes: Set, + userId: UserId, + ): Promise; + abstract checkForSingleOrganizationPolicy(): Promise; + abstract checkForOrganizationDataOwnershipPolicy(): Promise; } diff --git a/libs/angular/src/vault/vault-filter/components/vault-filter.component.ts b/libs/angular/src/vault/vault-filter/components/vault-filter.component.ts index 936d606b936..0b0cb14bbb8 100644 --- a/libs/angular/src/vault/vault-filter/components/vault-filter.component.ts +++ b/libs/angular/src/vault/vault-filter/components/vault-filter.component.ts @@ -7,6 +7,9 @@ import { firstValueFrom, Observable } from "rxjs"; // eslint-disable-next-line no-restricted-imports import { CollectionView } from "@bitwarden/admin-console/common"; 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 { UserId } from "@bitwarden/common/types/guid"; import { ITreeNodeObject } from "@bitwarden/common/vault/models/domain/tree-node"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; @@ -29,6 +32,8 @@ export class VaultFilterComponent implements OnInit { @Output() onAddFolder = new EventEmitter(); @Output() onEditFolder = new EventEmitter(); + private activeUserId: UserId; + isLoaded = false; collapsedFilterNodes: Set; organizations: Organization[]; @@ -37,14 +42,20 @@ export class VaultFilterComponent implements OnInit { collections: DynamicTreeNode; folders$: Observable>; - constructor(protected vaultFilterService: DeprecatedVaultFilterService) {} + constructor( + protected vaultFilterService: DeprecatedVaultFilterService, + protected accountService: AccountService, + ) {} get displayCollections() { return this.collections?.fullList != null && this.collections.fullList.length > 0; } async ngOnInit(): Promise { - this.collapsedFilterNodes = await this.vaultFilterService.buildCollapsedFilterNodes(); + this.activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)); + this.collapsedFilterNodes = await this.vaultFilterService.buildCollapsedFilterNodes( + this.activeUserId, + ); this.organizations = await this.vaultFilterService.buildOrganizations(); if (this.organizations != null && this.organizations.length > 0) { this.activeOrganizationDataOwnershipPolicy = @@ -68,7 +79,10 @@ export class VaultFilterComponent implements OnInit { } else { this.collapsedFilterNodes.add(node.id); } - await this.vaultFilterService.storeCollapsedFilterNodes(this.collapsedFilterNodes); + await this.vaultFilterService.storeCollapsedFilterNodes( + this.collapsedFilterNodes, + this.activeUserId, + ); } async applyFilter(filter: VaultFilter) { 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 a4114e63285..3317f0c9002 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 @@ -12,7 +12,7 @@ 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 { getUserId } from "@bitwarden/common/auth/services/account.service"; -import { ActiveUserState, StateProvider } from "@bitwarden/common/platform/state"; +import { SingleUserState, StateProvider } from "@bitwarden/common/platform/state"; import { UserId } 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"; @@ -28,10 +28,9 @@ const NestingDelimiter = "/"; @Injectable() export class VaultFilterService implements DeprecatedVaultFilterServiceAbstraction { - private collapsedGroupingsState: ActiveUserState = - this.stateProvider.getActive(COLLAPSED_GROUPINGS); - private readonly collapsedGroupings$: Observable> = - this.collapsedGroupingsState.state$.pipe(map((c) => new Set(c))); + private collapsedGroupingsState(userId: UserId): SingleUserState { + return this.stateProvider.getUser(userId, COLLAPSED_GROUPINGS); + } constructor( protected organizationService: OrganizationService, @@ -43,12 +42,17 @@ export class VaultFilterService implements DeprecatedVaultFilterServiceAbstracti protected accountService: AccountService, ) {} - async storeCollapsedFilterNodes(collapsedFilterNodes: Set): Promise { - await this.collapsedGroupingsState.update(() => Array.from(collapsedFilterNodes)); + async storeCollapsedFilterNodes( + collapsedFilterNodes: Set, + userId: UserId, + ): Promise { + await this.collapsedGroupingsState(userId).update(() => Array.from(collapsedFilterNodes)); } - async buildCollapsedFilterNodes(): Promise> { - return await firstValueFrom(this.collapsedGroupings$); + async buildCollapsedFilterNodes(userId: UserId): Promise> { + return await firstValueFrom( + this.collapsedGroupingsState(userId).state$.pipe(map((c) => new Set(c))), + ); } async buildOrganizations(): Promise { From ea5224da259b24442d7746f38b89db22196f2587 Mon Sep 17 00:00:00 2001 From: SmithThe4th Date: Mon, 30 Jun 2025 13:04:01 -0400 Subject: [PATCH 025/239] Properly converted date strings during imports and provided default values (#15398) --- libs/common/src/models/export/cipher.export.ts | 6 +++--- libs/common/src/vault/models/domain/cipher.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/common/src/models/export/cipher.export.ts b/libs/common/src/models/export/cipher.export.ts index 7d0ef9e9c34..fa050375391 100644 --- a/libs/common/src/models/export/cipher.export.ts +++ b/libs/common/src/models/export/cipher.export.ts @@ -124,9 +124,9 @@ export class CipherExport { domain.passwordHistory = req.passwordHistory.map((ph) => PasswordHistoryExport.toDomain(ph)); } - domain.creationDate = req.creationDate; - domain.revisionDate = req.revisionDate; - domain.deletedDate = req.deletedDate; + domain.creationDate = req.creationDate ? new Date(req.creationDate) : null; + domain.revisionDate = req.revisionDate ? new Date(req.revisionDate) : null; + domain.deletedDate = req.deletedDate ? new Date(req.deletedDate) : null; return domain; } diff --git a/libs/common/src/vault/models/domain/cipher.ts b/libs/common/src/vault/models/domain/cipher.ts index e6d11a82b69..9cc9226cd46 100644 --- a/libs/common/src/vault/models/domain/cipher.ts +++ b/libs/common/src/vault/models/domain/cipher.ts @@ -353,14 +353,14 @@ export class Cipher extends Domain implements Decryptable { type: this.type, favorite: this.favorite ?? false, organizationUseTotp: this.organizationUseTotp ?? false, - edit: this.edit, + edit: this.edit ?? true, permissions: this.permissions ? { delete: this.permissions.delete, restore: this.permissions.restore, } : undefined, - viewPassword: this.viewPassword, + viewPassword: this.viewPassword ?? true, localData: this.localData ? { lastUsedDate: this.localData.lastUsedDate From 64eb9b56d7634cc6804f3125b14781e363499f6e Mon Sep 17 00:00:00 2001 From: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com> Date: Mon, 30 Jun 2025 13:47:31 -0400 Subject: [PATCH 026/239] feat(anon-layout): [Auth/PM-17737] AnonLayout - Consolidate and extend max width control (#15362) * PM-17737 - feat(anon-layout-width) - consolidate width setting to control title, subtitle, and content together for a unified UX. Removes all titleAreaMaxWidth usages and the titleAreaMaxWidth property entirely. * PM-17737 - AnonLayout - consolidate stories into playground (w/ the exception of default icon story b/c I can't figure how to omit the icon conditionally). * PM-17737 - AnonLayoutStories - show secondary content by default * PM-17737 - Per PR feedback, adjust maxWidthClass logic to remove string concatenation as it can result in tailwind classes not being compiled and available at run time. * PM-17737 - Per PR feedback, refactor stories to use configuration to generate all the scenarios so we can still track them via snapshots * PM-17737 - Fix anon layout mdx reference * PM-17737 - Make AnonLayoutMaxWidths singular * PM-17737 - When inside of a max width container, the icon container needs explicit width to be able to scale viewbox icons that don't have defined heights / widths --- apps/web/src/app/oss-routing.module.ts | 2 - .../anon-layout-wrapper.component.html | 1 - .../anon-layout-wrapper.component.ts | 13 +- .../anon-layout/anon-layout.component.html | 11 +- .../src/anon-layout/anon-layout.component.ts | 31 +- .../src/anon-layout/anon-layout.mdx | 2 +- .../src/anon-layout/anon-layout.stories.ts | 340 +++++++++--------- 7 files changed, 198 insertions(+), 202 deletions(-) diff --git a/apps/web/src/app/oss-routing.module.ts b/apps/web/src/app/oss-routing.module.ts index 783fe6ada0a..0733d1ef289 100644 --- a/apps/web/src/app/oss-routing.module.ts +++ b/apps/web/src/app/oss-routing.module.ts @@ -347,7 +347,6 @@ const routes: Routes = [ pageSubtitle: { key: "singleSignOnEnterOrgIdentifierText", }, - titleAreaMaxWidth: "md", pageIcon: SsoKeyIcon, } satisfies RouteDataProperties & AnonLayoutWrapperData, children: [ @@ -381,7 +380,6 @@ const routes: Routes = [ pageTitle: { key: "verifyYourIdentity", }, - titleAreaMaxWidth: "md", } satisfies RouteDataProperties & AnonLayoutWrapperData, }, { diff --git a/libs/components/src/anon-layout/anon-layout-wrapper.component.html b/libs/components/src/anon-layout/anon-layout-wrapper.component.html index 2cba7ca7783..0d393b30362 100644 --- a/libs/components/src/anon-layout/anon-layout-wrapper.component.html +++ b/libs/components/src/anon-layout/anon-layout-wrapper.component.html @@ -4,7 +4,6 @@ [icon]="pageIcon" [showReadonlyHostname]="showReadonlyHostname" [maxWidth]="maxWidth" - [titleAreaMaxWidth]="titleAreaMaxWidth" [hideCardWrapper]="hideCardWrapper" > diff --git a/libs/components/src/anon-layout/anon-layout-wrapper.component.ts b/libs/components/src/anon-layout/anon-layout-wrapper.component.ts index ea6a518f70d..20380f137a6 100644 --- a/libs/components/src/anon-layout/anon-layout-wrapper.component.ts +++ b/libs/components/src/anon-layout/anon-layout-wrapper.component.ts @@ -10,7 +10,7 @@ import { Translation } from "../dialog"; import { Icon } from "../icon"; import { AnonLayoutWrapperDataService } from "./anon-layout-wrapper-data.service"; -import { AnonLayoutComponent } from "./anon-layout.component"; +import { AnonLayoutComponent, AnonLayoutMaxWidth } from "./anon-layout.component"; export interface AnonLayoutWrapperData { /** @@ -36,11 +36,7 @@ export interface AnonLayoutWrapperData { /** * Optional flag to set the max-width of the page. Defaults to 'md' if not provided. */ - maxWidth?: "md" | "3xl"; - /** - * Optional flag to set the max-width of the title area. Defaults to null if not provided. - */ - titleAreaMaxWidth?: "md"; + maxWidth?: AnonLayoutMaxWidth; /** * Hide the card that wraps the default content. Defaults to false. */ @@ -58,8 +54,7 @@ export class AnonLayoutWrapperComponent implements OnInit, OnDestroy { protected pageSubtitle: string; protected pageIcon: Icon; protected showReadonlyHostname: boolean; - protected maxWidth: "md" | "3xl"; - protected titleAreaMaxWidth: "md"; + protected maxWidth: AnonLayoutMaxWidth; protected hideCardWrapper: boolean; constructor( @@ -111,7 +106,6 @@ export class AnonLayoutWrapperComponent implements OnInit, OnDestroy { this.showReadonlyHostname = Boolean(firstChildRouteData["showReadonlyHostname"]); this.maxWidth = firstChildRouteData["maxWidth"]; - this.titleAreaMaxWidth = firstChildRouteData["titleAreaMaxWidth"]; this.hideCardWrapper = Boolean(firstChildRouteData["hideCardWrapper"]); } @@ -174,7 +168,6 @@ export class AnonLayoutWrapperComponent implements OnInit, OnDestroy { this.pageIcon = null; this.showReadonlyHostname = null; this.maxWidth = null; - this.titleAreaMaxWidth = null; this.hideCardWrapper = null; } diff --git a/libs/components/src/anon-layout/anon-layout.component.html b/libs/components/src/anon-layout/anon-layout.component.html index a8e091e6e72..4dfde5e7ef3 100644 --- a/libs/components/src/anon-layout/anon-layout.component.html +++ b/libs/components/src/anon-layout/anon-layout.component.html @@ -13,11 +13,8 @@ -
-
+
+
@@ -36,8 +33,8 @@
@if (hideCardWrapper) {
diff --git a/libs/components/src/anon-layout/anon-layout.component.ts b/libs/components/src/anon-layout/anon-layout.component.ts index abde48649af..ee3a7ca7bee 100644 --- a/libs/components/src/anon-layout/anon-layout.component.ts +++ b/libs/components/src/anon-layout/anon-layout.component.ts @@ -14,6 +14,8 @@ import { BitwardenLogo, BitwardenShield } from "../icon/icons"; import { SharedModule } from "../shared"; import { TypographyModule } from "../typography"; +export type AnonLayoutMaxWidth = "md" | "lg" | "xl" | "2xl" | "3xl"; + @Component({ selector: "auth-anon-layout", templateUrl: "./anon-layout.component.html", @@ -36,27 +38,35 @@ export class AnonLayoutComponent implements OnInit, OnChanges { @Input() hideCardWrapper: boolean = false; /** - * Max width of the title area content - * - * @default null - */ - @Input() titleAreaMaxWidth?: "md"; - - /** - * Max width of the layout content + * Max width of the anon layout title, subtitle, and content areas. * * @default 'md' */ - @Input() maxWidth: "md" | "3xl" = "md"; + @Input() maxWidth: AnonLayoutMaxWidth = "md"; protected logo = BitwardenLogo; - protected year = "2024"; + protected year: string; protected clientType: ClientType; protected hostname: string; protected version: string; protected hideYearAndVersion = false; + get maxWidthClass(): string { + switch (this.maxWidth) { + case "md": + return "tw-max-w-md"; + case "lg": + return "tw-max-w-lg"; + case "xl": + return "tw-max-w-xl"; + case "2xl": + return "tw-max-w-2xl"; + case "3xl": + return "tw-max-w-3xl"; + } + } + constructor( private environmentService: EnvironmentService, private platformUtilsService: PlatformUtilsService, @@ -68,7 +78,6 @@ export class AnonLayoutComponent implements OnInit, OnChanges { async ngOnInit() { this.maxWidth = this.maxWidth ?? "md"; - this.titleAreaMaxWidth = this.titleAreaMaxWidth ?? null; this.hostname = (await firstValueFrom(this.environmentService.environment$)).getHostname(); this.version = await this.platformUtilsService.getApplicationVersion(); diff --git a/libs/components/src/anon-layout/anon-layout.mdx b/libs/components/src/anon-layout/anon-layout.mdx index 039a1aa5f28..9d40d617b0d 100644 --- a/libs/components/src/anon-layout/anon-layout.mdx +++ b/libs/components/src/anon-layout/anon-layout.mdx @@ -165,4 +165,4 @@ import { EnvironmentSelectorComponent } from "./components/environment-selector/ --- - + diff --git a/libs/components/src/anon-layout/anon-layout.stories.ts b/libs/components/src/anon-layout/anon-layout.stories.ts index 1f4ac5bb14f..24aaf10f7ba 100644 --- a/libs/components/src/anon-layout/anon-layout.stories.ts +++ b/libs/components/src/anon-layout/anon-layout.stories.ts @@ -8,6 +8,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { ButtonModule } from "../button"; +import { Icon } from "../icon"; import { LockIcon } from "../icon/icons"; import { I18nMockService } from "../utils/i18n-mock.service"; @@ -18,6 +19,23 @@ class MockPlatformUtilsService implements Partial { getClientType = () => ClientType.Web; } +type StoryArgs = Pick< + AnonLayoutComponent, + | "title" + | "subtitle" + | "showReadonlyHostname" + | "hideCardWrapper" + | "hideIcon" + | "hideLogo" + | "hideFooter" + | "maxWidth" +> & { + contentLength: "normal" | "long" | "thin"; + showSecondary: boolean; + useDefaultIcon: boolean; + icon: Icon; +}; + export default { title: "Component Library/Anon Layout", component: AnonLayoutComponent, @@ -31,12 +49,11 @@ export default { }, { provide: I18nService, - useFactory: () => { - return new I18nMockService({ + useFactory: () => + new I18nMockService({ accessing: "Accessing", appLogoLabel: "app logo label", - }); - }, + }), }, { provide: EnvironmentService, @@ -55,196 +72,179 @@ export default { ], }), ], + + render: (args: StoryArgs) => { + const { useDefaultIcon, icon, ...rest } = args; + return { + props: { + ...rest, + icon: useDefaultIcon ? null : icon, + }, + template: ` + + +
Thin Content
+
+
Long Content
+
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
+
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
+
+
+
Normal Content
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+
+
+ +
+
+ Secondary Projected Content (optional) +
+ +
+
+ `, + }; + }, + + argTypes: { + title: { control: "text" }, + subtitle: { control: "text" }, + + icon: { control: false, table: { disable: true } }, + useDefaultIcon: { + control: false, + table: { disable: true }, + description: "If true, passes null so component falls back to its built-in icon", + }, + + showReadonlyHostname: { control: "boolean" }, + maxWidth: { + control: "select", + options: ["md", "lg", "xl", "2xl", "3xl"], + }, + + hideCardWrapper: { control: "boolean" }, + hideIcon: { control: "boolean" }, + hideLogo: { control: "boolean" }, + hideFooter: { control: "boolean" }, + + contentLength: { + control: "radio", + options: ["normal", "long", "thin"], + }, + + showSecondary: { control: "boolean" }, + }, + args: { title: "The Page Title", subtitle: "The subtitle (optional)", - showReadonlyHostname: true, icon: LockIcon, - hideLogo: false, + useDefaultIcon: false, + showReadonlyHostname: false, + maxWidth: "md", hideCardWrapper: false, + hideIcon: false, + hideLogo: false, + hideFooter: false, + contentLength: "normal", + showSecondary: false, }, -} as Meta; +} as Meta; -type Story = StoryObj; +type Story = StoryObj; -export const WithPrimaryContent: Story = { - render: (args) => ({ - props: args, - template: - // Projected content (the
) and styling is just a sample and can be replaced with any content/styling. - ` - -
-
Primary Projected Content Area (customizable)
-
Lorem ipsum dolor sit amet consectetur adipisicing elit. Necessitatibus illum vero, placeat recusandae esse ratione eius minima veniam nemo, quas beatae! Impedit molestiae alias sapiente explicabo. Sapiente corporis ipsa numquam?
-
-
- `, - }), +export const NormalPrimaryContent: Story = { + args: { + contentLength: "normal", + }, }; -export const WithSecondaryContent: Story = { - render: (args) => ({ - props: args, - template: - // Projected content (the
's) and styling is just a sample and can be replaced with any content/styling. - // Notice that slot="secondary" is requred to project any secondary content. - ` - -
-
Primary Projected Content Area (customizable)
-
Lorem ipsum dolor sit amet consectetur adipisicing elit. Necessitatibus illum vero, placeat recusandae esse ratione eius minima veniam nemo, quas beatae! Impedit molestiae alias sapiente explicabo. Sapiente corporis ipsa numquam?
-
- -
-
Secondary Projected Content (optional)
- -
-
- `, - }), +export const LongPrimaryContent: Story = { + args: { + contentLength: "long", + }, }; -export const WithLongContent: Story = { - render: (args) => ({ - props: args, - template: - // Projected content (the
's) and styling is just a sample and can be replaced with any content/styling. - ` - -
-
Primary Projected Content Area (customizable)
-
Lorem ipsum dolor sit amet consectetur adipisicing elit. Necessitatibus illum vero, placeat recusandae esse ratione eius minima veniam nemo, quas beatae! Impedit molestiae alias sapiente explicabo. Sapiente corporis ipsa numquam? Lorem ipsum dolor sit amet consectetur adipisicing elit. Lorem ipsum dolor sit amet consectetur adipisicing elit. Lorem ipsum dolor sit amet consectetur adipisicing elit. Lorem ipsum dolor sit amet consectetur adipisicing elit. Lorem ipsum dolor sit amet consectetur adipisicing elit. Lorem ipsum dolor sit amet consectetur adipisicing elit. Lorem ipsum dolor sit amet consectetur adipisicing elit. Lorem ipsum dolor sit amet consectetur adipisicing elit. Lorem ipsum dolor sit amet consectetur adipisicing elit.
-
- -
-
Secondary Projected Content (optional)
-

Lorem ipsum dolor sit amet consectetur adipisicing elit. Molestias laborum nostrum natus. Lorem ipsum dolor sit amet consectetur adipisicing elit. Molestias laborum nostrum natus. Expedita, quod est?

- -
-
- `, - }), +export const ThinPrimaryContent: Story = { + args: { + contentLength: "thin", + }, }; -export const WithThinPrimaryContent: Story = { - render: (args) => ({ - props: args, - template: - // Projected content (the
's) and styling is just a sample and can be replaced with any content/styling. - ` - -
Lorem ipsum
- -
-
Secondary Projected Content (optional)
- -
-
- `, - }), +export const LongContentAndTitlesAndDefaultWidth: Story = { + args: { + title: + "This is a very long title that might not fit in the default width. It's really long and descriptive, so it might take up more space than usual.", + subtitle: + "This is a very long subtitle that might not fit in the default width. It's really long and descriptive, so it might take up more space than usual.", + contentLength: "long", + }, }; -export const WithCustomIcon: Story = { - render: (args) => ({ - props: args, - template: - // Projected content (the
) and styling is just a sample and can be replaced with any content/styling. - ` - -
-
Primary Projected Content Area (customizable)
-
Lorem ipsum dolor sit amet consectetur adipisicing elit. Necessitatibus illum vero, placeat recusandae esse ratione eius minima veniam nemo, quas beatae! Impedit molestiae alias sapiente explicabo. Sapiente corporis ipsa numquam?
-
-
- `, - }), +export const LongContentAndTitlesAndLargestWidth: Story = { + args: { + title: + "This is a very long title that might not fit in the default width. It's really long and descriptive, so it might take up more space than usual.", + subtitle: + "This is a very long subtitle that might not fit in the default width. It's really long and descriptive, so it might take up more space than usual.", + contentLength: "long", + maxWidth: "3xl", + }, }; -export const HideCardWrapper: Story = { - render: (args) => ({ - props: { - ...args, - hideCardWrapper: true, - }, - template: ` - -
-
Primary Projected Content Area (customizable)
-
Lorem ipsum dolor sit amet consectetur adipisicing elit. Necessitatibus illum vero, placeat recusandae esse ratione eius minima veniam nemo, quas beatae! Impedit molestiae alias sapiente explicabo. Sapiente corporis ipsa numquam?
-
-
-
Secondary Projected Content (optional)
- -
-
- `, - }), +export const SecondaryContent: Story = { + args: { + showSecondary: true, + }, }; -export const HideIcon: Story = { - render: (args) => ({ - props: args, - template: - // Projected content (the
) and styling is just a sample and can be replaced with any content/styling. - ` - -
-
Primary Projected Content Area (customizable)
-
Lorem ipsum dolor sit amet consectetur adipisicing elit. Necessitatibus illum vero, placeat recusandae esse ratione eius minima veniam nemo, quas beatae! Impedit molestiae alias sapiente explicabo. Sapiente corporis ipsa numquam?
-
-
- `, - }), +export const NoTitle: Story = { args: { title: undefined } }; + +export const NoSubtitle: Story = { args: { subtitle: undefined } }; + +export const NoWrapper: Story = { + args: { hideCardWrapper: true }, }; -export const HideLogo: Story = { - render: (args) => ({ - props: args, - template: - // Projected content (the
) and styling is just a sample and can be replaced with any content/styling. - ` - -
-
Primary Projected Content Area (customizable)
-
Lorem ipsum dolor sit amet consectetur adipisicing elit. Necessitatibus illum vero, placeat recusandae esse ratione eius minima veniam nemo, quas beatae! Impedit molestiae alias sapiente explicabo. Sapiente corporis ipsa numquam?
-
-
- `, - }), +export const DefaultIcon: Story = { + args: { useDefaultIcon: true }, }; -export const HideFooter: Story = { - render: (args) => ({ - props: args, - template: - // Projected content (the
) and styling is just a sample and can be replaced with any content/styling. - ` - -
-
Primary Projected Content Area (customizable)
-
Lorem ipsum dolor sit amet consectetur adipisicing elit. Necessitatibus illum vero, placeat recusandae esse ratione eius minima veniam nemo, quas beatae! Impedit molestiae alias sapiente explicabo. Sapiente corporis ipsa numquam?
-
-
- `, - }), +export const NoIcon: Story = { + args: { hideIcon: true }, }; -export const WithTitleAreaMaxWidth: Story = { - render: (args) => ({ - props: { - ...args, - title: "This is a very long long title to demonstrate titleAreaMaxWidth set to 'md'", - subtitle: - "This is a very long subtitle that demonstrates how the max width container handles longer text content with the titleAreaMaxWidth input set to 'md'. Lorem ipsum dolor sit amet consectetur adipisicing elit. Expedita, quod est?", - }, - template: ` - -
-
Primary Projected Content Area (customizable)
-
Lorem ipsum dolor sit amet consectetur adipisicing elit. Necessitatibus illum vero, placeat recusandae esse ratione eius minima veniam nemo, quas beatae! Impedit molestiae alias sapiente explicabo. Sapiente corporis ipsa numquam?
-
-
- `, - }), +export const NoLogo: Story = { + args: { hideLogo: true }, +}; + +export const NoFooter: Story = { + args: { hideFooter: true }, +}; + +export const ReadonlyHostname: Story = { + args: { showReadonlyHostname: true }, +}; + +export const MinimalState: Story = { + args: { + title: undefined, + subtitle: undefined, + contentLength: "normal", + hideCardWrapper: true, + hideIcon: true, + hideLogo: true, + hideFooter: true, + }, }; From 782dc930ad16aaa9b94c3663b98b9b985497de96 Mon Sep 17 00:00:00 2001 From: Addison Beck Date: Mon, 30 Jun 2025 13:56:26 -0400 Subject: [PATCH 027/239] refactor(storage-test-utils): cut a new library for storage test tools (#15259) * refactor(platform): generate a storage-test-utils library * refactor(storage-test-utils): move FakeStorageService out of common --- .github/CODEOWNERS | 1 + libs/common/spec/fake-storage.service.ts | 120 +----------------- libs/storage-test-utils/README.md | 5 + libs/storage-test-utils/eslint.config.mjs | 3 + libs/storage-test-utils/jest.config.js | 10 ++ libs/storage-test-utils/package.json | 11 ++ libs/storage-test-utils/project.json | 33 +++++ .../src/fake-storage.service.ts | 119 +++++++++++++++++ libs/storage-test-utils/src/index.ts | 1 + .../src/storage-test-utils.spec.ts | 8 ++ libs/storage-test-utils/tsconfig.json | 13 ++ libs/storage-test-utils/tsconfig.lib.json | 10 ++ libs/storage-test-utils/tsconfig.spec.json | 10 ++ package-lock.json | 11 +- tsconfig.base.json | 1 + 15 files changed, 235 insertions(+), 121 deletions(-) create mode 100644 libs/storage-test-utils/README.md create mode 100644 libs/storage-test-utils/eslint.config.mjs create mode 100644 libs/storage-test-utils/jest.config.js create mode 100644 libs/storage-test-utils/package.json create mode 100644 libs/storage-test-utils/project.json create mode 100644 libs/storage-test-utils/src/fake-storage.service.ts create mode 100644 libs/storage-test-utils/src/index.ts create mode 100644 libs/storage-test-utils/src/storage-test-utils.spec.ts create mode 100644 libs/storage-test-utils/tsconfig.json create mode 100644 libs/storage-test-utils/tsconfig.lib.json create mode 100644 libs/storage-test-utils/tsconfig.spec.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 17a1cb5720e..db60ad6a93b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -91,6 +91,7 @@ libs/common/spec @bitwarden/team-platform-dev libs/common/src/state-migrations @bitwarden/team-platform-dev libs/platform @bitwarden/team-platform-dev libs/storage-core @bitwarden/team-platform-dev +libs/storage-test-utils @bitwarden/team-platform-dev # Web utils used across app and connectors apps/web/src/utils/ @bitwarden/team-platform-dev # Web core and shared files diff --git a/libs/common/spec/fake-storage.service.ts b/libs/common/spec/fake-storage.service.ts index c6d989c5abf..1eae3dbfbe3 100644 --- a/libs/common/spec/fake-storage.service.ts +++ b/libs/common/spec/fake-storage.service.ts @@ -1,119 +1 @@ -import { MockProxy, mock } from "jest-mock-extended"; -import { Subject } from "rxjs"; - -import { - AbstractStorageService, - ObservableStorageService, - StorageUpdate, -} from "../src/platform/abstractions/storage.service"; -import { StorageOptions } from "../src/platform/models/domain/storage-options"; - -const INTERNAL_KEY = "__internal__"; - -export class FakeStorageService implements AbstractStorageService, ObservableStorageService { - private store: Record; - private updatesSubject = new Subject(); - private _valuesRequireDeserialization = false; - - /** - * Returns a mock of a {@see AbstractStorageService} for asserting the expected - * amount of calls. It is not recommended to use this to mock implementations as - * they are not respected. - */ - mock: MockProxy; - - constructor(initial?: Record) { - this.store = initial ?? {}; - this.mock = mock(); - } - - /** - * Updates the internal store for this fake implementation, this bypasses any mock calls - * or updates to the {@link updates$} observable. - * @param store - */ - internalUpdateStore(store: Record) { - this.store = store; - } - - get internalStore() { - return this.store; - } - - internalUpdateValuesRequireDeserialization(value: boolean) { - this._valuesRequireDeserialization = value; - } - - get valuesRequireDeserialization(): boolean { - return this._valuesRequireDeserialization; - } - - get updates$() { - return this.updatesSubject.asObservable(); - } - - get(key: string, options?: StorageOptions): Promise { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.mock.get(key, options); - const value = this.store[key] as T; - return Promise.resolve(value); - } - has(key: string, options?: StorageOptions): Promise { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.mock.has(key, options); - return Promise.resolve(this.store[key] != null); - } - async save(key: string, obj: T, options?: StorageOptions): Promise { - // These exceptions are copied from https://github.com/sindresorhus/conf/blob/608adb0c46fb1680ddbd9833043478367a64c120/source/index.ts#L193-L203 - // which is a library that is used by `ElectronStorageService`. We add them here to ensure that the behavior in our testing mirrors the real world. - if (typeof key !== "string" && typeof key !== "object") { - throw new TypeError( - `Expected \`key\` to be of type \`string\` or \`object\`, got ${typeof key}`, - ); - } - - // We don't throw this error because ElectronStorageService automatically detects this case - // and calls `delete()` instead of `set()`. - // if (typeof key !== "object" && obj === undefined) { - // throw new TypeError("Use `delete()` to clear values"); - // } - - if (this._containsReservedKey(key)) { - throw new TypeError( - `Please don't use the ${INTERNAL_KEY} key, as it's used to manage this module internal operations.`, - ); - } - - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.mock.save(key, obj, options); - this.store[key] = obj; - this.updatesSubject.next({ key: key, updateType: "save" }); - } - remove(key: string, options?: StorageOptions): Promise { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.mock.remove(key, options); - delete this.store[key]; - this.updatesSubject.next({ key: key, updateType: "remove" }); - return Promise.resolve(); - } - - private _containsReservedKey(key: string | Partial): boolean { - if (typeof key === "object") { - const firsKey = Object.keys(key)[0]; - - if (firsKey === INTERNAL_KEY) { - return true; - } - } - - if (typeof key !== "string") { - return false; - } - - return false; - } -} +export { FakeStorageService } from "@bitwarden/storage-test-utils"; diff --git a/libs/storage-test-utils/README.md b/libs/storage-test-utils/README.md new file mode 100644 index 00000000000..2be8817e402 --- /dev/null +++ b/libs/storage-test-utils/README.md @@ -0,0 +1,5 @@ +# storage-test-utils + +Owned by: platform + +Test tools for the storage library diff --git a/libs/storage-test-utils/eslint.config.mjs b/libs/storage-test-utils/eslint.config.mjs new file mode 100644 index 00000000000..9c37d10e3ff --- /dev/null +++ b/libs/storage-test-utils/eslint.config.mjs @@ -0,0 +1,3 @@ +import baseConfig from "../../eslint.config.mjs"; + +export default [...baseConfig]; diff --git a/libs/storage-test-utils/jest.config.js b/libs/storage-test-utils/jest.config.js new file mode 100644 index 00000000000..a145b5b2f4c --- /dev/null +++ b/libs/storage-test-utils/jest.config.js @@ -0,0 +1,10 @@ +module.exports = { + displayName: "storage-test-utils", + preset: "../../jest.preset.js", + testEnvironment: "node", + transform: { + "^.+\\.[tj]s$": ["ts-jest", { tsconfig: "/tsconfig.spec.json" }], + }, + moduleFileExtensions: ["ts", "js", "html"], + coverageDirectory: "../../coverage/libs/storage-test-utils", +}; diff --git a/libs/storage-test-utils/package.json b/libs/storage-test-utils/package.json new file mode 100644 index 00000000000..22d83f2334e --- /dev/null +++ b/libs/storage-test-utils/package.json @@ -0,0 +1,11 @@ +{ + "name": "@bitwarden/storage-test-utils", + "version": "0.0.1", + "description": "Test tools for the storage library", + "private": true, + "type": "commonjs", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "license": "GPL-3.0", + "author": "platform" +} diff --git a/libs/storage-test-utils/project.json b/libs/storage-test-utils/project.json new file mode 100644 index 00000000000..f1aad63c9e3 --- /dev/null +++ b/libs/storage-test-utils/project.json @@ -0,0 +1,33 @@ +{ + "name": "storage-test-utils", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/storage-test-utils/src", + "projectType": "library", + "tags": [], + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/libs/storage-test-utils", + "main": "libs/storage-test-utils/src/index.ts", + "tsConfig": "libs/storage-test-utils/tsconfig.lib.json", + "assets": ["libs/storage-test-utils/*.md"] + } + }, + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["libs/storage-test-utils/**/*.ts"] + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/storage-test-utils/jest.config.js" + } + } + } +} diff --git a/libs/storage-test-utils/src/fake-storage.service.ts b/libs/storage-test-utils/src/fake-storage.service.ts new file mode 100644 index 00000000000..aa902cf0da8 --- /dev/null +++ b/libs/storage-test-utils/src/fake-storage.service.ts @@ -0,0 +1,119 @@ +import { MockProxy, mock } from "jest-mock-extended"; +import { Subject } from "rxjs"; + +import { + AbstractStorageService, + ObservableStorageService, + StorageUpdate, + StorageOptions, +} from "@bitwarden/storage-core"; + +const INTERNAL_KEY = "__internal__"; + +export class FakeStorageService implements AbstractStorageService, ObservableStorageService { + private store: Record; + private updatesSubject = new Subject(); + private _valuesRequireDeserialization = false; + + /** + * Returns a mock of a {@see AbstractStorageService} for asserting the expected + * amount of calls. It is not recommended to use this to mock implementations as + * they are not respected. + */ + mock: MockProxy; + + constructor(initial?: Record) { + this.store = initial ?? {}; + this.mock = mock(); + } + + /** + * Updates the internal store for this fake implementation, this bypasses any mock calls + * or updates to the {@link updates$} observable. + * @param store + */ + internalUpdateStore(store: Record) { + this.store = store; + } + + get internalStore() { + return this.store; + } + + internalUpdateValuesRequireDeserialization(value: boolean) { + this._valuesRequireDeserialization = value; + } + + get valuesRequireDeserialization(): boolean { + return this._valuesRequireDeserialization; + } + + get updates$() { + return this.updatesSubject.asObservable(); + } + + get(key: string, options?: StorageOptions): Promise { + // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. + // eslint-disable-next-line @typescript-eslint/no-floating-promises + this.mock.get(key, options); + const value = this.store[key] as T; + return Promise.resolve(value); + } + has(key: string, options?: StorageOptions): Promise { + // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. + // eslint-disable-next-line @typescript-eslint/no-floating-promises + this.mock.has(key, options); + return Promise.resolve(this.store[key] != null); + } + async save(key: string, obj: T, options?: StorageOptions): Promise { + // These exceptions are copied from https://github.com/sindresorhus/conf/blob/608adb0c46fb1680ddbd9833043478367a64c120/source/index.ts#L193-L203 + // which is a library that is used by `ElectronStorageService`. We add them here to ensure that the behavior in our testing mirrors the real world. + if (typeof key !== "string" && typeof key !== "object") { + throw new TypeError( + `Expected \`key\` to be of type \`string\` or \`object\`, got ${typeof key}`, + ); + } + + // We don't throw this error because ElectronStorageService automatically detects this case + // and calls `delete()` instead of `set()`. + // if (typeof key !== "object" && obj === undefined) { + // throw new TypeError("Use `delete()` to clear values"); + // } + + if (this._containsReservedKey(key)) { + throw new TypeError( + `Please don't use the ${INTERNAL_KEY} key, as it's used to manage this module internal operations.`, + ); + } + + // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. + // eslint-disable-next-line @typescript-eslint/no-floating-promises + this.mock.save(key, obj, options); + this.store[key] = obj; + this.updatesSubject.next({ key: key, updateType: "save" }); + } + remove(key: string, options?: StorageOptions): Promise { + // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. + // eslint-disable-next-line @typescript-eslint/no-floating-promises + this.mock.remove(key, options); + delete this.store[key]; + this.updatesSubject.next({ key: key, updateType: "remove" }); + return Promise.resolve(); + } + + private _containsReservedKey(key: string | Partial): boolean { + if (typeof key === "object") { + const firsKey = Object.keys(key)[0]; + + if (firsKey === INTERNAL_KEY) { + return true; + } + } + + if (typeof key !== "string") { + return false; + } + + return false; + } +} diff --git a/libs/storage-test-utils/src/index.ts b/libs/storage-test-utils/src/index.ts new file mode 100644 index 00000000000..dc5fdc1125b --- /dev/null +++ b/libs/storage-test-utils/src/index.ts @@ -0,0 +1 @@ +export * from "./fake-storage.service"; diff --git a/libs/storage-test-utils/src/storage-test-utils.spec.ts b/libs/storage-test-utils/src/storage-test-utils.spec.ts new file mode 100644 index 00000000000..c323d4ce386 --- /dev/null +++ b/libs/storage-test-utils/src/storage-test-utils.spec.ts @@ -0,0 +1,8 @@ +import * as lib from "./index"; + +describe("storage-test-utils", () => { + // This test will fail until something is exported from index.ts + it("should work", () => { + expect(lib).toBeDefined(); + }); +}); diff --git a/libs/storage-test-utils/tsconfig.json b/libs/storage-test-utils/tsconfig.json new file mode 100644 index 00000000000..62ebbd94647 --- /dev/null +++ b/libs/storage-test-utils/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/libs/storage-test-utils/tsconfig.lib.json b/libs/storage-test-utils/tsconfig.lib.json new file mode 100644 index 00000000000..9cbf6736007 --- /dev/null +++ b/libs/storage-test-utils/tsconfig.lib.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["jest.config.js", "src/**/*.spec.ts"] +} diff --git a/libs/storage-test-utils/tsconfig.spec.json b/libs/storage-test-utils/tsconfig.spec.json new file mode 100644 index 00000000000..901c72378dd --- /dev/null +++ b/libs/storage-test-utils/tsconfig.spec.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../..//dist/out-tsc", + "module": "commonjs", + "moduleResolution": "node10", + "types": ["jest", "node"] + }, + "include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"] +} diff --git a/package-lock.json b/package-lock.json index 0855df67e8b..176aa40a650 100644 --- a/package-lock.json +++ b/package-lock.json @@ -250,8 +250,6 @@ }, "apps/cli/node_modules/is-docker": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "license": "MIT", "bin": { "is-docker": "cli.js" @@ -375,6 +373,11 @@ "version": "0.0.1", "license": "GPL-3.0" }, + "libs/storage-test-utils": { + "name": "@bitwarden/storage-test-utils", + "version": "0.0.1", + "license": "GPL-3.0" + }, "libs/tools/export/vault-export/vault-export-core": { "name": "@bitwarden/vault-export-core", "version": "0.0.0", @@ -4621,6 +4624,10 @@ "resolved": "libs/storage-core", "link": true }, + "node_modules/@bitwarden/storage-test-utils": { + "resolved": "libs/storage-test-utils", + "link": true + }, "node_modules/@bitwarden/ui-common": { "resolved": "libs/ui/common", "link": true diff --git a/tsconfig.base.json b/tsconfig.base.json index fd3f898b319..b826d51e66e 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -43,6 +43,7 @@ "@bitwarden/platform/*": ["./libs/platform/src/*"], "@bitwarden/send-ui": ["./libs/tools/send/send-ui/src"], "@bitwarden/storage-core": ["libs/storage-core/src/index.ts"], + "@bitwarden/storage-test-utils": ["libs/storage-test-utils/src/index.ts"], "@bitwarden/ui-common": ["./libs/ui/common/src"], "@bitwarden/ui-common/setup-jest": ["./libs/ui/common/src/setup-jest"], "@bitwarden/vault": ["./libs/vault/src"], From 7eb7507229cec9dbf0fe0a2c69139970cd970ac5 Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Mon, 30 Jun 2025 20:04:31 +0200 Subject: [PATCH 028/239] Enable ptrace prevention on Linux (except snap) (#15204) --- apps/desktop/src/main/window.main.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/desktop/src/main/window.main.ts b/apps/desktop/src/main/window.main.ts index f1a55866079..4d9438b588d 100644 --- a/apps/desktop/src/main/window.main.ts +++ b/apps/desktop/src/main/window.main.ts @@ -16,7 +16,15 @@ import { BiometricStateService } from "@bitwarden/key-management"; import { WindowState } from "../platform/models/domain/window-state"; import { applyMainWindowStyles, applyPopupModalStyles } from "../platform/popup-modal-styles"; import { DesktopSettingsService } from "../platform/services/desktop-settings.service"; -import { cleanUserAgent, isDev, isLinux, isMac, isMacAppStore, isWindows } from "../utils"; +import { + cleanUserAgent, + isDev, + isLinux, + isMac, + isMacAppStore, + isSnapStore, + isWindows, +} from "../utils"; const mainWindowSizeKey = "mainWindowSize"; const WindowEventHandlingDelay = 100; @@ -156,9 +164,8 @@ export class WindowMain { } } - // this currently breaks the file portal, so should only be used when - // no files are needed but security requirements are super high https://github.com/flatpak/xdg-desktop-portal/issues/785 - if (process.env.EXPERIMENTAL_PREVENT_DEBUGGER_MEMORY_ACCESS === "true") { + // this currently breaks the file portal for snap https://github.com/flatpak/xdg-desktop-portal/issues/785 + if (!isSnapStore()) { this.logService.info("Disabling memory dumps in main process"); try { await processisolations.disableMemoryAccess(); From f9d0e6fe4a89834c458d59cfcb1029fcf54462e5 Mon Sep 17 00:00:00 2001 From: Jason Ng Date: Mon, 30 Jun 2025 15:10:01 -0400 Subject: [PATCH 029/239] [CL-572] adding new colors for icons, update icon docs (#15367) * adding new colors for icons, update icon docs, remove art from colors mdx --- libs/components/src/icon/icon.mdx | 24 +++++++++++++----------- libs/components/src/stories/colors.mdx | 10 ++++++++-- libs/components/src/tw-theme.css | 16 ++++++++++++++++ libs/components/tailwind.config.base.js | 9 +++++++++ 4 files changed, 46 insertions(+), 13 deletions(-) diff --git a/libs/components/src/icon/icon.mdx b/libs/components/src/icon/icon.mdx index d1809c81cd2..01f03d1861b 100644 --- a/libs/components/src/icon/icon.mdx +++ b/libs/components/src/icon/icon.mdx @@ -41,12 +41,14 @@ import { IconModule } from "@bitwarden/components"; - A non-comprehensive list of common colors and their associated classes is below: - | Hardcoded Value | Tailwind Stroke Class | Tailwind Fill Class | Tailwind Variable | - | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- | ----------------------- | ----------------------- | - | `#020F66` | `tw-stroke-art-primary` | `tw-fill-art-primary` | `--color-art-primary` | - | `#10949D` | `tw-stroke-art-accent` | `tw-fill-art-accent` | `--color-art-accent` | - | `#2CDDE9` | `tw-stroke-art-accent` | `tw-fill-art-accent` | `--color-art-accent` | - | `#89929F` | `tw-stroke-secondary-600` | `tw-fill-secondary-600` | `--color-secondary-600` | + | Hardcoded Value | Tailwind Stroke Class | Tailwind Fill Class | Tailwind Variable | + | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | ----------------------------------- | ----------------------------------- | + | `#020F66` | `tw-stroke-illustration-outline` | `tw-fill-illustration-outline` | `--color-illustration-outline` | + | `#DBE5F6` | `tw-stroke-illustration-bg-primary` | `tw-fill-illustration-bg-primary` | `--color-illustration-bg-primary` | + | `#AAC3EF` | `tw-stroke-illustration-bg-secondary` | `tw-fill-illustration-bg-secondary` | `--color-illustration-bg-secondary` | + | `#FFFFFF` | `tw-stroke-illustration-bg-tertiary` | `tw-fill-illustration-bg-tertiary` | `--color-illustration-bg-tertiary` | + | `#FFBF00` | `tw-stroke-illustration-tertiary` | `tw-fill-illustration-tertiary` | `--color-illustration-tertiary` | + | `#175DDC` | `tw-stroke-illustration-logo` | `tw-fill-illustration-logo` | `--color-illustration-logo` | - If the hex that you have on an SVG path is not listed above, there are a few ways to figure out the appropriate Tailwind class: @@ -56,20 +58,20 @@ import { IconModule } from "@bitwarden/components"; - Click on an individual path on the SVG until you see the path's properties in the right-hand panel. - Scroll down to the Colors section. - - Example: `Color/Art/Primary` + - Example: `Color/Illustration/Outline` - This also includes Hex or RGB values that can be used to find the appropriate Tailwind variable as well if you follow the manual search option below. - Create the appropriate stroke or fill class from the color used. - - Example: `Color/Art/Primary` corresponds to `--color-art-primary` which corresponds to - `tw-stroke-art-primary` or `tw-fill-art-primary`. + - Example: `Color/Illustration/Outline` corresponds to `--color-illustration-outline` which + corresponds to `tw-stroke-illustration-outline` or `tw-fill-illustration-outline`. - **Option 2: Manual Search** - Take the path's stroke or fill hex value and convert it to RGB using a tool like [Hex to RGB](https://www.rgbtohex.net/hex-to-rgb/). - Search for the RGB value without commas in our `tw-theme.css` to find the Tailwind variable that corresponds to the color. - Create the appropriate stroke or fill class using the Tailwind variable. - - Example: `--color-art-primary` corresponds to `tw-stroke-art-primary` or - `tw-fill-art-primary`. + - Example: `--color-illustration-outline` corresponds to `tw-stroke-illustration-outline` + or `tw-fill-illustration-outline`. 6. **Remove any hardcoded width or height attributes** if your SVG has a configured [viewBox](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox) attribute in order diff --git a/libs/components/src/stories/colors.mdx b/libs/components/src/stories/colors.mdx index 3a4a4f0fe3a..87ca673797b 100644 --- a/libs/components/src/stories/colors.mdx +++ b/libs/components/src/stories/colors.mdx @@ -62,9 +62,14 @@ export const Table = (args) => ( {Row("notification-600")} - {Row("art-primary")} - {Row("art-accent")} + {Row("illustration-outline")} + {Row("illustration-bg-primary")} + {Row("illustration-bg-secondary")} + {Row("illustration-bg-tertiary")} + {Row("illustration-tertiary")} + {Row("illustration-logo")} + Text @@ -78,6 +83,7 @@ export const Table = (args) => ( {Row("text-alt2")} {Row("text-code")} + ); diff --git a/libs/components/src/tw-theme.css b/libs/components/src/tw-theme.css index c8de973c3d1..078357491e5 100644 --- a/libs/components/src/tw-theme.css +++ b/libs/components/src/tw-theme.css @@ -46,6 +46,7 @@ --color-notification-100: 255 225 247; --color-notification-600: 192 17 118; + /*art styles deprecated, use 'illustration' instead*/ --color-art-primary: 2 15 102; --color-art-accent: 44 221 223; @@ -60,6 +61,13 @@ --tw-ring-offset-color: #ffffff; --tw-sm-breakpoint: 640px; + + --color-illustration-outline: 2 15 102; + --color-illustration-bg-primary: 219 229 246; + --color-illustration-bg-secondary: 170 195 239; + --color-illustration-bg-tertiary: 255 255 255; + --color-illustration-tertiary: 255 191 0; + --color-illustration-logo: 23 93 220; } .theme_light { @@ -106,6 +114,7 @@ --color-notification-100: 117 37 83; --color-notification-600: 255 143 208; + /*art styles deprecated, use 'illustration' instead*/ --color-art-primary: 243 246 249; --color-art-accent: 44 221 233; @@ -118,6 +127,13 @@ --color-marketing-logo: 255 255 255; --tw-ring-offset-color: #1f242e; + + --color-illustration-outline: 23 93 220; + --color-illustration-bg-primary: 170 195 239; + --color-illustration-bg-secondary: 121 161 233; + --color-illustration-bg-tertiary: 243 246 249; + --color-illustration-tertiary: 255 191 0; + --color-illustration-logo: 255 255 255; } /** diff --git a/libs/components/tailwind.config.base.js b/libs/components/tailwind.config.base.js index fde59f4a089..c38515cf775 100644 --- a/libs/components/tailwind.config.base.js +++ b/libs/components/tailwind.config.base.js @@ -63,6 +63,7 @@ module.exports = { 100: rgba("--color-notification-100"), 600: rgba("--color-notification-600"), }, + // art styles deprecated, use 'illustration' instead art: { primary: rgba("--color-art-primary"), accent: rgba("--color-art-accent"), @@ -83,6 +84,14 @@ module.exports = { alt4: rgba("--color-background-alt4"), }, "marketing-logo": rgba("--color-marketing-logo"), + illustration: { + outline: rgba("--color-illustration-outline"), + "bg-primary": rgba("--color-illustration-bg-primary"), + "bg-secondary": rgba("--color-illustration-bg-secondary"), + "bg-tertiary": rgba("--color-illustration-bg-tertiary"), + tertiary: rgba("--color-illustration-tertiary"), + logo: rgba("--color-illustration-logo"), + }, }, textColor: { main: rgba("--color-text-main"), From 5639668d3fa72643f540b29c51191fe3f6e453b5 Mon Sep 17 00:00:00 2001 From: rr-bw <102181210+rr-bw@users.noreply.github.com> Date: Mon, 30 Jun 2025 12:39:53 -0700 Subject: [PATCH 030/239] feat:(set-initial-password): [Auth/PM-18457] Create SetInitialPasswordComponent (#14186) Creates a `SetInitialPasswordComponent` to be used in scenarios where an existing and authed user must set an initial password. Feature Flag: `PM16117_SetInitialPasswordRefactor` --- apps/browser/src/_locales/en/messages.json | 3 + apps/browser/src/popup/app-routing.module.ts | 11 + apps/desktop/src/app/app-routing.module.ts | 10 + .../src/app/services/services.module.ts | 19 + ...sktop-set-initial-password.service.spec.ts | 177 +++++ .../desktop-set-initial-password.service.ts | 59 ++ apps/desktop/src/locales/en/messages.json | 3 + apps/web/src/app/auth/core/services/index.ts | 1 + .../services/password-management/index.ts | 1 + .../web-set-initial-password.service.spec.ts | 208 ++++++ .../web-set-initial-password.service.ts | 83 +++ apps/web/src/app/core/core.module.ts | 20 + apps/web/src/app/oss-routing.module.ts | 11 + apps/web/src/locales/en/messages.json | 3 + libs/angular/src/auth/guards/auth.guard.ts | 39 +- ...initial-password.service.implementation.ts | 248 +++++++ ...fault-set-initial-password.service.spec.ts | 633 ++++++++++++++++++ .../set-initial-password.component.html | 29 + .../set-initial-password.component.ts | 249 +++++++ ...et-initial-password.service.abstraction.ts | 64 ++ .../src/services/jslib-services.module.ts | 18 + 21 files changed, 1876 insertions(+), 13 deletions(-) create mode 100644 apps/desktop/src/app/services/set-initial-password/desktop-set-initial-password.service.spec.ts create mode 100644 apps/desktop/src/app/services/set-initial-password/desktop-set-initial-password.service.ts create mode 100644 apps/web/src/app/auth/core/services/password-management/index.ts create mode 100644 apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.spec.ts create mode 100644 apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.ts create mode 100644 libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.implementation.ts create mode 100644 libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.spec.ts create mode 100644 libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.html create mode 100644 libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.ts create mode 100644 libs/angular/src/auth/password-management/set-initial-password/set-initial-password.service.abstraction.ts diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index b6a8d1834b4..ce5787c46bd 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -2919,6 +2919,9 @@ "emailVerificationRequiredDesc": { "message": "You must verify your email to use this feature. You can verify your email in the web vault." }, + "masterPasswordSuccessfullySet": { + "message": "Master password successfully set" + }, "updatedMasterPassword": { "message": "Updated master password" }, diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts index e3574c4e142..f836f5ffac7 100644 --- a/apps/browser/src/popup/app-routing.module.ts +++ b/apps/browser/src/popup/app-routing.module.ts @@ -15,6 +15,8 @@ import { tdeDecryptionRequiredGuard, unauthGuardFn, } from "@bitwarden/angular/auth/guards"; +import { SetInitialPasswordComponent } from "@bitwarden/angular/auth/password-management/set-initial-password/set-initial-password.component"; +import { canAccessFeature } from "@bitwarden/angular/platform/guard/feature-flag.guard"; import { DevicesIcon, LoginComponent, @@ -38,6 +40,7 @@ import { UserLockIcon, VaultIcon, } from "@bitwarden/auth/angular"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { AnonLayoutWrapperComponent, AnonLayoutWrapperData, Icons } from "@bitwarden/components"; import { LockComponent } from "@bitwarden/key-management-ui"; @@ -376,6 +379,14 @@ const routes: Routes = [ }, ], }, + { + path: "set-initial-password", + canActivate: [canAccessFeature(FeatureFlag.PM16117_SetInitialPasswordRefactor), authGuard], + component: SetInitialPasswordComponent, + data: { + elevation: 1, + } satisfies RouteDataProperties, + }, { path: "login", canActivate: [unauthGuardFn(unauthRouteOverrides), IntroCarouselGuard], diff --git a/apps/desktop/src/app/app-routing.module.ts b/apps/desktop/src/app/app-routing.module.ts index d90f3cf0d26..42846878d03 100644 --- a/apps/desktop/src/app/app-routing.module.ts +++ b/apps/desktop/src/app/app-routing.module.ts @@ -14,6 +14,8 @@ import { tdeDecryptionRequiredGuard, unauthGuardFn, } from "@bitwarden/angular/auth/guards"; +import { SetInitialPasswordComponent } from "@bitwarden/angular/auth/password-management/set-initial-password/set-initial-password.component"; +import { canAccessFeature } from "@bitwarden/angular/platform/guard/feature-flag.guard"; import { featureFlaggedRoute } from "@bitwarden/angular/platform/utils/feature-flagged-route"; import { LoginComponent, @@ -315,6 +317,14 @@ const routes: Routes = [ }, } satisfies AnonLayoutWrapperData, }, + { + path: "set-initial-password", + canActivate: [canAccessFeature(FeatureFlag.PM16117_SetInitialPasswordRefactor), authGuard], + component: SetInitialPasswordComponent, + data: { + maxWidth: "lg", + } satisfies AnonLayoutWrapperData, + }, { path: "2fa", canActivate: [unauthGuardFn(), TwoFactorAuthGuard], diff --git a/apps/desktop/src/app/services/services.module.ts b/apps/desktop/src/app/services/services.module.ts index 06c42c5b0bc..0abd810bd18 100644 --- a/apps/desktop/src/app/services/services.module.ts +++ b/apps/desktop/src/app/services/services.module.ts @@ -5,6 +5,7 @@ import { Router } from "@angular/router"; import { Subject, merge } from "rxjs"; import { OrganizationUserApiService } from "@bitwarden/admin-console/common"; +import { SetInitialPasswordService } from "@bitwarden/angular/auth/password-management/set-initial-password/set-initial-password.service.abstraction"; import { SafeProvider, safeProvider } from "@bitwarden/angular/platform/utils/safe-provider"; import { SECURE_STORAGE, @@ -140,6 +141,7 @@ import { DesktopSetPasswordJitService } from "./desktop-set-password-jit.service import { InitService } from "./init.service"; import { NativeMessagingManifestService } from "./native-messaging-manifest.service"; import { RendererCryptoFunctionService } from "./renderer-crypto-function.service"; +import { DesktopSetInitialPasswordService } from "./set-initial-password/desktop-set-initial-password.service"; const RELOAD_CALLBACK = new SafeInjectionToken<() => any>("RELOAD_CALLBACK"); @@ -392,6 +394,23 @@ const safeProviders: SafeProvider[] = [ InternalUserDecryptionOptionsServiceAbstraction, ], }), + safeProvider({ + provide: SetInitialPasswordService, + useClass: DesktopSetInitialPasswordService, + deps: [ + ApiService, + EncryptService, + I18nServiceAbstraction, + KdfConfigService, + KeyService, + MasterPasswordApiService, + InternalMasterPasswordServiceAbstraction, + OrganizationApiServiceAbstraction, + OrganizationUserApiService, + InternalUserDecryptionOptionsServiceAbstraction, + MessagingServiceAbstraction, + ], + }), safeProvider({ provide: SsoUrlService, useClass: SsoUrlService, diff --git a/apps/desktop/src/app/services/set-initial-password/desktop-set-initial-password.service.spec.ts b/apps/desktop/src/app/services/set-initial-password/desktop-set-initial-password.service.spec.ts new file mode 100644 index 00000000000..02438300e94 --- /dev/null +++ b/apps/desktop/src/app/services/set-initial-password/desktop-set-initial-password.service.spec.ts @@ -0,0 +1,177 @@ +import { MockProxy, mock } from "jest-mock-extended"; +import { BehaviorSubject, of } from "rxjs"; + +import { OrganizationUserApiService } from "@bitwarden/admin-console/common"; +import { + SetInitialPasswordCredentials, + SetInitialPasswordService, + SetInitialPasswordUserType, +} from "@bitwarden/angular/auth/password-management/set-initial-password/set-initial-password.service.abstraction"; +import { + FakeUserDecryptionOptions as UserDecryptionOptions, + InternalUserDecryptionOptionsServiceAbstraction, +} from "@bitwarden/auth/common"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; +import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; +import { SetPasswordRequest } from "@bitwarden/common/auth/models/request/set-password.request"; +import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; +import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; +import { KeysRequest } from "@bitwarden/common/models/request/keys.request"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; +import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { CsprngArray } from "@bitwarden/common/types/csprng"; +import { UserId } from "@bitwarden/common/types/guid"; +import { MasterKey, UserKey } from "@bitwarden/common/types/key"; +import { DEFAULT_KDF_CONFIG, KdfConfigService, KeyService } from "@bitwarden/key-management"; + +import { DesktopSetInitialPasswordService } from "./desktop-set-initial-password.service"; + +describe("DesktopSetInitialPasswordService", () => { + let sut: SetInitialPasswordService; + + let apiService: MockProxy; + let encryptService: MockProxy; + let i18nService: MockProxy; + let kdfConfigService: MockProxy; + let keyService: MockProxy; + let masterPasswordApiService: MockProxy; + let masterPasswordService: MockProxy; + let organizationApiService: MockProxy; + let organizationUserApiService: MockProxy; + let userDecryptionOptionsService: MockProxy; + let messagingService: MockProxy; + + beforeEach(() => { + apiService = mock(); + encryptService = mock(); + i18nService = mock(); + kdfConfigService = mock(); + keyService = mock(); + masterPasswordApiService = mock(); + masterPasswordService = mock(); + organizationApiService = mock(); + organizationUserApiService = mock(); + userDecryptionOptionsService = mock(); + messagingService = mock(); + + sut = new DesktopSetInitialPasswordService( + apiService, + encryptService, + i18nService, + kdfConfigService, + keyService, + masterPasswordApiService, + masterPasswordService, + organizationApiService, + organizationUserApiService, + userDecryptionOptionsService, + messagingService, + ); + }); + + it("should instantiate", () => { + expect(sut).not.toBeFalsy(); + }); + + describe("setInitialPassword(...)", () => { + // Mock function parameters + let credentials: SetInitialPasswordCredentials; + let userType: SetInitialPasswordUserType; + let userId: UserId; + + // Mock other function data + let userKey: UserKey; + let userKeyEncString: EncString; + let masterKeyEncryptedUserKey: [UserKey, EncString]; + + let keyPair: [string, EncString]; + let keysRequest: KeysRequest; + + let userDecryptionOptions: UserDecryptionOptions; + let userDecryptionOptionsSubject: BehaviorSubject; + let setPasswordRequest: SetPasswordRequest; + + beforeEach(() => { + // Mock function parameters + credentials = { + newMasterKey: new SymmetricCryptoKey(new Uint8Array(32).buffer as CsprngArray) as MasterKey, + newServerMasterKeyHash: "newServerMasterKeyHash", + newLocalMasterKeyHash: "newLocalMasterKeyHash", + newPasswordHint: "newPasswordHint", + kdfConfig: DEFAULT_KDF_CONFIG, + orgSsoIdentifier: "orgSsoIdentifier", + orgId: "orgId", + resetPasswordAutoEnroll: false, + }; + userId = "userId" as UserId; + userType = SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER; + + // Mock other function data + userKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as UserKey; + userKeyEncString = new EncString("masterKeyEncryptedUserKey"); + masterKeyEncryptedUserKey = [userKey, userKeyEncString]; + + keyPair = ["publicKey", new EncString("privateKey")]; + keysRequest = new KeysRequest(keyPair[0], keyPair[1].encryptedString); + + userDecryptionOptions = new UserDecryptionOptions({ hasMasterPassword: true }); + userDecryptionOptionsSubject = new BehaviorSubject(userDecryptionOptions); + userDecryptionOptionsService.userDecryptionOptions$ = userDecryptionOptionsSubject; + + setPasswordRequest = new SetPasswordRequest( + credentials.newServerMasterKeyHash, + masterKeyEncryptedUserKey[1].encryptedString, + credentials.newPasswordHint, + credentials.orgSsoIdentifier, + keysRequest, + credentials.kdfConfig.kdfType, + credentials.kdfConfig.iterations, + ); + }); + + function setupMocks() { + // Mock makeMasterKeyEncryptedUserKey() values + keyService.userKey$.mockReturnValue(of(userKey)); + keyService.encryptUserKeyWithMasterKey.mockResolvedValue(masterKeyEncryptedUserKey); + + // Mock keyPair values + keyService.userPrivateKey$.mockReturnValue(of(null)); + keyService.userPublicKey$.mockReturnValue(of(null)); + keyService.makeKeyPair.mockResolvedValue(keyPair); + } + + describe("given the initial password was successfully set", () => { + it("should send a 'redrawMenu' message", async () => { + // Arrange + setupMocks(); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + expect(messagingService.send).toHaveBeenCalledTimes(1); + expect(messagingService.send).toHaveBeenCalledWith("redrawMenu"); + }); + }); + + describe("given the initial password was NOT successfully set (due to some error in setInitialPassword())", () => { + it("should NOT send a 'redrawMenu' message", async () => { + // Arrange + credentials.newMasterKey = null; // will trigger an error in setInitialPassword() + setupMocks(); + + // Act + const promise = sut.setInitialPassword(credentials, userType, userId); + + // Assert + await expect(promise).rejects.toThrow(); + expect(masterPasswordApiService.setPassword).not.toHaveBeenCalled(); + expect(messagingService.send).not.toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/apps/desktop/src/app/services/set-initial-password/desktop-set-initial-password.service.ts b/apps/desktop/src/app/services/set-initial-password/desktop-set-initial-password.service.ts new file mode 100644 index 00000000000..8de7e73fafe --- /dev/null +++ b/apps/desktop/src/app/services/set-initial-password/desktop-set-initial-password.service.ts @@ -0,0 +1,59 @@ +import { OrganizationUserApiService } from "@bitwarden/admin-console/common"; +import { DefaultSetInitialPasswordService } from "@bitwarden/angular/auth/password-management/set-initial-password/default-set-initial-password.service.implementation"; +import { + SetInitialPasswordCredentials, + SetInitialPasswordService, + SetInitialPasswordUserType, +} from "@bitwarden/angular/auth/password-management/set-initial-password/set-initial-password.service.abstraction"; +import { InternalUserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; +import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; +import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; +import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { UserId } from "@bitwarden/common/types/guid"; +import { KdfConfigService, KeyService } from "@bitwarden/key-management"; + +export class DesktopSetInitialPasswordService + extends DefaultSetInitialPasswordService + implements SetInitialPasswordService +{ + constructor( + protected apiService: ApiService, + protected encryptService: EncryptService, + protected i18nService: I18nService, + protected kdfConfigService: KdfConfigService, + protected keyService: KeyService, + protected masterPasswordApiService: MasterPasswordApiService, + protected masterPasswordService: InternalMasterPasswordServiceAbstraction, + protected organizationApiService: OrganizationApiServiceAbstraction, + protected organizationUserApiService: OrganizationUserApiService, + protected userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction, + private messagingService: MessagingService, + ) { + super( + apiService, + encryptService, + i18nService, + kdfConfigService, + keyService, + masterPasswordApiService, + masterPasswordService, + organizationApiService, + organizationUserApiService, + userDecryptionOptionsService, + ); + } + + override async setInitialPassword( + credentials: SetInitialPasswordCredentials, + userType: SetInitialPasswordUserType, + userId: UserId, + ) { + await super.setInitialPassword(credentials, userType, userId); + + this.messagingService.send("redrawMenu"); + } +} diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index f67de2d51d7..ac9307c482c 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -2392,6 +2392,9 @@ "passwordConfirmationDesc": { "message": "This action is protected. To continue, please re-enter your master password to verify your identity." }, + "masterPasswordSuccessfullySet": { + "message": "Master password successfully set" + }, "updatedMasterPassword": { "message": "Updated master password" }, diff --git a/apps/web/src/app/auth/core/services/index.ts b/apps/web/src/app/auth/core/services/index.ts index 5539e3b76ea..8c556986225 100644 --- a/apps/web/src/app/auth/core/services/index.ts +++ b/apps/web/src/app/auth/core/services/index.ts @@ -2,6 +2,7 @@ export * from "./change-password"; export * from "./login"; export * from "./login-decryption-options"; export * from "./webauthn-login"; +export * from "./password-management"; export * from "./set-password-jit"; export * from "./registration"; export * from "./two-factor-auth"; diff --git a/apps/web/src/app/auth/core/services/password-management/index.ts b/apps/web/src/app/auth/core/services/password-management/index.ts new file mode 100644 index 00000000000..1444fd024af --- /dev/null +++ b/apps/web/src/app/auth/core/services/password-management/index.ts @@ -0,0 +1 @@ +export * from "./set-initial-password/web-set-initial-password.service"; diff --git a/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.spec.ts b/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.spec.ts new file mode 100644 index 00000000000..b90d0624b3f --- /dev/null +++ b/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.spec.ts @@ -0,0 +1,208 @@ +import { MockProxy, mock } from "jest-mock-extended"; +import { BehaviorSubject, of } from "rxjs"; + +import { OrganizationUserApiService } from "@bitwarden/admin-console/common"; +import { + SetInitialPasswordCredentials, + SetInitialPasswordService, + SetInitialPasswordUserType, +} from "@bitwarden/angular/auth/password-management/set-initial-password/set-initial-password.service.abstraction"; +import { + FakeUserDecryptionOptions as UserDecryptionOptions, + InternalUserDecryptionOptionsServiceAbstraction, +} from "@bitwarden/auth/common"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; +import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; +import { SetPasswordRequest } from "@bitwarden/common/auth/models/request/set-password.request"; +import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; +import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; +import { KeysRequest } from "@bitwarden/common/models/request/keys.request"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; +import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { CsprngArray } from "@bitwarden/common/types/csprng"; +import { UserId } from "@bitwarden/common/types/guid"; +import { MasterKey, UserKey } from "@bitwarden/common/types/key"; +import { DEFAULT_KDF_CONFIG, KdfConfigService, KeyService } from "@bitwarden/key-management"; +import { AcceptOrganizationInviteService } from "@bitwarden/web-vault/app/auth/organization-invite/accept-organization.service"; +import { RouterService } from "@bitwarden/web-vault/app/core"; + +import { WebSetInitialPasswordService } from "./web-set-initial-password.service"; + +describe("WebSetInitialPasswordService", () => { + let sut: SetInitialPasswordService; + + let apiService: MockProxy; + let encryptService: MockProxy; + let i18nService: MockProxy; + let kdfConfigService: MockProxy; + let keyService: MockProxy; + let masterPasswordApiService: MockProxy; + let masterPasswordService: MockProxy; + let organizationApiService: MockProxy; + let organizationUserApiService: MockProxy; + let userDecryptionOptionsService: MockProxy; + let acceptOrganizationInviteService: MockProxy; + let routerService: MockProxy; + + beforeEach(() => { + apiService = mock(); + encryptService = mock(); + i18nService = mock(); + kdfConfigService = mock(); + keyService = mock(); + masterPasswordApiService = mock(); + masterPasswordService = mock(); + organizationApiService = mock(); + organizationUserApiService = mock(); + userDecryptionOptionsService = mock(); + acceptOrganizationInviteService = mock(); + routerService = mock(); + + sut = new WebSetInitialPasswordService( + apiService, + encryptService, + i18nService, + kdfConfigService, + keyService, + masterPasswordApiService, + masterPasswordService, + organizationApiService, + organizationUserApiService, + userDecryptionOptionsService, + acceptOrganizationInviteService, + routerService, + ); + }); + + it("should instantiate", () => { + expect(sut).not.toBeFalsy(); + }); + + describe("setInitialPassword(...)", () => { + // Mock function parameters + let credentials: SetInitialPasswordCredentials; + let userType: SetInitialPasswordUserType; + let userId: UserId; + + // Mock other function data + let userKey: UserKey; + let userKeyEncString: EncString; + let masterKeyEncryptedUserKey: [UserKey, EncString]; + + let keyPair: [string, EncString]; + let keysRequest: KeysRequest; + + let userDecryptionOptions: UserDecryptionOptions; + let userDecryptionOptionsSubject: BehaviorSubject; + let setPasswordRequest: SetPasswordRequest; + + beforeEach(() => { + // Mock function parameters + credentials = { + newMasterKey: new SymmetricCryptoKey(new Uint8Array(32).buffer as CsprngArray) as MasterKey, + newServerMasterKeyHash: "newServerMasterKeyHash", + newLocalMasterKeyHash: "newLocalMasterKeyHash", + newPasswordHint: "newPasswordHint", + kdfConfig: DEFAULT_KDF_CONFIG, + orgSsoIdentifier: "orgSsoIdentifier", + orgId: "orgId", + resetPasswordAutoEnroll: false, + }; + userId = "userId" as UserId; + userType = SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER; + + // Mock other function data + userKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as UserKey; + userKeyEncString = new EncString("masterKeyEncryptedUserKey"); + masterKeyEncryptedUserKey = [userKey, userKeyEncString]; + + keyPair = ["publicKey", new EncString("privateKey")]; + keysRequest = new KeysRequest(keyPair[0], keyPair[1].encryptedString); + + userDecryptionOptions = new UserDecryptionOptions({ hasMasterPassword: true }); + userDecryptionOptionsSubject = new BehaviorSubject(userDecryptionOptions); + userDecryptionOptionsService.userDecryptionOptions$ = userDecryptionOptionsSubject; + + setPasswordRequest = new SetPasswordRequest( + credentials.newServerMasterKeyHash, + masterKeyEncryptedUserKey[1].encryptedString, + credentials.newPasswordHint, + credentials.orgSsoIdentifier, + keysRequest, + credentials.kdfConfig.kdfType, + credentials.kdfConfig.iterations, + ); + }); + + function setupMocks() { + // Mock makeMasterKeyEncryptedUserKey() values + keyService.userKey$.mockReturnValue(of(userKey)); + keyService.encryptUserKeyWithMasterKey.mockResolvedValue(masterKeyEncryptedUserKey); + + // Mock keyPair values + keyService.userPrivateKey$.mockReturnValue(of(null)); + keyService.userPublicKey$.mockReturnValue(of(null)); + keyService.makeKeyPair.mockResolvedValue(keyPair); + } + + describe("given the initial password was successfully set", () => { + it("should call routerService.getAndClearLoginRedirectUrl()", async () => { + // Arrange + setupMocks(); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + expect(routerService.getAndClearLoginRedirectUrl).toHaveBeenCalledTimes(1); + }); + + it("should call acceptOrganizationInviteService.clearOrganizationInvitation()", async () => { + // Arrange + setupMocks(); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + expect(acceptOrganizationInviteService.clearOrganizationInvitation).toHaveBeenCalledTimes( + 1, + ); + }); + }); + + describe("given the initial password was NOT successfully set (due to some error in setInitialPassword())", () => { + it("should NOT call routerService.getAndClearLoginRedirectUrl()", async () => { + // Arrange + credentials.newMasterKey = null; // will trigger an error in setInitialPassword() + setupMocks(); + + // Act + const promise = sut.setInitialPassword(credentials, userType, userId); + + // Assert + await expect(promise).rejects.toThrow(); + expect(masterPasswordApiService.setPassword).not.toHaveBeenCalled(); + expect(routerService.getAndClearLoginRedirectUrl).not.toHaveBeenCalled(); + }); + + it("should NOT call acceptOrganizationInviteService.clearOrganizationInvitation()", async () => { + // Arrange + credentials.newMasterKey = null; // will trigger an error in setInitialPassword() + setupMocks(); + + // Act + const promise = sut.setInitialPassword(credentials, userType, userId); + + // Assert + await expect(promise).rejects.toThrow(); + expect(masterPasswordApiService.setPassword).not.toHaveBeenCalled(); + expect(acceptOrganizationInviteService.clearOrganizationInvitation).not.toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.ts b/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.ts new file mode 100644 index 00000000000..41e7e8ad4ab --- /dev/null +++ b/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.ts @@ -0,0 +1,83 @@ +import { OrganizationUserApiService } from "@bitwarden/admin-console/common"; +import { DefaultSetInitialPasswordService } from "@bitwarden/angular/auth/password-management/set-initial-password/default-set-initial-password.service.implementation"; +import { + SetInitialPasswordCredentials, + SetInitialPasswordService, + SetInitialPasswordUserType, +} from "@bitwarden/angular/auth/password-management/set-initial-password/set-initial-password.service.abstraction"; +import { InternalUserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; +import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; +import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; +import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { UserId } from "@bitwarden/common/types/guid"; +import { KdfConfigService, KeyService } from "@bitwarden/key-management"; +import { AcceptOrganizationInviteService } from "@bitwarden/web-vault/app/auth/organization-invite/accept-organization.service"; +import { RouterService } from "@bitwarden/web-vault/app/core"; + +export class WebSetInitialPasswordService + extends DefaultSetInitialPasswordService + implements SetInitialPasswordService +{ + constructor( + protected apiService: ApiService, + protected encryptService: EncryptService, + protected i18nService: I18nService, + protected kdfConfigService: KdfConfigService, + protected keyService: KeyService, + protected masterPasswordApiService: MasterPasswordApiService, + protected masterPasswordService: InternalMasterPasswordServiceAbstraction, + protected organizationApiService: OrganizationApiServiceAbstraction, + protected organizationUserApiService: OrganizationUserApiService, + protected userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction, + private acceptOrganizationInviteService: AcceptOrganizationInviteService, + private routerService: RouterService, + ) { + super( + apiService, + encryptService, + i18nService, + kdfConfigService, + keyService, + masterPasswordApiService, + masterPasswordService, + organizationApiService, + organizationUserApiService, + userDecryptionOptionsService, + ); + } + + override async setInitialPassword( + credentials: SetInitialPasswordCredentials, + userType: SetInitialPasswordUserType, + userId: UserId, + ) { + await super.setInitialPassword(credentials, userType, userId); + + /** + * TODO: Investigate refactoring the following logic in https://bitwarden.atlassian.net/browse/PM-22615 + * --- + * When a user has been invited to an org, they can be accepted into the org in two different ways: + * + * 1) By clicking the email invite link, which triggers the normal AcceptOrganizationComponent flow + * a. This flow sets an org invite in state + * b. However, if the user does not already have an account AND the org has SSO enabled AND the require + * SSO policy enabled, the AcceptOrganizationComponent will send the user to /sso to accelerate + * the user through the SSO JIT provisioning process (see #2 below) + * + * 2) By logging in via SSO, which triggers the JIT provisioning process + * a. This flow does NOT (itself) set an org invite in state + * b. The set initial password process on the server accepts the user into the org after successfully + * setting the password (see server - SetInitialMasterPasswordCommand.cs) + * + * If a user clicks the email link but gets accelerated through the SSO JIT process (see 1b), + * the SSO JIT process will accept the user into the org upon setting their initial password (see 2b), + * at which point we must remember to clear the deep linked URL used for accepting the org invite, as well + * as clear the org invite itself that was originally set in state by the AcceptOrganizationComponent. + */ + await this.routerService.getAndClearLoginRedirectUrl(); + await this.acceptOrganizationInviteService.clearOrganizationInvitation(); + } +} diff --git a/apps/web/src/app/core/core.module.ts b/apps/web/src/app/core/core.module.ts index 46435981a5e..b6a6ca102d8 100644 --- a/apps/web/src/app/core/core.module.ts +++ b/apps/web/src/app/core/core.module.ts @@ -10,6 +10,7 @@ import { OrganizationUserApiService, CollectionService, } from "@bitwarden/admin-console/common"; +import { SetInitialPasswordService } from "@bitwarden/angular/auth/password-management/set-initial-password/set-initial-password.service.abstraction"; import { SafeProvider, safeProvider } from "@bitwarden/angular/platform/utils/safe-provider"; import { CLIENT_TYPE, @@ -117,6 +118,7 @@ import { WebLoginDecryptionOptionsService, WebTwoFactorAuthDuoComponentService, LinkSsoService, + WebSetInitialPasswordService, } from "../auth"; import { WebSsoComponentService } from "../auth/core/services/login/web-sso-component.service"; import { AcceptOrganizationInviteService } from "../auth/organization-invite/accept-organization.service"; @@ -283,6 +285,24 @@ const safeProviders: SafeProvider[] = [ InternalUserDecryptionOptionsServiceAbstraction, ], }), + safeProvider({ + provide: SetInitialPasswordService, + useClass: WebSetInitialPasswordService, + deps: [ + ApiService, + EncryptService, + I18nServiceAbstraction, + KdfConfigService, + KeyServiceAbstraction, + MasterPasswordApiService, + InternalMasterPasswordServiceAbstraction, + OrganizationApiServiceAbstraction, + OrganizationUserApiService, + InternalUserDecryptionOptionsServiceAbstraction, + AcceptOrganizationInviteService, + RouterService, + ], + }), safeProvider({ provide: AppIdService, useClass: DefaultAppIdService, diff --git a/apps/web/src/app/oss-routing.module.ts b/apps/web/src/app/oss-routing.module.ts index 0733d1ef289..615bb545811 100644 --- a/apps/web/src/app/oss-routing.module.ts +++ b/apps/web/src/app/oss-routing.module.ts @@ -10,6 +10,8 @@ import { unauthGuardFn, activeAuthGuard, } from "@bitwarden/angular/auth/guards"; +import { SetInitialPasswordComponent } from "@bitwarden/angular/auth/password-management/set-initial-password/set-initial-password.component"; +import { canAccessFeature } from "@bitwarden/angular/platform/guard/feature-flag.guard"; import { PasswordHintComponent, RegistrationFinishComponent, @@ -36,6 +38,7 @@ import { NewDeviceVerificationComponent, DeviceVerificationIcon, } from "@bitwarden/auth/angular"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { AnonLayoutWrapperComponent, AnonLayoutWrapperData, Icons } from "@bitwarden/components"; import { LockComponent } from "@bitwarden/key-management-ui"; import { VaultIcons } from "@bitwarden/vault"; @@ -305,6 +308,14 @@ const routes: Routes = [ }, ], }, + { + path: "set-initial-password", + canActivate: [canAccessFeature(FeatureFlag.PM16117_SetInitialPasswordRefactor), authGuard], + component: SetInitialPasswordComponent, + data: { + maxWidth: "lg", + } satisfies AnonLayoutWrapperData, + }, { path: "set-password-jit", component: SetPasswordJitComponent, diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 5c9b02e5287..eed2757eacc 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -6065,6 +6065,9 @@ "add": { "message": "Add" }, + "masterPasswordSuccessfullySet": { + "message": "Master password successfully set" + }, "updatedMasterPassword": { "message": "Master password saved" }, diff --git a/libs/angular/src/auth/guards/auth.guard.ts b/libs/angular/src/auth/guards/auth.guard.ts index f99a91fda34..7b8c21fef62 100644 --- a/libs/angular/src/auth/guards/auth.guard.ts +++ b/libs/angular/src/auth/guards/auth.guard.ts @@ -39,7 +39,32 @@ export const authGuard: CanActivateFn = async ( return false; } - if (authStatus === AuthenticationStatus.Locked) { + const userId = (await firstValueFrom(accountService.activeAccount$)).id; + const forceSetPasswordReason = await firstValueFrom( + masterPasswordService.forceSetPasswordReason$(userId), + ); + + const isSetInitialPasswordFlagOn = await configService.getFeatureFlag( + FeatureFlag.PM16117_SetInitialPasswordRefactor, + ); + const isChangePasswordFlagOn = await configService.getFeatureFlag( + FeatureFlag.PM16117_ChangeExistingPasswordRefactor, + ); + + // User JIT provisioned into a master-password-encryption org + if ( + authStatus === AuthenticationStatus.Locked && + forceSetPasswordReason === ForceSetPasswordReason.SsoNewJitProvisionedUser && + !routerState.url.includes("set-initial-password") && + isSetInitialPasswordFlagOn + ) { + return router.createUrlTree(["/set-initial-password"]); + } + + if ( + authStatus === AuthenticationStatus.Locked && + forceSetPasswordReason !== ForceSetPasswordReason.SsoNewJitProvisionedUser + ) { if (routerState != null) { messagingService.send("lockedUrl", { url: routerState.url }); } @@ -55,18 +80,6 @@ export const authGuard: CanActivateFn = async ( return router.createUrlTree(["/remove-password"]); } - const userId = (await firstValueFrom(accountService.activeAccount$)).id; - const forceSetPasswordReason = await firstValueFrom( - masterPasswordService.forceSetPasswordReason$(userId), - ); - - const isSetInitialPasswordFlagOn = await configService.getFeatureFlag( - FeatureFlag.PM16117_SetInitialPasswordRefactor, - ); - const isChangePasswordFlagOn = await configService.getFeatureFlag( - FeatureFlag.PM16117_ChangeExistingPasswordRefactor, - ); - // TDE org user has "manage account recovery" permission if ( forceSetPasswordReason === diff --git a/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.implementation.ts b/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.implementation.ts new file mode 100644 index 00000000000..1c5edb00c8c --- /dev/null +++ b/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.implementation.ts @@ -0,0 +1,248 @@ +import { firstValueFrom } from "rxjs"; + +// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. +// eslint-disable-next-line no-restricted-imports +import { + OrganizationUserApiService, + OrganizationUserResetPasswordEnrollmentRequest, +} from "@bitwarden/admin-console/common"; +// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. +// eslint-disable-next-line no-restricted-imports +import { InternalUserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; +import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; +import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; +import { SetPasswordRequest } from "@bitwarden/common/auth/models/request/set-password.request"; +import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; +import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; +import { KeysRequest } from "@bitwarden/common/models/request/keys.request"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; +import { UserId } from "@bitwarden/common/types/guid"; +import { MasterKey, UserKey } from "@bitwarden/common/types/key"; +import { KdfConfigService, KeyService, KdfConfig } from "@bitwarden/key-management"; + +import { + SetInitialPasswordService, + SetInitialPasswordCredentials, + SetInitialPasswordUserType, +} from "./set-initial-password.service.abstraction"; + +export class DefaultSetInitialPasswordService implements SetInitialPasswordService { + constructor( + protected apiService: ApiService, + protected encryptService: EncryptService, + protected i18nService: I18nService, + protected kdfConfigService: KdfConfigService, + protected keyService: KeyService, + protected masterPasswordApiService: MasterPasswordApiService, + protected masterPasswordService: InternalMasterPasswordServiceAbstraction, + protected organizationApiService: OrganizationApiServiceAbstraction, + protected organizationUserApiService: OrganizationUserApiService, + protected userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction, + ) {} + + async setInitialPassword( + credentials: SetInitialPasswordCredentials, + userType: SetInitialPasswordUserType, + userId: UserId, + ): Promise { + const { + newMasterKey, + newServerMasterKeyHash, + newLocalMasterKeyHash, + newPasswordHint, + kdfConfig, + orgSsoIdentifier, + orgId, + resetPasswordAutoEnroll, + } = credentials; + + for (const [key, value] of Object.entries(credentials)) { + if (value == null) { + throw new Error(`${key} not found. Could not set password.`); + } + } + if (userId == null) { + throw new Error("userId not found. Could not set password."); + } + if (userType == null) { + throw new Error("userType not found. Could not set password."); + } + + const masterKeyEncryptedUserKey = await this.makeMasterKeyEncryptedUserKey( + newMasterKey, + userId, + ); + if (masterKeyEncryptedUserKey == null || !masterKeyEncryptedUserKey[1].encryptedString) { + throw new Error("masterKeyEncryptedUserKey not found. Could not set password."); + } + + let keyPair: [string, EncString] | null = null; + let keysRequest: KeysRequest | null = null; + + if (userType === SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER) { + /** + * A user being JIT provisioned into a MP encryption org does not yet have a user + * asymmetric key pair, so we create it for them here. + * + * Sidenote: + * In the case of a TDE user whose permissions require that they have a MP - that user + * will already have a user asymmetric key pair by this point, so we skip this if-block + * so that we don't create a new key pair for them. + */ + + // Extra safety check (see description on https://github.com/bitwarden/clients/pull/10180): + // In case we have have a local private key and are not sure whether it has been posted to the server, + // we post the local private key instead of generating a new one + const existingUserPrivateKey = (await firstValueFrom( + this.keyService.userPrivateKey$(userId), + )) as Uint8Array; + + const existingUserPublicKey = await firstValueFrom(this.keyService.userPublicKey$(userId)); + + if (existingUserPrivateKey != null && existingUserPublicKey != null) { + const existingUserPublicKeyB64 = Utils.fromBufferToB64(existingUserPublicKey); + + // Existing key pair + keyPair = [ + existingUserPublicKeyB64, + await this.encryptService.wrapDecapsulationKey( + existingUserPrivateKey, + masterKeyEncryptedUserKey[0], + ), + ]; + } else { + // New key pair + keyPair = await this.keyService.makeKeyPair(masterKeyEncryptedUserKey[0]); + } + + if (keyPair == null) { + throw new Error("keyPair not found. Could not set password."); + } + if (!keyPair[1].encryptedString) { + throw new Error("encrypted private key not found. Could not set password."); + } + + keysRequest = new KeysRequest(keyPair[0], keyPair[1].encryptedString); + } + + const request = new SetPasswordRequest( + newServerMasterKeyHash, + masterKeyEncryptedUserKey[1].encryptedString, + newPasswordHint, + orgSsoIdentifier, + keysRequest, + kdfConfig.kdfType, + kdfConfig.iterations, + ); + + await this.masterPasswordApiService.setPassword(request); + + // Clear force set password reason to allow navigation back to vault. + await this.masterPasswordService.setForceSetPasswordReason(ForceSetPasswordReason.None, userId); + + // User now has a password so update account decryption options in state + await this.updateAccountDecryptionProperties( + newMasterKey, + kdfConfig, + masterKeyEncryptedUserKey, + userId, + ); + + /** + * Set the private key only for new JIT provisioned users in MP encryption orgs. + * (Existing TDE users will have their private key set on sync or on login.) + */ + if (keyPair != null && userType === SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER) { + if (!keyPair[1].encryptedString) { + throw new Error("encrypted private key not found. Could not set private key in state."); + } + await this.keyService.setPrivateKey(keyPair[1].encryptedString, userId); + } + + await this.masterPasswordService.setMasterKeyHash(newLocalMasterKeyHash, userId); + + if (resetPasswordAutoEnroll) { + await this.handleResetPasswordAutoEnroll(newServerMasterKeyHash, orgId, userId); + } + } + + private async makeMasterKeyEncryptedUserKey( + masterKey: MasterKey, + userId: UserId, + ): Promise<[UserKey, EncString]> { + let masterKeyEncryptedUserKey: [UserKey, EncString] | null = null; + + const userKey = await firstValueFrom(this.keyService.userKey$(userId)); + + if (userKey == null) { + masterKeyEncryptedUserKey = await this.keyService.makeUserKey(masterKey); + } else { + masterKeyEncryptedUserKey = await this.keyService.encryptUserKeyWithMasterKey(masterKey); + } + + return masterKeyEncryptedUserKey; + } + + private async updateAccountDecryptionProperties( + masterKey: MasterKey, + kdfConfig: KdfConfig, + masterKeyEncryptedUserKey: [UserKey, EncString], + userId: UserId, + ) { + const userDecryptionOpts = await firstValueFrom( + this.userDecryptionOptionsService.userDecryptionOptions$, + ); + userDecryptionOpts.hasMasterPassword = true; + await this.userDecryptionOptionsService.setUserDecryptionOptions(userDecryptionOpts); + await this.kdfConfigService.setKdfConfig(userId, kdfConfig); + await this.masterPasswordService.setMasterKey(masterKey, userId); + await this.keyService.setUserKey(masterKeyEncryptedUserKey[0], userId); + } + + private async handleResetPasswordAutoEnroll( + masterKeyHash: string, + orgId: string, + userId: UserId, + ) { + const organizationKeys = await this.organizationApiService.getKeys(orgId); + + if (organizationKeys == null) { + throw new Error( + "Organization keys response is null. Could not handle reset password auto enroll.", + ); + } + + const orgPublicKey = Utils.fromB64ToArray(organizationKeys.publicKey); + const userKey = await firstValueFrom(this.keyService.userKey$(userId)); + + if (userKey == null) { + throw new Error("userKey not found. Could not handle reset password auto enroll."); + } + + // RSA encrypt user key with organization public key + const orgPublicKeyEncryptedUserKey = await this.encryptService.encapsulateKeyUnsigned( + userKey, + orgPublicKey, + ); + + if (orgPublicKeyEncryptedUserKey == null || !orgPublicKeyEncryptedUserKey.encryptedString) { + throw new Error( + "orgPublicKeyEncryptedUserKey not found. Could not handle reset password auto enroll.", + ); + } + + const enrollmentRequest = new OrganizationUserResetPasswordEnrollmentRequest(); + enrollmentRequest.masterPasswordHash = masterKeyHash; + enrollmentRequest.resetPasswordKey = orgPublicKeyEncryptedUserKey.encryptedString; + + await this.organizationUserApiService.putOrganizationUserResetPasswordEnrollment( + orgId, + userId, + enrollmentRequest, + ); + } +} diff --git a/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.spec.ts b/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.spec.ts new file mode 100644 index 00000000000..ca4d9adbd67 --- /dev/null +++ b/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.spec.ts @@ -0,0 +1,633 @@ +import { MockProxy, mock } from "jest-mock-extended"; +import { BehaviorSubject, of } from "rxjs"; + +// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. +// eslint-disable-next-line no-restricted-imports +import { + OrganizationUserApiService, + OrganizationUserResetPasswordEnrollmentRequest, +} from "@bitwarden/admin-console/common"; +// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. +// eslint-disable-next-line no-restricted-imports +import { + FakeUserDecryptionOptions as UserDecryptionOptions, + InternalUserDecryptionOptionsServiceAbstraction, +} from "@bitwarden/auth/common"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; +import { OrganizationKeysResponse } from "@bitwarden/common/admin-console/models/response/organization-keys.response"; +import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; +import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; +import { SetPasswordRequest } from "@bitwarden/common/auth/models/request/set-password.request"; +import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; +import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; +import { KeysRequest } from "@bitwarden/common/models/request/keys.request"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string"; +import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { CsprngArray } from "@bitwarden/common/types/csprng"; +import { UserId } from "@bitwarden/common/types/guid"; +import { MasterKey, UserKey, UserPrivateKey, UserPublicKey } from "@bitwarden/common/types/key"; +import { DEFAULT_KDF_CONFIG, KdfConfigService, KeyService } from "@bitwarden/key-management"; + +import { DefaultSetInitialPasswordService } from "./default-set-initial-password.service.implementation"; +import { + SetInitialPasswordCredentials, + SetInitialPasswordService, + SetInitialPasswordUserType, +} from "./set-initial-password.service.abstraction"; + +describe("DefaultSetInitialPasswordService", () => { + let sut: SetInitialPasswordService; + + let apiService: MockProxy; + let encryptService: MockProxy; + let i18nService: MockProxy; + let kdfConfigService: MockProxy; + let keyService: MockProxy; + let masterPasswordApiService: MockProxy; + let masterPasswordService: MockProxy; + let organizationApiService: MockProxy; + let organizationUserApiService: MockProxy; + let userDecryptionOptionsService: MockProxy; + + beforeEach(() => { + apiService = mock(); + encryptService = mock(); + i18nService = mock(); + kdfConfigService = mock(); + keyService = mock(); + masterPasswordApiService = mock(); + masterPasswordService = mock(); + organizationApiService = mock(); + organizationUserApiService = mock(); + userDecryptionOptionsService = mock(); + + sut = new DefaultSetInitialPasswordService( + apiService, + encryptService, + i18nService, + kdfConfigService, + keyService, + masterPasswordApiService, + masterPasswordService, + organizationApiService, + organizationUserApiService, + userDecryptionOptionsService, + ); + }); + + it("should instantiate", () => { + expect(sut).not.toBeFalsy(); + }); + + describe("setInitialPassword(...)", () => { + // Mock function parameters + let credentials: SetInitialPasswordCredentials; + let userType: SetInitialPasswordUserType; + let userId: UserId; + + // Mock other function data + let userKey: UserKey; + let userKeyEncString: EncString; + let masterKeyEncryptedUserKey: [UserKey, EncString]; + + let existingUserPublicKey: UserPublicKey; + let existingUserPrivateKey: UserPrivateKey; + let userKeyEncryptedPrivateKey: EncString; + + let keyPair: [string, EncString]; + let keysRequest: KeysRequest; + + let organizationKeys: OrganizationKeysResponse; + let orgPublicKeyEncryptedUserKey: EncString; + + let userDecryptionOptions: UserDecryptionOptions; + let userDecryptionOptionsSubject: BehaviorSubject; + let setPasswordRequest: SetPasswordRequest; + + let enrollmentRequest: OrganizationUserResetPasswordEnrollmentRequest; + + beforeEach(() => { + // Mock function parameters + credentials = { + newMasterKey: new SymmetricCryptoKey(new Uint8Array(32).buffer as CsprngArray) as MasterKey, + newServerMasterKeyHash: "newServerMasterKeyHash", + newLocalMasterKeyHash: "newLocalMasterKeyHash", + newPasswordHint: "newPasswordHint", + kdfConfig: DEFAULT_KDF_CONFIG, + orgSsoIdentifier: "orgSsoIdentifier", + orgId: "orgId", + resetPasswordAutoEnroll: false, + }; + userId = "userId" as UserId; + userType = SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER; + + // Mock other function data + userKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as UserKey; + userKeyEncString = new EncString("masterKeyEncryptedUserKey"); + masterKeyEncryptedUserKey = [userKey, userKeyEncString]; + + existingUserPublicKey = Utils.fromB64ToArray("existingUserPublicKey") as UserPublicKey; + existingUserPrivateKey = Utils.fromB64ToArray("existingUserPrivateKey") as UserPrivateKey; + userKeyEncryptedPrivateKey = new EncString("userKeyEncryptedPrivateKey"); + + keyPair = ["publicKey", new EncString("privateKey")]; + keysRequest = new KeysRequest(keyPair[0], keyPair[1].encryptedString); + + organizationKeys = { + privateKey: "orgPrivateKey", + publicKey: "orgPublicKey", + } as OrganizationKeysResponse; + orgPublicKeyEncryptedUserKey = new EncString("orgPublicKeyEncryptedUserKey"); + + userDecryptionOptions = new UserDecryptionOptions({ hasMasterPassword: true }); + userDecryptionOptionsSubject = new BehaviorSubject(userDecryptionOptions); + userDecryptionOptionsService.userDecryptionOptions$ = userDecryptionOptionsSubject; + + setPasswordRequest = new SetPasswordRequest( + credentials.newServerMasterKeyHash, + masterKeyEncryptedUserKey[1].encryptedString, + credentials.newPasswordHint, + credentials.orgSsoIdentifier, + keysRequest, + credentials.kdfConfig.kdfType, + credentials.kdfConfig.iterations, + ); + + enrollmentRequest = new OrganizationUserResetPasswordEnrollmentRequest(); + enrollmentRequest.masterPasswordHash = credentials.newServerMasterKeyHash; + enrollmentRequest.resetPasswordKey = orgPublicKeyEncryptedUserKey.encryptedString; + }); + + interface MockConfig { + userType: SetInitialPasswordUserType; + userHasUserKey: boolean; + userHasLocalKeyPair: boolean; + resetPasswordAutoEnroll: boolean; + } + + const defaultMockConfig: MockConfig = { + userType: SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER, + userHasUserKey: true, + userHasLocalKeyPair: false, + resetPasswordAutoEnroll: false, + }; + + function setupMocks(config: MockConfig = defaultMockConfig) { + // Mock makeMasterKeyEncryptedUserKey() values + if (config.userHasUserKey) { + keyService.userKey$.mockReturnValue(of(userKey)); + keyService.encryptUserKeyWithMasterKey.mockResolvedValue(masterKeyEncryptedUserKey); + } else { + keyService.userKey$.mockReturnValue(of(null)); + keyService.makeUserKey.mockResolvedValue(masterKeyEncryptedUserKey); + } + + // Mock keyPair values + if (config.userType === SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER) { + if (config.userHasLocalKeyPair) { + keyService.userPrivateKey$.mockReturnValue(of(existingUserPrivateKey)); + keyService.userPublicKey$.mockReturnValue(of(existingUserPublicKey)); + encryptService.wrapDecapsulationKey.mockResolvedValue(userKeyEncryptedPrivateKey); + } else { + keyService.userPrivateKey$.mockReturnValue(of(null)); + keyService.userPublicKey$.mockReturnValue(of(null)); + keyService.makeKeyPair.mockResolvedValue(keyPair); + } + } + + // Mock handleResetPasswordAutoEnroll() values + if (config.resetPasswordAutoEnroll) { + organizationApiService.getKeys.mockResolvedValue(organizationKeys); + encryptService.encapsulateKeyUnsigned.mockResolvedValue(orgPublicKeyEncryptedUserKey); + keyService.userKey$.mockReturnValue(of(userKey)); + } + } + + describe("general error handling", () => { + [ + "newMasterKey", + "newServerMasterKeyHash", + "newLocalMasterKeyHash", + "newPasswordHint", + "kdfConfig", + "orgSsoIdentifier", + "orgId", + "resetPasswordAutoEnroll", + ].forEach((key) => { + it(`should throw if ${key} is not provided on the SetInitialPasswordCredentials object`, async () => { + // Arrange + const invalidCredentials: SetInitialPasswordCredentials = { + ...credentials, + [key]: null, + }; + + // Act + const promise = sut.setInitialPassword(invalidCredentials, userType, userId); + + // Assert + await expect(promise).rejects.toThrow(`${key} not found. Could not set password.`); + }); + }); + + ["userId", "userType"].forEach((param) => { + it(`should throw if ${param} was not passed in`, async () => { + // Arrange & Act + const promise = sut.setInitialPassword( + credentials, + param === "userType" ? null : userType, + param === "userId" ? null : userId, + ); + + // Assert + await expect(promise).rejects.toThrow(`${param} not found. Could not set password.`); + }); + }); + }); + + describe("given SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER", () => { + beforeEach(() => { + userType = SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER; + }); + + describe("given the user has an existing local key pair", () => { + it("should NOT create a brand new key pair for the user", async () => { + // Arrange + setPasswordRequest.keys = { + encryptedPrivateKey: userKeyEncryptedPrivateKey.encryptedString, + publicKey: Utils.fromBufferToB64(existingUserPublicKey), + }; + + setupMocks({ ...defaultMockConfig, userHasLocalKeyPair: true }); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + expect(keyService.userPrivateKey$).toHaveBeenCalledWith(userId); + expect(keyService.userPublicKey$).toHaveBeenCalledWith(userId); + expect(encryptService.wrapDecapsulationKey).toHaveBeenCalledWith( + existingUserPrivateKey, + masterKeyEncryptedUserKey[0], + ); + expect(keyService.makeKeyPair).not.toHaveBeenCalled(); + }); + }); + + describe("given the user has a userKey", () => { + it("should successfully set an initial password", async () => { + // Arrange + setupMocks(); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + }); + }); + + describe("given the user does NOT have a userKey", () => { + it("should successfully set an initial password", async () => { + // Arrange + setupMocks({ ...defaultMockConfig, userHasUserKey: false }); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + }); + }); + + it("should throw if a key pair is not found", async () => { + // Arrange + keyPair = null; + + setupMocks(); + + // Act + const promise = sut.setInitialPassword(credentials, userType, userId); + + // Assert + await expect(promise).rejects.toThrow("keyPair not found. Could not set password."); + expect(masterPasswordApiService.setPassword).not.toHaveBeenCalled(); + }); + + it("should throw if an encrypted private key is not found", async () => { + // Arrange + keyPair[1].encryptedString = "" as EncryptedString; + + setupMocks(); + + // Act + const promise = sut.setInitialPassword(credentials, userType, userId); + + // Assert + await expect(promise).rejects.toThrow( + "encrypted private key not found. Could not set password.", + ); + expect(masterPasswordApiService.setPassword).not.toHaveBeenCalled(); + }); + + describe("given the initial password has been successfully set", () => { + it("should clear the ForceSetPasswordReason by setting it to None", async () => { + // Arrange + setupMocks(); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + expect(masterPasswordService.setForceSetPasswordReason).toHaveBeenCalledWith( + ForceSetPasswordReason.None, + userId, + ); + }); + + it("should update account decryption properties", async () => { + // Arrange + setupMocks(); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + expect(userDecryptionOptionsService.setUserDecryptionOptions).toHaveBeenCalledWith( + userDecryptionOptions, + ); + expect(kdfConfigService.setKdfConfig).toHaveBeenCalledWith(userId, credentials.kdfConfig); + expect(masterPasswordService.setMasterKey).toHaveBeenCalledWith( + credentials.newMasterKey, + userId, + ); + expect(keyService.setUserKey).toHaveBeenCalledWith(masterKeyEncryptedUserKey[0], userId); + }); + + it("should set the private key to state", async () => { + // Arrange + setupMocks(); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + expect(keyService.setPrivateKey).toHaveBeenCalledWith(keyPair[1].encryptedString, userId); + }); + + it("should set the local master key hash to state", async () => { + // Arrange + setupMocks(); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + expect(masterPasswordService.setMasterKeyHash).toHaveBeenCalledWith( + credentials.newLocalMasterKeyHash, + userId, + ); + }); + + describe("given resetPasswordAutoEnroll is true", () => { + it(`should handle reset password (account recovery) auto enroll`, async () => { + // Arrange + credentials.resetPasswordAutoEnroll = true; + + setupMocks({ ...defaultMockConfig, resetPasswordAutoEnroll: true }); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + expect( + organizationUserApiService.putOrganizationUserResetPasswordEnrollment, + ).toHaveBeenCalledWith(credentials.orgId, userId, enrollmentRequest); + }); + + it("should throw if organization keys are not found", async () => { + // Arrange + credentials.resetPasswordAutoEnroll = true; + organizationKeys = null; + + setupMocks({ ...defaultMockConfig, resetPasswordAutoEnroll: true }); + + // Act + const promise = sut.setInitialPassword(credentials, userType, userId); + + // Assert + await expect(promise).rejects.toThrow( + "Organization keys response is null. Could not handle reset password auto enroll.", + ); + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + expect( + organizationUserApiService.putOrganizationUserResetPasswordEnrollment, + ).not.toHaveBeenCalled(); + }); + + ["orgPublicKeyEncryptedUserKey", "orgPublicKeyEncryptedUserKey.encryptedString"].forEach( + (property) => { + it("should throw if orgPublicKeyEncryptedUserKey is not found", async () => { + // Arrange + credentials.resetPasswordAutoEnroll = true; + + if (property === "orgPublicKeyEncryptedUserKey") { + orgPublicKeyEncryptedUserKey = null; + } else { + orgPublicKeyEncryptedUserKey.encryptedString = "" as EncryptedString; + } + + setupMocks({ ...defaultMockConfig, resetPasswordAutoEnroll: true }); + + // Act + const promise = sut.setInitialPassword(credentials, userType, userId); + + // Assert + await expect(promise).rejects.toThrow( + "orgPublicKeyEncryptedUserKey not found. Could not handle reset password auto enroll.", + ); + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith( + setPasswordRequest, + ); + expect( + organizationUserApiService.putOrganizationUserResetPasswordEnrollment, + ).not.toHaveBeenCalled(); + }); + }, + ); + }); + + describe("given resetPasswordAutoEnroll is false", () => { + it(`should NOT handle reset password (account recovery) auto enroll`, async () => { + // Arrange + credentials.resetPasswordAutoEnroll = false; + + setupMocks(); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + expect( + organizationUserApiService.putOrganizationUserResetPasswordEnrollment, + ).not.toHaveBeenCalled(); + }); + }); + }); + }); + + describe("given SetInitialPasswordUserType.TDE_ORG_USER_RESET_PASSWORD_PERMISSION_REQUIRES_MP", () => { + beforeEach(() => { + userType = SetInitialPasswordUserType.TDE_ORG_USER_RESET_PASSWORD_PERMISSION_REQUIRES_MP; + setPasswordRequest.keys = null; + }); + + it("should NOT generate a keyPair", async () => { + // Arrange + setupMocks({ ...defaultMockConfig, userType }); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(keyService.userPrivateKey$).not.toHaveBeenCalled(); + expect(keyService.userPublicKey$).not.toHaveBeenCalled(); + expect(encryptService.wrapDecapsulationKey).not.toHaveBeenCalled(); + expect(keyService.makeKeyPair).not.toHaveBeenCalled(); + }); + + describe("given the user has a userKey", () => { + it("should successfully set an initial password", async () => { + // Arrange + setupMocks({ ...defaultMockConfig, userType }); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + }); + }); + + describe("given the user does NOT have a userKey", () => { + it("should successfully set an initial password", async () => { + // Arrange + setupMocks({ ...defaultMockConfig, userType }); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + }); + }); + + describe("given the initial password has been successfully set", () => { + it("should clear the ForceSetPasswordReason by setting it to None", async () => { + // Arrange + setupMocks({ ...defaultMockConfig, userType }); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + expect(masterPasswordService.setForceSetPasswordReason).toHaveBeenCalledWith( + ForceSetPasswordReason.None, + userId, + ); + }); + + it("should update account decryption properties", async () => { + // Arrange + setupMocks({ ...defaultMockConfig, userType }); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + expect(userDecryptionOptionsService.setUserDecryptionOptions).toHaveBeenCalledWith( + userDecryptionOptions, + ); + expect(kdfConfigService.setKdfConfig).toHaveBeenCalledWith(userId, credentials.kdfConfig); + expect(masterPasswordService.setMasterKey).toHaveBeenCalledWith( + credentials.newMasterKey, + userId, + ); + expect(keyService.setUserKey).toHaveBeenCalledWith(masterKeyEncryptedUserKey[0], userId); + }); + + it("should NOT set the private key to state", async () => { + // Arrange + setupMocks({ ...defaultMockConfig, userType }); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + expect(keyService.setPrivateKey).not.toHaveBeenCalled(); + }); + + it("should set the local master key hash to state", async () => { + // Arrange + setupMocks({ ...defaultMockConfig, userType }); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + expect(masterPasswordService.setMasterKeyHash).toHaveBeenCalledWith( + credentials.newLocalMasterKeyHash, + userId, + ); + }); + + describe("given resetPasswordAutoEnroll is true", () => { + it(`should handle reset password (account recovery) auto enroll`, async () => { + // Arrange + credentials.resetPasswordAutoEnroll = true; + + setupMocks({ ...defaultMockConfig, userType, resetPasswordAutoEnroll: true }); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + expect( + organizationUserApiService.putOrganizationUserResetPasswordEnrollment, + ).toHaveBeenCalledWith(credentials.orgId, userId, enrollmentRequest); + }); + }); + + describe("given resetPasswordAutoEnroll is false", () => { + it(`should NOT handle reset password (account recovery) auto enroll`, async () => { + // Arrange + setupMocks({ ...defaultMockConfig, userType }); + + // Act + await sut.setInitialPassword(credentials, userType, userId); + + // Assert + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + expect( + organizationUserApiService.putOrganizationUserResetPasswordEnrollment, + ).not.toHaveBeenCalled(); + }); + }); + }); + }); + }); +}); diff --git a/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.html b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.html new file mode 100644 index 00000000000..c83cbbe3521 --- /dev/null +++ b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.html @@ -0,0 +1,29 @@ +@if (initializing) { +
+ +
+} @else { + + {{ "resetPasswordAutoEnrollInviteWarning" | i18n }} + + + +} diff --git a/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.ts b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.ts new file mode 100644 index 00000000000..fbab9eaa2c3 --- /dev/null +++ b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.ts @@ -0,0 +1,249 @@ +import { CommonModule } from "@angular/common"; +import { Component, OnInit } from "@angular/core"; +import { ActivatedRoute, Router } from "@angular/router"; +import { firstValueFrom } from "rxjs"; + +// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. +// eslint-disable-next-line no-restricted-imports +import { + InputPasswordComponent, + InputPasswordFlow, + PasswordInputResult, +} from "@bitwarden/auth/angular"; +import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; +import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; +import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; +import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; +import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; +import { SyncService } from "@bitwarden/common/platform/sync"; +import { UserId } from "@bitwarden/common/types/guid"; +import { + AnonLayoutWrapperDataService, + CalloutComponent, + DialogService, + ToastService, +} from "@bitwarden/components"; +import { I18nPipe } from "@bitwarden/ui-common"; + +import { + SetInitialPasswordCredentials, + SetInitialPasswordService, + SetInitialPasswordUserType, +} from "./set-initial-password.service.abstraction"; + +@Component({ + standalone: true, + templateUrl: "set-initial-password.component.html", + imports: [CalloutComponent, CommonModule, InputPasswordComponent, I18nPipe], +}) +export class SetInitialPasswordComponent implements OnInit { + protected inputPasswordFlow = InputPasswordFlow.SetInitialPasswordAuthedUser; + + protected email?: string; + protected forceSetPasswordReason?: ForceSetPasswordReason; + protected initializing = true; + protected masterPasswordPolicyOptions: MasterPasswordPolicyOptions | null = null; + protected orgId?: string; + protected orgSsoIdentifier?: string; + protected resetPasswordAutoEnroll?: boolean; + protected submitting = false; + protected userId?: UserId; + protected userType?: SetInitialPasswordUserType; + + constructor( + private accountService: AccountService, + private activatedRoute: ActivatedRoute, + private anonLayoutWrapperDataService: AnonLayoutWrapperDataService, + private dialogService: DialogService, + private i18nService: I18nService, + private masterPasswordService: InternalMasterPasswordServiceAbstraction, + private messagingService: MessagingService, + private organizationApiService: OrganizationApiServiceAbstraction, + private policyApiService: PolicyApiServiceAbstraction, + private router: Router, + private setInitialPasswordService: SetInitialPasswordService, + private ssoLoginService: SsoLoginServiceAbstraction, + private syncService: SyncService, + private toastService: ToastService, + private validationService: ValidationService, + ) {} + + async ngOnInit() { + await this.syncService.fullSync(true); + + const activeAccount = await firstValueFrom(this.accountService.activeAccount$); + this.userId = activeAccount?.id; + this.email = activeAccount?.email; + + await this.determineUserType(); + await this.handleQueryParams(); + + this.initializing = false; + } + + private async determineUserType() { + if (!this.userId) { + throw new Error("userId not found. Could not determine user type."); + } + + this.forceSetPasswordReason = await firstValueFrom( + this.masterPasswordService.forceSetPasswordReason$(this.userId), + ); + + if ( + this.forceSetPasswordReason === + ForceSetPasswordReason.TdeUserWithoutPasswordHasPasswordResetPermission + ) { + this.userType = SetInitialPasswordUserType.TDE_ORG_USER_RESET_PASSWORD_PERMISSION_REQUIRES_MP; + this.anonLayoutWrapperDataService.setAnonLayoutWrapperData({ + pageTitle: { key: "setMasterPassword" }, + pageSubtitle: { key: "orgPermissionsUpdatedMustSetPassword" }, + }); + } else { + this.userType = SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER; + this.anonLayoutWrapperDataService.setAnonLayoutWrapperData({ + pageTitle: { key: "joinOrganization" }, + pageSubtitle: { key: "finishJoiningThisOrganizationBySettingAMasterPassword" }, + }); + } + } + + private async handleQueryParams() { + if (!this.userId) { + throw new Error("userId not found. Could not handle query params."); + } + + const qParams = await firstValueFrom(this.activatedRoute.queryParams); + + this.orgSsoIdentifier = + qParams.identifier ?? + (await this.ssoLoginService.getActiveUserOrganizationSsoIdentifier(this.userId)); + + if (this.orgSsoIdentifier != null) { + try { + const autoEnrollStatus = await this.organizationApiService.getAutoEnrollStatus( + this.orgSsoIdentifier, + ); + this.orgId = autoEnrollStatus.id; + this.resetPasswordAutoEnroll = autoEnrollStatus.resetPasswordEnabled; + this.masterPasswordPolicyOptions = + await this.policyApiService.getMasterPasswordPolicyOptsForOrgUser(this.orgId); + } catch { + this.toastService.showToast({ + variant: "error", + title: "", + message: this.i18nService.t("errorOccurred"), + }); + } + } + } + + protected async handlePasswordFormSubmit(passwordInputResult: PasswordInputResult) { + this.submitting = true; + + if (!passwordInputResult.newMasterKey) { + throw new Error("newMasterKey not found. Could not set initial password."); + } + if (!passwordInputResult.newServerMasterKeyHash) { + throw new Error("newServerMasterKeyHash not found. Could not set initial password."); + } + if (!passwordInputResult.newLocalMasterKeyHash) { + throw new Error("newLocalMasterKeyHash not found. Could not set initial password."); + } + // newPasswordHint can have an empty string as a valid value, so we specifically check for null or undefined + if (passwordInputResult.newPasswordHint == null) { + throw new Error("newPasswordHint not found. Could not set initial password."); + } + if (!passwordInputResult.kdfConfig) { + throw new Error("kdfConfig not found. Could not set initial password."); + } + if (!this.userId) { + throw new Error("userId not found. Could not set initial password."); + } + if (!this.userType) { + throw new Error("userType not found. Could not set initial password."); + } + if (!this.orgSsoIdentifier) { + throw new Error("orgSsoIdentifier not found. Could not set initial password."); + } + if (!this.orgId) { + throw new Error("orgId not found. Could not set initial password."); + } + // resetPasswordAutoEnroll can have `false` as a valid value, so we specifically check for null or undefined + if (this.resetPasswordAutoEnroll == null) { + throw new Error("resetPasswordAutoEnroll not found. Could not set initial password."); + } + + try { + const credentials: SetInitialPasswordCredentials = { + newMasterKey: passwordInputResult.newMasterKey, + newServerMasterKeyHash: passwordInputResult.newServerMasterKeyHash, + newLocalMasterKeyHash: passwordInputResult.newLocalMasterKeyHash, + newPasswordHint: passwordInputResult.newPasswordHint, + kdfConfig: passwordInputResult.kdfConfig, + orgSsoIdentifier: this.orgSsoIdentifier, + orgId: this.orgId, + resetPasswordAutoEnroll: this.resetPasswordAutoEnroll, + }; + + await this.setInitialPasswordService.setInitialPassword( + credentials, + this.userType, + this.userId, + ); + + this.showSuccessToastByUserType(); + + this.submitting = false; + await this.router.navigate(["vault"]); + } catch (e) { + this.validationService.showError(e); + this.submitting = false; + } + } + + private showSuccessToastByUserType() { + if (this.userType === SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER) { + this.toastService.showToast({ + variant: "success", + title: "", + message: this.i18nService.t("accountSuccessfullyCreated"), + }); + + this.toastService.showToast({ + variant: "success", + title: "", + message: this.i18nService.t("inviteAccepted"), + }); + } + + if ( + this.userType === + SetInitialPasswordUserType.TDE_ORG_USER_RESET_PASSWORD_PERMISSION_REQUIRES_MP + ) { + this.toastService.showToast({ + variant: "success", + title: "", + message: this.i18nService.t("masterPasswordSuccessfullySet"), + }); + } + } + + protected async logout() { + const confirmed = await this.dialogService.openSimpleDialog({ + title: { key: "logOut" }, + content: { key: "logOutConfirmation" }, + acceptButtonText: { key: "logOut" }, + type: "warning", + }); + + if (confirmed) { + this.messagingService.send("logout"); + } + } +} diff --git a/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.service.abstraction.ts b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.service.abstraction.ts new file mode 100644 index 00000000000..e594053a906 --- /dev/null +++ b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.service.abstraction.ts @@ -0,0 +1,64 @@ +import { UserId } from "@bitwarden/common/types/guid"; +import { MasterKey } from "@bitwarden/common/types/key"; +import { KdfConfig } from "@bitwarden/key-management"; + +export const _SetInitialPasswordUserType = { + /** + * A user being "just-in-time" (JIT) provisioned into a master-password-encryption org + */ + JIT_PROVISIONED_MP_ORG_USER: "jit_provisioned_mp_org_user", + + /** + * Could be one of two scenarios: + * 1. A user being "just-in-time" (JIT) provisioned into a trusted-device-encryption org + * with the reset password permission granted ("manage account recovery"), which requires + * that the user sets a master password + * 2. An user in a trusted-device-encryption org whose permissions were upgraded to include + * the reset password permission ("manage account recovery"), which requires that the user + * sets a master password + */ + TDE_ORG_USER_RESET_PASSWORD_PERMISSION_REQUIRES_MP: + "tde_org_user_reset_password_permission_requires_mp", +} as const; + +type _SetInitialPasswordUserType = typeof _SetInitialPasswordUserType; + +export type SetInitialPasswordUserType = + _SetInitialPasswordUserType[keyof _SetInitialPasswordUserType]; +export const SetInitialPasswordUserType: Readonly<{ + [K in keyof typeof _SetInitialPasswordUserType]: SetInitialPasswordUserType; +}> = Object.freeze(_SetInitialPasswordUserType); + +export interface SetInitialPasswordCredentials { + newMasterKey: MasterKey; + newServerMasterKeyHash: string; + newLocalMasterKeyHash: string; + newPasswordHint: string; + kdfConfig: KdfConfig; + orgSsoIdentifier: string; + orgId: string; + resetPasswordAutoEnroll: boolean; +} + +/** + * Handles setting an initial password for an existing authed user. + * + * To see the different scenarios where an existing authed user needs to set an + * initial password, see {@link SetInitialPasswordUserType} + */ +export abstract class SetInitialPasswordService { + /** + * Sets an initial password for an existing authed user who is either: + * - {@link SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER} + * - {@link SetInitialPasswordUserType.TDE_ORG_USER_RESET_PASSWORD_PERMISSION_REQUIRES_MP} + * + * @param credentials An object of the credentials needed to set the initial password + * @throws If any property on the `credentials` object is null or undefined, or if a + * masterKeyEncryptedUserKey or newKeyPair could not be created. + */ + abstract setInitialPassword: ( + credentials: SetInitialPasswordCredentials, + userType: SetInitialPasswordUserType, + userId: UserId, + ) => Promise; +} diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 780604f048d..96a95de501e 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -339,6 +339,8 @@ import { VaultExportServiceAbstraction, } from "@bitwarden/vault-export-core"; +import { DefaultSetInitialPasswordService } from "../auth/password-management/set-initial-password/default-set-initial-password.service.implementation"; +import { SetInitialPasswordService } from "../auth/password-management/set-initial-password/set-initial-password.service.abstraction"; import { DeviceTrustToastService as DeviceTrustToastServiceAbstraction } from "../auth/services/device-trust-toast.service.abstraction"; import { DeviceTrustToastService } from "../auth/services/device-trust-toast.service.implementation"; import { FormValidationErrorsService as FormValidationErrorsServiceAbstraction } from "../platform/abstractions/form-validation-errors.service"; @@ -1419,6 +1421,22 @@ const safeProviders: SafeProvider[] = [ InternalUserDecryptionOptionsServiceAbstraction, ], }), + safeProvider({ + provide: SetInitialPasswordService, + useClass: DefaultSetInitialPasswordService, + deps: [ + ApiServiceAbstraction, + EncryptService, + I18nServiceAbstraction, + KdfConfigService, + KeyService, + MasterPasswordApiServiceAbstraction, + InternalMasterPasswordServiceAbstraction, + OrganizationApiServiceAbstraction, + OrganizationUserApiService, + InternalUserDecryptionOptionsServiceAbstraction, + ], + }), safeProvider({ provide: DefaultServerSettingsService, useClass: DefaultServerSettingsService, From 6b627502bea44314910d64ddb1915c23fdbec824 Mon Sep 17 00:00:00 2001 From: Daniel James Smith <2670567+djsmith85@users.noreply.github.com> Date: Tue, 1 Jul 2025 15:52:04 +0200 Subject: [PATCH 031/239] [PM-18668] Create importer for xml files from Password Depot 17 (#14760) * Create importer for xml file from Password Depot 17 - Create importer - Create test data - Create unit tests * Add support for parsing credit cards * Update comment on importer class * Wire up the importer to be selectable in the UI * Import and set favorites based on export file * Refactor: Extract method for parsing login fields * Parse comment on credit cards * Add support for parsing identity records * Add support for parsing rdp records * Remove html decoding of password field * Include setting credit card brand * Create type to describe the different source item types * Add support for SoftwareLicense item type * Add support for teamviewer item type * Add support for Putty item type * Skip processing historical entries * Add support for banking item type * Add support for information item type * Add support for certificate into login type * Rename encrypted-file.xml to noop-encrypted-file due to a source type with the same name * Add support for encrypted file item type * Add support for document type * Add mapping of source field types to bitwarden custom field types * Remove duplicate code (copy-pasta mistake) * Added missing docs * Adding fallback to support MacOS Password Depot 17 xml files Instead of a version node they have a dataformat node which contains the file format version * Add support to parse export files from the MacOS client * Skip creating a folder if it has no name * Fix recognition and assignment to folders/collections --------- Co-authored-by: Daniel James Smith --- .../src/components/import.component.html | 6 + libs/importer/src/importers/index.ts | 1 + .../src/importers/password-depot/index.ts | 1 + ...ssword-depot-17-macos-xml-importer.spec.ts | 62 +++ .../password-depot-17-xml-importer.spec.ts | 496 +++++++++++++++++ .../password-depot-17-xml-importer.ts | 500 ++++++++++++++++++ .../importers/password-depot/types/index.ts | 2 + .../types/password-depot-custom-field-type.ts | 15 + .../types/password-depot-item-type.ts | 19 + .../password-depot-xml/banking.xml.ts | 283 ++++++++++ .../password-depot-xml/certificate.xml.ts | 76 +++ .../password-depot-xml/credit-card.xml.ts | 148 ++++++ .../password-depot-xml/document.xml.ts | 99 ++++ .../password-depot-xml/encrypted-file.xml.ts | 76 +++ .../password-depot-xml/identity.xml.ts | 197 +++++++ .../spec-data/password-depot-xml/index.ts | 19 + .../password-depot-xml/information.xml.ts | 85 +++ .../macos-customfields.xml.ts | 42 ++ .../macos-multiple-folders.xml.ts | 215 ++++++++ .../macos-wrong-version.xml.ts | 21 + .../missing-passwords-node.xml.ts | 25 + .../missing-root-node.xml.ts | 28 + .../noop-encrypted-file.xml.ts | 27 + .../password-depot-xml/password.xml.ts | 222 ++++++++ .../spec-data/password-depot-xml/putty.xml.ts | 106 ++++ .../spec-data/password-depot-xml/rdp.xml.ts | 76 +++ .../software-license.xml.ts | 169 ++++++ .../password-depot-xml/team-viewer.xml.ts | 85 +++ .../password-depot-xml/wrong-version.xml.ts | 28 + libs/importer/src/models/import-options.ts | 1 + libs/importer/src/services/import.service.ts | 3 + 31 files changed, 3133 insertions(+) create mode 100644 libs/importer/src/importers/password-depot/index.ts create mode 100644 libs/importer/src/importers/password-depot/password-depot-17-macos-xml-importer.spec.ts create mode 100644 libs/importer/src/importers/password-depot/password-depot-17-xml-importer.spec.ts create mode 100644 libs/importer/src/importers/password-depot/password-depot-17-xml-importer.ts create mode 100644 libs/importer/src/importers/password-depot/types/index.ts create mode 100644 libs/importer/src/importers/password-depot/types/password-depot-custom-field-type.ts create mode 100644 libs/importer/src/importers/password-depot/types/password-depot-item-type.ts create mode 100644 libs/importer/src/importers/spec-data/password-depot-xml/banking.xml.ts create mode 100644 libs/importer/src/importers/spec-data/password-depot-xml/certificate.xml.ts create mode 100644 libs/importer/src/importers/spec-data/password-depot-xml/credit-card.xml.ts create mode 100644 libs/importer/src/importers/spec-data/password-depot-xml/document.xml.ts create mode 100644 libs/importer/src/importers/spec-data/password-depot-xml/encrypted-file.xml.ts create mode 100644 libs/importer/src/importers/spec-data/password-depot-xml/identity.xml.ts create mode 100644 libs/importer/src/importers/spec-data/password-depot-xml/index.ts create mode 100644 libs/importer/src/importers/spec-data/password-depot-xml/information.xml.ts create mode 100644 libs/importer/src/importers/spec-data/password-depot-xml/macos-customfields.xml.ts create mode 100644 libs/importer/src/importers/spec-data/password-depot-xml/macos-multiple-folders.xml.ts create mode 100644 libs/importer/src/importers/spec-data/password-depot-xml/macos-wrong-version.xml.ts create mode 100644 libs/importer/src/importers/spec-data/password-depot-xml/missing-passwords-node.xml.ts create mode 100644 libs/importer/src/importers/spec-data/password-depot-xml/missing-root-node.xml.ts create mode 100644 libs/importer/src/importers/spec-data/password-depot-xml/noop-encrypted-file.xml.ts create mode 100644 libs/importer/src/importers/spec-data/password-depot-xml/password.xml.ts create mode 100644 libs/importer/src/importers/spec-data/password-depot-xml/putty.xml.ts create mode 100644 libs/importer/src/importers/spec-data/password-depot-xml/rdp.xml.ts create mode 100644 libs/importer/src/importers/spec-data/password-depot-xml/software-license.xml.ts create mode 100644 libs/importer/src/importers/spec-data/password-depot-xml/team-viewer.xml.ts create mode 100644 libs/importer/src/importers/spec-data/password-depot-xml/wrong-version.xml.ts diff --git a/libs/importer/src/components/import.component.html b/libs/importer/src/components/import.component.html index 59ab6739c06..f6d6603dca9 100644 --- a/libs/importer/src/components/import.component.html +++ b/libs/importer/src/components/import.component.html @@ -435,6 +435,12 @@ and select Export items → Enter your Master Password and select Continue. → Save the CSV file on your device. + + On the desktop application, go to Tools → Export → Enter your master password + → Select XML Format (*.xml) as Export format → Click on next → Choose which + entries should be included in the export → Click on next to export into the location + previously chosen. + { + it("should return error with invalid export version", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(MacOS_WrongVersion); + expect(result.errorMessage).toBe( + "Unsupported export version detected - (only 17.0 is supported)", + ); + }); + + it("should not create a folder/collection if the group fingerprint is null", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(MacOS_PasswordDepotXmlFile); + expect(result.folders.length).toBe(0); + }); + + it("should create folders and with correct assignments", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(MacOS_MultipleFolders); + + // Expect 10 ciphers, 5 without a folder and 3 within 'folder macos' and 2 with 'folder 2' + expect(result.ciphers.length).toBe(10); + + expect(result.folders.length).toBe(2); + expect(result.folders[0].name).toBe("folder macos"); + expect(result.folders[1].name).toBe("folder 2"); + + // 3 items within 'folder macos' + expect(result.folderRelationships[0]).toEqual([5, 0]); + expect(result.folderRelationships[1]).toEqual([6, 0]); + expect(result.folderRelationships[2]).toEqual([7, 0]); + + //2 items with 'folder 2' + expect(result.folderRelationships[3]).toEqual([8, 1]); + expect(result.folderRelationships[4]).toEqual([9, 1]); + }); + + it("should parse custom fields from a MacOS exported file", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(MacOS_PasswordDepotXmlFile); + + const cipher = result.ciphers.shift(); + expect(cipher.name).toBe("card 1"); + expect(cipher.notes).toBe("comment"); + + expect(cipher.card).not.toBeNull(); + + expect(cipher.card.cardholderName).toBe("some CC holder"); + expect(cipher.card.number).toBe("4242424242424242"); + expect(cipher.card.brand).toBe("Visa"); + expect(cipher.card.expMonth).toBe("8"); + expect(cipher.card.expYear).toBe("2028"); + expect(cipher.card.code).toBe("125"); + }); +}); diff --git a/libs/importer/src/importers/password-depot/password-depot-17-xml-importer.spec.ts b/libs/importer/src/importers/password-depot/password-depot-17-xml-importer.spec.ts new file mode 100644 index 00000000000..ea84603aef4 --- /dev/null +++ b/libs/importer/src/importers/password-depot/password-depot-17-xml-importer.spec.ts @@ -0,0 +1,496 @@ +// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. +// eslint-disable-next-line no-restricted-imports +import { CollectionView } from "@bitwarden/admin-console/common"; +import { FieldType, SecureNoteType } from "@bitwarden/common/vault/enums"; +import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; +import { CipherType } from "@bitwarden/sdk-internal"; + +import { + EncryptedFileData, + InvalidRootNodeData, + InvalidVersionData, + CreditCardTestData, + MissingPasswordsNodeData, + PasswordTestData, + IdentityTestData, + RDPTestData, + SoftwareLicenseTestData, + TeamViewerTestData, + PuttyTestData, + BankingTestData, + InformationTestData, + CertificateTestData, + EncryptedFileTestData, + DocumentTestData, +} from "../spec-data/password-depot-xml"; + +import { PasswordDepot17XmlImporter } from "./password-depot-17-xml-importer"; + +describe("Password Depot 17 Xml Importer", () => { + it("should return error with missing root tag", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(InvalidRootNodeData); + expect(result.errorMessage).toBe("Missing `passwordfile` node."); + }); + + it("should return error with invalid export version", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(InvalidVersionData); + expect(result.errorMessage).toBe( + "Unsupported export version detected - (only 17.0 is supported)", + ); + }); + + it("should return error if file is marked as encrypted", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(EncryptedFileData); + expect(result.errorMessage).toBe("Encrypted Password Depot files are not supported."); + }); + + it("should return error with missing passwords node tag", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(MissingPasswordsNodeData); + expect(result.success).toBe(false); + expect(result.errorMessage).toBe("Missing `passwordfile > passwords` node."); + }); + + it("should parse groups nodes into folders", async () => { + const importer = new PasswordDepot17XmlImporter(); + const folder = new FolderView(); + folder.name = "tempDB"; + const actual = [folder]; + + const result = await importer.parse(PasswordTestData); + expect(result.folders).toEqual(actual); + }); + + it("should parse password type into logins", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(PasswordTestData); + + const cipher = result.ciphers.shift(); + + expect(cipher.type).toEqual(CipherType.Login); + expect(cipher.name).toBe("password type"); + expect(cipher.notes).toBe("someComment"); + + expect(cipher.login).not.toBeNull(); + expect(cipher.login.username).toBe("someUser"); + expect(cipher.login.password).toBe("p6J<]fmjv!:H&iJ7/Mwt@3i8"); + expect(cipher.login.uri).toBe("http://example.com"); + }); + + it("should parse any unmapped fields as custom fields", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(PasswordTestData); + + const cipher = result.ciphers.shift(); + + expect(cipher.type).toBe(CipherType.Login); + expect(cipher.name).toBe("password type"); + + expect(cipher.fields).not.toBeNull(); + + expect(cipher.fields[0].name).toBe("lastmodified"); + expect(cipher.fields[0].value).toBe("07.05.2025 13:37:56"); + expect(cipher.fields[0].type).toBe(FieldType.Text); + + expect(cipher.fields[1].name).toBe("expirydate"); + expect(cipher.fields[1].value).toBe("07.05.2025"); + expect(cipher.fields[0].type).toBe(FieldType.Text); + + expect(cipher.fields[2].name).toBe("importance"); + expect(cipher.fields[2].value).toBe("0"); + + let customField = cipher.fields.find((f) => f.name === "passwort"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("password"); + expect(customField.type).toEqual(FieldType.Hidden); + + customField = cipher.fields.find((f) => f.name === "memo"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("memo"); + expect(customField.type).toEqual(FieldType.Text); + + customField = cipher.fields.find((f) => f.name === "datum"); + expect(customField).toBeDefined(); + const expectedDate = new Date("2025-05-13T00:00:00Z"); + expect(customField.value).toEqual(expectedDate.toLocaleDateString()); + expect(customField.type).toEqual(FieldType.Text); + + customField = cipher.fields.find((f) => f.name === "nummer"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("1"); + expect(customField.type).toEqual(FieldType.Text); + + customField = cipher.fields.find((f) => f.name === "boolean"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("1"); + expect(customField.type).toEqual(FieldType.Boolean); + + customField = cipher.fields.find((f) => f.name === "decimal"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("1,01"); + expect(customField.type).toEqual(FieldType.Text); + + customField = cipher.fields.find((f) => f.name === "email"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("who@cares.com"); + expect(customField.type).toEqual(FieldType.Text); + + customField = cipher.fields.find((f) => f.name === "url"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("example.com"); + expect(customField.type).toEqual(FieldType.Text); + }); + + it("should parse credit cards", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(CreditCardTestData); + + const cipher = result.ciphers.shift(); + expect(cipher.name).toBe("some CreditCard"); + expect(cipher.notes).toBe("someComment"); + + expect(cipher.card).not.toBeNull(); + + expect(cipher.card.cardholderName).toBe("some CC holder"); + expect(cipher.card.number).toBe("4222422242224222"); + expect(cipher.card.brand).toBe("Visa"); + expect(cipher.card.expMonth).toBe("5"); + expect(cipher.card.expYear).toBe("2026"); + expect(cipher.card.code).toBe("123"); + }); + + it("should parse identity type", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(IdentityTestData); + + const cipher = result.ciphers.shift(); + expect(cipher.name).toBe("identity type"); + expect(cipher.notes).toBe("someNote"); + + expect(cipher.identity).not.toBeNull(); + + expect(cipher.identity.firstName).toBe("firstName"); + expect(cipher.identity.lastName).toBe("surName"); + expect(cipher.identity.email).toBe("email"); + expect(cipher.identity.company).toBe("someCompany"); + expect(cipher.identity.address1).toBe("someStreet"); + expect(cipher.identity.address2).toBe("address 2"); + expect(cipher.identity.city).toBe("town"); + expect(cipher.identity.state).toBe("state"); + expect(cipher.identity.postalCode).toBe("zipCode"); + expect(cipher.identity.country).toBe("country"); + expect(cipher.identity.phone).toBe("phoneNumber"); + }); + + it("should parse RDP type", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(RDPTestData); + + const cipher = result.ciphers.shift(); + expect(cipher.type).toEqual(CipherType.Login); + expect(cipher.name).toBe("rdp type"); + expect(cipher.notes).toBe("someNote"); + + expect(cipher.login).not.toBeNull(); + expect(cipher.login.username).toBe("someUser"); + expect(cipher.login.password).toBe("somePassword"); + expect(cipher.login.uri).toBe("ms-rd:subscribe?url=https://contoso.com"); + }); + + it("should parse software license into secure notes", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(SoftwareLicenseTestData); + + const cipher = result.ciphers.shift(); + + expect(cipher.type).toEqual(CipherType.SecureNote); + expect(cipher.name).toBe("software-license type"); + expect(cipher.notes).toBe("someComment"); + + expect(cipher.secureNote).not.toBeNull(); + expect(cipher.secureNote.type).toBe(SecureNoteType.Generic); + + let customField = cipher.fields.find((f) => f.name === "IDS_LicenseProduct"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("someProduct"); + + customField = cipher.fields.find((f) => f.name === "IDS_LicenseVersion"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("someVersion"); + + customField = cipher.fields.find((f) => f.name === "IDS_LicenseName"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("some User"); + + customField = cipher.fields.find((f) => f.name === "IDS_LicenseKey"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("license-key"); + + customField = cipher.fields.find((f) => f.name === "IDS_LicenseAdditionalKey"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("additional-license-key"); + + customField = cipher.fields.find((f) => f.name === "IDS_LicenseURL"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("example.com"); + + customField = cipher.fields.find((f) => f.name === "IDS_LicenseProtected"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("1"); + + customField = cipher.fields.find((f) => f.name === "IDS_LicenseUserName"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("someUserName"); + + customField = cipher.fields.find((f) => f.name === "IDS_LicensePassword"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("somePassword"); + + customField = cipher.fields.find((f) => f.name === "IDS_LicensePurchaseDate"); + expect(customField).toBeDefined(); + const expectedDate = new Date("2025-05-12T00:00:00Z"); + expect(customField.value).toEqual(expectedDate.toLocaleDateString()); + + customField = cipher.fields.find((f) => f.name === "IDS_LicenseOrderNumber"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("order number"); + + customField = cipher.fields.find((f) => f.name === "IDS_LicenseEmail"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("someEmail"); + + customField = cipher.fields.find((f) => f.name === "IDS_LicenseExpires"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("Nie"); + }); + + it("should parse team viewer into login type", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(TeamViewerTestData); + + const cipher = result.ciphers.shift(); + + expect(cipher.type).toEqual(CipherType.Login); + expect(cipher.name).toBe("TeamViewer type"); + expect(cipher.notes).toBe("someNote"); + + expect(cipher.login).not.toBeNull(); + expect(cipher.login.password).toBe("somePassword"); + expect(cipher.login.username).toBe(""); + expect(cipher.login.uri).toBe("partnerId"); + + const customField = cipher.fields.find((f) => f.name === "IDS_TeamViewerMode"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("0"); + }); + + it("should parse putty into login type", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(PuttyTestData); + + const cipher = result.ciphers.shift(); + + expect(cipher.type).toEqual(CipherType.Login); + expect(cipher.name).toBe("Putty type"); + expect(cipher.notes).toBe("someNote"); + + expect(cipher.login).not.toBeNull(); + expect(cipher.login.password).toBe("somePassword"); + expect(cipher.login.username).toBe("someUser"); + expect(cipher.login.uri).toBe("localhost"); + + let customField = cipher.fields.find((f) => f.name === "IDS_PuTTyProtocol"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("0"); + + customField = cipher.fields.find((f) => f.name === "IDS_PuTTyKeyFile"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("pathToKeyFile"); + + customField = cipher.fields.find((f) => f.name === "IDS_PuTTyKeyPassword"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("passwordForKeyFile"); + + customField = cipher.fields.find((f) => f.name === "IDS_PuTTyPort"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("8080"); + }); + + it("should parse banking item type into login type", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(BankingTestData); + + const cipher = result.ciphers.shift(); + + expect(cipher.type).toEqual(CipherType.Login); + expect(cipher.name).toBe("banking type"); + expect(cipher.notes).toBe("someNote"); + + expect(cipher.login).not.toBeNull(); + expect(cipher.login.password).toBe("somePassword"); + expect(cipher.login.username).toBe("someUser"); + expect(cipher.login.uri).toBe("http://some-bank.com"); + + let customField = cipher.fields.find((f) => f.name === "IDS_ECHolder"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("account holder"); + + customField = cipher.fields.find((f) => f.name === "IDS_ECAccountNumber"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("1234567890"); + + customField = cipher.fields.find((f) => f.name === "IDS_ECBLZ"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("12345678"); + + customField = cipher.fields.find((f) => f.name === "IDS_ECBankName"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("someBank"); + + customField = cipher.fields.find((f) => f.name === "IDS_ECBIC"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("bic"); + + customField = cipher.fields.find((f) => f.name === "IDS_ECIBAN"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("iban"); + + customField = cipher.fields.find((f) => f.name === "IDS_ECCardNumber"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("12345678"); + + customField = cipher.fields.find((f) => f.name === "IDS_ECPhone"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("0049"); + + customField = cipher.fields.find((f) => f.name === "IDS_ECLegitimacyID"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("1234"); + + customField = cipher.fields.find((f) => f.name === "IDS_ECPIN"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("123"); + + customField = cipher.fields.find((f) => f.name === "tan_1_value"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("1234"); + + customField = cipher.fields.find((f) => f.name === "tan_1_used"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("12.05.2025 15:10:54"); + + // TAN entries + customField = cipher.fields.find((f) => f.name === "tan_1_amount"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual(" 100,00"); + + customField = cipher.fields.find((f) => f.name === "tan_1_comment"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("some TAN note"); + + customField = cipher.fields.find((f) => f.name === "tan_1_ccode"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("123"); + + customField = cipher.fields.find((f) => f.name === "tan_2_value"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("4321"); + + customField = cipher.fields.find((f) => f.name === "tan_2_amount"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual(" 0,00"); + }); + + it("should parse information into secure note type", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(InformationTestData); + + const cipher = result.ciphers.shift(); + + expect(cipher.type).toEqual(CipherType.SecureNote); + expect(cipher.name).toBe("information type"); + expect(cipher.notes).toBe("some note content"); + }); + + it("should parse certificate into login type", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(CertificateTestData); + + const cipher = result.ciphers.shift(); + + expect(cipher.type).toEqual(CipherType.Login); + expect(cipher.name).toBe("certificate type"); + expect(cipher.notes).toBe("someNote"); + + expect(cipher.login).not.toBeNull(); + expect(cipher.login.password).toBe("somePassword"); + }); + + it("should parse encrypted file into login type", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(EncryptedFileTestData); + + const cipher = result.ciphers.shift(); + + expect(cipher.type).toEqual(CipherType.Login); + expect(cipher.name).toBe("encrypted file type"); + expect(cipher.notes).toBe("some comment"); + + expect(cipher.login).not.toBeNull(); + expect(cipher.login.password).toBe("somePassword"); + }); + + it("should parse document type into secure note", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(DocumentTestData); + + const cipher = result.ciphers.shift(); + + expect(cipher.type).toEqual(CipherType.SecureNote); + expect(cipher.name).toBe("document type"); + expect(cipher.notes).toBe("document comment"); + + let customField = cipher.fields.find((f) => f.name === "IDS_DocumentSize"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("27071"); + + customField = cipher.fields.find((f) => f.name === "IDS_DocumentFolder"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("C:\\Users\\DJSMI\\Downloads\\"); + + customField = cipher.fields.find((f) => f.name === "IDS_DocumentFile"); + expect(customField).toBeDefined(); + expect(customField.value).toEqual("C:\\Users\\DJSMI\\Downloads\\some.pdf"); + }); + + it("should parse favourites and set them on the target item", async () => { + const importer = new PasswordDepot17XmlImporter(); + const result = await importer.parse(PasswordTestData); + + let cipher = result.ciphers.shift(); + expect(cipher.name).toBe("password type"); + expect(cipher.favorite).toBe(false); + + cipher = result.ciphers.shift(); + expect(cipher.name).toBe("password type (2)"); + expect(cipher.favorite).toBe(true); + + cipher = result.ciphers.shift(); + expect(cipher.name).toBe("password type (3)"); + expect(cipher.favorite).toBe(true); + }); + + it("should parse groups nodes into collections when importing into an organization", async () => { + const importer = new PasswordDepot17XmlImporter(); + importer.organizationId = "someOrgId"; + const collection = new CollectionView(); + collection.name = "tempDB"; + const actual = [collection]; + + const result = await importer.parse(PasswordTestData); + expect(result.collections).toEqual(actual); + }); +}); diff --git a/libs/importer/src/importers/password-depot/password-depot-17-xml-importer.ts b/libs/importer/src/importers/password-depot/password-depot-17-xml-importer.ts new file mode 100644 index 00000000000..ab1f6b4689f --- /dev/null +++ b/libs/importer/src/importers/password-depot/password-depot-17-xml-importer.ts @@ -0,0 +1,500 @@ +// FIXME: Update this file to be type safe and remove this and next line +// @ts-strict-ignore +import { CipherType, FieldType, SecureNoteType } from "@bitwarden/common/vault/enums"; +import { CardView } from "@bitwarden/common/vault/models/view/card.view"; +import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { FieldView } from "@bitwarden/common/vault/models/view/field.view"; +import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; +import { IdentityView } from "@bitwarden/common/vault/models/view/identity.view"; +import { LoginView } from "@bitwarden/common/vault/models/view/login.view"; +import { SecureNoteView } from "@bitwarden/common/vault/models/view/secure-note.view"; + +import { ImportResult } from "../../models/import-result"; +import { BaseImporter } from "../base-importer"; +import { Importer } from "../importer"; + +import { PasswordDepotItemType, PasswordDepotCustomFieldType } from "./types"; + +/** + * Importer for Password Depot 17 xml files. + * @see https://www.password-depot.de/ + * It provides methods to parse the XML data, extract relevant information, and create cipher objects + */ +export class PasswordDepot17XmlImporter extends BaseImporter implements Importer { + result = new ImportResult(); + + _favouritesLookupTable = new Set(); + + // Parse the XML data from the Password Depot export file and extracts the relevant information + parse(data: string): Promise { + const doc: XMLDocument = this.parseXml(data); + if (doc == null) { + this.result.success = false; + return Promise.resolve(this.result); + } + + // Check if the root node is present + const rootNode = doc.querySelector("passwordfile"); + if (rootNode == null) { + this.result.errorMessage = "Missing `passwordfile` node."; + this.result.success = false; + return Promise.resolve(this.result); + } + + // Check if the version is supported + const headerNode = this.querySelectorDirectChild(rootNode, "header"); + if (headerNode == null) { + this.result.success = false; + return Promise.resolve(this.result); + } + + let versionNode = this.querySelectorDirectChild(headerNode, "version"); + if (versionNode == null) { + // Adding a fallback for MacOS Password Depot 17.0 export files + // These files do not have a version node, but a dataformat node instead + versionNode = this.querySelectorDirectChild(headerNode, "dataformat"); + if (versionNode == null) { + this.result.success = false; + return Promise.resolve(this.result); + } + } + + const version = versionNode.textContent; + if (!version.startsWith("17")) { + this.result.errorMessage = "Unsupported export version detected - (only 17.0 is supported)"; + this.result.success = false; + return Promise.resolve(this.result); + } + + // Abort import if the file is encrypted + const encryptedNode = this.querySelectorDirectChild(headerNode, "encrypted"); + if (encryptedNode != null && encryptedNode.textContent == "True") { + this.result.errorMessage = "Encrypted Password Depot files are not supported."; + this.result.success = false; + return Promise.resolve(this.result); + } + + // Check if the passwords node is present + // This node contains all the password entries + const passwordsNode = rootNode.querySelector("passwords"); + if (passwordsNode == null) { + this.result.errorMessage = "Missing `passwordfile > passwords` node."; + this.result.success = false; + return Promise.resolve(this.result); + } + + this.buildFavouritesLookupTable(rootNode); + + this.querySelectorAllDirectChild(passwordsNode, "group").forEach((group) => { + this.traverse(group, ""); + }); + + if (this.organization) { + this.moveFoldersToCollections(this.result); + } + + this.result.success = true; + return Promise.resolve(this.result); + } + + // Traverses the XML tree and processes each node + // It starts from the root node and goes through each group and item + // This method is recursive and handles nested groups + private traverse(node: Element, groupPrefixName: string) { + const folderIndex = this.result.folders.length; + let groupName = groupPrefixName; + + if (groupName !== "") { + groupName += "/"; + } + + // Check if the group has a fingerprint attribute (GUID of a folder) + const groupFingerprint = node.attributes.getNamedItem("fingerprint"); + if (groupFingerprint?.textContent != "" && groupFingerprint.textContent != "null") { + const nameEl = node.attributes.getNamedItem("name"); + groupName += nameEl == null ? "-" : nameEl.textContent; + const folder = new FolderView(); + folder.name = groupName; + this.result.folders.push(folder); + } + + this.querySelectorAllDirectChild(node, "item").forEach((entry) => { + const cipherIndex = this.result.ciphers.length; + + const cipher = this.initLoginCipher(); + //Set default item type similar how we default to Login in other importers + let sourceType: PasswordDepotItemType = PasswordDepotItemType.Password; + + const entryFields = entry.children; + for (let i = 0; i < entryFields.length; i++) { + const entryField = entryFields[i]; + + // Skip processing historical entries + if (entryField.tagName === "hitems") { + continue; + } + + if (entryField.tagName === "description") { + cipher.name = entryField.textContent; + continue; + } + + if (entryField.tagName === "comment") { + cipher.notes = entryField.textContent; + continue; + } + + if (entryField.tagName === "type") { + sourceType = entryField.textContent as PasswordDepotItemType; + switch (sourceType) { + case PasswordDepotItemType.Password: + case PasswordDepotItemType.RDP: + case PasswordDepotItemType.Putty: + case PasswordDepotItemType.TeamViewer: + case PasswordDepotItemType.Banking: + case PasswordDepotItemType.Certificate: + case PasswordDepotItemType.EncryptedFile: + cipher.type = CipherType.Login; + cipher.login = new LoginView(); + break; + case PasswordDepotItemType.CreditCard: + cipher.type = CipherType.Card; + cipher.card = new CardView(); + break; + case PasswordDepotItemType.SoftwareLicense: + case PasswordDepotItemType.Information: + case PasswordDepotItemType.Document: + cipher.type = CipherType.SecureNote; + cipher.secureNote = new SecureNoteView(); + cipher.secureNote.type = SecureNoteType.Generic; + break; + case PasswordDepotItemType.Identity: + cipher.type = CipherType.Identity; + cipher.identity = new IdentityView(); + break; + } + continue; + } + + if ( + sourceType === PasswordDepotItemType.Password || + sourceType === PasswordDepotItemType.RDP || + sourceType === PasswordDepotItemType.Putty || + sourceType === PasswordDepotItemType.TeamViewer || + sourceType === PasswordDepotItemType.Banking || + sourceType === PasswordDepotItemType.Certificate || + sourceType === PasswordDepotItemType.EncryptedFile + ) { + if (this.parseLoginFields(entryField, cipher)) { + continue; + } + } + + // fingerprint is the GUID of the entry + // Base on the previously parsed favourites, we can identify an entry and set the favorite flag accordingly + if (entryField.tagName === "fingerprint") { + if (this._favouritesLookupTable.has(entryField.textContent)) { + cipher.favorite = true; + } + } + + if (entryField.tagName === "customfields") { + this.parseCustomFields(entryField, sourceType, cipher); + continue; + } + + if (sourceType === PasswordDepotItemType.Banking && entryField.tagName === "tans") { + this.querySelectorAllDirectChild(entryField, "tan").forEach((tanEntry) => { + this.parseBankingTANs(tanEntry, cipher); + }); + continue; + } + + this.processKvp(cipher, entryField.tagName, entryField.textContent, FieldType.Text); + } + + this.cleanupCipher(cipher); + this.result.ciphers.push(cipher); + + if (groupName !== "") { + this.result.folderRelationships.push([cipherIndex, folderIndex]); + } + }); + + this.querySelectorAllDirectChild(node, "group").forEach((group) => { + this.traverse(group, groupName); + }); + } + + // Parses custom fields and adds them to the cipher + // It iterates through all the custom fields and adds them to the cipher + private parseCustomFields( + entryField: Element, + sourceType: PasswordDepotItemType, + cipher: CipherView, + ) { + this.querySelectorAllDirectChild(entryField, "field").forEach((customField) => { + const customFieldObject = this.parseCustomField(customField); + if (customFieldObject == null) { + return; + } + + switch (sourceType) { + case PasswordDepotItemType.CreditCard: + if (this.parseCreditCardCustomFields(customFieldObject, cipher)) { + return; + } + break; + case PasswordDepotItemType.Identity: + if (this.parseIdentityCustomFields(customFieldObject, cipher)) { + return; + } + break; + case PasswordDepotItemType.Information: + if (this.parseInformationCustomFields(customFieldObject, cipher)) { + return; + } + break; + default: + // For other types, we will process the custom field as a regular key-value pair + break; + } + + this.processKvp( + cipher, + customFieldObject.name, + customFieldObject.value, + customFieldObject.type, + ); + }); + } + + // Parses login fields and adds them to the cipher + private parseLoginFields(entryField: Element, cipher: CipherView): boolean { + if (entryField.tagName === "username") { + cipher.login.username = entryField.textContent; + return true; + } + + if (entryField.tagName === "password") { + cipher.login.password = entryField.textContent; + return true; + } + + if (entryField.tagName === "url") { + cipher.login.uris = this.makeUriArray(entryField.textContent); + return true; + } + + return false; + } + + // Parses a custom field and adds it to the cipher + private parseCustomField(customField: Element): FieldView | null { + let key: string = undefined; + let value: string = undefined; + let sourceFieldType: PasswordDepotCustomFieldType = PasswordDepotCustomFieldType.Memo; + let visible: string = undefined; + // A custom field is represented by a element + // On exports from the Windows clients: It contains a , , and optionally a and element + // On exports from the MacOs clients the key-values are defined as xml attributes instead of child nodes + if (customField.hasAttributes()) { + key = customField.getAttribute("name"); + if (key == null) { + return null; + } + + value = customField.getAttribute("value"); + + const typeAttr = customField.getAttribute("type"); + sourceFieldType = + typeAttr != null + ? (typeAttr as PasswordDepotCustomFieldType) + : PasswordDepotCustomFieldType.Memo; + + visible = customField.getAttribute("visible"); + } else { + const keyEl = this.querySelectorDirectChild(customField, "name"); + key = keyEl != null ? keyEl.textContent : null; + + if (key == null) { + return null; + } + + const valueEl = this.querySelectorDirectChild(customField, "value"); + value = valueEl != null ? valueEl.textContent : null; + + const typeEl = this.querySelectorDirectChild(customField, "type"); + sourceFieldType = + typeEl != null + ? (typeEl.textContent as PasswordDepotCustomFieldType) + : PasswordDepotCustomFieldType.Memo; + + const visibleEl = this.querySelectorDirectChild(customField, "visible"); + visible = visibleEl != null ? visibleEl.textContent : null; + } + + if (sourceFieldType === PasswordDepotCustomFieldType.Date) { + if (!isNaN(value as unknown as number)) { + // Convert excel date format to JavaScript date + const numericValue = parseInt(value); + const secondsInDay = 86400; + const missingLeapYearDays = secondsInDay * 1000; + value = new Date((numericValue - (25567 + 2)) * missingLeapYearDays).toLocaleDateString(); + } + } + + if (sourceFieldType === PasswordDepotCustomFieldType.Password) { + return { name: key, value: value, type: FieldType.Hidden, linkedId: null } as FieldView; + } + + if (sourceFieldType === PasswordDepotCustomFieldType.Boolean) { + return { name: key, value: value, type: FieldType.Boolean, linkedId: null } as FieldView; + } + + if (visible == "0") { + return { name: key, value: value, type: FieldType.Hidden, linkedId: null } as FieldView; + } + + return { name: key, value: value, type: FieldType.Text, linkedId: null } as FieldView; + } + + // Parses credit card fields and adds them to the cipher + private parseCreditCardCustomFields(customField: FieldView, cipher: CipherView): boolean { + if (customField.name === "IDS_CardHolder") { + cipher.card.cardholderName = customField.value; + return true; + } + + if (customField.name === "IDS_CardNumber") { + cipher.card.number = customField.value; + cipher.card.brand = CardView.getCardBrandByPatterns(cipher.card.number); + return true; + } + + if (customField.name === "IDS_CardExpires") { + this.setCardExpiration(cipher, customField.value); + return true; + } + + if (customField.name === "IDS_CardCode") { + cipher.card.code = customField.value; + return true; + } + + return false; + } + + // Parses identity fields and adds them to the cipher + private parseIdentityCustomFields(customField: FieldView, cipher: CipherView): boolean { + if (customField.name === "IDS_IdentityName") { + this.processFullName(cipher, customField.value); + return true; + } + + if (customField.name === "IDS_IdentityEmail") { + cipher.identity.email = customField.value; + return true; + } + + if (customField.name === "IDS_IdentityFirstName") { + cipher.identity.firstName = customField.value; + return true; + } + + if (customField.name === "IDS_IdentityLastName") { + cipher.identity.lastName = customField.value; + return true; + } + + if (customField.name === "IDS_IdentityCompany") { + cipher.identity.company = customField.value; + return true; + } + + if (customField.name === "IDS_IdentityAddress1") { + cipher.identity.address1 = customField.value; + return true; + } + + if (customField.name === "IDS_IdentityAddress2") { + cipher.identity.address2 = customField.value; + return true; + } + + if (customField.name === "IDS_IdentityCity") { + cipher.identity.city = customField.value; + return true; + } + + if (customField.name === "IDS_IdentityState") { + cipher.identity.state = customField.value; + return true; + } + + if (customField.name === "IDS_IdentityZIP") { + cipher.identity.postalCode = customField.value; + return true; + } + + if (customField.name === "IDS_IdentityCountry") { + cipher.identity.country = customField.value; + return true; + } + + if (customField.name === "IDS_IdentityPhone") { + cipher.identity.phone = customField.value; + return true; + } + + return false; + } + + // Parses information custom fields and adds them to the cipher + private parseInformationCustomFields(customField: FieldView, cipher: CipherView): boolean { + if (customField.name === "IDS_InformationText") { + cipher.notes = customField.value; + return true; + } + + return false; + } + + // Parses TAN objects and adds them to the cipher + // It iterates through all the TAN fields and adds them to the cipher + private parseBankingTANs(TANsField: Element, cipher: CipherView) { + let tanNumber = "0"; + const entryFields = TANsField.children; + for (let i = 0; i < entryFields.length; i++) { + const entryField = entryFields[i]; + + if (entryField.tagName === "number") { + tanNumber = entryField.textContent; + continue; + } + + this.processKvp(cipher, `tan_${tanNumber}_${entryField.tagName}`, entryField.textContent); + } + } + + // Parses the favourites-node from the XML file, which contains a base64 encoded string + // The string contains the fingerprints/GUIDs of the favourited entries, separated by new lines + private buildFavouritesLookupTable(rootNode: Element): void { + const favouritesNode = this.querySelectorDirectChild(rootNode, "favorites"); + if (favouritesNode == null) { + return; + } + + const decodedBase64String = atob(favouritesNode.textContent); + if (decodedBase64String.indexOf("\r\n") > 0) { + decodedBase64String.split("\r\n").forEach((line) => { + this._favouritesLookupTable.add(line); + }); + return; + } + + decodedBase64String.split("\n").forEach((line) => { + this._favouritesLookupTable.add(line); + }); + } +} diff --git a/libs/importer/src/importers/password-depot/types/index.ts b/libs/importer/src/importers/password-depot/types/index.ts new file mode 100644 index 00000000000..709e5992ae8 --- /dev/null +++ b/libs/importer/src/importers/password-depot/types/index.ts @@ -0,0 +1,2 @@ +export * from "./password-depot-item-type"; +export * from "./password-depot-custom-field-type"; diff --git a/libs/importer/src/importers/password-depot/types/password-depot-custom-field-type.ts b/libs/importer/src/importers/password-depot/types/password-depot-custom-field-type.ts new file mode 100644 index 00000000000..166378b38b4 --- /dev/null +++ b/libs/importer/src/importers/password-depot/types/password-depot-custom-field-type.ts @@ -0,0 +1,15 @@ +/** This object represents the different custom field types in Password Depot */ +export const PasswordDepotCustomFieldType = Object.freeze({ + Password: "1", + Memo: "2", + Date: "3", + Number: "4", + Boolean: "5", + Decimal: "6", + Email: "7", + URL: "8", +} as const); + +/** This type represents the different custom field types in Password Depot */ +export type PasswordDepotCustomFieldType = + (typeof PasswordDepotCustomFieldType)[keyof typeof PasswordDepotCustomFieldType]; diff --git a/libs/importer/src/importers/password-depot/types/password-depot-item-type.ts b/libs/importer/src/importers/password-depot/types/password-depot-item-type.ts new file mode 100644 index 00000000000..04ec3a48c85 --- /dev/null +++ b/libs/importer/src/importers/password-depot/types/password-depot-item-type.ts @@ -0,0 +1,19 @@ +/** This object represents the different item types in Password Depot */ +export const PasswordDepotItemType = Object.freeze({ + Password: "0", + CreditCard: "1", + SoftwareLicense: "2", + Identity: "3", + Information: "4", + Banking: "5", + EncryptedFile: "6", + Document: "7", + RDP: "8", + Putty: "9", + TeamViewer: "10", + Certificate: "11", +} as const); + +/** This type represents the different item types in Password Depot */ +export type PasswordDepotItemType = + (typeof PasswordDepotItemType)[keyof typeof PasswordDepotItemType]; diff --git a/libs/importer/src/importers/spec-data/password-depot-xml/banking.xml.ts b/libs/importer/src/importers/spec-data/password-depot-xml/banking.xml.ts new file mode 100644 index 00000000000..3a2da1c27bf --- /dev/null +++ b/libs/importer/src/importers/spec-data/password-depot-xml/banking.xml.ts @@ -0,0 +1,283 @@ +export const BankingTestData = ` + +
+ Password Depot + 17.0.0 + + + CCDA8015-7F21-4344-BDF0-9EA6AF8AE31D + 12.05.2025 15:16:11 + False + 0 + 30.12.1899 00:00:00 + +
+ + + + banking type + 5 + somePassword + someUser + some-bank.com + someNote + 12.05.2025 15:11:29 + 02.05.2027 + 1 + DEB91652-52C6-402E-9D44-3557829BC6DF + + 127 + 0 + + + Allgemein + + 0 + + + 12.05.2025 15:09:17 + 12.05.2025 15:09:17 + 0 + 0 + 0 + 1 + + 0 + 2 + + DJSMI + + + 0 + + 0 + + 0 + + 161 + 0 + + + + IDS_ECHolder + account holder + -1 + 0 + 0 + + + IDS_ECAccountNumber + 1234567890 + -1 + 0 + 0 + + + IDS_ECBLZ + 12345678 + -1 + 0 + 0 + + + IDS_ECBankName + someBank + -1 + 0 + 0 + + + IDS_ECBIC + bic + -1 + 0 + 0 + + + IDS_ECIBAN + iban + -1 + 0 + 0 + + + IDS_ECCardNumber + 12345678 + -1 + 0 + 10 + + + IDS_ECPhone + 0049 + 0 + 0 + 0 + + + IDS_ECLegitimacyID + 1234 + -1 + 0 + 0 + + + IDS_ECPIN + 123 + 0 + 0 + 1 + + + + + 1 + 1234 + 12.05.2025 15:10:54 + 100,00 + some TAN note + 123 + + + 2 + 4321 + 0,00 + + + + + + + banking type + 5 + somePassword + someUser + some-bank.com + someNote + 12.05.2025 15:10:35 + 02.05.2027 + 1 + DEB91652-52C6-402E-9D44-3557829BC6DF + + 127 + 0 + + + Allgemein + + 0 + + + 12.05.2025 15:09:17 + 12.05.2025 15:09:17 + 0 + 0 + 0 + 1 + + 0 + 2 + + DJSMI + + + 0 + + 0 + + 0 + + 161 + 0 + + + + IDS_ECHolder + account holder + -1 + 0 + 0 + + + IDS_ECAccountNumber + 1234567890 + -1 + 0 + 0 + + + IDS_ECBLZ + 12345678 + -1 + 0 + 0 + + + IDS_ECBankName + someBank + -1 + 0 + 0 + + + IDS_ECBIC + bic + -1 + 0 + 0 + + + IDS_ECIBAN + iban + -1 + 0 + 0 + + + IDS_ECCardNumber + 12345678 + -1 + 0 + 10 + + + IDS_ECPhone + 0049 + 0 + 0 + 0 + + + IDS_ECLegitimacyID + 1234 + -1 + 0 + 0 + + + IDS_ECPIN + 123 + 0 + 0 + 1 + + + + + + + + + + + + + QUY3NEZGODYtRkUzOS00NTg0LThFOTYtRkU5NTBDMjg5REY4DQo= + + + + + + QWxsZ2VtZWluDQpIb21lIEJhbmtpbmcNCkludGVybmV0DQpQcml2YXQNCldpbmRvd3MNCg== + +
`; diff --git a/libs/importer/src/importers/spec-data/password-depot-xml/certificate.xml.ts b/libs/importer/src/importers/spec-data/password-depot-xml/certificate.xml.ts new file mode 100644 index 00000000000..eb8c463d57f --- /dev/null +++ b/libs/importer/src/importers/spec-data/password-depot-xml/certificate.xml.ts @@ -0,0 +1,76 @@ +export const CertificateTestData = ` + +
+ Password Depot + 17.0.0 + + + CCDA8015-7F21-4344-BDF0-9EA6AF8AE31D + 12.05.2025 15:16:11 + False + 0 + 30.12.1899 00:00:00 + +
+ + + + certificate type + 11 + somePassword + + + someNote + 12.05.2025 15:15:57 + 00.00.0000 + 1 + 21288702-B042-46D9-9DDF-B44A5CD04A72 + + 130 + 0 + + + Allgemein + + 0 + + + 12.05.2025 15:15:26 + 12.05.2025 15:15:26 + 0 + 0 + 0 + 1 + + 0 + 2 + someTag + DJSMI + + + 0 + + 0 + + 0 + + 161 + 0 + + + + + + + + + + QUY3NEZGODYtRkUzOS00NTg0LThFOTYtRkU5NTBDMjg5REY4DQo= + + + + + + QWxsZ2VtZWluDQpIb21lIEJhbmtpbmcNCkludGVybmV0DQpQcml2YXQNCldpbmRvd3MNCg== + +
`; diff --git a/libs/importer/src/importers/spec-data/password-depot-xml/credit-card.xml.ts b/libs/importer/src/importers/spec-data/password-depot-xml/credit-card.xml.ts new file mode 100644 index 00000000000..f0af49bbfae --- /dev/null +++ b/libs/importer/src/importers/spec-data/password-depot-xml/credit-card.xml.ts @@ -0,0 +1,148 @@ +export const CreditCardTestData = ` + +
+ Password Depot + 17.0.0 + + + CCDA8015-7F21-4344-BDF0-9EA6AF8AE31D + 12.05.2025 15:16:11 + False + 0 + 30.12.1899 00:00:00 + +
+ + + + some CreditCard + 1 + 4222422242224222 + some CC holder + + someComment + 08.05.2025 12:09:47 + 08.05.2026 + 1 + DD9B52F8-B2CE-42C2-A891-5E20DA23EA20 + + 126 + 0 + + + + + 0 + + + 08.05.2025 12:08:48 + 08.05.2025 12:08:48 + 0 + 0 + 0 + 1 + + 0 + 2 + + DJSMI + + + 0 + + 0 + + 0 + + 161 + 0 + + + + IDS_CardType + 0 + 0 + 0 + 4 + + + IDS_CardHolder + some CC holder + -1 + 0 + 0 + + + IDS_CardNumber + 4222422242224222 + -1 + 0 + 10 + + + IDS_CardExpires + 05/2026 + -1 + 0 + 3 + + + IDS_CardCode + 123 + -1 + 0 + 0 + + + IDS_CardPhone + + -1 + 0 + 0 + + + IDS_CardURL + + -1 + 0 + 8 + + + IDS_CardAdditionalCode + + -1 + 0 + 0 + + + IDS_CardAdditionalInfo + + -1 + 0 + 0 + + + IDS_CardPIN + 123 + -1 + 0 + 1 + + + + + + + + + + + QUY3NEZGODYtRkUzOS00NTg0LThFOTYtRkU5NTBDMjg5REY4DQo= + + + + + + QWxsZ2VtZWluDQpIb21lIEJhbmtpbmcNCkludGVybmV0DQpQcml2YXQNCldpbmRvd3MNCg== + +
`; diff --git a/libs/importer/src/importers/spec-data/password-depot-xml/document.xml.ts b/libs/importer/src/importers/spec-data/password-depot-xml/document.xml.ts new file mode 100644 index 00000000000..4f607c9b048 --- /dev/null +++ b/libs/importer/src/importers/spec-data/password-depot-xml/document.xml.ts @@ -0,0 +1,99 @@ +export const DocumentTestData = ` + +
+ Password Depot + 17.0.0 + + + CCDA8015-7F21-4344-BDF0-9EA6AF8AE31D + 12.05.2025 15:16:11 + False + 0 + 30.12.1899 00:00:00 + +
+ + + + document type + 7 + + + + document comment + 03.06.2025 17:45:30 + 00.00.0000 + 1 + 1B8E7F2C-9229-43C6-AB89-42101809C822 + + 133 + 0 + + + Allgemein + + 0 + + + 05.06.2025 21:49:49 + 30.12.1899 00:00:00 + 0 + 0 + 0 + 1 + + 0 + 2 + + DJSMI + + + 0 + + 0 + + 0 + + 161 + 0 + + + + IDS_DocumentSize + 27071 + 0 + 0 + 4 + + + IDS_DocumentFolder + C:\\Users\\DJSMI\\Downloads\\ + 0 + 0 + 0 + + + IDS_DocumentFile + C:\\Users\\DJSMI\\Downloads\\some.pdf + 0 + 0 + 0 + + + + + + + + + + + QUY3NEZGODYtRkUzOS00NTg0LThFOTYtRkU5NTBDMjg5REY4DQo= + + + + + + QWxsZ2VtZWluDQpIb21lIEJhbmtpbmcNCkludGVybmV0DQpQcml2YXQNCldpbmRvd3MNCg== + +
`; diff --git a/libs/importer/src/importers/spec-data/password-depot-xml/encrypted-file.xml.ts b/libs/importer/src/importers/spec-data/password-depot-xml/encrypted-file.xml.ts new file mode 100644 index 00000000000..2d2e929440a --- /dev/null +++ b/libs/importer/src/importers/spec-data/password-depot-xml/encrypted-file.xml.ts @@ -0,0 +1,76 @@ +export const EncryptedFileTestData = ` + +
+ Password Depot + 17.0.0 + + + CCDA8015-7F21-4344-BDF0-9EA6AF8AE31D + 12.05.2025 15:16:11 + False + 0 + 30.12.1899 00:00:00 + +
+ + + + encrypted file type + 6 + somePassword + + + some comment + 12.05.2025 15:15:17 + 00.00.0000 + 1 + E4CA245D-A326-4359-9488-CC207B33C6C0 + + 132 + 0 + + + Allgemein + + 0 + + + 12.05.2025 15:14:58 + 12.05.2025 15:14:58 + 0 + 0 + 0 + 1 + + 0 + 2 + + DJSMI + + + 0 + + 0 + + 0 + + 161 + 0 + + + + + + + + + + QUY3NEZGODYtRkUzOS00NTg0LThFOTYtRkU5NTBDMjg5REY4DQo= + + + + + + QWxsZ2VtZWluDQpIb21lIEJhbmtpbmcNCkludGVybmV0DQpQcml2YXQNCldpbmRvd3MNCg== + +
`; diff --git a/libs/importer/src/importers/spec-data/password-depot-xml/identity.xml.ts b/libs/importer/src/importers/spec-data/password-depot-xml/identity.xml.ts new file mode 100644 index 00000000000..dfa275aa778 --- /dev/null +++ b/libs/importer/src/importers/spec-data/password-depot-xml/identity.xml.ts @@ -0,0 +1,197 @@ +export const IdentityTestData = ` + +
+ Password Depot + 17.0.0 + + + CCDA8015-7F21-4344-BDF0-9EA6AF8AE31D + 12.05.2025 15:16:11 + False + 0 + 30.12.1899 00:00:00 + +
+ + + + identity type + 3 + + account-name/id + website + someNote + 12.05.2025 15:14:33 + 00.00.0000 + 1 + 0E6085E9-7560-4826-814E-EFE1724E1377 + + 129 + 0 + + + Allgemein + + 0 + + + 12.05.2025 15:12:52 + 12.05.2025 15:12:52 + 0 + 0 + 0 + 1 + + 0 + 2 + + DJSMI + + + 0 + + 0 + + 0 + + 161 + 0 + + + + IDS_IdentityName + account-name/id + -1 + 0 + 0 + + + IDS_IdentityEmail + email + -1 + 0 + 0 + + + IDS_IdentityFirstName + firstName + -1 + 0 + 0 + + + IDS_IdentityLastName + surName + -1 + 0 + 0 + + + IDS_IdentityCompany + someCompany + -1 + 0 + 0 + + + IDS_IdentityAddress1 + someStreet + -1 + 0 + 0 + + + IDS_IdentityAddress2 + address 2 + -1 + 0 + 0 + + + IDS_IdentityCity + town + -1 + 0 + 0 + + + IDS_IdentityState + state + -1 + 0 + 0 + + + IDS_IdentityZIP + zipCode + -1 + 0 + 0 + + + IDS_IdentityCountry + country + -1 + 0 + 0 + + + IDS_IdentityPhone + phoneNumber + -1 + 0 + 0 + + + IDS_IdentityWebsite + website + -1 + 0 + 8 + + + IDS_IdentityBirthDate + 45789 + -1 + 0 + 3 + + + IDS_IdentityMobile + mobileNumber + -1 + 0 + 0 + + + IDS_IdentityFax + faxNumber + -1 + 0 + 0 + + + IDS_IdentityHouseNumber + 123 + -1 + 0 + 0 + + + + + + + + + + + QUY3NEZGODYtRkUzOS00NTg0LThFOTYtRkU5NTBDMjg5REY4DQo= + + + + + + QWxsZ2VtZWluDQpIb21lIEJhbmtpbmcNCkludGVybmV0DQpQcml2YXQNCldpbmRvd3MNCg== + +
`; diff --git a/libs/importer/src/importers/spec-data/password-depot-xml/index.ts b/libs/importer/src/importers/spec-data/password-depot-xml/index.ts new file mode 100644 index 00000000000..6d5903ed471 --- /dev/null +++ b/libs/importer/src/importers/spec-data/password-depot-xml/index.ts @@ -0,0 +1,19 @@ +export { InvalidRootNodeData } from "./missing-root-node.xml"; +export { MissingPasswordsNodeData } from "./missing-passwords-node.xml"; +export { InvalidVersionData } from "./wrong-version.xml"; +export { EncryptedFileData } from "./noop-encrypted-file.xml"; +export { PasswordTestData } from "./password.xml"; +export { CreditCardTestData } from "./credit-card.xml"; +export { IdentityTestData } from "./identity.xml"; +export { RDPTestData } from "./rdp.xml"; +export { SoftwareLicenseTestData } from "./software-license.xml"; +export { TeamViewerTestData } from "./team-viewer.xml"; +export { PuttyTestData } from "./putty.xml"; +export { BankingTestData } from "./banking.xml"; +export { InformationTestData } from "./information.xml"; +export { CertificateTestData } from "./certificate.xml"; +export { EncryptedFileTestData } from "./encrypted-file.xml"; +export { DocumentTestData } from "./document.xml"; +export { MacOS_WrongVersion } from "./macos-wrong-version.xml"; +export { MacOS_PasswordDepotXmlFile } from "./macos-customfields.xml"; +export { MacOS_MultipleFolders } from "./macos-multiple-folders.xml"; diff --git a/libs/importer/src/importers/spec-data/password-depot-xml/information.xml.ts b/libs/importer/src/importers/spec-data/password-depot-xml/information.xml.ts new file mode 100644 index 00000000000..1f07882ea64 --- /dev/null +++ b/libs/importer/src/importers/spec-data/password-depot-xml/information.xml.ts @@ -0,0 +1,85 @@ +export const InformationTestData = ` + +
+ Password Depot + 17.0.0 + + + CCDA8015-7F21-4344-BDF0-9EA6AF8AE31D + 12.05.2025 15:16:11 + False + 0 + 30.12.1899 00:00:00 + +
+ + + + information type + 4 + + + + + 12.05.2025 15:14:54 + 00.00.0000 + 1 + 546AFAE7-6F64-4040-838B-AFE691580356 + + 131 + 0 + + + Allgemein + + 0 + + + 12.05.2025 15:14:39 + 12.05.2025 15:14:39 + 0 + 0 + 0 + 1 + + 0 + 2 + + DJSMI + + + 0 + + 0 + + 0 + + 161 + 0 + + + + IDS_InformationText + some note content + 0 + 0 + 2 + + + + + + + + + + + QUY3NEZGODYtRkUzOS00NTg0LThFOTYtRkU5NTBDMjg5REY4DQo= + + + + + + QWxsZ2VtZWluDQpIb21lIEJhbmtpbmcNCkludGVybmV0DQpQcml2YXQNCldpbmRvd3MNCg== + +
`; diff --git a/libs/importer/src/importers/spec-data/password-depot-xml/macos-customfields.xml.ts b/libs/importer/src/importers/spec-data/password-depot-xml/macos-customfields.xml.ts new file mode 100644 index 00000000000..d83eae6bb6d --- /dev/null +++ b/libs/importer/src/importers/spec-data/password-depot-xml/macos-customfields.xml.ts @@ -0,0 +1,42 @@ +export const MacOS_PasswordDepotXmlFile = ` + +
+ Password Depot + 0 + 0 + 0 + 1 + 1 + 17 + 30.12.1899 00:00:00 + 23.06.2025 16:30:50 + 25.06.2025 14:30:47 + 2C1A154A-3BB0-4871-9537-3634DE303F8E + 7 +
+ + + + card 1 + 1 + comment + 23.06.2025 16:14:33 + EBF4AC3D-86C9-49BE-826B-BAE5FF9E3575 + 23.06.2025 16:13:40 + 25.06.2025 14:17:10 + + + + + + + + + + + + + + + +
`; diff --git a/libs/importer/src/importers/spec-data/password-depot-xml/macos-multiple-folders.xml.ts b/libs/importer/src/importers/spec-data/password-depot-xml/macos-multiple-folders.xml.ts new file mode 100644 index 00000000000..174e9415fa1 --- /dev/null +++ b/libs/importer/src/importers/spec-data/password-depot-xml/macos-multiple-folders.xml.ts @@ -0,0 +1,215 @@ +export const MacOS_MultipleFolders = ` + +
+ Password Depot + 0 + 0 + 0 + 1 + 1 + 17 + 30.12.1899 00:00:00 + 27.06.2025 10:39:07 + 27.06.2025 10:39:27 + 7DCDD3FA-F512-4CD4-AEED-DE2A4C8375CF + 7 +
+ + + + remote desktop + 8 + pass + username + compjter + comment + 26.06.2025 16:04:57 + 81316050-9B9C-4D9B-9549-45B52A0BE6BB + + Private + 26.06.2025 16:04:32 + 27.06.2025 10:28:02 + tgmac + + + teamviewer + 10 + pass + partnerid + comment + 26.06.2025 16:05:28 + 26.06.2025 + 8AAACC16-4FD4-4E52-9C1F-6979B051B510 + Internet + 26.06.2025 16:05:03 + 27.06.2025 10:28:02 + tag + + + + + + ec card + 5 + pass + user + url + 26.06.2025 16:08:35 + B5C148A4-C408-427C-B69C-F88E7C529FA4 + + 26.06.2025 16:08:00 + 27.06.2025 10:28:02 + + + + + + + + + + + + + + + identity + 3 + 26.06.2025 16:09:50 + 87574AD4-8844-4A01-9381-AFF0907198A3 + 26.06.2025 16:09:19 + 27.06.2025 10:28:02 + + + + + + + + + + + + + + + + + + + + + + credit card + 1 + comment + 26.06.2025 19:07:38 + E98E3CBA-1578-48AD-8E41-CFD3280045BB + 26.06.2025 16:06:32 + 27.06.2025 10:28:02 + + + + + + + + + + + + + + + + password + passmac + usernam + comment + 26.06.2025 16:04:30 + DE8AD61B-8EC0-4E72-9BC8-971E80712B50 + + General + 26.06.2025 16:04:04 + 27.06.2025 10:28:02 + tagmac + + + informationb + 4 + 26.06.2025 16:10:01 + 7E9E6941-BB3B-47F2-9E43-33F900EBBF95 + Banking + 26.06.2025 16:09:53 + 27.06.2025 10:28:02 + + + + + + certificat + 11 + passsss + comment + 26.06.2025 16:10:28 + 26.06.2025 + 1F36748F-0374-445E-B020-282EAE26259F + Internet + 26.06.2025 16:10:10 + 27.06.2025 10:28:02 + tag + + + + + putty + 9 + pass + username + host + comment + 26.06.2025 16:06:08 + 26.06.2025 + 7947A949-98F0-4F26-BE12-5FFAFE7601C8 + + Banking + 26.06.2025 16:05:38 + 27.06.2025 10:28:02 + tag + + + + + + + + + soft license + 2 + 26.06.2025 16:09:02 + 2A5CF4C1-70D0-4F27-A1DE-4CFEF5FB71CF + 26.06.2025 16:08:43 + 27.06.2025 10:28:02 + + + + + + + + + + + + + + + + + + + +
`; diff --git a/libs/importer/src/importers/spec-data/password-depot-xml/macos-wrong-version.xml.ts b/libs/importer/src/importers/spec-data/password-depot-xml/macos-wrong-version.xml.ts new file mode 100644 index 00000000000..771bf813e48 --- /dev/null +++ b/libs/importer/src/importers/spec-data/password-depot-xml/macos-wrong-version.xml.ts @@ -0,0 +1,21 @@ +export const MacOS_WrongVersion = ` + +
+ Password Depot + 0 + 0 + 0 + 1 + 1 + 18 + 30.12.1899 00:00:00 + 23.06.2025 16:30:50 + 25.06.2025 14:30:47 + 2C1A154A-3BB0-4871-9537-3634DE303F8E + 7 +
+ + + + +
`; diff --git a/libs/importer/src/importers/spec-data/password-depot-xml/missing-passwords-node.xml.ts b/libs/importer/src/importers/spec-data/password-depot-xml/missing-passwords-node.xml.ts new file mode 100644 index 00000000000..d07beb8521c --- /dev/null +++ b/libs/importer/src/importers/spec-data/password-depot-xml/missing-passwords-node.xml.ts @@ -0,0 +1,25 @@ +export const MissingPasswordsNodeData = ` + +
+ Password Depot + 17.0.0 + + + CCDA8015-7F21-4344-BDF0-9EA6AF8AE31D + 12.05.2025 15:16:11 + False + 0 + 30.12.1899 00:00:00 + +
+ + + + + + + + + + +
`; diff --git a/libs/importer/src/importers/spec-data/password-depot-xml/missing-root-node.xml.ts b/libs/importer/src/importers/spec-data/password-depot-xml/missing-root-node.xml.ts new file mode 100644 index 00000000000..aca2a2f6fa1 --- /dev/null +++ b/libs/importer/src/importers/spec-data/password-depot-xml/missing-root-node.xml.ts @@ -0,0 +1,28 @@ +export const InvalidRootNodeData = ` + +
+ Password Depot + 17.0.0 + + + CCDA8015-7F21-4344-BDF0-9EA6AF8AE31D + 12.05.2025 15:16:11 + False + 0 + 30.12.1899 00:00:00 + +
+ + + + + + + + + + + + + +
`; diff --git a/libs/importer/src/importers/spec-data/password-depot-xml/noop-encrypted-file.xml.ts b/libs/importer/src/importers/spec-data/password-depot-xml/noop-encrypted-file.xml.ts new file mode 100644 index 00000000000..e8050726b25 --- /dev/null +++ b/libs/importer/src/importers/spec-data/password-depot-xml/noop-encrypted-file.xml.ts @@ -0,0 +1,27 @@ +export const EncryptedFileData = ` + +
+ Password Depot + 17.0.0 + + + CCDA8015-7F21-4344-BDF0-9EA6AF8AE31D + 12.05.2025 15:16:11 + True + 0 + 30.12.1899 00:00:00 + +
+ + + + + + + + + + + + +
`; diff --git a/libs/importer/src/importers/spec-data/password-depot-xml/password.xml.ts b/libs/importer/src/importers/spec-data/password-depot-xml/password.xml.ts new file mode 100644 index 00000000000..7d15fce3aa8 --- /dev/null +++ b/libs/importer/src/importers/spec-data/password-depot-xml/password.xml.ts @@ -0,0 +1,222 @@ +export const PasswordTestData = ` + +
+ Password Depot + 17.0.0 + + + CCDA8015-7F21-4344-BDF0-9EA6AF8AE31D + 12.05.2025 15:16:11 + False + 0 + 30.12.1899 00:00:00 + +
+ + + + password type + 0 + p6J<]fmjv!:H&iJ7/Mwt@3i8 + someUser + example.com + someComment + 07.05.2025 13:37:56 + 07.05.2025 + 0 + 27ACAC2D-8DDA-4088-8D3A-E6C5F40ED46E + + 0 + 0 + + + Allgemein + + 0 + + + 07.05.2025 13:36:48 + 07.05.2025 13:36:48 + 0 + 0 + 0 + 1 + + 0 + 2 + someTag + DJSMI + + + 0 + + 0 + + 0 + + 161 + 0 + + + + passwort + password + -1 + 0 + 1 + + + memo + memo + -1 + 0 + 2 + + + datum + 45790 + -1 + 0 + 3 + + + nummer + 1 + -1 + 0 + 4 + + + boolean + 1 + -1 + 0 + 5 + + + decimal + 1,01 + -1 + 0 + 6 + + + email + who@cares.com + -1 + 0 + 7 + + + url + example.com + -1 + 0 + 8 + + + + + password type (2) + 0 + p6J<]fmjv!:H&iJ7/Mwt@3i8 + someUser + + someComment + 07.05.2025 13:37:56 + 07.05.2025 + 0 + AF74FF86-FE39-4584-8E96-FE950C289DF8 + + 0 + 0 + + + Allgemein + + 0 + + + 07.05.2025 13:36:48 + 07.05.2025 13:36:48 + 0 + 0 + 0 + 1 + + 0 + 2 + someTag + DJSMI + + + 0 + + 0 + + 0 + + 161 + 0 + + + + password type (3) + 0 + p6J<]fmjv!:H&iJ7/Mwt@3i8 + someUser + + someComment + 07.05.2025 13:37:56 + 07.05.2025 + 0 + BF74FF86-FA39-4584-8E96-FA950C249DF8 + + 0 + 0 + + + Allgemein + + 0 + + + 07.05.2025 13:36:48 + 07.05.2025 13:36:48 + 0 + 0 + 0 + 1 + + 0 + 2 + someTag + DJSMI + + + 0 + + 0 + + 0 + + 161 + 0 + + + + + + + + + + QUY3NEZGODYtRkUzOS00NTg0LThFOTYtRkU5NTBDMjg5REY4CkJGNzRGRjg2LUZBMzktNDU4NC04RTk2LUZBOTUwQzI0OURGOA== + + + + + + QWxsZ2VtZWluDQpIb21lIEJhbmtpbmcNCkludGVybmV0DQpQcml2YXQNCldpbmRvd3MNCg== + +
`; diff --git a/libs/importer/src/importers/spec-data/password-depot-xml/putty.xml.ts b/libs/importer/src/importers/spec-data/password-depot-xml/putty.xml.ts new file mode 100644 index 00000000000..d878b04cd3c --- /dev/null +++ b/libs/importer/src/importers/spec-data/password-depot-xml/putty.xml.ts @@ -0,0 +1,106 @@ +export const PuttyTestData = ` + +
+ Password Depot + 17.0.0 + + + CCDA8015-7F21-4344-BDF0-9EA6AF8AE31D + 12.05.2025 15:16:11 + False + 0 + 30.12.1899 00:00:00 + +
+ + + + Putty type + 9 + somePassword + someUser + localhost + someNote + 12.05.2025 15:09:09 + 00.00.0000 + 1 + 32207D79-B70B-4987-BC73-3F7AD75D2C63 + + 125 + 0 + + cli command + Allgemein + + 0 + + + 12.05.2025 15:08:18 + 12.05.2025 15:08:18 + 0 + 0 + 0 + 1 + + 0 + 2 + someTag + DJSMI + + + 0 + + 0 + + 0 + + 161 + 0 + + + + IDS_PuTTyProtocol + 0 + 0 + 0 + 0 + + + IDS_PuTTyKeyFile + pathToKeyFile + -1 + 0 + 0 + + + IDS_PuTTyKeyPassword + passwordForKeyFile + -1 + 0 + 1 + + + IDS_PuTTyPort + 8080 + -1 + 0 + 4 + + + + + + + + + + + QUY3NEZGODYtRkUzOS00NTg0LThFOTYtRkU5NTBDMjg5REY4DQo= + + + + + + QWxsZ2VtZWluDQpIb21lIEJhbmtpbmcNCkludGVybmV0DQpQcml2YXQNCldpbmRvd3MNCg== + +
`; diff --git a/libs/importer/src/importers/spec-data/password-depot-xml/rdp.xml.ts b/libs/importer/src/importers/spec-data/password-depot-xml/rdp.xml.ts new file mode 100644 index 00000000000..fafc375f9a6 --- /dev/null +++ b/libs/importer/src/importers/spec-data/password-depot-xml/rdp.xml.ts @@ -0,0 +1,76 @@ +export const RDPTestData = ` + +
+ Password Depot + 17.0.0 + + + CCDA8015-7F21-4344-BDF0-9EA6AF8AE31D + 12.05.2025 15:16:11 + False + 0 + 30.12.1899 00:00:00 + +
+ + + + rdp type + 8 + somePassword + someUser + ms-rd:subscribe?url=https://contoso.com + someNote + 12.05.2025 15:07:33 + 12.05.2025 + 1 + 24CFF328-3036-48E3-99A3-85CD337725D3 + + 123 + 0 + + commandline command + Allgemein + + 0 + + + 12.05.2025 15:06:24 + 12.05.2025 15:06:24 + 0 + 0 + 0 + 1 + + 0 + 2 + sometag + DJSMI + + + 0 + + 0 + + 0 + + 161 + 0 + + + + + + + + + + QUY3NEZGODYtRkUzOS00NTg0LThFOTYtRkU5NTBDMjg5REY4DQo= + + + + + + QWxsZ2VtZWluDQpIb21lIEJhbmtpbmcNCkludGVybmV0DQpQcml2YXQNCldpbmRvd3MNCg== + +
`; diff --git a/libs/importer/src/importers/spec-data/password-depot-xml/software-license.xml.ts b/libs/importer/src/importers/spec-data/password-depot-xml/software-license.xml.ts new file mode 100644 index 00000000000..5ab9437c3d7 --- /dev/null +++ b/libs/importer/src/importers/spec-data/password-depot-xml/software-license.xml.ts @@ -0,0 +1,169 @@ +export const SoftwareLicenseTestData = ` + +
+ Password Depot + 17.0.0 + + + CCDA8015-7F21-4344-BDF0-9EA6AF8AE31D + 12.05.2025 15:16:11 + False + 0 + 30.12.1899 00:00:00 + +
+ + + + software-license type + 2 + somePassword + someUserName + example.com + someComment + 12.05.2025 15:12:48 + 00.00.0000 + 1 + 220206EB-BE82-4E78-8FFB-9316D854721F + + 128 + 0 + + + Allgemein + + 0 + + + 12.05.2025 15:11:33 + 12.05.2025 15:11:33 + 0 + 0 + 0 + 1 + + 0 + 2 + + DJSMI + + + 0 + + 0 + + 0 + + 161 + 0 + + + + IDS_LicenseProduct + someProduct + 0 + 0 + 0 + + + IDS_LicenseVersion + someVersion + 0 + 0 + 0 + + + IDS_LicenseName + some User + -1 + 0 + 0 + + + IDS_LicenseKey + license-key + -1 + 0 + 0 + + + IDS_LicenseAdditionalKey + additional-license-key + -1 + 0 + 0 + + + IDS_LicenseURL + example.com + -1 + 0 + 8 + + + IDS_LicenseProtected + 1 + 0 + 0 + 5 + + + IDS_LicenseUserName + someUserName + -1 + 0 + 0 + + + IDS_LicensePassword + somePassword + -1 + 0 + 1 + + + IDS_LicensePurchaseDate + 45789 + 0 + 0 + 3 + + + IDS_LicenseOrderNumber + order number + -1 + 0 + 0 + + + IDS_LicenseEmail + someEmail + -1 + 0 + 7 + + + IDS_LicenseExpires + Nie + 0 + 0 + 3 + + + + + + + + + + + QUY3NEZGODYtRkUzOS00NTg0LThFOTYtRkU5NTBDMjg5REY4DQo= + + + + + + QWxsZ2VtZWluDQpIb21lIEJhbmtpbmcNCkludGVybmV0DQpQcml2YXQNCldpbmRvd3MNCg== + +
`; diff --git a/libs/importer/src/importers/spec-data/password-depot-xml/team-viewer.xml.ts b/libs/importer/src/importers/spec-data/password-depot-xml/team-viewer.xml.ts new file mode 100644 index 00000000000..911c621c59a --- /dev/null +++ b/libs/importer/src/importers/spec-data/password-depot-xml/team-viewer.xml.ts @@ -0,0 +1,85 @@ +export const TeamViewerTestData = ` + +
+ Password Depot + 17.0.0 + + + CCDA8015-7F21-4344-BDF0-9EA6AF8AE31D + 12.05.2025 15:16:11 + False + 0 + 30.12.1899 00:00:00 + +
+ + + + TeamViewer type + 10 + somePassword + + partnerId + someNote + 12.05.2025 15:08:14 + 00.00.0000 + 1 + AE650032-5963-4D93-8E2E-69F216405C29 + + 124 + 0 + + + Allgemein + + 0 + + + 12.05.2025 15:07:41 + 12.05.2025 15:07:41 + 0 + 0 + 0 + 1 + + 0 + 2 + someTag + DJSMI + + + 0 + + 0 + + 0 + + 161 + 0 + + + + IDS_TeamViewerMode + 0 + 0 + 0 + 0 + + + + + + + + + + + QUY3NEZGODYtRkUzOS00NTg0LThFOTYtRkU5NTBDMjg5REY4DQo= + + + + + + QWxsZ2VtZWluDQpIb21lIEJhbmtpbmcNCkludGVybmV0DQpQcml2YXQNCldpbmRvd3MNCg== + +
`; diff --git a/libs/importer/src/importers/spec-data/password-depot-xml/wrong-version.xml.ts b/libs/importer/src/importers/spec-data/password-depot-xml/wrong-version.xml.ts new file mode 100644 index 00000000000..90b766ded1b --- /dev/null +++ b/libs/importer/src/importers/spec-data/password-depot-xml/wrong-version.xml.ts @@ -0,0 +1,28 @@ +export const InvalidVersionData = ` + +
+ Password Depot + 18.0.0 + + + CCDA8015-7F21-4344-BDF0-9EA6AF8AE31D + 12.05.2025 15:16:11 + False + 0 + 30.12.1899 00:00:00 + +
+ + + + + + + + + + + + + +
`; diff --git a/libs/importer/src/models/import-options.ts b/libs/importer/src/models/import-options.ts index a8c4b4e0a8a..205dbaf0198 100644 --- a/libs/importer/src/models/import-options.ts +++ b/libs/importer/src/models/import-options.ts @@ -73,6 +73,7 @@ export const regularImportOptions = [ { id: "passkyjson", name: "Passky (json)" }, { id: "passwordxpcsv", name: "Password XP (csv)" }, { id: "netwrixpasswordsecure", name: "Netwrix Password Secure (csv)" }, + { id: "passworddepot17xml", name: "Password Depot 17 (xml)" }, ] as const; export type ImportType = diff --git a/libs/importer/src/services/import.service.ts b/libs/importer/src/services/import.service.ts index 3789ee7536c..2b9d2e490f7 100644 --- a/libs/importer/src/services/import.service.ts +++ b/libs/importer/src/services/import.service.ts @@ -90,6 +90,7 @@ import { YotiCsvImporter, ZohoVaultCsvImporter, PasswordXPCsvImporter, + PasswordDepot17XmlImporter, } from "../importers"; import { Importer } from "../importers/importer"; import { @@ -348,6 +349,8 @@ export class ImportService implements ImportServiceAbstraction { return new PasswordXPCsvImporter(); case "netwrixpasswordsecure": return new NetwrixPasswordSecureCsvImporter(); + case "passworddepot17xml": + return new PasswordDepot17XmlImporter(); default: return null; } From 2810f2aaafa66f189cd35a152635830dda7ba92f Mon Sep 17 00:00:00 2001 From: Github Actions Date: Tue, 1 Jul 2025 17:02:17 +0000 Subject: [PATCH 032/239] Bumped client version(s) --- apps/browser/package.json | 2 +- apps/browser/src/manifest.json | 2 +- apps/browser/src/manifest.v3.json | 2 +- package-lock.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/browser/package.json b/apps/browser/package.json index 9b6d0174b0f..16e460a9025 100644 --- a/apps/browser/package.json +++ b/apps/browser/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/browser", - "version": "2025.6.0", + "version": "2025.6.1", "scripts": { "build": "npm run build:chrome", "build:chrome": "cross-env BROWSER=chrome MANIFEST_VERSION=3 NODE_OPTIONS=\"--max-old-space-size=8192\" webpack", diff --git a/apps/browser/src/manifest.json b/apps/browser/src/manifest.json index 9f6529643c4..c46674083b2 100644 --- a/apps/browser/src/manifest.json +++ b/apps/browser/src/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "__MSG_extName__", "short_name": "Bitwarden", - "version": "2025.6.0", + "version": "2025.6.1", "description": "__MSG_extDesc__", "default_locale": "en", "author": "Bitwarden Inc.", diff --git a/apps/browser/src/manifest.v3.json b/apps/browser/src/manifest.v3.json index bf5c4e439b9..6d38a5880d5 100644 --- a/apps/browser/src/manifest.v3.json +++ b/apps/browser/src/manifest.v3.json @@ -3,7 +3,7 @@ "minimum_chrome_version": "102.0", "name": "__MSG_extName__", "short_name": "Bitwarden", - "version": "2025.6.0", + "version": "2025.6.1", "description": "__MSG_extDesc__", "default_locale": "en", "author": "Bitwarden Inc.", diff --git a/package-lock.json b/package-lock.json index 176aa40a650..9d2eded4c7a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -197,7 +197,7 @@ }, "apps/browser": { "name": "@bitwarden/browser", - "version": "2025.6.0" + "version": "2025.6.1" }, "apps/cli": { "name": "@bitwarden/cli", From 3ae5e063a73fb179b8f7430e7db1c01aa98802bf Mon Sep 17 00:00:00 2001 From: Github Actions Date: Tue, 1 Jul 2025 17:11:29 +0000 Subject: [PATCH 033/239] Bumped client version(s) --- apps/cli/package.json | 2 +- package-lock.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/cli/package.json b/apps/cli/package.json index ea94314c641..520140a676d 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,7 +1,7 @@ { "name": "@bitwarden/cli", "description": "A secure and free password manager for all of your devices.", - "version": "2025.6.0", + "version": "2025.6.1", "keywords": [ "bitwarden", "password", diff --git a/package-lock.json b/package-lock.json index 9d2eded4c7a..a6b965f89f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -201,7 +201,7 @@ }, "apps/cli": { "name": "@bitwarden/cli", - "version": "2025.6.0", + "version": "2025.6.1", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@koa/multer": "3.1.0", From 4cb80b4a037c075cfc2b77bc73f35575131d9ec7 Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Tue, 1 Jul 2025 13:47:02 -0400 Subject: [PATCH 034/239] Platform logging lib (#15338) * Add Platform Logging Lib * Move console log spec and test util back into libs/common * Fix ConsoleLogServer re-export * Fix types error --- .github/CODEOWNERS | 1 + .../src/platform/abstractions/log.service.ts | 10 +--- .../src/platform/enums/log-level-type.enum.ts | 9 +-- .../services/console-log.service.spec.ts | 4 +- .../platform/services/console-log.service.ts | 60 +------------------ libs/logging/README.md | 5 ++ libs/logging/eslint.config.mjs | 3 + libs/logging/jest.config.js | 10 ++++ libs/logging/package.json | 11 ++++ libs/logging/project.json | 33 ++++++++++ libs/logging/src/console-log.service.ts | 57 ++++++++++++++++++ libs/logging/src/index.ts | 3 + libs/logging/src/log-level.ts | 8 +++ libs/logging/src/log.service.ts | 9 +++ libs/logging/src/logging.spec.ts | 8 +++ libs/logging/tsconfig.json | 13 ++++ libs/logging/tsconfig.lib.json | 10 ++++ libs/logging/tsconfig.spec.json | 16 +++++ package-lock.json | 8 +++ tsconfig.base.json | 1 + 20 files changed, 201 insertions(+), 78 deletions(-) create mode 100644 libs/logging/README.md create mode 100644 libs/logging/eslint.config.mjs create mode 100644 libs/logging/jest.config.js create mode 100644 libs/logging/package.json create mode 100644 libs/logging/project.json create mode 100644 libs/logging/src/console-log.service.ts create mode 100644 libs/logging/src/index.ts create mode 100644 libs/logging/src/log-level.ts create mode 100644 libs/logging/src/log.service.ts create mode 100644 libs/logging/src/logging.spec.ts create mode 100644 libs/logging/tsconfig.json create mode 100644 libs/logging/tsconfig.lib.json create mode 100644 libs/logging/tsconfig.spec.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index db60ad6a93b..590887b3cad 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -91,6 +91,7 @@ libs/common/spec @bitwarden/team-platform-dev libs/common/src/state-migrations @bitwarden/team-platform-dev libs/platform @bitwarden/team-platform-dev libs/storage-core @bitwarden/team-platform-dev +libs/logging @bitwarden/team-platform-dev libs/storage-test-utils @bitwarden/team-platform-dev # Web utils used across app and connectors apps/web/src/utils/ @bitwarden/team-platform-dev diff --git a/libs/common/src/platform/abstractions/log.service.ts b/libs/common/src/platform/abstractions/log.service.ts index d77a4f69906..c540f1a2b8f 100644 --- a/libs/common/src/platform/abstractions/log.service.ts +++ b/libs/common/src/platform/abstractions/log.service.ts @@ -1,9 +1 @@ -import { LogLevelType } from "../enums/log-level-type.enum"; - -export abstract class LogService { - abstract debug(message?: any, ...optionalParams: any[]): void; - abstract info(message?: any, ...optionalParams: any[]): void; - abstract warning(message?: any, ...optionalParams: any[]): void; - abstract error(message?: any, ...optionalParams: any[]): void; - abstract write(level: LogLevelType, message?: any, ...optionalParams: any[]): void; -} +export { LogService } from "@bitwarden/logging"; diff --git a/libs/common/src/platform/enums/log-level-type.enum.ts b/libs/common/src/platform/enums/log-level-type.enum.ts index b5f84467d6e..024c71c9f97 100644 --- a/libs/common/src/platform/enums/log-level-type.enum.ts +++ b/libs/common/src/platform/enums/log-level-type.enum.ts @@ -1,8 +1 @@ -// FIXME: update to use a const object instead of a typescript enum -// eslint-disable-next-line @bitwarden/platform/no-enums -export enum LogLevelType { - Debug, - Info, - Warning, - Error, -} +export { LogLevel as LogLevelType } from "@bitwarden/logging"; diff --git a/libs/common/src/platform/services/console-log.service.spec.ts b/libs/common/src/platform/services/console-log.service.spec.ts index 508ca4eb327..e73aed5f3b5 100644 --- a/libs/common/src/platform/services/console-log.service.spec.ts +++ b/libs/common/src/platform/services/console-log.service.spec.ts @@ -1,6 +1,6 @@ -import { interceptConsole, restoreConsole } from "../../../spec"; +import { ConsoleLogService } from "@bitwarden/logging"; -import { ConsoleLogService } from "./console-log.service"; +import { interceptConsole, restoreConsole } from "../../../spec"; describe("ConsoleLogService", () => { const error = new Error("this is an error"); diff --git a/libs/common/src/platform/services/console-log.service.ts b/libs/common/src/platform/services/console-log.service.ts index cb6554e2aa2..6d55614757b 100644 --- a/libs/common/src/platform/services/console-log.service.ts +++ b/libs/common/src/platform/services/console-log.service.ts @@ -1,59 +1 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { LogService as LogServiceAbstraction } from "../abstractions/log.service"; -import { LogLevelType } from "../enums/log-level-type.enum"; - -export class ConsoleLogService implements LogServiceAbstraction { - protected timersMap: Map = new Map(); - - constructor( - protected isDev: boolean, - protected filter: (level: LogLevelType) => boolean = null, - ) {} - - debug(message?: any, ...optionalParams: any[]) { - if (!this.isDev) { - return; - } - this.write(LogLevelType.Debug, message, ...optionalParams); - } - - info(message?: any, ...optionalParams: any[]) { - this.write(LogLevelType.Info, message, ...optionalParams); - } - - warning(message?: any, ...optionalParams: any[]) { - this.write(LogLevelType.Warning, message, ...optionalParams); - } - - error(message?: any, ...optionalParams: any[]) { - this.write(LogLevelType.Error, message, ...optionalParams); - } - - write(level: LogLevelType, message?: any, ...optionalParams: any[]) { - if (this.filter != null && this.filter(level)) { - return; - } - - switch (level) { - case LogLevelType.Debug: - // eslint-disable-next-line - console.log(message, ...optionalParams); - break; - case LogLevelType.Info: - // eslint-disable-next-line - console.log(message, ...optionalParams); - break; - case LogLevelType.Warning: - // eslint-disable-next-line - console.warn(message, ...optionalParams); - break; - case LogLevelType.Error: - // eslint-disable-next-line - console.error(message, ...optionalParams); - break; - default: - break; - } - } -} +export { ConsoleLogService } from "@bitwarden/logging"; diff --git a/libs/logging/README.md b/libs/logging/README.md new file mode 100644 index 00000000000..d2ef90cb3f9 --- /dev/null +++ b/libs/logging/README.md @@ -0,0 +1,5 @@ +# logging + +Owned by: platform + +Logging primitives diff --git a/libs/logging/eslint.config.mjs b/libs/logging/eslint.config.mjs new file mode 100644 index 00000000000..9c37d10e3ff --- /dev/null +++ b/libs/logging/eslint.config.mjs @@ -0,0 +1,3 @@ +import baseConfig from "../../eslint.config.mjs"; + +export default [...baseConfig]; diff --git a/libs/logging/jest.config.js b/libs/logging/jest.config.js new file mode 100644 index 00000000000..a231d3bfce9 --- /dev/null +++ b/libs/logging/jest.config.js @@ -0,0 +1,10 @@ +module.exports = { + displayName: "logging", + preset: "../../jest.preset.js", + testEnvironment: "node", + transform: { + "^.+\\.[tj]s$": ["ts-jest", { tsconfig: "/tsconfig.spec.json" }], + }, + moduleFileExtensions: ["ts", "js", "html"], + coverageDirectory: "../../coverage/libs/logging", +}; diff --git a/libs/logging/package.json b/libs/logging/package.json new file mode 100644 index 00000000000..b9cfbe35eb0 --- /dev/null +++ b/libs/logging/package.json @@ -0,0 +1,11 @@ +{ + "name": "@bitwarden/logging", + "version": "0.0.1", + "description": "Logging primitives", + "private": true, + "type": "commonjs", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "license": "GPL-3.0", + "author": "platform" +} diff --git a/libs/logging/project.json b/libs/logging/project.json new file mode 100644 index 00000000000..f2b5db313be --- /dev/null +++ b/libs/logging/project.json @@ -0,0 +1,33 @@ +{ + "name": "logging", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/logging/src", + "projectType": "library", + "tags": [], + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/libs/logging", + "main": "libs/logging/src/index.ts", + "tsConfig": "libs/logging/tsconfig.lib.json", + "assets": ["libs/logging/*.md"] + } + }, + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["libs/logging/**/*.ts"] + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/logging/jest.config.js" + } + } + } +} diff --git a/libs/logging/src/console-log.service.ts b/libs/logging/src/console-log.service.ts new file mode 100644 index 00000000000..3a4ffe9ead1 --- /dev/null +++ b/libs/logging/src/console-log.service.ts @@ -0,0 +1,57 @@ +import { LogLevel } from "./log-level"; +import { LogService } from "./log.service"; + +export class ConsoleLogService implements LogService { + protected timersMap: Map = new Map(); + + constructor( + protected isDev: boolean, + protected filter: ((level: LogLevel) => boolean) | null = null, + ) {} + + debug(message?: any, ...optionalParams: any[]) { + if (!this.isDev) { + return; + } + this.write(LogLevel.Debug, message, ...optionalParams); + } + + info(message?: any, ...optionalParams: any[]) { + this.write(LogLevel.Info, message, ...optionalParams); + } + + warning(message?: any, ...optionalParams: any[]) { + this.write(LogLevel.Warning, message, ...optionalParams); + } + + error(message?: any, ...optionalParams: any[]) { + this.write(LogLevel.Error, message, ...optionalParams); + } + + write(level: LogLevel, message?: any, ...optionalParams: any[]) { + if (this.filter != null && this.filter(level)) { + return; + } + + switch (level) { + case LogLevel.Debug: + // eslint-disable-next-line + console.log(message, ...optionalParams); + break; + case LogLevel.Info: + // eslint-disable-next-line + console.log(message, ...optionalParams); + break; + case LogLevel.Warning: + // eslint-disable-next-line + console.warn(message, ...optionalParams); + break; + case LogLevel.Error: + // eslint-disable-next-line + console.error(message, ...optionalParams); + break; + default: + break; + } + } +} diff --git a/libs/logging/src/index.ts b/libs/logging/src/index.ts new file mode 100644 index 00000000000..8ce4b62cd3f --- /dev/null +++ b/libs/logging/src/index.ts @@ -0,0 +1,3 @@ +export { LogService } from "./log.service"; +export { LogLevel } from "./log-level"; +export { ConsoleLogService } from "./console-log.service"; diff --git a/libs/logging/src/log-level.ts b/libs/logging/src/log-level.ts new file mode 100644 index 00000000000..adf6c145c3d --- /dev/null +++ b/libs/logging/src/log-level.ts @@ -0,0 +1,8 @@ +// FIXME: update to use a const object instead of a typescript enum +// eslint-disable-next-line @bitwarden/platform/no-enums +export enum LogLevel { + Debug, + Info, + Warning, + Error, +} diff --git a/libs/logging/src/log.service.ts b/libs/logging/src/log.service.ts new file mode 100644 index 00000000000..a63ad47c07e --- /dev/null +++ b/libs/logging/src/log.service.ts @@ -0,0 +1,9 @@ +import { LogLevel } from "./log-level"; + +export abstract class LogService { + abstract debug(message?: any, ...optionalParams: any[]): void; + abstract info(message?: any, ...optionalParams: any[]): void; + abstract warning(message?: any, ...optionalParams: any[]): void; + abstract error(message?: any, ...optionalParams: any[]): void; + abstract write(level: LogLevel, message?: any, ...optionalParams: any[]): void; +} diff --git a/libs/logging/src/logging.spec.ts b/libs/logging/src/logging.spec.ts new file mode 100644 index 00000000000..04a057a156f --- /dev/null +++ b/libs/logging/src/logging.spec.ts @@ -0,0 +1,8 @@ +import * as lib from "./index"; + +describe("logging", () => { + // This test will fail until something is exported from index.ts + it("should work", () => { + expect(lib).toBeDefined(); + }); +}); diff --git a/libs/logging/tsconfig.json b/libs/logging/tsconfig.json new file mode 100644 index 00000000000..62ebbd94647 --- /dev/null +++ b/libs/logging/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/libs/logging/tsconfig.lib.json b/libs/logging/tsconfig.lib.json new file mode 100644 index 00000000000..9cbf6736007 --- /dev/null +++ b/libs/logging/tsconfig.lib.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["jest.config.js", "src/**/*.spec.ts"] +} diff --git a/libs/logging/tsconfig.spec.json b/libs/logging/tsconfig.spec.json new file mode 100644 index 00000000000..a19b962c49a --- /dev/null +++ b/libs/logging/tsconfig.spec.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../..//dist/out-tsc", + "module": "commonjs", + "moduleResolution": "node10", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts", + "src/intercept-console.ts" + ] +} diff --git a/package-lock.json b/package-lock.json index a6b965f89f7..e9701cbd7ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -353,6 +353,10 @@ "version": "0.0.0", "license": "GPL-3.0" }, + "libs/logging": { + "version": "0.0.1", + "license": "GPL-3.0" + }, "libs/node": { "name": "@bitwarden/node", "version": "0.0.0", @@ -4583,6 +4587,10 @@ "resolved": "libs/key-management-ui", "link": true }, + "node_modules/@bitwarden/logging": { + "resolved": "libs/logging", + "link": true + }, "node_modules/@bitwarden/node": { "resolved": "libs/node", "link": true diff --git a/tsconfig.base.json b/tsconfig.base.json index b826d51e66e..c820306fd15 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -37,6 +37,7 @@ "@bitwarden/importer-ui": ["./libs/importer/src/components"], "@bitwarden/key-management": ["./libs/key-management/src"], "@bitwarden/key-management-ui": ["./libs/key-management-ui/src"], + "@bitwarden/logging": ["libs/logging/src"], "@bitwarden/node/*": ["./libs/node/src/*"], "@bitwarden/nx-plugin": ["libs/nx-plugin/src/index.ts"], "@bitwarden/platform": ["./libs/platform/src"], From 832e4b16f08be43aa60bda15623f6e129d45be91 Mon Sep 17 00:00:00 2001 From: Tom <144813356+ttalty@users.noreply.github.com> Date: Tue, 1 Jul 2025 13:58:12 -0400 Subject: [PATCH 035/239] Org permission guards for accessing reports and displaying access intelligence (#15060) --- .../organizations/layouts/organization-layout.component.html | 2 +- .../organizations/organizations-routing.module.ts | 1 + .../access-intelligence/access-intelligence-routing.module.ts | 4 +++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html index f991678e834..d5e771d1b17 100644 --- a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html +++ b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html @@ -4,7 +4,7 @@ diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations-routing.module.ts b/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations-routing.module.ts index f63140a8b23..35659d05dce 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations-routing.module.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations-routing.module.ts @@ -79,6 +79,7 @@ const routes: Routes = [ }, { path: "access-intelligence", + canActivate: [organizationPermissionsGuard((org) => org.canAccessReports)], loadChildren: () => import("../../dirt/access-intelligence/access-intelligence.module").then( (m) => m.AccessIntelligenceModule, diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/access-intelligence-routing.module.ts b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/access-intelligence-routing.module.ts index 6df0f01bc8b..2e3c53d8d9f 100644 --- a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/access-intelligence-routing.module.ts +++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/access-intelligence-routing.module.ts @@ -9,7 +9,9 @@ const routes: Routes = [ { path: "", pathMatch: "full", redirectTo: "risk-insights" }, { path: "risk-insights", - canActivate: [organizationPermissionsGuard((org) => org.useRiskInsights)], + canActivate: [ + organizationPermissionsGuard((org) => org.useRiskInsights && org.canAccessReports), + ], component: RiskInsightsComponent, data: { titleId: "RiskInsights", From c9aa8498c7a66b792768768c116098eef77e1bab Mon Sep 17 00:00:00 2001 From: Addison Beck Date: Tue, 1 Jul 2025 14:03:08 -0400 Subject: [PATCH 036/239] fix(desktop): save zoom level to state when it is adjusted (#15406) --- apps/desktop/src/main/window.main.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/desktop/src/main/window.main.ts b/apps/desktop/src/main/window.main.ts index 4d9438b588d..5b81cf8140b 100644 --- a/apps/desktop/src/main/window.main.ts +++ b/apps/desktop/src/main/window.main.ts @@ -295,6 +295,15 @@ export class WindowMain { this.win.webContents.zoomFactor = this.windowStates[mainWindowSizeKey].zoomFactor ?? 1.0; }); + // Persist zoom changes immediately when user zooms in/out or resets zoom + // We can't depend on higher level web events (like close) to do this + // because locking the vault resets window state. + this.win.webContents.on("zoom-changed", async () => { + const newZoom = this.win.webContents.zoomFactor; + this.windowStates[mainWindowSizeKey].zoomFactor = newZoom; + await this.desktopSettingsService.setWindow(this.windowStates[mainWindowSizeKey]); + }); + if (this.windowStates[mainWindowSizeKey].isMaximized) { this.win.maximize(); } From 5eca3a591667766ff8dd42b67642ce960391004e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20=C3=85berg?= Date: Tue, 1 Jul 2025 21:00:13 +0200 Subject: [PATCH 037/239] [PM-18809] Passkey: use ArrayBuffer instead of Uint8Array (#15092) * Passkey: use ArrayBuffer instead of Uint8Array to conform WebAuthn spec * ArrayBufferView generics was too modern for this project * Correctly update the types from Uint8arrays to ArrayBuffers * Fixed broken tests + bugs * Removed arrayBufferViewToArrayBuffer as it's not needed in this invocation paths --------- Co-authored-by: ozraru Co-authored-by: Todd Martin <106564991+trmartin4@users.noreply.github.com> --- .../autofill/services/desktop-autofill.service.ts | 10 +++++----- .../fido2-authenticator.service.abstraction.ts | 10 +++++----- .../services/fido2/credential-id-utils.spec.ts | 4 ++-- .../services/fido2/credential-id-utils.ts | 15 +++++++++------ .../services/fido2/fido2-authenticator.service.ts | 2 +- .../services/fido2/fido2-client.service.ts | 4 ++-- .../src/platform/services/fido2/fido2-utils.ts | 4 ++-- 7 files changed, 26 insertions(+), 23 deletions(-) diff --git a/apps/desktop/src/autofill/services/desktop-autofill.service.ts b/apps/desktop/src/autofill/services/desktop-autofill.service.ts index 7e60c6b8d76..5500bc58f5a 100644 --- a/apps/desktop/src/autofill/services/desktop-autofill.service.ts +++ b/apps/desktop/src/autofill/services/desktop-autofill.service.ts @@ -209,7 +209,7 @@ export class DesktopAutofillService implements OnDestroy { } request.credentialId = Array.from( - parseCredentialId(decrypted.login.fido2Credentials?.[0].credentialId), + new Uint8Array(parseCredentialId(decrypted.login.fido2Credentials?.[0].credentialId)), ); } @@ -336,12 +336,12 @@ export class DesktopAutofillService implements OnDestroy { response: Fido2AuthenticatorGetAssertionResult, ): autofill.PasskeyAssertionResponse { return { - userHandle: Array.from(response.selectedCredential.userHandle), + userHandle: Array.from(new Uint8Array(response.selectedCredential.userHandle)), rpId: request.rpId, - signature: Array.from(response.signature), + signature: Array.from(new Uint8Array(response.signature)), clientDataHash: request.clientDataHash, - authenticatorData: Array.from(response.authenticatorData), - credentialId: Array.from(response.selectedCredential.id), + authenticatorData: Array.from(new Uint8Array(response.authenticatorData)), + credentialId: Array.from(new Uint8Array(response.selectedCredential.id)), }; } diff --git a/libs/common/src/platform/abstractions/fido2/fido2-authenticator.service.abstraction.ts b/libs/common/src/platform/abstractions/fido2/fido2-authenticator.service.abstraction.ts index 15655393362..fd3453198e6 100644 --- a/libs/common/src/platform/abstractions/fido2/fido2-authenticator.service.abstraction.ts +++ b/libs/common/src/platform/abstractions/fido2/fido2-authenticator.service.abstraction.ts @@ -70,7 +70,7 @@ export class Fido2AuthenticatorError extends Error { } export interface PublicKeyCredentialDescriptor { - id: Uint8Array; + id: ArrayBuffer; transports?: ("ble" | "hybrid" | "internal" | "nfc" | "usb")[]; type: "public-key"; } @@ -155,9 +155,9 @@ export interface Fido2AuthenticatorGetAssertionParams { export interface Fido2AuthenticatorGetAssertionResult { selectedCredential: { - id: Uint8Array; - userHandle?: Uint8Array; + id: ArrayBuffer; + userHandle?: ArrayBuffer; }; - authenticatorData: Uint8Array; - signature: Uint8Array; + authenticatorData: ArrayBuffer; + signature: ArrayBuffer; } diff --git a/libs/common/src/platform/services/fido2/credential-id-utils.spec.ts b/libs/common/src/platform/services/fido2/credential-id-utils.spec.ts index 76e068ac01c..1f2217ccd63 100644 --- a/libs/common/src/platform/services/fido2/credential-id-utils.spec.ts +++ b/libs/common/src/platform/services/fido2/credential-id-utils.spec.ts @@ -9,7 +9,7 @@ describe("credential-id-utils", () => { new Uint8Array([ 0x08, 0xd7, 0x0b, 0x74, 0xe9, 0xf5, 0x45, 0x22, 0xa4, 0x25, 0xe5, 0xdc, 0xd4, 0x01, 0x07, 0xe7, - ]), + ]).buffer, ); }); @@ -20,7 +20,7 @@ describe("credential-id-utils", () => { new Uint8Array([ 0x08, 0xd7, 0x0b, 0x74, 0xe9, 0xf5, 0x45, 0x22, 0xa4, 0x25, 0xe5, 0xdc, 0xd4, 0x01, 0x07, 0xe7, - ]), + ]).buffer, ); }); diff --git a/libs/common/src/platform/services/fido2/credential-id-utils.ts b/libs/common/src/platform/services/fido2/credential-id-utils.ts index 685669f0da3..08ea33114f5 100644 --- a/libs/common/src/platform/services/fido2/credential-id-utils.ts +++ b/libs/common/src/platform/services/fido2/credential-id-utils.ts @@ -3,13 +3,13 @@ import { Fido2Utils } from "./fido2-utils"; import { guidToRawFormat } from "./guid-utils"; -export function parseCredentialId(encodedCredentialId: string): Uint8Array { +export function parseCredentialId(encodedCredentialId: string): ArrayBuffer { try { if (encodedCredentialId.startsWith("b64.")) { return Fido2Utils.stringToBuffer(encodedCredentialId.slice(4)); } - return guidToRawFormat(encodedCredentialId); + return guidToRawFormat(encodedCredentialId).buffer; } catch { return undefined; } @@ -18,13 +18,16 @@ export function parseCredentialId(encodedCredentialId: string): Uint8Array { /** * Compares two credential IDs for equality. */ -export function compareCredentialIds(a: Uint8Array, b: Uint8Array): boolean { - if (a.length !== b.length) { +export function compareCredentialIds(a: ArrayBuffer, b: ArrayBuffer): boolean { + if (a.byteLength !== b.byteLength) { return false; } - for (let i = 0; i < a.length; i++) { - if (a[i] !== b[i]) { + const viewA = new Uint8Array(a); + const viewB = new Uint8Array(b); + + for (let i = 0; i < viewA.length; i++) { + if (viewA[i] !== viewB[i]) { return false; } } diff --git a/libs/common/src/platform/services/fido2/fido2-authenticator.service.ts b/libs/common/src/platform/services/fido2/fido2-authenticator.service.ts index bac1b218657..e560a77cc2e 100644 --- a/libs/common/src/platform/services/fido2/fido2-authenticator.service.ts +++ b/libs/common/src/platform/services/fido2/fido2-authenticator.service.ts @@ -514,7 +514,7 @@ async function getPrivateKeyFromFido2Credential( const keyBuffer = Fido2Utils.stringToBuffer(fido2Credential.keyValue); return await crypto.subtle.importKey( "pkcs8", - keyBuffer, + new Uint8Array(keyBuffer), { name: fido2Credential.keyAlgorithm, namedCurve: fido2Credential.keyCurve, diff --git a/libs/common/src/platform/services/fido2/fido2-client.service.ts b/libs/common/src/platform/services/fido2/fido2-client.service.ts index 5d5f2a879cb..431585441a7 100644 --- a/libs/common/src/platform/services/fido2/fido2-client.service.ts +++ b/libs/common/src/platform/services/fido2/fido2-client.service.ts @@ -127,9 +127,9 @@ export class Fido2ClientService } const userId = Fido2Utils.stringToBuffer(params.user.id); - if (userId.length < 1 || userId.length > 64) { + if (userId.byteLength < 1 || userId.byteLength > 64) { this.logService?.warning( - `[Fido2Client] Invalid 'user.id' length: ${params.user.id} (${userId.length})`, + `[Fido2Client] Invalid 'user.id' length: ${params.user.id} (${userId.byteLength})`, ); throw new TypeError("Invalid 'user.id' length"); } diff --git a/libs/common/src/platform/services/fido2/fido2-utils.ts b/libs/common/src/platform/services/fido2/fido2-utils.ts index 6413eeade04..99e260f4a53 100644 --- a/libs/common/src/platform/services/fido2/fido2-utils.ts +++ b/libs/common/src/platform/services/fido2/fido2-utils.ts @@ -47,8 +47,8 @@ export class Fido2Utils { .replace(/=/g, ""); } - static stringToBuffer(str: string): Uint8Array { - return Fido2Utils.fromB64ToArray(Fido2Utils.fromUrlB64ToB64(str)); + static stringToBuffer(str: string): ArrayBuffer { + return Fido2Utils.fromB64ToArray(Fido2Utils.fromUrlB64ToB64(str)).buffer; } static bufferSourceToUint8Array(bufferSource: BufferSource): Uint8Array { From 172623e0505a044001bb5ffbec1f30e8061e4379 Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Tue, 1 Jul 2025 15:59:11 -0400 Subject: [PATCH 038/239] [PM-20247] Initialize user-core library (#15029) * Initialize user-core library * Run `npm install` * Fix patched generator bug --- .github/CODEOWNERS | 1 + libs/common/src/types/guid.ts | 4 +++- libs/user-core/README.md | 6 ++++++ libs/user-core/eslint.config.mjs | 3 +++ libs/user-core/jest.config.js | 10 ++++++++++ libs/user-core/package.json | 10 ++++++++++ libs/user-core/project.json | 27 +++++++++++++++++++++++++++ libs/user-core/src/index.ts | 9 +++++++++ libs/user-core/tsconfig.json | 13 +++++++++++++ libs/user-core/tsconfig.lib.json | 10 ++++++++++ libs/user-core/tsconfig.spec.json | 10 ++++++++++ package-lock.json | 8 ++++++++ tsconfig.base.json | 1 + 13 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 libs/user-core/README.md create mode 100644 libs/user-core/eslint.config.mjs create mode 100644 libs/user-core/jest.config.js create mode 100644 libs/user-core/package.json create mode 100644 libs/user-core/project.json create mode 100644 libs/user-core/src/index.ts create mode 100644 libs/user-core/tsconfig.json create mode 100644 libs/user-core/tsconfig.lib.json create mode 100644 libs/user-core/tsconfig.spec.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 590887b3cad..9502a9c404d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -18,6 +18,7 @@ apps/cli/src/auth @bitwarden/team-auth-dev apps/desktop/src/auth @bitwarden/team-auth-dev apps/web/src/app/auth @bitwarden/team-auth-dev libs/auth @bitwarden/team-auth-dev +libs/user-core @bitwarden/team-auth-dev # web connectors used for auth apps/web/src/connectors @bitwarden/team-auth-dev bitwarden_license/bit-web/src/app/auth @bitwarden/team-auth-dev diff --git a/libs/common/src/types/guid.ts b/libs/common/src/types/guid.ts index bf891b55691..5edd34e4fc5 100644 --- a/libs/common/src/types/guid.ts +++ b/libs/common/src/types/guid.ts @@ -2,7 +2,9 @@ import { Opaque } from "type-fest"; export type Guid = Opaque; -export type UserId = Opaque; +// Convenience re-export of UserId from it's original location, any library that +// wants to be lower level than common should instead import it from user-core. +export { UserId } from "@bitwarden/user-core"; export type OrganizationId = Opaque; export type CollectionId = Opaque; export type ProviderId = Opaque; diff --git a/libs/user-core/README.md b/libs/user-core/README.md new file mode 100644 index 00000000000..57975746606 --- /dev/null +++ b/libs/user-core/README.md @@ -0,0 +1,6 @@ +# user-core + +Owned by: auth + +The very basic concept that constitutes a user, this needs to be very low level to facilitate +Platform keeping their own code low level. diff --git a/libs/user-core/eslint.config.mjs b/libs/user-core/eslint.config.mjs new file mode 100644 index 00000000000..9c37d10e3ff --- /dev/null +++ b/libs/user-core/eslint.config.mjs @@ -0,0 +1,3 @@ +import baseConfig from "../../eslint.config.mjs"; + +export default [...baseConfig]; diff --git a/libs/user-core/jest.config.js b/libs/user-core/jest.config.js new file mode 100644 index 00000000000..e38a12f3eb5 --- /dev/null +++ b/libs/user-core/jest.config.js @@ -0,0 +1,10 @@ +module.exports = { + displayName: "user-core", + preset: "../../jest.preset.js", + testEnvironment: "node", + transform: { + "^.+\\.[tj]s$": ["ts-jest", { tsconfig: "/tsconfig.spec.json" }], + }, + moduleFileExtensions: ["ts", "js", "html"], + coverageDirectory: "../../coverage/libs/user-core", +}; diff --git a/libs/user-core/package.json b/libs/user-core/package.json new file mode 100644 index 00000000000..2251d2ceace --- /dev/null +++ b/libs/user-core/package.json @@ -0,0 +1,10 @@ +{ + "name": "@bitwarden/user-core", + "version": "0.0.0", + "description": "The very basic concept that constitutes a user, this needs to be very low level to facilitate Platform keeping their own code low level.", + "type": "commonjs", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "license": "GPL-3.0", + "author": "auth" +} diff --git a/libs/user-core/project.json b/libs/user-core/project.json new file mode 100644 index 00000000000..60d5873208d --- /dev/null +++ b/libs/user-core/project.json @@ -0,0 +1,27 @@ +{ + "name": "user-core", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/user-core/src", + "projectType": "library", + "tags": [], + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/libs/user-core", + "main": "libs/user-core/src/index.ts", + "tsConfig": "libs/user-core/tsconfig.lib.json", + "assets": ["libs/user-core/*.md"] + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/user-core/jest.config.js", + "passWithNoTests": true + } + } + } +} diff --git a/libs/user-core/src/index.ts b/libs/user-core/src/index.ts new file mode 100644 index 00000000000..42e663c851a --- /dev/null +++ b/libs/user-core/src/index.ts @@ -0,0 +1,9 @@ +import { Opaque } from "type-fest"; + +/** + * The main identifier for a user. It is a string that should be in valid guid format. + * + * You should avoid `as UserId`-ing strings as much as possible and instead retrieve the {@see UserId} from + * a valid source instead. + */ +export type UserId = Opaque; diff --git a/libs/user-core/tsconfig.json b/libs/user-core/tsconfig.json new file mode 100644 index 00000000000..62ebbd94647 --- /dev/null +++ b/libs/user-core/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/libs/user-core/tsconfig.lib.json b/libs/user-core/tsconfig.lib.json new file mode 100644 index 00000000000..9cbf6736007 --- /dev/null +++ b/libs/user-core/tsconfig.lib.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["jest.config.js", "src/**/*.spec.ts"] +} diff --git a/libs/user-core/tsconfig.spec.json b/libs/user-core/tsconfig.spec.json new file mode 100644 index 00000000000..1275f148a18 --- /dev/null +++ b/libs/user-core/tsconfig.spec.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "moduleResolution": "node10", + "types": ["jest", "node"] + }, + "include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"] +} diff --git a/package-lock.json b/package-lock.json index e9701cbd7ee..d7c23e0997b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -427,6 +427,10 @@ "version": "0.0.0", "license": "GPL-3.0" }, + "libs/user-core": { + "version": "0.0.0", + "license": "GPL-3.0" + }, "libs/vault": { "name": "@bitwarden/vault", "version": "0.0.0", @@ -4640,6 +4644,10 @@ "resolved": "libs/ui/common", "link": true }, + "node_modules/@bitwarden/user-core": { + "resolved": "libs/user-core", + "link": true + }, "node_modules/@bitwarden/vault": { "resolved": "libs/vault", "link": true diff --git a/tsconfig.base.json b/tsconfig.base.json index c820306fd15..c462ab97d37 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -47,6 +47,7 @@ "@bitwarden/storage-test-utils": ["libs/storage-test-utils/src/index.ts"], "@bitwarden/ui-common": ["./libs/ui/common/src"], "@bitwarden/ui-common/setup-jest": ["./libs/ui/common/src/setup-jest"], + "@bitwarden/user-core": ["libs/user-core/src/index.ts"], "@bitwarden/vault": ["./libs/vault/src"], "@bitwarden/vault-export-core": ["./libs/tools/export/vault-export/vault-export-core/src"], "@bitwarden/vault-export-ui": ["./libs/tools/export/vault-export/vault-export-ui/src"], From 586d91e81676b2be27fefa0321cbc2420f1012e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Tue, 1 Jul 2025 22:02:57 +0200 Subject: [PATCH 039/239] Redact SignalR token from logs (#15402) --- .../internal/signalr-connection.service.ts | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/libs/common/src/platform/notifications/internal/signalr-connection.service.ts b/libs/common/src/platform/notifications/internal/signalr-connection.service.ts index 8bea98cb506..58d6311c668 100644 --- a/libs/common/src/platform/notifications/internal/signalr-connection.service.ts +++ b/libs/common/src/platform/notifications/internal/signalr-connection.service.ts @@ -31,22 +31,35 @@ export type TimeoutManager = { class SignalRLogger implements ILogger { constructor(private readonly logService: LogService) {} + redactMessage(message: string): string { + const ACCESS_TOKEN_TEXT = "access_token="; + // Redact the access token from the logs if it exists. + const accessTokenIndex = message.indexOf(ACCESS_TOKEN_TEXT); + if (accessTokenIndex !== -1) { + return message.substring(0, accessTokenIndex + ACCESS_TOKEN_TEXT.length) + "[REDACTED]"; + } + + return message; + } + log(logLevel: LogLevel, message: string): void { + const redactedMessage = `[SignalR] ${this.redactMessage(message)}`; + switch (logLevel) { case LogLevel.Critical: - this.logService.error(message); + this.logService.error(redactedMessage); break; case LogLevel.Error: - this.logService.error(message); + this.logService.error(redactedMessage); break; case LogLevel.Warning: - this.logService.warning(message); + this.logService.warning(redactedMessage); break; case LogLevel.Information: - this.logService.info(message); + this.logService.info(redactedMessage); break; case LogLevel.Debug: - this.logService.debug(message); + this.logService.debug(redactedMessage); break; } } From 3f7cb674afd1cb1452cf615d218eb638f2423418 Mon Sep 17 00:00:00 2001 From: Tyler <71953103+fntyler@users.noreply.github.com> Date: Tue, 1 Jul 2025 16:31:59 -0400 Subject: [PATCH 040/239] BRE-883 build(firefox): check file size (#15399) * build(firefox): check file size if building `firefox` or `firefox-mv3` * check if any file(s) exceeds 4M (megabytes) - If true, fail and provide basic message. * style: add clarity sytle: add error message * fix: relocate step ensure final step of source files before validating * test: add failure condition * fix: source file target directory * fix: test for failure condition * test: remove failure condition remove lines used for testing --- .github/workflows/build-browser.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.github/workflows/build-browser.yml b/.github/workflows/build-browser.yml index ea113f8b9a5..c75298a3e92 100644 --- a/.github/workflows/build-browser.yml +++ b/.github/workflows/build-browser.yml @@ -268,6 +268,29 @@ jobs: working-directory: browser-source/ run: npm link ../sdk-internal + - name: Check source file size + if: ${{ startsWith(matrix.name, 'firefox') }} + run: | + # Declare variable as indexed array + declare -a FILES + + # Search for source files that are greater than 4M + TARGET_DIR='./browser-source/apps/browser' + while IFS=' ' read -r RESULT; do + FILES+=("$RESULT") + done < <(find $TARGET_DIR -size +4M) + + # Validate results and provide messaging + if [[ ${#FILES[@]} -ne 0 ]]; then + echo "File(s) exceeds size limit: 4MB" + for FILE in ${FILES[@]}; do + echo "- $(du --si $FILE)" + done + echo "ERROR Firefox rejects extension uploads that contain files larger than 4MB" + # Invoke failure + exit 1 + fi + - name: Build extension run: npm run ${{ matrix.npm_command }} working-directory: browser-source/apps/browser From 616ac9a3c8e6ab613933236c3f5dee18d9bc9525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Tue, 1 Jul 2025 22:36:18 +0200 Subject: [PATCH 041/239] Fix Clippy 1.88 warnings (#15396) * Fix Clippy 1.88 warnings * Fmt --- .../desktop_native/core/src/ssh_agent/mod.rs | 9 ++++----- .../desktop_native/core/src/ssh_agent/unix.rs | 20 ++++--------------- .../desktop_native/macos_provider/src/lib.rs | 3 +-- apps/desktop/desktop_native/napi/src/lib.rs | 4 ++-- apps/desktop/desktop_native/objc/src/lib.rs | 8 ++------ apps/desktop/desktop_native/proxy/src/main.rs | 4 ++-- 6 files changed, 15 insertions(+), 33 deletions(-) diff --git a/apps/desktop/desktop_native/core/src/ssh_agent/mod.rs b/apps/desktop/desktop_native/core/src/ssh_agent/mod.rs index 5f794b49c73..63348904e46 100644 --- a/apps/desktop/desktop_native/core/src/ssh_agent/mod.rs +++ b/apps/desktop/desktop_native/core/src/ssh_agent/mod.rs @@ -51,7 +51,7 @@ impl ssh_agent::Agent for BitwardenDesktopAgent { let request_data = match request_parser::parse_request(data) { Ok(data) => data, Err(e) => { - println!("[SSH Agent] Error while parsing request: {}", e); + println!("[SSH Agent] Error while parsing request: {e}"); return false; } }; @@ -178,7 +178,7 @@ impl BitwardenDesktopAgent { ); } Err(e) => { - eprintln!("[SSH Agent Native Module] Error while parsing key: {}", e); + eprintln!("[SSH Agent Native Module] Error while parsing key: {e}"); } } } @@ -234,10 +234,9 @@ fn parse_key_safe(pem: &str) -> Result match key.public_key().to_bytes() { Ok(_) => Ok(key), Err(e) => Err(anyhow::Error::msg(format!( - "Failed to parse public key: {}", - e + "Failed to parse public key: {e}" ))), }, - Err(e) => Err(anyhow::Error::msg(format!("Failed to parse key: {}", e))), + Err(e) => Err(anyhow::Error::msg(format!("Failed to parse key: {e}"))), } } diff --git a/apps/desktop/desktop_native/core/src/ssh_agent/unix.rs b/apps/desktop/desktop_native/core/src/ssh_agent/unix.rs index 6644da508f4..ed297a9002f 100644 --- a/apps/desktop/desktop_native/core/src/ssh_agent/unix.rs +++ b/apps/desktop/desktop_native/core/src/ssh_agent/unix.rs @@ -65,16 +65,10 @@ impl BitwardenDesktopAgent { } }; - println!( - "[SSH Agent Native Module] Starting SSH Agent server on {:?}", - ssh_path - ); + println!("[SSH Agent Native Module] Starting SSH Agent server on {ssh_path:?}"); let sockname = std::path::Path::new(&ssh_path); if let Err(e) = std::fs::remove_file(sockname) { - println!( - "[SSH Agent Native Module] Could not remove existing socket file: {}", - e - ); + println!("[SSH Agent Native Module] Could not remove existing socket file: {e}"); if e.kind() != std::io::ErrorKind::NotFound { return; } @@ -85,10 +79,7 @@ impl BitwardenDesktopAgent { // Only the current user should be able to access the socket if let Err(e) = fs::set_permissions(sockname, fs::Permissions::from_mode(0o600)) { - println!( - "[SSH Agent Native Module] Could not set socket permissions: {}", - e - ); + println!("[SSH Agent Native Module] Could not set socket permissions: {e}"); return; } @@ -112,10 +103,7 @@ impl BitwardenDesktopAgent { println!("[SSH Agent Native Module] SSH Agent server exited"); } Err(e) => { - eprintln!( - "[SSH Agent Native Module] Error while starting agent server: {}", - e - ); + eprintln!("[SSH Agent Native Module] Error while starting agent server: {e}"); } } }); diff --git a/apps/desktop/desktop_native/macos_provider/src/lib.rs b/apps/desktop/desktop_native/macos_provider/src/lib.rs index 8f2499ae68d..32d2514f1dd 100644 --- a/apps/desktop/desktop_native/macos_provider/src/lib.rs +++ b/apps/desktop/desktop_native/macos_provider/src/lib.rs @@ -214,8 +214,7 @@ impl MacOSProviderClient { .remove(&sequence_number) { cb.error(BitwardenError::Internal(format!( - "Error sending message: {}", - e + "Error sending message: {e}" ))); } } diff --git a/apps/desktop/desktop_native/napi/src/lib.rs b/apps/desktop/desktop_native/napi/src/lib.rs index e538dc8d432..fb80ec451a4 100644 --- a/apps/desktop/desktop_native/napi/src/lib.rs +++ b/apps/desktop/desktop_native/napi/src/lib.rs @@ -237,7 +237,7 @@ pub mod sshagent { .expect("should be able to send auth response to agent"); } Err(e) => { - println!("[SSH Agent Native Module] calling UI callback promise was rejected: {}", e); + println!("[SSH Agent Native Module] calling UI callback promise was rejected: {e}"); let _ = auth_response_tx_arc .lock() .await @@ -246,7 +246,7 @@ pub mod sshagent { } }, Err(e) => { - println!("[SSH Agent Native Module] calling UI callback could not create promise: {}", e); + println!("[SSH Agent Native Module] calling UI callback could not create promise: {e}"); let _ = auth_response_tx_arc .lock() .await diff --git a/apps/desktop/desktop_native/objc/src/lib.rs b/apps/desktop/desktop_native/objc/src/lib.rs index f5a7623cfc3..60e48760da8 100644 --- a/apps/desktop/desktop_native/objc/src/lib.rs +++ b/apps/desktop/desktop_native/objc/src/lib.rs @@ -80,8 +80,7 @@ mod objc { Ok(value) => value, Err(e) => { println!( - "Error: Failed to convert ObjCString to Rust string during commandReturn: {}", - e + "Error: Failed to convert ObjCString to Rust string during commandReturn: {e}" ); return false; @@ -91,10 +90,7 @@ mod objc { match context.send(value) { Ok(_) => 0, Err(e) => { - println!( - "Error: Failed to return ObjCString from ObjC code to Rust code: {}", - e - ); + println!("Error: Failed to return ObjCString from ObjC code to Rust code: {e}"); return false; } diff --git a/apps/desktop/desktop_native/proxy/src/main.rs b/apps/desktop/desktop_native/proxy/src/main.rs index ba29e00cf13..7b3337cce71 100644 --- a/apps/desktop/desktop_native/proxy/src/main.rs +++ b/apps/desktop/desktop_native/proxy/src/main.rs @@ -29,12 +29,12 @@ fn init_logging(log_path: &Path, console_level: LevelFilter, file_level: LevelFi loggers.push(simplelog::WriteLogger::new(file_level, config, file)); } Err(e) => { - eprintln!("Can't create file: {}", e); + eprintln!("Can't create file: {e}"); } } if let Err(e) = CombinedLogger::init(loggers) { - eprintln!("Failed to initialize logger: {}", e); + eprintln!("Failed to initialize logger: {e}"); } } From 5497063e7e79fd74c7dbef7ee3d30ba34b6bce52 Mon Sep 17 00:00:00 2001 From: Addison Beck Date: Tue, 1 Jul 2025 19:23:34 -0400 Subject: [PATCH 042/239] refactor(state): point storage imports to @bitwarden/storage-core (#15414) This change updates every import of StorageServiceProvider, AbstractStorageService, and ObservableStorageService throughout the common state code (including spec files) to pull from the new @bitwarden/storage-core package instead of their old relative paths. The cuts out one of the issues that needs to be resolved before state can hold its own as a library without importing common. --- .../implementations/default-active-user-state.spec.ts | 3 ++- .../implementations/default-global-state.provider.ts | 3 ++- .../state/implementations/default-global-state.ts | 6 ++---- .../implementations/default-single-user-state.provider.ts | 3 ++- .../state/implementations/default-single-user-state.ts | 6 ++---- .../state/implementations/specific-state.provider.spec.ts | 3 ++- .../src/platform/state/implementations/state-base.ts | 6 ++---- libs/common/src/platform/state/implementations/util.ts | 2 +- .../platform/state/state-event-registrar.service.spec.ts | 8 ++++++-- .../src/platform/state/state-event-runner.service.spec.ts | 8 ++++++-- .../src/platform/state/state-event-runner.service.ts | 3 ++- 11 files changed, 29 insertions(+), 22 deletions(-) diff --git a/libs/common/src/platform/state/implementations/default-active-user-state.spec.ts b/libs/common/src/platform/state/implementations/default-active-user-state.spec.ts index b73415d6b79..1cb1453a509 100644 --- a/libs/common/src/platform/state/implementations/default-active-user-state.spec.ts +++ b/libs/common/src/platform/state/implementations/default-active-user-state.spec.ts @@ -6,12 +6,13 @@ import { any, mock } from "jest-mock-extended"; import { BehaviorSubject, firstValueFrom, map, of, timeout } from "rxjs"; import { Jsonify } from "type-fest"; +import { StorageServiceProvider } from "@bitwarden/storage-core"; + import { awaitAsync, trackEmissions } from "../../../../spec"; import { FakeStorageService } from "../../../../spec/fake-storage.service"; import { Account } from "../../../auth/abstractions/account.service"; import { UserId } from "../../../types/guid"; import { LogService } from "../../abstractions/log.service"; -import { StorageServiceProvider } from "../../services/storage-service.provider"; import { StateDefinition } from "../state-definition"; import { StateEventRegistrarService } from "../state-event-registrar.service"; import { UserKeyDefinition } from "../user-key-definition"; diff --git a/libs/common/src/platform/state/implementations/default-global-state.provider.ts b/libs/common/src/platform/state/implementations/default-global-state.provider.ts index 18e9c21e75e..bd0cfc1dc9a 100644 --- a/libs/common/src/platform/state/implementations/default-global-state.provider.ts +++ b/libs/common/src/platform/state/implementations/default-global-state.provider.ts @@ -1,7 +1,8 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore +import { StorageServiceProvider } from "@bitwarden/storage-core"; + import { LogService } from "../../abstractions/log.service"; -import { StorageServiceProvider } from "../../services/storage-service.provider"; import { GlobalState } from "../global-state"; import { GlobalStateProvider } from "../global-state.provider"; import { KeyDefinition } from "../key-definition"; diff --git a/libs/common/src/platform/state/implementations/default-global-state.ts b/libs/common/src/platform/state/implementations/default-global-state.ts index c88e9303c8e..a06eb23e010 100644 --- a/libs/common/src/platform/state/implementations/default-global-state.ts +++ b/libs/common/src/platform/state/implementations/default-global-state.ts @@ -1,8 +1,6 @@ +import { AbstractStorageService, ObservableStorageService } from "@bitwarden/storage-core"; + import { LogService } from "../../abstractions/log.service"; -import { - AbstractStorageService, - ObservableStorageService, -} from "../../abstractions/storage.service"; import { GlobalState } from "../global-state"; import { KeyDefinition, globalKeyBuilder } from "../key-definition"; diff --git a/libs/common/src/platform/state/implementations/default-single-user-state.provider.ts b/libs/common/src/platform/state/implementations/default-single-user-state.provider.ts index 54e268e0b69..bef56ad2309 100644 --- a/libs/common/src/platform/state/implementations/default-single-user-state.provider.ts +++ b/libs/common/src/platform/state/implementations/default-single-user-state.provider.ts @@ -1,8 +1,9 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore +import { StorageServiceProvider } from "@bitwarden/storage-core"; + import { UserId } from "../../../types/guid"; import { LogService } from "../../abstractions/log.service"; -import { StorageServiceProvider } from "../../services/storage-service.provider"; import { StateEventRegistrarService } from "../state-event-registrar.service"; import { UserKeyDefinition } from "../user-key-definition"; import { SingleUserState } from "../user-state"; diff --git a/libs/common/src/platform/state/implementations/default-single-user-state.ts b/libs/common/src/platform/state/implementations/default-single-user-state.ts index 1dafd3aecad..db776c3d11d 100644 --- a/libs/common/src/platform/state/implementations/default-single-user-state.ts +++ b/libs/common/src/platform/state/implementations/default-single-user-state.ts @@ -1,11 +1,9 @@ import { Observable, combineLatest, of } from "rxjs"; +import { AbstractStorageService, ObservableStorageService } from "@bitwarden/storage-core"; + import { UserId } from "../../../types/guid"; import { LogService } from "../../abstractions/log.service"; -import { - AbstractStorageService, - ObservableStorageService, -} from "../../abstractions/storage.service"; import { StateEventRegistrarService } from "../state-event-registrar.service"; import { UserKeyDefinition } from "../user-key-definition"; import { CombinedState, SingleUserState } from "../user-state"; diff --git a/libs/common/src/platform/state/implementations/specific-state.provider.spec.ts b/libs/common/src/platform/state/implementations/specific-state.provider.spec.ts index 1b5a36445c9..6674c2577d7 100644 --- a/libs/common/src/platform/state/implementations/specific-state.provider.spec.ts +++ b/libs/common/src/platform/state/implementations/specific-state.provider.spec.ts @@ -1,10 +1,11 @@ import { mock } from "jest-mock-extended"; +import { StorageServiceProvider } from "@bitwarden/storage-core"; + import { mockAccountServiceWith } from "../../../../spec/fake-account-service"; import { FakeStorageService } from "../../../../spec/fake-storage.service"; import { UserId } from "../../../types/guid"; import { LogService } from "../../abstractions/log.service"; -import { StorageServiceProvider } from "../../services/storage-service.provider"; import { KeyDefinition } from "../key-definition"; import { StateDefinition } from "../state-definition"; import { StateEventRegistrarService } from "../state-event-registrar.service"; diff --git a/libs/common/src/platform/state/implementations/state-base.ts b/libs/common/src/platform/state/implementations/state-base.ts index 578720a2281..03140e1fe1f 100644 --- a/libs/common/src/platform/state/implementations/state-base.ts +++ b/libs/common/src/platform/state/implementations/state-base.ts @@ -15,12 +15,10 @@ import { } from "rxjs"; import { Jsonify } from "type-fest"; +import { AbstractStorageService, ObservableStorageService } from "@bitwarden/storage-core"; + import { StorageKey } from "../../../types/state"; import { LogService } from "../../abstractions/log.service"; -import { - AbstractStorageService, - ObservableStorageService, -} from "../../abstractions/storage.service"; import { DebugOptions } from "../key-definition"; import { populateOptionsWithDefault, StateUpdateOptions } from "../state-update-options"; diff --git a/libs/common/src/platform/state/implementations/util.ts b/libs/common/src/platform/state/implementations/util.ts index 0a9d76f6da5..14b11f6b553 100644 --- a/libs/common/src/platform/state/implementations/util.ts +++ b/libs/common/src/platform/state/implementations/util.ts @@ -1,6 +1,6 @@ import { Jsonify } from "type-fest"; -import { AbstractStorageService } from "../../abstractions/storage.service"; +import { AbstractStorageService } from "@bitwarden/storage-core"; export async function getStoredValue( key: string, diff --git a/libs/common/src/platform/state/state-event-registrar.service.spec.ts b/libs/common/src/platform/state/state-event-registrar.service.spec.ts index 2fae985033b..b022e2ce413 100644 --- a/libs/common/src/platform/state/state-event-registrar.service.spec.ts +++ b/libs/common/src/platform/state/state-event-registrar.service.spec.ts @@ -1,8 +1,12 @@ import { mock } from "jest-mock-extended"; +import { + AbstractStorageService, + ObservableStorageService, + StorageServiceProvider, +} from "@bitwarden/storage-core"; + import { FakeGlobalStateProvider } from "../../../spec"; -import { AbstractStorageService, ObservableStorageService } from "../abstractions/storage.service"; -import { StorageServiceProvider } from "../services/storage-service.provider"; import { StateDefinition } from "./state-definition"; import { STATE_LOCK_EVENT, StateEventRegistrarService } from "./state-event-registrar.service"; diff --git a/libs/common/src/platform/state/state-event-runner.service.spec.ts b/libs/common/src/platform/state/state-event-runner.service.spec.ts index 1c98099a518..4aef3d8516c 100644 --- a/libs/common/src/platform/state/state-event-runner.service.spec.ts +++ b/libs/common/src/platform/state/state-event-runner.service.spec.ts @@ -1,9 +1,13 @@ import { mock } from "jest-mock-extended"; +import { + AbstractStorageService, + ObservableStorageService, + StorageServiceProvider, +} from "@bitwarden/storage-core"; + import { FakeGlobalStateProvider } from "../../../spec"; import { UserId } from "../../types/guid"; -import { AbstractStorageService, ObservableStorageService } from "../abstractions/storage.service"; -import { StorageServiceProvider } from "../services/storage-service.provider"; import { STATE_LOCK_EVENT } from "./state-event-registrar.service"; import { StateEventRunnerService } from "./state-event-runner.service"; diff --git a/libs/common/src/platform/state/state-event-runner.service.ts b/libs/common/src/platform/state/state-event-runner.service.ts index f24c50f86d6..9e6f8f214e1 100644 --- a/libs/common/src/platform/state/state-event-runner.service.ts +++ b/libs/common/src/platform/state/state-event-runner.service.ts @@ -2,8 +2,9 @@ // @ts-strict-ignore import { firstValueFrom } from "rxjs"; +import { StorageServiceProvider } from "@bitwarden/storage-core"; + import { UserId } from "../../types/guid"; -import { StorageServiceProvider } from "../services/storage-service.provider"; import { GlobalState } from "./global-state"; import { GlobalStateProvider } from "./global-state.provider"; From 1837974e0a86be48b519c9974476f4fb9a995bff Mon Sep 17 00:00:00 2001 From: SmithThe4th Date: Wed, 2 Jul 2025 09:41:35 -0400 Subject: [PATCH 043/239] show failed to decrypt dialog when viewing a cipher on desktop (#15405) --- apps/desktop/src/vault/app/vault/vault-v2.component.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/desktop/src/vault/app/vault/vault-v2.component.ts b/apps/desktop/src/vault/app/vault/vault-v2.component.ts index 1248f32d1ac..2d741944071 100644 --- a/apps/desktop/src/vault/app/vault/vault-v2.component.ts +++ b/apps/desktop/src/vault/app/vault/vault-v2.component.ts @@ -388,6 +388,13 @@ export class VaultV2Component implements OnInit, OnDestroy, CopyClickListener { } async viewCipher(cipher: CipherView) { + if (cipher.decryptionFailure) { + DecryptionFailureDialogComponent.open(this.dialogService, { + cipherIds: [cipher.id as CipherId], + }); + return; + } + if (await this.shouldReprompt(cipher, "view")) { return; } From cc65f5efc6a417acea6e6349e3e3d97783f20139 Mon Sep 17 00:00:00 2001 From: rr-bw <102181210+rr-bw@users.noreply.github.com> Date: Wed, 2 Jul 2025 07:23:45 -0700 Subject: [PATCH 044/239] feat(set-initial-password): [Auth/PM-18784] SetInitialPasswordComponent Handle TDE Offboarding (#14861) This PR makes it so that `SetInitialPasswordComponent` handles the TDE offboarding flow where an org user now needs to set an initial master password. Feature flag: `PM16117_SetInitialPasswordRefactor` --- ...initial-password.service.implementation.ts | 42 +++++ ...fault-set-initial-password.service.spec.ts | 132 ++++++++++++++-- .../set-initial-password.component.html | 7 +- .../set-initial-password.component.ts | 148 ++++++++++++------ ...et-initial-password.service.abstraction.ts | 25 +++ .../src/auth/utils/assert-non-nullish.util.ts | 45 ++++++ .../src/auth/utils/assert-truthy.util.ts | 46 ++++++ libs/common/src/auth/utils/index.ts | 2 + 8 files changed, 391 insertions(+), 56 deletions(-) create mode 100644 libs/common/src/auth/utils/assert-non-nullish.util.ts create mode 100644 libs/common/src/auth/utils/assert-truthy.util.ts create mode 100644 libs/common/src/auth/utils/index.ts diff --git a/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.implementation.ts b/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.implementation.ts index 1c5edb00c8c..dd81f560939 100644 --- a/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.implementation.ts +++ b/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.implementation.ts @@ -14,6 +14,7 @@ import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-conso import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; import { SetPasswordRequest } from "@bitwarden/common/auth/models/request/set-password.request"; +import { UpdateTdeOffboardingPasswordRequest } from "@bitwarden/common/auth/models/request/update-tde-offboarding-password.request"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { KeysRequest } from "@bitwarden/common/models/request/keys.request"; @@ -28,6 +29,7 @@ import { SetInitialPasswordService, SetInitialPasswordCredentials, SetInitialPasswordUserType, + SetInitialPasswordTdeOffboardingCredentials, } from "./set-initial-password.service.abstraction"; export class DefaultSetInitialPasswordService implements SetInitialPasswordService { @@ -245,4 +247,44 @@ export class DefaultSetInitialPasswordService implements SetInitialPasswordServi enrollmentRequest, ); } + + async setInitialPasswordTdeOffboarding( + credentials: SetInitialPasswordTdeOffboardingCredentials, + userId: UserId, + ) { + const { newMasterKey, newServerMasterKeyHash, newPasswordHint } = credentials; + for (const [key, value] of Object.entries(credentials)) { + if (value == null) { + throw new Error(`${key} not found. Could not set password.`); + } + } + + if (userId == null) { + throw new Error("userId not found. Could not set password."); + } + + const userKey = await firstValueFrom(this.keyService.userKey$(userId)); + if (userKey == null) { + throw new Error("userKey not found. Could not set password."); + } + + const newMasterKeyEncryptedUserKey = await this.keyService.encryptUserKeyWithMasterKey( + newMasterKey, + userKey, + ); + + if (!newMasterKeyEncryptedUserKey[1].encryptedString) { + throw new Error("newMasterKeyEncryptedUserKey not found. Could not set password."); + } + + const request = new UpdateTdeOffboardingPasswordRequest(); + request.key = newMasterKeyEncryptedUserKey[1].encryptedString; + request.newMasterPasswordHash = newServerMasterKeyHash; + request.masterPasswordHint = newPasswordHint; + + await this.masterPasswordApiService.putUpdateTdeOffboardingPassword(request); + + // Clear force set password reason to allow navigation back to vault. + await this.masterPasswordService.setForceSetPasswordReason(ForceSetPasswordReason.None, userId); + } } diff --git a/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.spec.ts b/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.spec.ts index ca4d9adbd67..979dc5ee82f 100644 --- a/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.spec.ts +++ b/libs/angular/src/auth/password-management/set-initial-password/default-set-initial-password.service.spec.ts @@ -19,6 +19,7 @@ import { OrganizationKeysResponse } from "@bitwarden/common/admin-console/models import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; import { SetPasswordRequest } from "@bitwarden/common/auth/models/request/set-password.request"; +import { UpdateTdeOffboardingPasswordRequest } from "@bitwarden/common/auth/models/request/update-tde-offboarding-password.request"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { KeysRequest } from "@bitwarden/common/models/request/keys.request"; @@ -35,6 +36,7 @@ import { DefaultSetInitialPasswordService } from "./default-set-initial-password import { SetInitialPasswordCredentials, SetInitialPasswordService, + SetInitialPasswordTdeOffboardingCredentials, SetInitialPasswordUserType, } from "./set-initial-password.service.abstraction"; @@ -52,6 +54,11 @@ describe("DefaultSetInitialPasswordService", () => { let organizationUserApiService: MockProxy; let userDecryptionOptionsService: MockProxy; + let userId: UserId; + let userKey: UserKey; + let userKeyEncString: EncString; + let masterKeyEncryptedUserKey: [UserKey, EncString]; + beforeEach(() => { apiService = mock(); encryptService = mock(); @@ -64,6 +71,11 @@ describe("DefaultSetInitialPasswordService", () => { organizationUserApiService = mock(); userDecryptionOptionsService = mock(); + userId = "userId" as UserId; + userKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as UserKey; + userKeyEncString = new EncString("masterKeyEncryptedUserKey"); + masterKeyEncryptedUserKey = [userKey, userKeyEncString]; + sut = new DefaultSetInitialPasswordService( apiService, encryptService, @@ -86,13 +98,8 @@ describe("DefaultSetInitialPasswordService", () => { // Mock function parameters let credentials: SetInitialPasswordCredentials; let userType: SetInitialPasswordUserType; - let userId: UserId; // Mock other function data - let userKey: UserKey; - let userKeyEncString: EncString; - let masterKeyEncryptedUserKey: [UserKey, EncString]; - let existingUserPublicKey: UserPublicKey; let existingUserPrivateKey: UserPrivateKey; let userKeyEncryptedPrivateKey: EncString; @@ -121,14 +128,9 @@ describe("DefaultSetInitialPasswordService", () => { orgId: "orgId", resetPasswordAutoEnroll: false, }; - userId = "userId" as UserId; userType = SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER; // Mock other function data - userKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as UserKey; - userKeyEncString = new EncString("masterKeyEncryptedUserKey"); - masterKeyEncryptedUserKey = [userKey, userKeyEncString]; - existingUserPublicKey = Utils.fromB64ToArray("existingUserPublicKey") as UserPublicKey; existingUserPrivateKey = Utils.fromB64ToArray("existingUserPrivateKey") as UserPrivateKey; userKeyEncryptedPrivateKey = new EncString("userKeyEncryptedPrivateKey"); @@ -630,4 +632,114 @@ describe("DefaultSetInitialPasswordService", () => { }); }); }); + + describe("setInitialPasswordTdeOffboarding(...)", () => { + // Mock function parameters + let credentials: SetInitialPasswordTdeOffboardingCredentials; + + beforeEach(() => { + // Mock function parameters + credentials = { + newMasterKey: new SymmetricCryptoKey(new Uint8Array(32).buffer as CsprngArray) as MasterKey, + newServerMasterKeyHash: "newServerMasterKeyHash", + newPasswordHint: "newPasswordHint", + }; + }); + + function setupTdeOffboardingMocks() { + keyService.userKey$.mockReturnValue(of(userKey)); + keyService.encryptUserKeyWithMasterKey.mockResolvedValue(masterKeyEncryptedUserKey); + } + + it("should successfully set an initial password for the TDE offboarding user", async () => { + // Arrange + setupTdeOffboardingMocks(); + + const request = new UpdateTdeOffboardingPasswordRequest(); + request.key = masterKeyEncryptedUserKey[1].encryptedString; + request.newMasterPasswordHash = credentials.newServerMasterKeyHash; + request.masterPasswordHint = credentials.newPasswordHint; + + // Act + await sut.setInitialPasswordTdeOffboarding(credentials, userId); + + // Assert + expect(masterPasswordApiService.putUpdateTdeOffboardingPassword).toHaveBeenCalledTimes(1); + expect(masterPasswordApiService.putUpdateTdeOffboardingPassword).toHaveBeenCalledWith( + request, + ); + }); + + describe("given the initial password has been successfully set", () => { + it("should clear the ForceSetPasswordReason by setting it to None", async () => { + // Arrange + setupTdeOffboardingMocks(); + + // Act + await sut.setInitialPasswordTdeOffboarding(credentials, userId); + + // Assert + expect(masterPasswordApiService.putUpdateTdeOffboardingPassword).toHaveBeenCalledTimes(1); + expect(masterPasswordService.setForceSetPasswordReason).toHaveBeenCalledWith( + ForceSetPasswordReason.None, + userId, + ); + }); + }); + + describe("general error handling", () => { + ["newMasterKey", "newServerMasterKeyHash", "newPasswordHint"].forEach((key) => { + it(`should throw if ${key} is not provided on the SetInitialPasswordTdeOffboardingCredentials object`, async () => { + // Arrange + const invalidCredentials: SetInitialPasswordTdeOffboardingCredentials = { + ...credentials, + [key]: null, + }; + + // Act + const promise = sut.setInitialPasswordTdeOffboarding(invalidCredentials, userId); + + // Assert + await expect(promise).rejects.toThrow(`${key} not found. Could not set password.`); + }); + }); + + it(`should throw if the userId was not passed in`, async () => { + // Arrange + userId = null; + + // Act + const promise = sut.setInitialPasswordTdeOffboarding(credentials, userId); + + // Assert + await expect(promise).rejects.toThrow("userId not found. Could not set password."); + }); + + it(`should throw if the userKey was not found`, async () => { + // Arrange + keyService.userKey$.mockReturnValue(of(null)); + + // Act + const promise = sut.setInitialPasswordTdeOffboarding(credentials, userId); + + // Assert + await expect(promise).rejects.toThrow("userKey not found. Could not set password."); + }); + + it(`should throw if a newMasterKeyEncryptedUserKey was not returned`, async () => { + // Arrange + masterKeyEncryptedUserKey[1].encryptedString = "" as EncryptedString; + + setupTdeOffboardingMocks(); + + // Act + const promise = sut.setInitialPasswordTdeOffboarding(credentials, userId); + + // Assert + await expect(promise).rejects.toThrow( + "newMasterKeyEncryptedUserKey not found. Could not set password.", + ); + }); + }); + }); }); diff --git a/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.html b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.html index c83cbbe3521..4956f293d1e 100644 --- a/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.html +++ b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.html @@ -21,7 +21,12 @@ [userId]="userId" [loading]="submitting" [masterPasswordPolicyOptions]="masterPasswordPolicyOptions" - [primaryButtonText]="{ key: 'createAccount' }" + [primaryButtonText]="{ + key: + userType === SetInitialPasswordUserType.OFFBOARDED_TDE_ORG_USER + ? 'setPassword' + : 'createAccount', + }" [secondaryButtonText]="{ key: 'logOut' }" (onPasswordFormSubmit)="handlePasswordFormSubmit($event)" (onSecondaryButtonClick)="logout()" diff --git a/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.ts b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.ts index fbab9eaa2c3..2de9aaf7b75 100644 --- a/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.ts +++ b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.ts @@ -10,14 +10,20 @@ import { InputPasswordFlow, PasswordInputResult, } from "@bitwarden/auth/angular"; +// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. +// eslint-disable-next-line no-restricted-imports +import { LogoutService } from "@bitwarden/auth/common"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; +import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; +import { assertTruthy, assertNonNullish } from "@bitwarden/common/auth/utils"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; import { SyncService } from "@bitwarden/common/platform/sync"; @@ -33,6 +39,7 @@ import { I18nPipe } from "@bitwarden/ui-common"; import { SetInitialPasswordCredentials, SetInitialPasswordService, + SetInitialPasswordTdeOffboardingCredentials, SetInitialPasswordUserType, } from "./set-initial-password.service.abstraction"; @@ -54,6 +61,7 @@ export class SetInitialPasswordComponent implements OnInit { protected submitting = false; protected userId?: UserId; protected userType?: SetInitialPasswordUserType; + protected SetInitialPasswordUserType = SetInitialPasswordUserType; constructor( private accountService: AccountService, @@ -61,10 +69,13 @@ export class SetInitialPasswordComponent implements OnInit { private anonLayoutWrapperDataService: AnonLayoutWrapperDataService, private dialogService: DialogService, private i18nService: I18nService, + private logoutService: LogoutService, + private logService: LogService, private masterPasswordService: InternalMasterPasswordServiceAbstraction, private messagingService: MessagingService, private organizationApiService: OrganizationApiServiceAbstraction, private policyApiService: PolicyApiServiceAbstraction, + private policyService: PolicyService, private router: Router, private setInitialPasswordService: SetInitialPasswordService, private ssoLoginService: SsoLoginServiceAbstraction, @@ -80,13 +91,13 @@ export class SetInitialPasswordComponent implements OnInit { this.userId = activeAccount?.id; this.email = activeAccount?.email; - await this.determineUserType(); - await this.handleQueryParams(); + await this.establishUserType(); + await this.getOrgInfo(); this.initializing = false; } - private async determineUserType() { + private async establishUserType() { if (!this.userId) { throw new Error("userId not found. Could not determine user type."); } @@ -95,6 +106,14 @@ export class SetInitialPasswordComponent implements OnInit { this.masterPasswordService.forceSetPasswordReason$(this.userId), ); + if (this.forceSetPasswordReason === ForceSetPasswordReason.SsoNewJitProvisionedUser) { + this.userType = SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER; + this.anonLayoutWrapperDataService.setAnonLayoutWrapperData({ + pageTitle: { key: "joinOrganization" }, + pageSubtitle: { key: "finishJoiningThisOrganizationBySettingAMasterPassword" }, + }); + } + if ( this.forceSetPasswordReason === ForceSetPasswordReason.TdeUserWithoutPasswordHasPasswordResetPermission @@ -104,20 +123,35 @@ export class SetInitialPasswordComponent implements OnInit { pageTitle: { key: "setMasterPassword" }, pageSubtitle: { key: "orgPermissionsUpdatedMustSetPassword" }, }); - } else { - this.userType = SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER; + } + + if (this.forceSetPasswordReason === ForceSetPasswordReason.TdeOffboarding) { + this.userType = SetInitialPasswordUserType.OFFBOARDED_TDE_ORG_USER; this.anonLayoutWrapperDataService.setAnonLayoutWrapperData({ - pageTitle: { key: "joinOrganization" }, - pageSubtitle: { key: "finishJoiningThisOrganizationBySettingAMasterPassword" }, + pageTitle: { key: "setMasterPassword" }, + pageSubtitle: { key: "tdeDisabledMasterPasswordRequired" }, }); } + + // If we somehow end up here without a reason, navigate to root + if (this.forceSetPasswordReason === ForceSetPasswordReason.None) { + await this.router.navigate(["/"]); + } } - private async handleQueryParams() { + private async getOrgInfo() { if (!this.userId) { throw new Error("userId not found. Could not handle query params."); } + if (this.userType === SetInitialPasswordUserType.OFFBOARDED_TDE_ORG_USER) { + this.masterPasswordPolicyOptions = + (await firstValueFrom(this.policyService.masterPasswordPolicyOptions$(this.userId))) ?? + null; + + return; + } + const qParams = await firstValueFrom(this.activatedRoute.queryParams); this.orgSsoIdentifier = @@ -146,38 +180,34 @@ export class SetInitialPasswordComponent implements OnInit { protected async handlePasswordFormSubmit(passwordInputResult: PasswordInputResult) { this.submitting = true; - if (!passwordInputResult.newMasterKey) { - throw new Error("newMasterKey not found. Could not set initial password."); - } - if (!passwordInputResult.newServerMasterKeyHash) { - throw new Error("newServerMasterKeyHash not found. Could not set initial password."); - } - if (!passwordInputResult.newLocalMasterKeyHash) { - throw new Error("newLocalMasterKeyHash not found. Could not set initial password."); - } - // newPasswordHint can have an empty string as a valid value, so we specifically check for null or undefined - if (passwordInputResult.newPasswordHint == null) { - throw new Error("newPasswordHint not found. Could not set initial password."); - } - if (!passwordInputResult.kdfConfig) { - throw new Error("kdfConfig not found. Could not set initial password."); - } - if (!this.userId) { - throw new Error("userId not found. Could not set initial password."); - } - if (!this.userType) { - throw new Error("userType not found. Could not set initial password."); - } - if (!this.orgSsoIdentifier) { - throw new Error("orgSsoIdentifier not found. Could not set initial password."); - } - if (!this.orgId) { - throw new Error("orgId not found. Could not set initial password."); - } - // resetPasswordAutoEnroll can have `false` as a valid value, so we specifically check for null or undefined - if (this.resetPasswordAutoEnroll == null) { - throw new Error("resetPasswordAutoEnroll not found. Could not set initial password."); + switch (this.userType) { + case SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER: + case SetInitialPasswordUserType.TDE_ORG_USER_RESET_PASSWORD_PERMISSION_REQUIRES_MP: + await this.setInitialPassword(passwordInputResult); + break; + case SetInitialPasswordUserType.OFFBOARDED_TDE_ORG_USER: + await this.setInitialPasswordTdeOffboarding(passwordInputResult); + break; + default: + this.logService.error( + `Unexpected user type: ${this.userType}. Could not set initial password.`, + ); + this.validationService.showError("Unexpected user type. Could not set initial password."); } + } + + private async setInitialPassword(passwordInputResult: PasswordInputResult) { + const ctx = "Could not set initial password."; + assertTruthy(passwordInputResult.newMasterKey, "newMasterKey", ctx); + assertTruthy(passwordInputResult.newServerMasterKeyHash, "newServerMasterKeyHash", ctx); + assertTruthy(passwordInputResult.newLocalMasterKeyHash, "newLocalMasterKeyHash", ctx); + assertTruthy(passwordInputResult.kdfConfig, "kdfConfig", ctx); + assertTruthy(this.orgSsoIdentifier, "orgSsoIdentifier", ctx); + assertTruthy(this.orgId, "orgId", ctx); + assertTruthy(this.userType, "userType", ctx); + assertTruthy(this.userId, "userId", ctx); + assertNonNullish(passwordInputResult.newPasswordHint, "newPasswordHint", ctx); // can have an empty string as a valid value, so check non-nullish + assertNonNullish(this.resetPasswordAutoEnroll, "resetPasswordAutoEnroll", ctx); // can have `false` as a valid value, so check non-nullish try { const credentials: SetInitialPasswordCredentials = { @@ -202,11 +232,44 @@ export class SetInitialPasswordComponent implements OnInit { this.submitting = false; await this.router.navigate(["vault"]); } catch (e) { + this.logService.error("Error setting initial password", e); this.validationService.showError(e); this.submitting = false; } } + private async setInitialPasswordTdeOffboarding(passwordInputResult: PasswordInputResult) { + const ctx = "Could not set initial password."; + assertTruthy(passwordInputResult.newMasterKey, "newMasterKey", ctx); + assertTruthy(passwordInputResult.newServerMasterKeyHash, "newServerMasterKeyHash", ctx); + assertTruthy(this.userId, "userId", ctx); + assertNonNullish(passwordInputResult.newPasswordHint, "newPasswordHint", ctx); // can have an empty string as a valid value, so check non-nullish + + try { + const credentials: SetInitialPasswordTdeOffboardingCredentials = { + newMasterKey: passwordInputResult.newMasterKey, + newServerMasterKeyHash: passwordInputResult.newServerMasterKeyHash, + newPasswordHint: passwordInputResult.newPasswordHint, + }; + + await this.setInitialPasswordService.setInitialPasswordTdeOffboarding( + credentials, + this.userId, + ); + + this.showSuccessToastByUserType(); + + await this.logoutService.logout(this.userId); + // navigate to root so redirect guard can properly route next active user or null user to correct page + await this.router.navigate(["/"]); + } catch (e) { + this.logService.error("Error setting initial password during TDE offboarding", e); + this.validationService.showError(e); + } finally { + this.submitting = false; + } + } + private showSuccessToastByUserType() { if (this.userType === SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER) { this.toastService.showToast({ @@ -220,12 +283,7 @@ export class SetInitialPasswordComponent implements OnInit { title: "", message: this.i18nService.t("inviteAccepted"), }); - } - - if ( - this.userType === - SetInitialPasswordUserType.TDE_ORG_USER_RESET_PASSWORD_PERMISSION_REQUIRES_MP - ) { + } else { this.toastService.showToast({ variant: "success", title: "", diff --git a/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.service.abstraction.ts b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.service.abstraction.ts index e594053a906..c167c1675c1 100644 --- a/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.service.abstraction.ts +++ b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.service.abstraction.ts @@ -19,6 +19,12 @@ export const _SetInitialPasswordUserType = { */ TDE_ORG_USER_RESET_PASSWORD_PERMISSION_REQUIRES_MP: "tde_org_user_reset_password_permission_requires_mp", + + /** + * A user in an org that offboarded from trusted device encryption and is now a + * master-password-encryption org + */ + OFFBOARDED_TDE_ORG_USER: "offboarded_tde_org_user", } as const; type _SetInitialPasswordUserType = typeof _SetInitialPasswordUserType; @@ -40,6 +46,12 @@ export interface SetInitialPasswordCredentials { resetPasswordAutoEnroll: boolean; } +export interface SetInitialPasswordTdeOffboardingCredentials { + newMasterKey: MasterKey; + newServerMasterKeyHash: string; + newPasswordHint: string; +} + /** * Handles setting an initial password for an existing authed user. * @@ -61,4 +73,17 @@ export abstract class SetInitialPasswordService { userType: SetInitialPasswordUserType, userId: UserId, ) => Promise; + + /** + * Sets an initial password for a user who logs in after their org offboarded from + * trusted device encryption and is now a master-password-encryption org: + * - {@link SetInitialPasswordUserType.OFFBOARDED_TDE_ORG_USER} + * + * @param passwordInputResult credentials object received from the `InputPasswordComponent` + * @param userId the account `userId` + */ + abstract setInitialPasswordTdeOffboarding: ( + credentials: SetInitialPasswordTdeOffboardingCredentials, + userId: UserId, + ) => Promise; } diff --git a/libs/common/src/auth/utils/assert-non-nullish.util.ts b/libs/common/src/auth/utils/assert-non-nullish.util.ts new file mode 100644 index 00000000000..91fb8ef44b8 --- /dev/null +++ b/libs/common/src/auth/utils/assert-non-nullish.util.ts @@ -0,0 +1,45 @@ +/** + * Asserts that a value is non-nullish (not `null` or `undefined`); throws if value is nullish. + * + * @param val the value to check + * @param name the name of the value to include in the error message + * @param ctx context to optionally append to the error message + * @throws if the value is null or undefined + * + * @example + * + * ``` + * // `newPasswordHint` can have an empty string as a valid value, so we check non-nullish + * this.assertNonNullish( + * passwordInputResult.newPasswordHint, + * "newPasswordHint", + * "Could not set initial password." + * ); + * // Output error message: "newPasswordHint is null or undefined. Could not set initial password." + * ``` + * + * @remarks + * + * If you use this method repeatedly to check several values, it may help to assign any + * additional context (`ctx`) to a variable and pass it in to each call. This prevents the + * call from reformatting vertically via prettier in your text editor, taking up multiple lines. + * + * For example: + * ``` + * const ctx = "Could not set initial password."; + * + * this.assertNonNullish(valueOne, "valueOne", ctx); + * this.assertNonNullish(valueTwo, "valueTwo", ctx); + * this.assertNonNullish(valueThree, "valueThree", ctx); + * ``` + */ +export function assertNonNullish( + val: T, + name: string, + ctx?: string, +): asserts val is NonNullable { + if (val == null) { + // If context is provided, append it to the error message with a space before it. + throw new Error(`${name} is null or undefined.${ctx ? ` ${ctx}` : ""}`); + } +} diff --git a/libs/common/src/auth/utils/assert-truthy.util.ts b/libs/common/src/auth/utils/assert-truthy.util.ts new file mode 100644 index 00000000000..8e003186929 --- /dev/null +++ b/libs/common/src/auth/utils/assert-truthy.util.ts @@ -0,0 +1,46 @@ +/** + * Asserts that a value is truthy; throws if value is falsy. + * + * @param val the value to check + * @param name the name of the value to include in the error message + * @param ctx context to optionally append to the error message + * @throws if the value is falsy (`false`, `""`, `0`, `null`, `undefined`, `void`, or `NaN`) + * + * @example + * + * ``` + * this.assertTruthy( + * this.organizationId, + * "organizationId", + * "Could not set initial password." + * ); + * // Output error message: "organizationId is falsy. Could not set initial password." + * ``` + * + * @remarks + * + * If you use this method repeatedly to check several values, it may help to assign any + * additional context (`ctx`) to a variable and pass it in to each call. This prevents the + * call from reformatting vertically via prettier in your text editor, taking up multiple lines. + * + * For example: + * ``` + * const ctx = "Could not set initial password."; + * + * this.assertTruthy(valueOne, "valueOne", ctx); + * this.assertTruthy(valueTwo, "valueTwo", ctx); + * this.assertTruthy(valueThree, "valueThree", ctx); + */ +export function assertTruthy( + val: T, + name: string, + ctx?: string, +): asserts val is Exclude { + // Because `NaN` is a value (not a type) of type 'number', that means we cannot add + // it to the list of falsy values in the type assertion. Instead, we check for it + // separately at runtime. + if (!val || (typeof val === "number" && Number.isNaN(val))) { + // If context is provided, append it to the error message with a space before it. + throw new Error(`${name} is falsy.${ctx ? ` ${ctx}` : ""}`); + } +} diff --git a/libs/common/src/auth/utils/index.ts b/libs/common/src/auth/utils/index.ts new file mode 100644 index 00000000000..96bab53d3f9 --- /dev/null +++ b/libs/common/src/auth/utils/index.ts @@ -0,0 +1,2 @@ +export { assertTruthy } from "./assert-truthy.util"; +export { assertNonNullish } from "./assert-non-nullish.util"; From 0d204fb9f77335f30be185e644476b843e1cfcad Mon Sep 17 00:00:00 2001 From: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com> Date: Wed, 2 Jul 2025 10:30:41 -0400 Subject: [PATCH 045/239] feat(manifest): [Auth/PM-14942] add notifications to requested permissions (#15316) --- apps/browser/src/manifest.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/browser/src/manifest.json b/apps/browser/src/manifest.json index c46674083b2..aa80222c672 100644 --- a/apps/browser/src/manifest.json +++ b/apps/browser/src/manifest.json @@ -56,7 +56,8 @@ "unlimitedStorage", "webNavigation", "webRequest", - "webRequestBlocking" + "webRequestBlocking", + "notifications" ], "__safari__permissions": [ "", From 87a42cc5071109db20794ae7dcfe850059974e79 Mon Sep 17 00:00:00 2001 From: Github Actions Date: Wed, 2 Jul 2025 15:40:45 +0000 Subject: [PATCH 046/239] Bumped Desktop client to 2025.7.0 --- apps/desktop/package.json | 2 +- apps/desktop/src/package-lock.json | 4 ++-- apps/desktop/src/package.json | 2 +- package-lock.json | 4 +++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 4a59d5bbcf0..2ab88fed621 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@bitwarden/desktop", "description": "A secure and free password manager for all of your devices.", - "version": "2025.6.1", + "version": "2025.7.0", "keywords": [ "bitwarden", "password", diff --git a/apps/desktop/src/package-lock.json b/apps/desktop/src/package-lock.json index 128cf94a09d..a4e00046476 100644 --- a/apps/desktop/src/package-lock.json +++ b/apps/desktop/src/package-lock.json @@ -1,12 +1,12 @@ { "name": "@bitwarden/desktop", - "version": "2025.6.1", + "version": "2025.7.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bitwarden/desktop", - "version": "2025.6.1", + "version": "2025.7.0", "license": "GPL-3.0", "dependencies": { "@bitwarden/desktop-napi": "file:../desktop_native/napi" diff --git a/apps/desktop/src/package.json b/apps/desktop/src/package.json index 9c6d5712b6d..0128692f3b4 100644 --- a/apps/desktop/src/package.json +++ b/apps/desktop/src/package.json @@ -2,7 +2,7 @@ "name": "@bitwarden/desktop", "productName": "Bitwarden", "description": "A secure and free password manager for all of your devices.", - "version": "2025.6.1", + "version": "2025.7.0", "author": "Bitwarden Inc. (https://bitwarden.com)", "homepage": "https://bitwarden.com", "license": "GPL-3.0", diff --git a/package-lock.json b/package-lock.json index d7c23e0997b..900dc0d0b00 100644 --- a/package-lock.json +++ b/package-lock.json @@ -288,7 +288,7 @@ }, "apps/desktop": { "name": "@bitwarden/desktop", - "version": "2025.6.1", + "version": "2025.7.0", "hasInstallScript": true, "license": "GPL-3.0" }, @@ -354,6 +354,7 @@ "license": "GPL-3.0" }, "libs/logging": { + "name": "@bitwarden/logging", "version": "0.0.1", "license": "GPL-3.0" }, @@ -428,6 +429,7 @@ "license": "GPL-3.0" }, "libs/user-core": { + "name": "@bitwarden/user-core", "version": "0.0.0", "license": "GPL-3.0" }, From 369c1edaf782fc2799362c79e16cef48aae7b178 Mon Sep 17 00:00:00 2001 From: Jordan Aasen <166539328+jaasen-livefront@users.noreply.github.com> Date: Wed, 2 Jul 2025 08:54:42 -0700 Subject: [PATCH 047/239] [PM-22376] - [Vault] [Clients] Update cipher form component to default to My Items collections (#15356) * fix tests * remove unused code * fix storybook * fix storybook * cleanup * move observable to function. update tests * fix type error * move call to getDefaultCollectionId * fix test --- .../src/cipher-form/cipher-form.stories.ts | 8 +++ .../item-details-section.component.spec.ts | 53 ++++++++++++-- .../item-details-section.component.ts | 71 ++++++++++++++++--- 3 files changed, 115 insertions(+), 17 deletions(-) diff --git a/libs/vault/src/cipher-form/cipher-form.stories.ts b/libs/vault/src/cipher-form/cipher-form.stories.ts index f46eb457e30..25494350dc3 100644 --- a/libs/vault/src/cipher-form/cipher-form.stories.ts +++ b/libs/vault/src/cipher-form/cipher-form.stories.ts @@ -19,6 +19,7 @@ import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; import { NudgeStatus, NudgesService } from "@bitwarden/angular/vault"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; +import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; @@ -243,6 +244,7 @@ export default { provide: ConfigService, useValue: { getFeatureFlag: () => Promise.resolve(false), + getFeatureFlag$: () => new BehaviorSubject(false), }, }, { @@ -253,6 +255,12 @@ export default { }, }, }, + { + provide: PolicyService, + useValue: { + policiesByType$: new BehaviorSubject([]), + }, + }, ], }), componentWrapperDecorator( diff --git a/libs/vault/src/cipher-form/components/item-details/item-details-section.component.spec.ts b/libs/vault/src/cipher-form/components/item-details/item-details-section.component.spec.ts index 12fba0c7409..99c377a0873 100644 --- a/libs/vault/src/cipher-form/components/item-details/item-details-section.component.spec.ts +++ b/libs/vault/src/cipher-form/components/item-details/item-details-section.component.spec.ts @@ -3,18 +3,24 @@ import { ComponentFixture, fakeAsync, TestBed, tick } from "@angular/core/testin import { ReactiveFormsModule } from "@angular/forms"; import { By } from "@angular/platform-browser"; import { mock, MockProxy } from "jest-mock-extended"; -import { BehaviorSubject } from "rxjs"; +import { BehaviorSubject, of } from "rxjs"; // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // eslint-disable-next-line no-restricted-imports import { CollectionTypes, CollectionView } from "@bitwarden/admin-console/common"; +import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; +import { Policy } from "@bitwarden/common/admin-console/models/domain/policy"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { SelectComponent } from "@bitwarden/components"; -import { CipherFormConfig } from "../../abstractions/cipher-form-config.service"; +import { + CipherFormConfig, + OptionalInitialValues, +} from "../../abstractions/cipher-form-config.service"; import { CipherFormContainer } from "../../cipher-form-container"; import { ItemDetailsSectionComponent } from "./item-details-section.component"; @@ -48,6 +54,8 @@ describe("ItemDetailsSectionComponent", () => { let fixture: ComponentFixture; let cipherFormProvider: MockProxy; let i18nService: MockProxy; + let mockConfigService: MockProxy; + let mockPolicyService: MockProxy; const activeAccount$ = new BehaviorSubject<{ email: string }>({ email: "test@example.com" }); const getInitialCipherView = jest.fn(() => null); @@ -66,12 +74,19 @@ describe("ItemDetailsSectionComponent", () => { compare: (a: string, b: string) => a.localeCompare(b), } as Intl.Collator; + mockConfigService = mock(); + mockConfigService.getFeatureFlag$.mockReturnValue(of(true)); + mockPolicyService = mock(); + mockPolicyService.policiesByType$.mockReturnValue(of([])); + await TestBed.configureTestingModule({ imports: [ItemDetailsSectionComponent, CommonModule, ReactiveFormsModule], providers: [ { provide: CipherFormContainer, useValue: cipherFormProvider }, { provide: I18nService, useValue: i18nService }, { provide: AccountService, useValue: { activeAccount$ } }, + { provide: ConfigService, useValue: mockConfigService }, + { provide: PolicyService, useValue: mockPolicyService }, ], }).compileComponents(); @@ -369,7 +384,7 @@ describe("ItemDetailsSectionComponent", () => { expect(collectionSelect).toBeNull(); }); - it("should enable/show collection control when an organization is selected", async () => { + it("should enable/show collection control when an organization is selected", fakeAsync(() => { component.config.organizationDataOwnershipDisabled = true; component.config.organizations = [{ id: "org1" } as Organization]; component.config.collections = [ @@ -378,12 +393,12 @@ describe("ItemDetailsSectionComponent", () => { ]; fixture.detectChanges(); - await fixture.whenStable(); + tick(); component.itemDetailsForm.controls.organizationId.setValue("org1"); + tick(); fixture.detectChanges(); - await fixture.whenStable(); const collectionSelect = fixture.nativeElement.querySelector( "bit-multi-select[formcontrolname='collectionIds']", @@ -391,7 +406,7 @@ describe("ItemDetailsSectionComponent", () => { expect(component.itemDetailsForm.controls.collectionIds.enabled).toBe(true); expect(collectionSelect).not.toBeNull(); - }); + })); it("should set collectionIds to originalCipher collections on first load", async () => { component.config.mode = "clone"; @@ -488,6 +503,9 @@ describe("ItemDetailsSectionComponent", () => { component.itemDetailsForm.controls.organizationId.setValue("org1"); + fixture.detectChanges(); + await fixture.whenStable(); + expect(component["collectionOptions"].map((c) => c.id)).toEqual(["col1", "col2", "col3"]); }); }); @@ -548,4 +566,27 @@ describe("ItemDetailsSectionComponent", () => { expect(label).toBe("org1"); }); }); + + describe("getDefaultCollectionId", () => { + it("returns matching default when flag & policy match", async () => { + const def = createMockCollection("def1", "Def", "orgA"); + component.config.collections = [def] as CollectionView[]; + component.config.initialValues = { collectionIds: [] } as OptionalInitialValues; + mockConfigService.getFeatureFlag.mockResolvedValue(true); + mockPolicyService.policiesByType$.mockReturnValue(of([{ organizationId: "orgA" } as Policy])); + + const id = await (component as any).getDefaultCollectionId("orgA"); + expect(id).toEqual("def1"); + }); + + it("returns undefined when no default found", async () => { + component.config.collections = [createMockCollection("c1", "C1", "orgB")] as CollectionView[]; + component.config.initialValues = { collectionIds: [] } as OptionalInitialValues; + mockConfigService.getFeatureFlag.mockResolvedValue(true); + mockPolicyService.policiesByType$.mockReturnValue(of([{ organizationId: "orgA" } as Policy])); + + const result = await (component as any).getDefaultCollectionId("orgA"); + expect(result).toBeUndefined(); + }); + }); }); diff --git a/libs/vault/src/cipher-form/components/item-details/item-details-section.component.ts b/libs/vault/src/cipher-form/components/item-details/item-details-section.component.ts index 1d30edf27e0..1064980050f 100644 --- a/libs/vault/src/cipher-form/components/item-details/item-details-section.component.ts +++ b/libs/vault/src/cipher-form/components/item-details/item-details-section.component.ts @@ -4,15 +4,19 @@ import { CommonModule } from "@angular/common"; import { Component, DestroyRef, Input, OnInit } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { FormBuilder, FormControl, ReactiveFormsModule, Validators } from "@angular/forms"; -import { concatMap, map } from "rxjs"; +import { concatMap, firstValueFrom, map } from "rxjs"; // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // eslint-disable-next-line no-restricted-imports -import { CollectionView } from "@bitwarden/admin-console/common"; +import { CollectionTypes, CollectionView } from "@bitwarden/admin-console/common"; import { JslibModule } from "@bitwarden/angular/jslib.module"; -import { OrganizationUserType } from "@bitwarden/common/admin-console/enums"; +import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { OrganizationUserType, 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 { getUserId } from "@bitwarden/common/auth/services/account.service"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid"; @@ -124,6 +128,8 @@ export class ItemDetailsSectionComponent implements OnInit { private i18nService: I18nService, private destroyRef: DestroyRef, private accountService: AccountService, + private configService: ConfigService, + private policyService: PolicyService, ) { this.cipherFormContainer.registerChildForm("itemDetails", this.itemDetailsForm); this.itemDetailsForm.valueChanges @@ -200,30 +206,61 @@ export class ItemDetailsSectionComponent implements OnInit { if (prefillCipher) { await this.initFromExistingCipher(prefillCipher); } else { + const orgId = this.initialValues?.organizationId; this.itemDetailsForm.setValue({ name: this.initialValues?.name || "", - organizationId: this.initialValues?.organizationId || this.defaultOwner, + organizationId: orgId || this.defaultOwner, folderId: this.initialValues?.folderId || null, collectionIds: [], favorite: false, }); - await this.updateCollectionOptions(this.initialValues?.collectionIds || []); + await this.updateCollectionOptions(this.initialValues?.collectionIds); } - if (!this.allowOwnershipChange) { this.itemDetailsForm.controls.organizationId.disable(); } - this.itemDetailsForm.controls.organizationId.valueChanges .pipe( takeUntilDestroyed(this.destroyRef), - concatMap(async () => { - await this.updateCollectionOptions(); - }), + concatMap(async () => await this.updateCollectionOptions()), ) .subscribe(); } + /** + * Gets the default collection IDs for the selected organization. + * Returns null if any of the following apply: + * - the feature flag is disabled + * - no org is currently selected + * - the selected org doesn't have the "no private data policy" enabled + */ + private async getDefaultCollectionId(orgId?: OrganizationId) { + if (!orgId) { + return; + } + const isFeatureEnabled = await this.configService.getFeatureFlag( + FeatureFlag.CreateDefaultLocation, + ); + if (!isFeatureEnabled) { + return; + } + const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)); + const selectedOrgHasPolicyEnabled = ( + await firstValueFrom( + this.policyService.policiesByType$(PolicyType.OrganizationDataOwnership, userId), + ) + ).find((p) => p.organizationId); + if (!selectedOrgHasPolicyEnabled) { + return; + } + const defaultUserCollection = this.collections.find( + (c) => c.organizationId === orgId && c.type === CollectionTypes.DefaultUserCollection, + ); + // If the user was added after the policy was enabled as they will not have any private data + // and will not have a default collection. + return defaultUserCollection?.id; + } + private async initFromExistingCipher(prefillCipher: CipherView) { const { name, folderId, collectionIds } = prefillCipher; @@ -332,6 +369,11 @@ export class ItemDetailsSectionComponent implements OnInit { // Non-admins can only select assigned collections that are not read only. (Non-AC) return c.assigned && !c.readOnly; }) + .sort((a, b) => { + const aIsDefaultCollection = a.type === CollectionTypes.DefaultUserCollection ? -1 : 0; + const bIsDefaultCollection = b.type === CollectionTypes.DefaultUserCollection ? -1 : 0; + return aIsDefaultCollection - bIsDefaultCollection; + }) .map((c) => ({ id: c.id, name: c.name, @@ -349,10 +391,17 @@ export class ItemDetailsSectionComponent implements OnInit { return; } - if (startingSelection.length > 0) { + if (startingSelection.filter(Boolean).length > 0) { collectionsControl.setValue( this.collectionOptions.filter((c) => startingSelection.includes(c.id as CollectionId)), ); + } else { + const defaultCollectionId = await this.getDefaultCollectionId(orgId); + if (defaultCollectionId) { + collectionsControl.setValue( + this.collectionOptions.filter((c) => c.id === defaultCollectionId), + ); + } } } } From 023b057f3e6be2f4203491aa88f247ab2b94a532 Mon Sep 17 00:00:00 2001 From: Bryan Cunningham Date: Wed, 2 Jul 2025 14:08:05 -0400 Subject: [PATCH 048/239] [CL-124] Add validator stories (#15400) * adding validation stories * add one story for all validations * fix form field story import * move validation docs * fix maxValue default value * add play function to submit form --- .../src/form-field/form-field.stories.ts | 2 +- libs/components/src/form/form.stories.ts | 122 +++++++++++++++--- libs/components/src/form/forms.mdx | 18 ++- 3 files changed, 116 insertions(+), 26 deletions(-) diff --git a/libs/components/src/form-field/form-field.stories.ts b/libs/components/src/form-field/form-field.stories.ts index 738ac96bf76..0c1fa8e6f6c 100644 --- a/libs/components/src/form-field/form-field.stories.ts +++ b/libs/components/src/form-field/form-field.stories.ts @@ -72,6 +72,7 @@ export default { decorators: [ moduleMetadata({ imports: [ + A11yTitleDirective, FormsModule, ReactiveFormsModule, FormFieldModule, @@ -88,7 +89,6 @@ export default { TextFieldModule, BadgeModule, ], - declarations: [A11yTitleDirective], providers: [ { provide: I18nService, diff --git a/libs/components/src/form/form.stories.ts b/libs/components/src/form/form.stories.ts index 6aef140fe5f..1fc9bbef751 100644 --- a/libs/components/src/form/form.stories.ts +++ b/libs/components/src/form/form.stories.ts @@ -1,13 +1,6 @@ -import { - AbstractControl, - FormBuilder, - FormsModule, - ReactiveFormsModule, - ValidationErrors, - ValidatorFn, - Validators, -} from "@angular/forms"; +import { FormBuilder, FormsModule, ReactiveFormsModule, Validators } from "@angular/forms"; import { Meta, StoryObj, moduleMetadata } from "@storybook/angular"; +import { userEvent, getByText } from "@storybook/test"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -15,6 +8,7 @@ import { ButtonModule } from "../button"; import { CheckboxModule } from "../checkbox"; import { FormControlModule } from "../form-control"; import { FormFieldModule } from "../form-field"; +import { trimValidator, forbiddenCharacters } from "../form-field/bit-validators"; import { InputModule } from "../input/input.module"; import { MultiSelectModule } from "../multi-select"; import { RadioButtonModule } from "../radio-button"; @@ -48,13 +42,19 @@ export default { required: "required", checkboxRequired: "Option is required", inputRequired: "Input is required.", - inputEmail: "Input is not an email-address.", + inputEmail: "Input is not an email address.", + inputForbiddenCharacters: (char) => + `The following characters are not allowed: "${char}"`, inputMinValue: (min) => `Input value must be at least ${min}.`, inputMaxValue: (max) => `Input value must not exceed ${max}.`, + inputMinLength: (min) => `Input value must be at least ${min} characters long.`, + inputMaxLength: (max) => `Input value must not exceed ${max} characters in length.`, + inputTrimValidator: `Input must not contain only whitespace.`, multiSelectPlaceholder: "-- Type to Filter --", multiSelectLoading: "Retrieving options...", multiSelectNotFound: "No items found", multiSelectClearAll: "Clear all", + fieldsNeedAttention: "__$1__ field(s) above need your attention.", }); }, }, @@ -72,7 +72,7 @@ export default { const fb = new FormBuilder(); const exampleFormObj = fb.group({ name: ["", [Validators.required]], - email: ["", [Validators.required, Validators.email, forbiddenNameValidator(/bit/i)]], + email: ["", [Validators.required, Validators.email, forbiddenCharacters(["#"])]], country: [undefined as string | undefined, [Validators.required]], groups: [], terms: [false, [Validators.requiredTrue]], @@ -80,14 +80,6 @@ const exampleFormObj = fb.group({ age: [null, [Validators.min(0), Validators.max(150)]], }); -// Custom error message, `message` is shown as the error message -function forbiddenNameValidator(nameRe: RegExp): ValidatorFn { - return (control: AbstractControl): ValidationErrors | null => { - const forbidden = nameRe.test(control.value); - return forbidden ? { forbiddenName: { message: "forbiddenName" } } : null; - }; -} - type Story = StoryObj; export const FullExample: Story = { @@ -177,3 +169,95 @@ export const FullExample: Story = { ], }, }; + +const showValidationsFormObj = fb.group({ + required: ["", [Validators.required]], + whitespace: [" ", trimValidator], + email: ["example?bad-email", [Validators.email]], + minLength: ["Hello", [Validators.minLength(8)]], + maxLength: ["Hello there", [Validators.maxLength(8)]], + minValue: [9, [Validators.min(10)]], + maxValue: [15, [Validators.max(10)]], + forbiddenChars: ["Th!$ value cont#in$ forbidden char$", forbiddenCharacters(["#", "!", "$"])], +}); + +export const Validations: Story = { + render: (args) => ({ + props: { + formObj: showValidationsFormObj, + submit: () => showValidationsFormObj.markAllAsTouched(), + ...args, + }, + template: /*html*/ ` +
+ + Required validation + + This field is required. Submit form or blur input to see error + + + + Email validation + + This field contains a malformed email address. Submit form or blur input to see error + + + + Min length validation + + Value must be at least 8 characters. Submit form or blur input to see error + + + + Max length validation + + Value must be less then 8 characters. Submit form or blur input to see error + + + + Min number value validation + + Value must be greater than 10. Submit form or blur input to see error + + + + Max number value validation + + Value must be less than than 10. Submit form or blur input to see error + + + + Forbidden characters validation + + Value must not contain '#', '!' or '$'. Submit form or blur input to see error + + + + White space validation + + This input contains only white space. Submit form or blur input to see error + + + + +
+ `, + }), + play: async (context) => { + const canvas = context.canvasElement; + const submitButton = getByText(canvas, "Submit"); + + await userEvent.click(submitButton); + }, +}; diff --git a/libs/components/src/form/forms.mdx b/libs/components/src/form/forms.mdx index e3baf200f96..498eb8a3ed2 100644 --- a/libs/components/src/form/forms.mdx +++ b/libs/components/src/form/forms.mdx @@ -142,8 +142,20 @@ If a checkbox group has more than 4 options a +## Validation messages + +These are examples of our default validation error messages: + + + ## Accessibility +### Icon Buttons in Form Fields + +When adding prefix or suffix icon buttons to a form field, be sure to use the `appA11yTitle` +directive to provide a label for screenreaders. Typically, the label should follow this pattern: +`{Action} {field label}`, i.e. "Copy username". + ### Required Fields - Use "(required)" in the label of each required form field styled the same as the field's helper @@ -152,12 +164,6 @@ If a checkbox group has more than 4 options a helper text. - **Example:** "Billing Email is required if owned by a business". -### Icon Buttons in Form Fields - -When adding prefix or suffix icon buttons to a form field, be sure to use the `appA11yTitle` -directive to provide a label for screenreaders. Typically, the label should follow this pattern: -`{Action} {field label}`, i.e. "Copy username". - ### Form Field Errors - When a resting field is filled out, validation is triggered when the user de-focuses the field From ece5ebe844e3fd4e97210c196d5ff7d2c63682cb Mon Sep 17 00:00:00 2001 From: Shane Melton Date: Wed, 2 Jul 2025 13:19:17 -0700 Subject: [PATCH 049/239] [PM-17663] Fix extension Fill button display on page load (#15359) * [PM-17663] Convert vault-list-items-container inputs to signals - Cleaned up some grouping logic - Cleaned up strict null checks and removed eslint comment * [PM-17663] Prefer undefined over null * [PM-17663] Fix flashing Fill buttons --- .../autofill-vault-list-items.component.html | 2 +- .../autofill-vault-list-items.component.ts | 10 +- .../vault-list-items-container.component.html | 38 ++--- .../vault-list-items-container.component.ts | 149 ++++++++---------- 4 files changed, 94 insertions(+), 105 deletions(-) diff --git a/apps/browser/src/vault/popup/components/vault-v2/autofill-vault-list-items/autofill-vault-list-items.component.html b/apps/browser/src/vault/popup/components/vault-v2/autofill-vault-list-items/autofill-vault-list-items.component.html index 19f1668eba4..47ef0284d6a 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/autofill-vault-list-items/autofill-vault-list-items.component.html +++ b/apps/browser/src/vault/popup/components/vault-v2/autofill-vault-list-items/autofill-vault-list-items.component.html @@ -4,7 +4,7 @@ [title]="((currentURIIsBlocked$ | async) ? 'itemSuggestions' : 'autofillSuggestions') | i18n" [showRefresh]="showRefresh" (onRefresh)="refreshCurrentTab()" - [description]="(showEmptyAutofillTip$ | async) ? ('autofillSuggestionsTip' | i18n) : null" + [description]="(showEmptyAutofillTip$ | async) ? ('autofillSuggestionsTip' | i18n) : undefined" showAutofillButton [disableDescriptionMargin]="showEmptyAutofillTip$ | async" [primaryActionAutofill]="clickItemsToAutofillVaultView$ | async" diff --git a/apps/browser/src/vault/popup/components/vault-v2/autofill-vault-list-items/autofill-vault-list-items.component.ts b/apps/browser/src/vault/popup/components/vault-v2/autofill-vault-list-items/autofill-vault-list-items.component.ts index 47f104cd4d3..aa790d24ede 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/autofill-vault-list-items/autofill-vault-list-items.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/autofill-vault-list-items/autofill-vault-list-items.component.ts @@ -1,7 +1,7 @@ import { CommonModule } from "@angular/common"; import { Component } from "@angular/core"; import { toSignal } from "@angular/core/rxjs-interop"; -import { combineLatest, map, Observable } from "rxjs"; +import { combineLatest, map, Observable, startWith } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service"; @@ -41,7 +41,9 @@ export class AutofillVaultListItemsComponent { /** Flag indicating whether the login item should automatically autofill when clicked */ protected clickItemsToAutofillVaultView$: Observable = - this.vaultSettingsService.clickItemsToAutofillVaultView$; + this.vaultSettingsService.clickItemsToAutofillVaultView$.pipe( + startWith(true), // Start with true to avoid flashing the fill button on first load + ); protected groupByType = toSignal( this.vaultPopupItemsService.hasFilterApplied$.pipe(map((hasFilter) => !hasFilter)), @@ -74,9 +76,7 @@ export class AutofillVaultListItemsComponent { private vaultPopupItemsService: VaultPopupItemsService, private vaultPopupAutofillService: VaultPopupAutofillService, private vaultSettingsService: VaultSettingsService, - ) { - // TODO: Migrate logic to show Autofill policy toast PM-8144 - } + ) {} /** * Refreshes the current tab to re-populate the autofill ciphers. diff --git a/apps/browser/src/vault/popup/components/vault-v2/vault-list-items-container/vault-list-items-container.component.html b/apps/browser/src/vault/popup/components/vault-v2/vault-list-items-container/vault-list-items-container.component.html index 87d13d4d18a..8dca1f9e576 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/vault-list-items-container/vault-list-items-container.component.html +++ b/apps/browser/src/vault/popup/components/vault-v2/vault-list-items-container/vault-list-items-container.component.html @@ -1,8 +1,8 @@ - +
- +

{{ group.subHeaderKey | i18n }} @@ -97,7 +97,7 @@ (click)="primaryActionOnSelect(cipher)" (dblclick)="launchCipher(cipher)" [appA11yTitle]=" - cipherItemTitleKey(cipher) | async | i18n: cipher.name : cipher.login.username + cipherItemTitleKey()(cipher) | i18n: cipher.name : cipher.login.username " class="{{ itemHeightClass }}" > @@ -109,7 +109,7 @@ *ngIf="cipher.organizationId" slot="default-trailing" appOrgIcon - [tierType]="cipher.organization.productTierType" + [tierType]="cipher.organization!.productTierType" [size]="'small'" [appA11yTitle]="orgIconTooltip(cipher)" > @@ -122,7 +122,7 @@ - + +

+ + +
+ +

{{ "bitwardenExtensionInstalled" | i18n }}

+
+

{{ "openExtensionToAutofill" | i18n }}

+ + + {{ "skipToWebApp" | i18n }} + +
+

+ {{ "gettingStartedWithBitwardenPart1" | i18n }} + + {{ "gettingStartedWithBitwardenPart2" | i18n }} + + {{ "and" | i18n }} + + {{ "gettingStartedWithBitwardenPart3" | i18n }} + +

+
diff --git a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.spec.ts b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.spec.ts new file mode 100644 index 00000000000..304aaafab9e --- /dev/null +++ b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.spec.ts @@ -0,0 +1,124 @@ +import { ComponentFixture, TestBed } from "@angular/core/testing"; +import { By } from "@angular/platform-browser"; +import { Router, RouterModule } from "@angular/router"; +import { BehaviorSubject } from "rxjs"; + +import { DeviceType } from "@bitwarden/common/enums"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; + +import { WebBrowserInteractionService } from "../../services/web-browser-interaction.service"; + +import { SetupExtensionComponent } from "./setup-extension.component"; + +describe("SetupExtensionComponent", () => { + let fixture: ComponentFixture; + let component: SetupExtensionComponent; + + const getFeatureFlag = jest.fn().mockResolvedValue(false); + const navigate = jest.fn().mockResolvedValue(true); + const openExtension = jest.fn().mockResolvedValue(true); + const extensionInstalled$ = new BehaviorSubject(null); + + beforeEach(async () => { + navigate.mockClear(); + openExtension.mockClear(); + getFeatureFlag.mockClear().mockResolvedValue(true); + + await TestBed.configureTestingModule({ + imports: [SetupExtensionComponent, RouterModule.forRoot([])], + providers: [ + { provide: I18nService, useValue: { t: (key: string) => key } }, + { provide: ConfigService, useValue: { getFeatureFlag } }, + { provide: WebBrowserInteractionService, useValue: { extensionInstalled$, openExtension } }, + { provide: PlatformUtilsService, useValue: { getDevice: () => DeviceType.UnknownBrowser } }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(SetupExtensionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + const router = TestBed.inject(Router); + router.navigate = navigate; + }); + + it("initially shows the loading spinner", () => { + const spinner = fixture.debugElement.query(By.css("i")); + + expect(spinner.nativeElement.title).toBe("loading"); + }); + + it("sets webStoreUrl", () => { + expect(component["webStoreUrl"]).toBe("https://bitwarden.com/download/#downloads-web-browser"); + }); + + describe("initialization", () => { + it("redirects to the vault if the feature flag is disabled", async () => { + Utils.isMobileBrowser = false; + getFeatureFlag.mockResolvedValue(false); + navigate.mockClear(); + + await component.ngOnInit(); + + expect(navigate).toHaveBeenCalledWith(["/vault"]); + }); + + it("redirects to the vault if the user is on a mobile browser", async () => { + Utils.isMobileBrowser = true; + getFeatureFlag.mockResolvedValue(true); + navigate.mockClear(); + + await component.ngOnInit(); + + expect(navigate).toHaveBeenCalledWith(["/vault"]); + }); + + it("does not redirect the user", async () => { + Utils.isMobileBrowser = false; + getFeatureFlag.mockResolvedValue(true); + navigate.mockClear(); + + await component.ngOnInit(); + + expect(getFeatureFlag).toHaveBeenCalledWith(FeatureFlag.PM19315EndUserActivationMvp); + expect(navigate).not.toHaveBeenCalled(); + }); + }); + + describe("extensionInstalled$", () => { + it("redirects the user to the vault when the first emitted value is true", () => { + extensionInstalled$.next(true); + + expect(navigate).toHaveBeenCalledWith(["/vault"]); + }); + + describe("success state", () => { + beforeEach(() => { + // avoid initial redirect + extensionInstalled$.next(false); + + fixture.detectChanges(); + + extensionInstalled$.next(true); + fixture.detectChanges(); + }); + + it("shows link to the vault", () => { + const successLink = fixture.debugElement.query(By.css("a")); + + expect(successLink.nativeElement.href).toContain("/vault"); + }); + + it("shows open extension button", () => { + const openExtensionButton = fixture.debugElement.query(By.css("button")); + + openExtensionButton.triggerEventHandler("click"); + + expect(openExtension).toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.ts b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.ts new file mode 100644 index 00000000000..839572f3a30 --- /dev/null +++ b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.ts @@ -0,0 +1,107 @@ +import { NgIf } from "@angular/common"; +import { Component, DestroyRef, inject, OnInit } from "@angular/core"; +import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; +import { Router, RouterModule } from "@angular/router"; +import { pairwise, startWith } from "rxjs"; + +import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { UnionOfValues } from "@bitwarden/common/vault/types/union-of-values"; +import { getWebStoreUrl } from "@bitwarden/common/vault/utils/get-web-store-url"; +import { + ButtonComponent, + DialogRef, + DialogService, + IconModule, + LinkModule, +} from "@bitwarden/components"; +import { VaultIcons } from "@bitwarden/vault"; + +import { WebBrowserInteractionService } from "../../services/web-browser-interaction.service"; + +import { AddExtensionLaterDialogComponent } from "./add-extension-later-dialog.component"; + +const SetupExtensionState = { + Loading: "loading", + NeedsExtension: "needs-extension", + Success: "success", +} as const; + +type SetupExtensionState = UnionOfValues; + +@Component({ + selector: "vault-setup-extension", + templateUrl: "./setup-extension.component.html", + imports: [NgIf, JslibModule, ButtonComponent, LinkModule, IconModule, RouterModule], +}) +export class SetupExtensionComponent implements OnInit { + private webBrowserExtensionInteractionService = inject(WebBrowserInteractionService); + private configService = inject(ConfigService); + private router = inject(Router); + private destroyRef = inject(DestroyRef); + private platformUtilsService = inject(PlatformUtilsService); + private dialogService = inject(DialogService); + + protected SetupExtensionState = SetupExtensionState; + protected PartyIcon = VaultIcons.Party; + + /** The current state of the setup extension component. */ + protected state: SetupExtensionState = SetupExtensionState.Loading; + + /** Download Url for the extension based on the browser */ + protected webStoreUrl: string = ""; + + /** Reference to the add it later dialog */ + protected dialogRef: DialogRef | null = null; + + async ngOnInit() { + await this.conditionallyRedirectUser(); + + this.webStoreUrl = getWebStoreUrl(this.platformUtilsService.getDevice()); + + this.webBrowserExtensionInteractionService.extensionInstalled$ + .pipe(takeUntilDestroyed(this.destroyRef), startWith(null), pairwise()) + .subscribe(([previousState, currentState]) => { + // Initial state transitioned to extension installed, redirect the user + if (previousState === null && currentState) { + void this.router.navigate(["/vault"]); + } + + // Extension was not installed and now it is, show success state + if (previousState === false && currentState) { + this.dialogRef?.close(); + this.state = SetupExtensionState.Success; + } + + // Extension is not installed + if (currentState === false) { + this.state = SetupExtensionState.NeedsExtension; + } + }); + } + + /** Conditionally redirects the user to the vault upon landing on the page. */ + async conditionallyRedirectUser() { + const isFeatureEnabled = await this.configService.getFeatureFlag( + FeatureFlag.PM19315EndUserActivationMvp, + ); + const isMobile = Utils.isMobileBrowser; + + if (!isFeatureEnabled || isMobile) { + await this.router.navigate(["/vault"]); + } + } + + /** Opens the add extension later dialog */ + addItLater() { + this.dialogRef = this.dialogService.open(AddExtensionLaterDialogComponent); + } + + /** Opens the browser extension */ + openExtension() { + void this.webBrowserExtensionInteractionService.openExtension(); + } +} diff --git a/apps/web/src/app/vault/services/web-browser-interaction.service.spec.ts b/apps/web/src/app/vault/services/web-browser-interaction.service.spec.ts index 68a9ca6d099..fef5d45e8c3 100644 --- a/apps/web/src/app/vault/services/web-browser-interaction.service.spec.ts +++ b/apps/web/src/app/vault/services/web-browser-interaction.service.spec.ts @@ -61,6 +61,7 @@ describe("WebBrowserInteractionService", () => { tick(1500); expect(results[0]).toBe(false); + tick(2500); // then emit `HasBwInstalled` dispatchEvent(VaultMessages.HasBwInstalled); tick(); diff --git a/apps/web/src/app/vault/services/web-browser-interaction.service.ts b/apps/web/src/app/vault/services/web-browser-interaction.service.ts index 46c566140e4..f1005ef6dc9 100644 --- a/apps/web/src/app/vault/services/web-browser-interaction.service.ts +++ b/apps/web/src/app/vault/services/web-browser-interaction.service.ts @@ -1,6 +1,21 @@ import { DestroyRef, inject, Injectable } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; -import { concatWith, filter, fromEvent, map, Observable, race, take, tap, timer } from "rxjs"; +import { + concat, + filter, + fromEvent, + interval, + map, + Observable, + of, + race, + shareReplay, + switchMap, + take, + takeWhile, + tap, + timer, +} from "rxjs"; import { ExtensionPageUrls } from "@bitwarden/common/vault/enums"; import { VaultMessages } from "@bitwarden/common/vault/enums/vault-messages.enum"; @@ -22,13 +37,22 @@ export class WebBrowserInteractionService { ); /** Emits the installation status of the extension. */ - extensionInstalled$ = this.checkForExtension().pipe( - concatWith( - this.messages$.pipe( - filter((event) => event.data.command === VaultMessages.HasBwInstalled), - map(() => true), - ), - ), + extensionInstalled$: Observable = this.checkForExtension().pipe( + switchMap((installed) => { + if (installed) { + return of(true); + } + + return concat( + of(false), + interval(2500).pipe( + switchMap(() => this.checkForExtension()), + takeWhile((installed) => !installed, true), + filter((installed) => installed), + ), + ); + }), + shareReplay({ bufferSize: 1, refCount: true }), ); /** Attempts to open the extension, rejects if the extension is not installed or it fails to open. */ diff --git a/apps/web/src/images/setup-extension/setup-extension-placeholder.png b/apps/web/src/images/setup-extension/setup-extension-placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..03a6d8951c01924b20d9e3c52d35d0456ae4ede9 GIT binary patch literal 788300 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 nlX(VT~LJ|WfU9AH3^B7gkCFDTFz@~KbL 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 z⋙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≀hBDBf1d1YzW@7f)Xa>zL~9ax|{K?Wc1U49z* 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

#B6&u|u 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 z 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 z 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%0Du!MrOpF7sf@;bUH1Yd|OY#zf-4TA-! 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

bb2IjozVCgUKB=i)MeU?#r> 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Ŏj1=aIkkTpEnAZ) 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 { + return Promise.resolve("/vault"); + } + async finishRegistration( email: string, passwordInputResult: PasswordInputResult, diff --git a/libs/auth/src/angular/registration/registration-finish/registration-finish.component.ts b/libs/auth/src/angular/registration/registration-finish/registration-finish.component.ts index 7ef4d9690a7..1d1a2d8f892 100644 --- a/libs/auth/src/angular/registration/registration-finish/registration-finish.component.ts +++ b/libs/auth/src/angular/registration/registration-finish/registration-finish.component.ts @@ -10,7 +10,9 @@ import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/mod import { AccountApiService } from "@bitwarden/common/auth/abstractions/account-api.service"; import { RegisterVerificationEmailClickedRequest } from "@bitwarden/common/auth/models/request/registration/register-verification-email-clicked.request"; import { HttpStatusCode } from "@bitwarden/common/enums"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; @@ -77,6 +79,7 @@ export class RegistrationFinishComponent implements OnInit, OnDestroy { private logService: LogService, private anonLayoutWrapperDataService: AnonLayoutWrapperDataService, private loginSuccessHandlerService: LoginSuccessHandlerService, + private configService: ConfigService, ) {} async ngOnInit() { @@ -186,15 +189,23 @@ export class RegistrationFinishComponent implements OnInit, OnDestroy { return; } - this.toastService.showToast({ - variant: "success", - title: null, - message: this.i18nService.t("youHaveBeenLoggedIn"), - }); + const endUserActivationFlagEnabled = await this.configService.getFeatureFlag( + FeatureFlag.PM19315EndUserActivationMvp, + ); + + if (!endUserActivationFlagEnabled) { + // Only show the toast when the end user activation feature flag is _not_ enabled + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("youHaveBeenLoggedIn"), + }); + } await this.loginSuccessHandlerService.run(authenticationResult.userId); - await this.router.navigate(["/vault"]); + const successRoute = await this.registrationFinishService.determineLoginSuccessRoute(); + await this.router.navigate([successRoute]); } catch (e) { // If login errors, redirect to login page per product. Don't show error this.logService.error("Error logging in after registration: ", e.message); diff --git a/libs/auth/src/angular/registration/registration-finish/registration-finish.service.ts b/libs/auth/src/angular/registration/registration-finish/registration-finish.service.ts index 5f3c04e5155..523a4c79c54 100644 --- a/libs/auth/src/angular/registration/registration-finish/registration-finish.service.ts +++ b/libs/auth/src/angular/registration/registration-finish/registration-finish.service.ts @@ -16,6 +16,11 @@ export abstract class RegistrationFinishService { */ abstract getMasterPasswordPolicyOptsFromOrgInvite(): Promise; + /** + * Returns the route the user is redirected to after a successful login. + */ + abstract determineLoginSuccessRoute(): Promise; + /** * Finishes the registration process by creating a new user account. * diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index 55c96c2334c..dd2aadc0009 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -55,6 +55,7 @@ export enum FeatureFlag { PM18520_UpdateDesktopCipherForm = "pm-18520-desktop-cipher-forms", EndUserNotifications = "pm-10609-end-user-notifications", RemoveCardItemTypePolicy = "pm-16442-remove-card-item-type-policy", + PM19315EndUserActivationMvp = "pm-19315-end-user-activation-mvp", /* Platform */ IpcChannelFramework = "ipc-channel-framework", @@ -99,6 +100,7 @@ export const DefaultFeatureFlagValue = { [FeatureFlag.EndUserNotifications]: FALSE, [FeatureFlag.PM19941MigrateCipherDomainToSdk]: FALSE, [FeatureFlag.RemoveCardItemTypePolicy]: FALSE, + [FeatureFlag.PM19315EndUserActivationMvp]: FALSE, /* Auth */ [FeatureFlag.PM16117_SetInitialPasswordRefactor]: FALSE, diff --git a/libs/common/src/vault/utils/get-web-store-url.ts b/libs/common/src/vault/utils/get-web-store-url.ts new file mode 100644 index 00000000000..87698d65de2 --- /dev/null +++ b/libs/common/src/vault/utils/get-web-store-url.ts @@ -0,0 +1,22 @@ +import { DeviceType } from "@bitwarden/common/enums"; + +/** + * Returns the web store URL for the Bitwarden browser extension based on the device type. + * @defaults Bitwarden download page + */ +export const getWebStoreUrl = (deviceType: DeviceType): string => { + switch (deviceType) { + case DeviceType.ChromeBrowser: + return "https://chromewebstore.google.com/detail/bitwarden-password-manage/nngceckbapebfimnlniiiahkandclblb"; + case DeviceType.FirefoxBrowser: + return "https://addons.mozilla.org/en-US/firefox/addon/bitwarden-password-manager/"; + case DeviceType.SafariBrowser: + return "https://apps.apple.com/us/app/bitwarden/id1352778147?mt=12"; + case DeviceType.OperaBrowser: + return "https://addons.opera.com/extensions/details/bitwarden-free-password-manager/"; + case DeviceType.EdgeBrowser: + return "https://microsoftedge.microsoft.com/addons/detail/jbkfoedolllekgbhcbcoahefnbanhhlh"; + default: + return "https://bitwarden.com/download/#downloads-web-browser"; + } +}; diff --git a/libs/components/src/anon-layout/anon-layout-wrapper.component.html b/libs/components/src/anon-layout/anon-layout-wrapper.component.html index 0d393b30362..3509e4dcdb0 100644 --- a/libs/components/src/anon-layout/anon-layout-wrapper.component.html +++ b/libs/components/src/anon-layout/anon-layout-wrapper.component.html @@ -5,6 +5,7 @@ [showReadonlyHostname]="showReadonlyHostname" [maxWidth]="maxWidth" [hideCardWrapper]="hideCardWrapper" + [hideIcon]="hideIcon" > diff --git a/libs/components/src/anon-layout/anon-layout-wrapper.component.ts b/libs/components/src/anon-layout/anon-layout-wrapper.component.ts index 20380f137a6..ac192645ee6 100644 --- a/libs/components/src/anon-layout/anon-layout-wrapper.component.ts +++ b/libs/components/src/anon-layout/anon-layout-wrapper.component.ts @@ -29,6 +29,10 @@ export interface AnonLayoutWrapperData { * The optional icon to display on the page. */ pageIcon?: Icon | null; + /** + * Hides the default Bitwarden shield icon. + */ + hideIcon?: boolean; /** * Optional flag to either show the optional environment selector (false) or just a readonly hostname (true). */ @@ -56,6 +60,7 @@ export class AnonLayoutWrapperComponent implements OnInit, OnDestroy { protected showReadonlyHostname: boolean; protected maxWidth: AnonLayoutMaxWidth; protected hideCardWrapper: boolean; + protected hideIcon: boolean = false; constructor( private router: Router, @@ -104,6 +109,10 @@ export class AnonLayoutWrapperComponent implements OnInit, OnDestroy { this.pageIcon = firstChildRouteData["pageIcon"]; } + if (firstChildRouteData["hideIcon"] !== undefined) { + this.hideIcon = firstChildRouteData["hideIcon"]; + } + this.showReadonlyHostname = Boolean(firstChildRouteData["showReadonlyHostname"]); this.maxWidth = firstChildRouteData["maxWidth"]; this.hideCardWrapper = Boolean(firstChildRouteData["hideCardWrapper"]); diff --git a/libs/vault/src/icons/index.ts b/libs/vault/src/icons/index.ts index ef4a7f52a3d..904399da4b3 100644 --- a/libs/vault/src/icons/index.ts +++ b/libs/vault/src/icons/index.ts @@ -8,3 +8,4 @@ export * from "./security-handshake"; export * from "./login-cards"; export * from "./secure-user"; export * from "./secure-devices"; +export * from "./party"; diff --git a/libs/vault/src/icons/party.ts b/libs/vault/src/icons/party.ts new file mode 100644 index 00000000000..2e506c5d705 --- /dev/null +++ b/libs/vault/src/icons/party.ts @@ -0,0 +1,30 @@ +import { svgIcon } from "@bitwarden/components"; + +export const Party = svgIcon` + + + + + + + + + + + + + + + + + + + + + + + + + + +`; From 0311d0aaabe0c2580ab4755d4530a5f711282d08 Mon Sep 17 00:00:00 2001 From: Daniel Riera Date: Thu, 3 Jul 2025 10:41:20 -0400 Subject: [PATCH 053/239] [PM-22391] display simple dialog when advanced matching strategy selected for login ciphers (#15260) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * PM-22391 WIP * update autofill base desc * fill cog when match uri open * switch to button, populate dialog when option selected * default strategy hint * update match hint string and dialog behavior * clean up naming for callbacks and variables * revert global setting hint — this will be addressed separately * add tests * update copy and remove repeated copy to use quoted string * Update apps/browser/src/_locales/en/messages.json Co-authored-by: Nick Krantz <125900171+nick-livefront@users.noreply.github.com> * add translation to web and desktop, make continue and cancel required --------- Co-authored-by: Nick Krantz <125900171+nick-livefront@users.noreply.github.com> --- apps/browser/src/_locales/en/messages.json | 20 ++++++ apps/desktop/src/locales/en/messages.json | 16 +++++ apps/web/src/locales/en/messages.json | 16 +++++ .../advanced-uri-option-dialog.component.html | 27 ++++++++ .../advanced-uri-option-dialog.component.ts | 58 +++++++++++++++++ .../uri-option.component.html | 10 ++- .../uri-option.component.spec.ts | 47 ++++++++++++++ .../autofill-options/uri-option.component.ts | 63 ++++++++++++++++++- 8 files changed, 253 insertions(+), 4 deletions(-) create mode 100644 libs/vault/src/cipher-form/components/autofill-options/advanced-uri-option-dialog.component.html create mode 100644 libs/vault/src/cipher-form/components/autofill-options/advanced-uri-option-dialog.component.ts diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index ce5787c46bd..996bdcdae79 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -4246,6 +4246,26 @@ "commonImportFormats": { "message": "Common formats", "description": "Label indicating the most common import formats" + }, + "uriMatchDefaultStrategyHint": { + "message": "URI match detection is how Bitwarden identifies autofill suggestions.", + "description": "Explains to the user that URI match detection determines how Bitwarden suggests autofill options, and clarifies that this default strategy applies when no specific match detection is set for a login item." + }, + "regExAdvancedOptionWarning": { + "message": "\"Regular expression\" is an advanced option with increased risk of exposing credentials.", + "description": "Content for dialog which warns a user when selecting 'regular expression' matching strategy as a cipher match strategy" + }, + "startsWithAdvancedOptionWarning": { + "message": "\"Starts with\" is an advanced option with increased risk of exposing credentials.", + "description": "Content for dialog which warns a user when selecting 'starts with' matching strategy as a cipher match strategy" + }, + "uriMatchWarningDialogLink": { + "message": "More about match detection", + "description": "Link to match detection docs on warning dialog for advance match strategy" + }, + "uriAdvancedOption":{ + "message": "Advanced options", + "description": "Advanced option placeholder for uri option component" }, "confirmContinueToBrowserSettingsTitle": { "message": "Continue to browser settings?", diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index ac9307c482c..991d07fb9df 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -3534,6 +3534,22 @@ "commonImportFormats": { "message": "Common formats", "description": "Label indicating the most common import formats" + }, + "uriMatchDefaultStrategyHint": { + "message": "URI match detection is how Bitwarden identifies autofill suggestions.", + "description": "Explains to the user that URI match detection determines how Bitwarden suggests autofill options, and clarifies that this default strategy applies when no specific match detection is set for a login item." + }, + "regExAdvancedOptionWarning": { + "message": "\"Regular expression\" is an advanced option with increased risk of exposing credentials.", + "description": "Content for dialog which warns a user when selecting 'regular expression' matching strategy as a cipher match strategy" + }, + "startsWithAdvancedOptionWarning": { + "message": "\"Starts with\" is an advanced option with increased risk of exposing credentials.", + "description": "Content for dialog which warns a user when selecting 'starts with' matching strategy as a cipher match strategy" + }, + "uriMatchWarningDialogLink": { + "message": "More about match detection", + "description": "Link to match detection docs on warning dialog for advance match strategy" }, "success": { "message": "Success" diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 6ed8ffe9bb3..ce35f2abd33 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -8907,6 +8907,22 @@ "commonImportFormats": { "message": "Common formats", "description": "Label indicating the most common import formats" + }, + "uriMatchDefaultStrategyHint": { + "message": "URI match detection is how Bitwarden identifies autofill suggestions.", + "description": "Explains to the user that URI match detection determines how Bitwarden suggests autofill options, and clarifies that this default strategy applies when no specific match detection is set for a login item." + }, + "regExAdvancedOptionWarning": { + "message": "\"Regular expression\" is an advanced option with increased risk of exposing credentials.", + "description": "Content for dialog which warns a user when selecting 'regular expression' matching strategy as a cipher match strategy" + }, + "startsWithAdvancedOptionWarning": { + "message": "\"Starts with\" is an advanced option with increased risk of exposing credentials.", + "description": "Content for dialog which warns a user when selecting 'starts with' matching strategy as a cipher match strategy" + }, + "uriMatchWarningDialogLink": { + "message": "More about match detection", + "description": "Link to match detection docs on warning dialog for advance match strategy" }, "maintainYourSubscription": { "message": "To maintain your subscription for $ORG$, ", diff --git a/libs/vault/src/cipher-form/components/autofill-options/advanced-uri-option-dialog.component.html b/libs/vault/src/cipher-form/components/autofill-options/advanced-uri-option-dialog.component.html new file mode 100644 index 00000000000..627989a3397 --- /dev/null +++ b/libs/vault/src/cipher-form/components/autofill-options/advanced-uri-option-dialog.component.html @@ -0,0 +1,27 @@ + + + + {{ "warningCapitalized" | i18n }} + +

+

+ {{ contentKey | i18n }} +
+ +

+
+ + + + + diff --git a/libs/vault/src/cipher-form/components/autofill-options/advanced-uri-option-dialog.component.ts b/libs/vault/src/cipher-form/components/autofill-options/advanced-uri-option-dialog.component.ts new file mode 100644 index 00000000000..e63aa224149 --- /dev/null +++ b/libs/vault/src/cipher-form/components/autofill-options/advanced-uri-option-dialog.component.ts @@ -0,0 +1,58 @@ +import { Component, inject } from "@angular/core"; + +import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { + ButtonLinkDirective, + ButtonModule, + DialogModule, + DialogService, + DIALOG_DATA, + DialogRef, +} from "@bitwarden/components"; + +export type AdvancedUriOptionDialogParams = { + contentKey: string; + onCancel: () => void; + onContinue: () => void; +}; + +@Component({ + templateUrl: "advanced-uri-option-dialog.component.html", + imports: [ButtonLinkDirective, ButtonModule, DialogModule, JslibModule], +}) +export class AdvancedUriOptionDialogComponent { + constructor(private dialogRef: DialogRef) {} + + protected platformUtilsService = inject(PlatformUtilsService); + protected params = inject(DIALOG_DATA); + + get contentKey(): string { + return this.params.contentKey; + } + + onCancel() { + this.params.onCancel?.(); + this.dialogRef.close(false); + } + + onContinue() { + this.params.onContinue?.(); + this.dialogRef.close(true); + } + + openLink(event: Event) { + event.preventDefault(); + this.platformUtilsService.launchUri("https://bitwarden.com/help/uri-match-detection/"); + } + + static open( + dialogService: DialogService, + params: AdvancedUriOptionDialogParams, + ): DialogRef { + return dialogService.open(AdvancedUriOptionDialogComponent, { + data: params, + disableClose: true, + }); + } +} diff --git a/libs/vault/src/cipher-form/components/autofill-options/uri-option.component.html b/libs/vault/src/cipher-form/components/autofill-options/uri-option.component.html index 84b43edfbac..2e88a68a0d4 100644 --- a/libs/vault/src/cipher-form/components/autofill-options/uri-option.component.html +++ b/libs/vault/src/cipher-form/components/autofill-options/uri-option.component.html @@ -6,7 +6,7 @@

Qps#nxX>YAs0(XABFa%WM)zC;y(?dhOGAV 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

diff --git a/libs/vault/src/cipher-form/components/autofill-options/uri-option.component.spec.ts b/libs/vault/src/cipher-form/components/autofill-options/uri-option.component.spec.ts index d259566cc57..0d7f3663967 100644 --- a/libs/vault/src/cipher-form/components/autofill-options/uri-option.component.spec.ts +++ b/libs/vault/src/cipher-form/components/autofill-options/uri-option.component.spec.ts @@ -1,14 +1,19 @@ import { ComponentFixture, TestBed } from "@angular/core/testing"; import { NG_VALUE_ACCESSOR } from "@angular/forms"; +import { of } from "rxjs"; import { UriMatchStrategy } from "@bitwarden/common/models/domain/domain-service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { DialogRef, DialogService } from "@bitwarden/components"; +import { AdvancedUriOptionDialogComponent } from "./advanced-uri-option-dialog.component"; import { UriOptionComponent } from "./uri-option.component"; describe("UriOptionComponent", () => { let component: UriOptionComponent; let fixture: ComponentFixture; + let dialogServiceMock: jest.Mocked; + let dialogRefMock: jest.Mocked>; const getToggleMatchDetectionBtn = () => fixture.nativeElement.querySelector( @@ -26,9 +31,19 @@ describe("UriOptionComponent", () => { ) as HTMLButtonElement; beforeEach(async () => { + dialogServiceMock = { + open: jest.fn().mockReturnValue(dialogRefMock), + } as unknown as jest.Mocked; + + dialogRefMock = { + close: jest.fn(), + afterClosed: jest.fn().mockReturnValue(of(true)), + } as unknown as jest.Mocked>; + await TestBed.configureTestingModule({ imports: [UriOptionComponent], providers: [ + { provide: DialogService, useValue: dialogServiceMock }, { provide: I18nService, useValue: { t: (...keys: string[]) => keys.filter(Boolean).join(" ") }, @@ -165,4 +180,36 @@ describe("UriOptionComponent", () => { expect(component.remove.emit).toHaveBeenCalled(); }); }); + + describe("advanced match strategy dialog", () => { + function testDialogAction(action: "onContinue" | "onCancel", expected: number) { + const openSpy = jest + .spyOn(AdvancedUriOptionDialogComponent, "open") + .mockReturnValue(dialogRefMock); + + component["uriForm"].controls.matchDetection.setValue(UriMatchStrategy.Domain); + component["uriForm"].controls.matchDetection.setValue(UriMatchStrategy.StartsWith); + + const [, params] = openSpy.mock.calls[0] as [ + DialogService, + { + contentKey: string; + onContinue: () => void; + onCancel: () => void; + }, + ]; + + params[action](); + + expect(component["uriForm"].value.matchDetection).toBe(expected); + } + + it("should apply the advanced match strategy when the user continues", () => { + testDialogAction("onContinue", UriMatchStrategy.StartsWith); + }); + + it("should revert to the previous strategy when the user cancels", () => { + testDialogAction("onCancel", UriMatchStrategy.Domain); + }); + }); }); diff --git a/libs/vault/src/cipher-form/components/autofill-options/uri-option.component.ts b/libs/vault/src/cipher-form/components/autofill-options/uri-option.component.ts index 3f12382b931..4287d5b96c8 100644 --- a/libs/vault/src/cipher-form/components/autofill-options/uri-option.component.ts +++ b/libs/vault/src/cipher-form/components/autofill-options/uri-option.component.ts @@ -18,6 +18,7 @@ import { NG_VALUE_ACCESSOR, ReactiveFormsModule, } from "@angular/forms"; +import { concatMap, pairwise } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { @@ -26,12 +27,15 @@ import { } from "@bitwarden/common/models/domain/domain-service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { + DialogService, FormFieldModule, IconButtonModule, SelectComponent, SelectModule, } from "@bitwarden/components"; +import { AdvancedUriOptionDialogComponent } from "./advanced-uri-option-dialog.component"; + @Component({ selector: "vault-autofill-uri-option", templateUrl: "./uri-option.component.html", @@ -65,16 +69,26 @@ export class UriOptionComponent implements ControlValueAccessor { matchDetection: [null as UriMatchStrategySetting], }); - protected uriMatchOptions: { label: string; value: UriMatchStrategySetting }[] = [ + protected uriMatchOptions: { + label: string; + value: UriMatchStrategySetting; + disabled?: boolean; + }[] = [ { label: this.i18nService.t("default"), value: null }, { label: this.i18nService.t("baseDomain"), value: UriMatchStrategy.Domain }, { label: this.i18nService.t("host"), value: UriMatchStrategy.Host }, - { label: this.i18nService.t("startsWith"), value: UriMatchStrategy.StartsWith }, - { label: this.i18nService.t("regEx"), value: UriMatchStrategy.RegularExpression }, { label: this.i18nService.t("exact"), value: UriMatchStrategy.Exact }, { label: this.i18nService.t("never"), value: UriMatchStrategy.Never }, + { label: this.i18nService.t("uriAdvancedOption"), value: null, disabled: true }, + { label: this.i18nService.t("startsWith"), value: UriMatchStrategy.StartsWith }, + { label: this.i18nService.t("regEx"), value: UriMatchStrategy.RegularExpression }, ]; + protected advancedOptionWarningMap: Partial> = { + [UriMatchStrategy.StartsWith]: "startsWithAdvancedOptionWarning", + [UriMatchStrategy.RegularExpression]: "regExAdvancedOptionWarning", + }; + /** * Whether the option can be reordered. If false, the reorder button will be hidden. */ @@ -147,6 +161,7 @@ export class UriOptionComponent implements ControlValueAccessor { } constructor( + private dialogService: DialogService, private formBuilder: FormBuilder, private i18nService: I18nService, ) { @@ -157,6 +172,36 @@ export class UriOptionComponent implements ControlValueAccessor { this.uriForm.statusChanges.pipe(takeUntilDestroyed()).subscribe(() => { this.onTouched(); }); + + this.uriForm.controls.matchDetection.valueChanges + .pipe( + pairwise(), + concatMap(([previous, current]) => this.handleAdvancedMatch(previous, current)), + takeUntilDestroyed(), + ) + .subscribe(); + } + + private async handleAdvancedMatch( + previous: UriMatchStrategySetting, + current: UriMatchStrategySetting, + ) { + const valueChange = previous !== current; + const isAdvanced = + current === UriMatchStrategy.StartsWith || current === UriMatchStrategy.RegularExpression; + + if (!valueChange || !isAdvanced) { + return; + } + AdvancedUriOptionDialogComponent.open(this.dialogService, { + contentKey: this.advancedOptionWarningMap[current], + onContinue: () => { + this.uriForm.controls.matchDetection.setValue(current); + }, + onCancel: () => { + this.uriForm.controls.matchDetection.setValue(previous); + }, + }); } focusInput() { @@ -193,4 +238,16 @@ export class UriOptionComponent implements ControlValueAccessor { setDisabledState?(isDisabled: boolean): void { isDisabled ? this.uriForm.disable() : this.uriForm.enable(); } + + getMatchHints() { + const hints = ["uriMatchDefaultStrategyHint"]; + const strategy = this.uriForm.get("matchDetection")?.value; + if ( + strategy === UriMatchStrategy.StartsWith || + strategy === UriMatchStrategy.RegularExpression + ) { + hints.push(this.advancedOptionWarningMap[strategy]); + } + return hints; + } } From 522acf571885c6688d2767f6dd45f3b8444b04eb Mon Sep 17 00:00:00 2001 From: SmithThe4th Date: Thu, 3 Jul 2025 11:12:08 -0400 Subject: [PATCH 054/239] Fixed date conversion issue when importing (#15434) --- libs/common/src/models/export/password-history.export.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/common/src/models/export/password-history.export.ts b/libs/common/src/models/export/password-history.export.ts index ece7e331009..5382b9cb974 100644 --- a/libs/common/src/models/export/password-history.export.ts +++ b/libs/common/src/models/export/password-history.export.ts @@ -22,7 +22,7 @@ export class PasswordHistoryExport { static toDomain(req: PasswordHistoryExport, domain = new Password()) { domain.password = req.password != null ? new EncString(req.password) : null; - domain.lastUsedDate = req.lastUsedDate; + domain.lastUsedDate = req.lastUsedDate ? new Date(req.lastUsedDate) : null; return domain; } From d1c6b334b1ec547fe1921d07426468f8f4458378 Mon Sep 17 00:00:00 2001 From: Todd Martin <106564991+trmartin4@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:27:28 -0400 Subject: [PATCH 055/239] feat(DuckDuckGo): [PM-9388] Add new device type for DuckDuckGo browser * Add new device type for DuckDuckGo browser * Added feature support property for sync domains * Added new features * Added isDuckDuckGo() to CLI * Addressed PR feedback. * Renamed new property * Fixed rename that missed CLI. --- .../browser-platform-utils.service.ts | 8 ++ .../services/cli-platform-utils.service.ts | 8 ++ .../electron-platform-utils.service.ts | 8 ++ .../src/app/core/web-file-download.service.ts | 2 +- .../core/web-platform-utils.service.spec.ts | 89 +++++++++++++++++++ .../app/core/web-platform-utils.service.ts | 20 +++++ .../shared/secrets-list.component.ts | 18 ---- .../src/tools/send/add-edit.component.ts | 8 -- libs/common/src/enums/device-type.enum.ts | 2 + .../abstractions/platform-utils.service.ts | 9 ++ libs/common/src/services/api.service.ts | 26 ++---- 11 files changed, 150 insertions(+), 48 deletions(-) diff --git a/apps/browser/src/platform/services/platform-utils/browser-platform-utils.service.ts b/apps/browser/src/platform/services/platform-utils/browser-platform-utils.service.ts index 4ae412fbda6..beac7616d8d 100644 --- a/apps/browser/src/platform/services/platform-utils/browser-platform-utils.service.ts +++ b/apps/browser/src/platform/services/platform-utils/browser-platform-utils.service.ts @@ -207,6 +207,14 @@ export abstract class BrowserPlatformUtilsService implements PlatformUtilsServic return true; } + supportsAutofill(): boolean { + return true; + } + + supportsFileDownloads(): boolean { + return false; + } + abstract showToast( type: "error" | "success" | "warning" | "info", title: string, diff --git a/apps/cli/src/platform/services/cli-platform-utils.service.ts b/apps/cli/src/platform/services/cli-platform-utils.service.ts index 4e00b58607b..7bed495bbf5 100644 --- a/apps/cli/src/platform/services/cli-platform-utils.service.ts +++ b/apps/cli/src/platform/services/cli-platform-utils.service.ts @@ -108,6 +108,14 @@ export class CliPlatformUtilsService implements PlatformUtilsService { return false; } + supportsAutofill(): boolean { + return false; + } + + supportsFileDownloads(): boolean { + return false; + } + showToast( type: "error" | "success" | "warning" | "info", title: string, diff --git a/apps/desktop/src/platform/services/electron-platform-utils.service.ts b/apps/desktop/src/platform/services/electron-platform-utils.service.ts index b7c82f4e5db..43b867b7a68 100644 --- a/apps/desktop/src/platform/services/electron-platform-utils.service.ts +++ b/apps/desktop/src/platform/services/electron-platform-utils.service.ts @@ -86,6 +86,14 @@ export class ElectronPlatformUtilsService implements PlatformUtilsService { return true; } + supportsAutofill(): boolean { + return false; + } + + supportsFileDownloads(): boolean { + return false; + } + showToast( type: "error" | "success" | "warning" | "info", title: string, diff --git a/apps/web/src/app/core/web-file-download.service.ts b/apps/web/src/app/core/web-file-download.service.ts index ad034702a55..3421203737a 100644 --- a/apps/web/src/app/core/web-file-download.service.ts +++ b/apps/web/src/app/core/web-file-download.service.ts @@ -12,7 +12,7 @@ export class WebFileDownloadService implements FileDownloadService { download(request: FileDownloadRequest): void { const builder = new FileDownloadBuilder(request); const a = window.document.createElement("a"); - if (!this.platformUtilsService.isSafari()) { + if (!this.platformUtilsService.supportsFileDownloads()) { a.rel = "noreferrer"; a.target = "_blank"; } diff --git a/apps/web/src/app/core/web-platform-utils.service.spec.ts b/apps/web/src/app/core/web-platform-utils.service.spec.ts index 3b5cb96b718..6dba3fda782 100644 --- a/apps/web/src/app/core/web-platform-utils.service.spec.ts +++ b/apps/web/src/app/core/web-platform-utils.service.spec.ts @@ -1,5 +1,7 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore +import { DeviceType } from "@bitwarden/common/enums"; + import { WebPlatformUtilsService } from "./web-platform-utils.service"; describe("Web Platform Utils Service", () => { @@ -114,4 +116,91 @@ describe("Web Platform Utils Service", () => { expect(result).toBe("2022.10.2"); }); }); + describe("getDevice", () => { + const originalUserAgent = navigator.userAgent; + + const setUserAgent = (userAgent: string) => { + Object.defineProperty(navigator, "userAgent", { + value: userAgent, + configurable: true, + }); + }; + + const setWindowProperties = (props?: Record) => { + if (!props) { + return; + } + Object.keys(props).forEach((key) => { + Object.defineProperty(window, key, { + value: props[key], + configurable: true, + }); + }); + }; + + afterEach(() => { + // Reset to original after each test + setUserAgent(originalUserAgent); + }); + + const testData: { + userAgent: string; + expectedDevice: DeviceType; + windowProps?: Record; + }[] = [ + { + // DuckDuckGo macoOS browser v1.13 + userAgent: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3.1 Safari/605.1.15 Ddg/18.3.1", + expectedDevice: DeviceType.DuckDuckGoBrowser, + }, + // DuckDuckGo Windows browser v0.109.7, which does not present the Ddg suffix and is therefore detected as Edge + { + userAgent: + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0", + expectedDevice: DeviceType.EdgeBrowser, + }, + { + userAgent: + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36", + expectedDevice: DeviceType.ChromeBrowser, + windowProps: { chrome: {} }, // set window.chrome = {} to simulate Chrome + }, + { + userAgent: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0", + expectedDevice: DeviceType.FirefoxBrowser, + }, + { + userAgent: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 13_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15", + expectedDevice: DeviceType.SafariBrowser, + }, + { + userAgent: + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Edg/120.0.0.0 Chrome/120.0.0.0 Safari/537.36", + expectedDevice: DeviceType.EdgeBrowser, + }, + { + userAgent: + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.65 Safari/537.36 OPR/95.0.4635.46", + expectedDevice: DeviceType.OperaBrowser, + }, + { + userAgent: + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.57 Safari/537.36 Vivaldi/6.5.3206.48", + expectedDevice: DeviceType.VivaldiBrowser, + }, + ]; + + test.each(testData)( + "returns $expectedDevice for User-Agent: $userAgent", + ({ userAgent, expectedDevice, windowProps }) => { + setUserAgent(userAgent); + setWindowProperties(windowProps); + const result = webPlatformUtilsService.getDevice(); + expect(result).toBe(expectedDevice); + }, + ); + }); }); diff --git a/apps/web/src/app/core/web-platform-utils.service.ts b/apps/web/src/app/core/web-platform-utils.service.ts index 3df2a7d895b..c3d1f5e3c1a 100644 --- a/apps/web/src/app/core/web-platform-utils.service.ts +++ b/apps/web/src/app/core/web-platform-utils.service.ts @@ -34,6 +34,13 @@ export class WebPlatformUtilsService implements PlatformUtilsService { this.browserCache = DeviceType.EdgeBrowser; } else if (navigator.userAgent.indexOf(" Vivaldi/") !== -1) { this.browserCache = DeviceType.VivaldiBrowser; + } else if ( + // We are only detecting DuckDuckGo browser on macOS currently, as + // it is not presenting the Ddg suffix on Windows. DuckDuckGo users + // on Windows will be detected as Edge. + navigator.userAgent.indexOf("Ddg") !== -1 + ) { + this.browserCache = DeviceType.DuckDuckGoBrowser; } else if ( navigator.userAgent.indexOf(" Safari/") !== -1 && navigator.userAgent.indexOf("Chrome") === -1 @@ -83,6 +90,10 @@ export class WebPlatformUtilsService implements PlatformUtilsService { return this.getDevice() === DeviceType.SafariBrowser; } + isWebKit(): boolean { + return true; + } + isMacAppStore(): boolean { return false; } @@ -120,6 +131,15 @@ export class WebPlatformUtilsService implements PlatformUtilsService { return true; } + supportsAutofill(): boolean { + return false; + } + + // Safari support for blob downloads is inconsistent and requires workarounds + supportsFileDownloads(): boolean { + return !(this.getDevice() === DeviceType.SafariBrowser); + } + showToast( type: "error" | "success" | "warning" | "info", title: string, diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/shared/secrets-list.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/shared/secrets-list.component.ts index a7ee818a01f..18ac0a80454 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/shared/secrets-list.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/shared/secrets-list.component.ts @@ -180,22 +180,4 @@ export class SecretsListComponent implements OnDestroy { i18nService.t("valueCopied", i18nService.t("uuid")), ); } - - /** - * TODO: Remove in favor of updating `PlatformUtilsService.copyToClipboard` - */ - private static copyToClipboardAsync( - text: Promise, - platformUtilsService: PlatformUtilsService, - ) { - if (platformUtilsService.isSafari()) { - return navigator.clipboard.write([ - new ClipboardItem({ - ["text/plain"]: text, - }), - ]); - } - - return text.then((t) => platformUtilsService.copyToClipboard(t)); - } } diff --git a/libs/angular/src/tools/send/add-edit.component.ts b/libs/angular/src/tools/send/add-edit.component.ts index 0289664c365..221b751528a 100644 --- a/libs/angular/src/tools/send/add-edit.component.ts +++ b/libs/angular/src/tools/send/add-edit.component.ts @@ -148,14 +148,6 @@ export class AddEditComponent implements OnInit, OnDestroy { return null; } - get isSafari() { - return this.platformUtilsService.isSafari(); - } - - get isDateTimeLocalSupported(): boolean { - return !(this.platformUtilsService.isFirefox() || this.platformUtilsService.isSafari()); - } - async ngOnInit() { this.accountService.activeAccount$ .pipe( diff --git a/libs/common/src/enums/device-type.enum.ts b/libs/common/src/enums/device-type.enum.ts index d5628536ff7..c462081140e 100644 --- a/libs/common/src/enums/device-type.enum.ts +++ b/libs/common/src/enums/device-type.enum.ts @@ -27,6 +27,7 @@ export enum DeviceType { WindowsCLI = 23, MacOsCLI = 24, LinuxCLI = 25, + DuckDuckGoBrowser = 26, } /** @@ -55,6 +56,7 @@ export const DeviceTypeMetadata: Record = { [DeviceType.IEBrowser]: { category: "webVault", platform: "IE" }, [DeviceType.SafariBrowser]: { category: "webVault", platform: "Safari" }, [DeviceType.VivaldiBrowser]: { category: "webVault", platform: "Vivaldi" }, + [DeviceType.DuckDuckGoBrowser]: { category: "webVault", platform: "DuckDuckGo" }, [DeviceType.UnknownBrowser]: { category: "webVault", platform: "Unknown" }, [DeviceType.WindowsDesktop]: { category: "desktop", platform: "Windows" }, [DeviceType.MacOsDesktop]: { category: "desktop", platform: "macOS" }, diff --git a/libs/common/src/platform/abstractions/platform-utils.service.ts b/libs/common/src/platform/abstractions/platform-utils.service.ts index fa0fc8f2501..7586da5a564 100644 --- a/libs/common/src/platform/abstractions/platform-utils.service.ts +++ b/libs/common/src/platform/abstractions/platform-utils.service.ts @@ -28,6 +28,15 @@ export abstract class PlatformUtilsService { abstract getApplicationVersionNumber(): Promise; abstract supportsWebAuthn(win: Window): boolean; abstract supportsDuo(): boolean; + /** + * Returns true if the device supports autofill functionality + */ + abstract supportsAutofill(): boolean; + /** + * Returns true if the device supports native file downloads without + * the need for `target="_blank"` + */ + abstract supportsFileDownloads(): boolean; /** * @deprecated use `@bitwarden/components/ToastService.showToast` instead * diff --git a/libs/common/src/services/api.service.ts b/libs/common/src/services/api.service.ts index ca6cd6570a4..62d300fc029 100644 --- a/libs/common/src/services/api.service.ts +++ b/libs/common/src/services/api.service.ts @@ -97,7 +97,7 @@ import { PaymentResponse } from "../billing/models/response/payment.response"; import { PlanResponse } from "../billing/models/response/plan.response"; import { SubscriptionResponse } from "../billing/models/response/subscription.response"; import { TaxInfoResponse } from "../billing/models/response/tax-info.response"; -import { DeviceType } from "../enums"; +import { ClientType, DeviceType } from "../enums"; import { KeyConnectorUserKeyRequest } from "../key-management/key-connector/models/key-connector-user-key.request"; import { SetKeyConnectorKeyRequest } from "../key-management/key-connector/models/set-key-connector-key.request"; import { VaultTimeoutSettingsService } from "../key-management/vault-timeout"; @@ -154,8 +154,6 @@ export type HttpOperations = { export class ApiService implements ApiServiceAbstraction { private device: DeviceType; private deviceType: string; - private isWebClient = false; - private isDesktopClient = false; private refreshTokenPromise: Promise | undefined; /** @@ -178,22 +176,6 @@ export class ApiService implements ApiServiceAbstraction { ) { this.device = platformUtilsService.getDevice(); this.deviceType = this.device.toString(); - this.isWebClient = - this.device === DeviceType.IEBrowser || - this.device === DeviceType.ChromeBrowser || - this.device === DeviceType.EdgeBrowser || - this.device === DeviceType.FirefoxBrowser || - this.device === DeviceType.OperaBrowser || - this.device === DeviceType.SafariBrowser || - this.device === DeviceType.UnknownBrowser || - this.device === DeviceType.VivaldiBrowser; - this.isDesktopClient = - this.device === DeviceType.WindowsDesktop || - this.device === DeviceType.MacOsDesktop || - this.device === DeviceType.LinuxDesktop || - this.device === DeviceType.WindowsCLI || - this.device === DeviceType.MacOsCLI || - this.device === DeviceType.LinuxCLI; } // Auth APIs @@ -838,7 +820,9 @@ export class ApiService implements ApiServiceAbstraction { // Sync APIs async getSync(): Promise { - const path = this.isDesktopClient || this.isWebClient ? "/sync?excludeDomains=true" : "/sync"; + const path = !this.platformUtilsService.supportsAutofill() + ? "/sync?excludeDomains=true" + : "/sync"; const r = await this.send("GET", path, null, true, true); return new SyncResponse(r); } @@ -1875,7 +1859,7 @@ export class ApiService implements ApiServiceAbstraction { private async getCredentials(): Promise { const env = await firstValueFrom(this.environmentService.environment$); - if (!this.isWebClient || env.hasBaseUrl()) { + if (this.platformUtilsService.getClientType() !== ClientType.Web || env.hasBaseUrl()) { return "include"; } return undefined; From 913c3ddbec4dab7a28ffc340a076a8ed2b0914b8 Mon Sep 17 00:00:00 2001 From: Bryan Cunningham Date: Thu, 3 Jul 2025 12:14:10 -0400 Subject: [PATCH 056/239] [CL-620] add padding to increase checkbox clickable area (#15331) * add padding to increaase checkbox clickable area * fix checkbox story imports * enlarge click area of checkbox w/out label * apply disabled states to before * WIP * revert experimental changes * add negative margin to account for extra padding * Remove margin from checkbox and apply in form control * Remove margin from radio as it's applied in form control * add back line height removed in error --- .../src/checkbox/checkbox.component.ts | 99 ++++++++++--------- .../src/checkbox/checkbox.stories.ts | 16 +-- .../form-control/form-control.component.html | 2 +- .../src/radio-button/radio-input.component.ts | 1 - 4 files changed, 65 insertions(+), 53 deletions(-) diff --git a/libs/components/src/checkbox/checkbox.component.ts b/libs/components/src/checkbox/checkbox.component.ts index 079ede287cc..c420b3f3473 100644 --- a/libs/components/src/checkbox/checkbox.component.ts +++ b/libs/components/src/checkbox/checkbox.component.ts @@ -20,64 +20,75 @@ export class CheckboxComponent implements BitFormControlAbstraction { "tw-cursor-pointer", "tw-inline-block", "tw-align-sub", - "tw-rounded", - "tw-border", - "tw-border-solid", - "tw-border-secondary-500", - "tw-h-[1.12rem]", - "tw-w-[1.12rem]", - "tw-me-1.5", "tw-flex-none", // Flexbox fix for bit-form-control + "!tw-p-1", + "after:tw-inset-1", + // negative margin to negate the positioning added by the padding + "!-tw-mt-1", + "!-tw-mb-1", + "!-tw-ms-1", "before:tw-content-['']", "before:tw-block", - "before:tw-absolute", "before:tw-inset-0", + "before:tw-h-[1.12rem]", + "before:tw-w-[1.12rem]", + "before:tw-rounded", + "before:tw-border", + "before:tw-border-solid", + "before:tw-border-secondary-500", - "hover:tw-border-2", - "[&>label]:tw-border-2", + "after:tw-content-['']", + "after:tw-block", + "after:tw-absolute", + "after:tw-inset-0", + "after:tw-h-[1.12rem]", + "after:tw-w-[1.12rem]", + + "hover:before:tw-border-2", + "[&>label]:before:tw-border-2", // if it exists, the parent form control handles focus - "[&:not(bit-form-control_*)]:focus-visible:tw-ring-2", - "[&:not(bit-form-control_*)]:focus-visible:tw-ring-offset-2", - "[&:not(bit-form-control_*)]:focus-visible:tw-ring-primary-600", + "[&:not(bit-form-control_*)]:focus-visible:before:tw-ring-2", + "[&:not(bit-form-control_*)]:focus-visible:before:tw-ring-offset-2", + "[&:not(bit-form-control_*)]:focus-visible:before:tw-ring-primary-600", - "disabled:tw-cursor-auto", - "disabled:tw-border", - "disabled:hover:tw-border", - "disabled:tw-bg-secondary-100", - "disabled:hover:tw-bg-secondary-100", + "disabled:before:tw-cursor-auto", + "disabled:before:tw-border", + "disabled:before:hover:tw-border", + "disabled:before:tw-bg-secondary-100", + "disabled:hover:before:tw-bg-secondary-100", - "checked:tw-bg-primary-600", - "checked:tw-border-primary-600", - "checked:hover:tw-bg-primary-700", - "checked:hover:tw-border-primary-700", - "[&>label:hover]:checked:tw-bg-primary-700", - "[&>label:hover]:checked:tw-border-primary-700", - "checked:before:tw-bg-text-contrast", - "checked:before:tw-mask-position-[center]", - "checked:before:tw-mask-repeat-[no-repeat]", - "checked:disabled:tw-border-secondary-100", - "checked:disabled:hover:tw-border-secondary-100", - "checked:disabled:tw-bg-secondary-100", - "checked:disabled:before:tw-bg-text-muted", + "checked:before:tw-bg-primary-600", + "checked:before:tw-border-primary-600", + "checked:before:hover:tw-bg-primary-700", + "checked:before:hover:tw-border-primary-700", + "[&>label:hover]:checked:before:tw-bg-primary-700", + "[&>label:hover]:checked:before:tw-border-primary-700", + "checked:after:tw-bg-text-contrast", + "checked:after:tw-mask-position-[center]", + "checked:after:tw-mask-repeat-[no-repeat]", + "checked:disabled:before:tw-border-secondary-100", + "checked:disabled:hover:before:tw-border-secondary-100", + "checked:disabled:before:tw-bg-secondary-100", + "checked:disabled:after:tw-bg-text-muted", - "[&:not(:indeterminate)]:checked:before:tw-mask-image-[var(--mask-image)]", - "indeterminate:before:tw-mask-image-[var(--indeterminate-mask-image)]", + "[&:not(:indeterminate)]:checked:after:tw-mask-image-[var(--mask-image)]", + "indeterminate:after:tw-mask-image-[var(--indeterminate-mask-image)]", - "indeterminate:tw-bg-primary-600", - "indeterminate:tw-border-primary-600", - "indeterminate:hover:tw-bg-primary-700", - "indeterminate:hover:tw-border-primary-700", - "[&>label:hover]:indeterminate:tw-bg-primary-700", - "[&>label:hover]:indeterminate:tw-border-primary-700", - "indeterminate:before:tw-bg-text-contrast", - "indeterminate:before:tw-mask-position-[center]", - "indeterminate:before:tw-mask-repeat-[no-repeat]", - "indeterminate:before:tw-mask-image-[var(--indeterminate-mask-image)]", + "indeterminate:before:tw-bg-primary-600", + "indeterminate:before:tw-border-primary-600", + "indeterminate:hover:before:tw-bg-primary-700", + "indeterminate:hover:before:tw-border-primary-700", + "[&>label:hover]:indeterminate:before:tw-bg-primary-700", + "[&>label:hover]:indeterminate:before:tw-border-primary-700", + "indeterminate:after:tw-bg-text-contrast", + "indeterminate:after:tw-mask-position-[center]", + "indeterminate:after:tw-mask-repeat-[no-repeat]", + "indeterminate:after:tw-mask-image-[var(--indeterminate-mask-image)]", "indeterminate:disabled:tw-border-secondary-100", "indeterminate:disabled:tw-bg-secondary-100", - "indeterminate:disabled:before:tw-bg-text-muted", + "indeterminate:disabled:after:tw-bg-text-muted", ]; constructor(@Optional() @Self() private ngControl?: NgControl) {} diff --git a/libs/components/src/checkbox/checkbox.stories.ts b/libs/components/src/checkbox/checkbox.stories.ts index 123c6704ff4..9050d97cafc 100644 --- a/libs/components/src/checkbox/checkbox.stories.ts +++ b/libs/components/src/checkbox/checkbox.stories.ts @@ -13,6 +13,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { BadgeModule } from "../badge"; import { FormControlModule } from "../form-control"; +import { FormFieldModule } from "../form-field"; import { TableModule } from "../table"; import { I18nMockService } from "../utils/i18n-mock.service"; @@ -30,6 +31,7 @@ const template = /*html*/ ` @Component({ selector: "app-example", template, + imports: [CheckboxModule, FormFieldModule, ReactiveFormsModule], }) class ExampleComponent { protected formObj = this.formBuilder.group({ @@ -55,8 +57,8 @@ export default { title: "Component Library/Form/Checkbox", decorators: [ moduleMetadata({ - declarations: [ExampleComponent], imports: [ + ExampleComponent, FormsModule, ReactiveFormsModule, FormControlModule, @@ -195,17 +197,17 @@ export const Custom: Story = { props: args, template: /*html*/ `
-
`, diff --git a/libs/components/src/form-control/form-control.component.html b/libs/components/src/form-control/form-control.component.html index 735e375a29a..15d422b01a1 100644 --- a/libs/components/src/form-control/form-control.component.html +++ b/libs/components/src/form-control/form-control.component.html @@ -1,5 +1,5 @@
Open Simple Dialog`, + template: ` + + + + `, imports: [ButtonModule], }) class StoryDialogComponent { constructor(public dialogService: DialogService) {} - openDialog() { - this.dialogService.open(StoryDialogContentComponent, { + openSimpleDialog() { + this.dialogService.open(SimpleDialogContent, { data: { animal: "panda", }, }); } + + openNonDismissableWithPrimaryButtonDialog() { + this.dialogService.open(NonDismissableWithPrimaryButtonContent, { + data: { + animal: "panda", + }, + disableClose: true, + }); + } + + openNonDismissableWithNoButtonsDialog() { + this.dialogService.open(NonDismissableWithNoButtonsContent, { + data: { + animal: "panda", + }, + disableClose: true, + }); + } } @Component({ @@ -49,7 +76,60 @@ class StoryDialogComponent { `, imports: [ButtonModule, DialogModule], }) -class StoryDialogContentComponent { +class SimpleDialogContent { + constructor( + public dialogRef: DialogRef, + @Inject(DIALOG_DATA) private data: Animal, + ) {} + + get animal() { + return this.data?.animal; + } +} + +@Component({ + template: ` + + Dialog Title + + Dialog body text goes here. +
+ Animal: {{ animal }} +
+ + + +
+ `, + imports: [ButtonModule, DialogModule], +}) +class NonDismissableWithPrimaryButtonContent { + constructor( + public dialogRef: DialogRef, + @Inject(DIALOG_DATA) private data: Animal, + ) {} + + get animal() { + return this.data?.animal; + } +} + +@Component({ + template: ` + + Dialog Title + + Dialog body text goes here. +
+ Animal: {{ animal }} +
+
+ `, + imports: [ButtonModule, DialogModule], +}) +class NonDismissableWithNoButtonsContent { constructor( public dialogRef: DialogRef, @Inject(DIALOG_DATA) private data: Animal, @@ -89,4 +169,29 @@ export default { type Story = StoryObj; -export const Default: Story = {}; +export const Default: Story = { + play: async (context) => { + const canvas = context.canvasElement; + + const button = getAllByRole(canvas, "button")[0]; + await userEvent.click(button); + }, +}; + +export const NonDismissableWithPrimaryButton: Story = { + play: async (context) => { + const canvas = context.canvasElement; + + const button = getAllByRole(canvas, "button")[1]; + await userEvent.click(button); + }, +}; + +export const NonDismissableWithNoButtons: Story = { + play: async (context) => { + const canvas = context.canvasElement; + + const button = getAllByRole(canvas, "button")[2]; + await userEvent.click(button); + }, +}; From b4d87007baa2fc771fae5b19bfc218e4f2395a38 Mon Sep 17 00:00:00 2001 From: Bryan Cunningham Date: Thu, 3 Jul 2025 16:12:56 -0400 Subject: [PATCH 061/239] [CL-718] nav updates (#15226) * add basic new nav item styling * update alt-3 bg color * add x padding to item * remove copy left in error * style app switcher to match nav items * adding new button hover colors * add new logo lockups * use new logos in web vault * fix color and svg fills * use set height for nav items * optimize SVGs * move if logic * use rem for icon size * move shield logo * use shield svg for collapsed icon * remove unused eslint disable directive * run prettier * remove variables * update logo hover styles * use more standard flow control syntax * update admin console logo svg * add new hover variables * use class instead of fill * use variable for logo hover * remove unnecessary container * use hover variable for nav switcher * use correct variables for fill colors * update hover state to use variable left in error * give icon width to preserve text alignment * remove tree story as functionality no longer supported * remove nested styles helper * remove obsolete afterContentInit * remove tree example from layout story * remove tree example from secondary layout story * remove tree example from kitchen sink story * Fix interaction test * remove remaining references to tree variant --- .../layouts/organization-layout.component.ts | 3 +- .../navigation-switcher.component.html | 72 ++--- .../src/app/layouts/user-layout.component.ts | 3 +- .../layout/navigation.component.ts | 2 +- .../src/anon-layout/anon-layout.component.ts | 3 +- .../src/icon/icons/bitwarden-shield.icon.ts | 7 - libs/components/src/icon/icons/index.ts | 1 - libs/components/src/icon/index.ts | 1 + .../src/icon/logos/bitwarden/admin-console.ts | 7 + .../src/icon/logos/bitwarden/index.ts | 4 + .../icon/logos/bitwarden/password-manager.ts | 7 + .../icon/logos/bitwarden/secrets-manager.ts | 7 + .../src/icon/logos/bitwarden/shield.ts | 7 + libs/components/src/icon/logos/index.ts | 1 + libs/components/src/layout/layout.stories.ts | 288 ++---------------- .../src/navigation/nav-base.component.ts | 10 - .../src/navigation/nav-divider.component.html | 2 +- .../src/navigation/nav-group.component.html | 16 +- .../src/navigation/nav-group.component.ts | 19 +- .../src/navigation/nav-group.stories.ts | 25 -- .../src/navigation/nav-item.component.html | 174 +++++------ .../src/navigation/nav-logo.component.html | 42 ++- .../src/navigation/nav-logo.component.ts | 8 +- .../src/navigation/side-nav.component.html | 1 + .../kitchen-sink/kitchen-sink.stories.ts | 22 +- libs/components/src/tw-theme.css | 8 +- libs/components/tailwind.config.base.js | 4 + 27 files changed, 213 insertions(+), 531 deletions(-) delete mode 100644 libs/components/src/icon/icons/bitwarden-shield.icon.ts create mode 100644 libs/components/src/icon/logos/bitwarden/admin-console.ts create mode 100644 libs/components/src/icon/logos/bitwarden/index.ts create mode 100644 libs/components/src/icon/logos/bitwarden/password-manager.ts create mode 100644 libs/components/src/icon/logos/bitwarden/secrets-manager.ts create mode 100644 libs/components/src/icon/logos/bitwarden/shield.ts create mode 100644 libs/components/src/icon/logos/index.ts diff --git a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts index e60cc918fb8..dc1913a5336 100644 --- a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts +++ b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts @@ -27,12 +27,11 @@ import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { getById } from "@bitwarden/common/platform/misc"; -import { BannerModule, IconModule } from "@bitwarden/components"; +import { BannerModule, IconModule, AdminConsoleLogo } from "@bitwarden/components"; import { FreeFamiliesPolicyService } from "../../../billing/services/free-families-policy.service"; import { OrgSwitcherComponent } from "../../../layouts/org-switcher/org-switcher.component"; import { WebLayoutModule } from "../../../layouts/web-layout.module"; -import { AdminConsoleLogo } from "../../icons/admin-console-logo"; @Component({ selector: "app-organization-layout", diff --git a/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.component.html b/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.component.html index 08195d95bf9..f8ebfa60451 100644 --- a/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.component.html +++ b/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.component.html @@ -16,43 +16,45 @@ > {{ "moreFromBitwarden" | i18n }} - -
- -
- {{ more.otherProductOverrides?.name ?? more.name }} -
- {{ more.otherProductOverrides.supportingText }} + - - - - - diff --git a/apps/web/src/app/layouts/user-layout.component.ts b/apps/web/src/app/layouts/user-layout.component.ts index cd07d625281..db4c181cd0f 100644 --- a/apps/web/src/app/layouts/user-layout.component.ts +++ b/apps/web/src/app/layouts/user-layout.component.ts @@ -9,11 +9,10 @@ import { JslibModule } from "@bitwarden/angular/jslib.module"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { SyncService } from "@bitwarden/common/platform/sync"; -import { IconModule } from "@bitwarden/components"; +import { IconModule, PasswordManagerLogo } from "@bitwarden/components"; import { BillingFreeFamiliesNavItemComponent } from "../billing/shared/billing-free-families-nav-item.component"; -import { PasswordManagerLogo } from "./password-manager-logo"; import { WebLayoutModule } from "./web-layout.module"; @Component({ diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/layout/navigation.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/layout/navigation.component.ts index 1eef528b639..24da000f213 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/layout/navigation.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/layout/navigation.component.ts @@ -22,7 +22,7 @@ import { 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 { SecretsManagerLogo } from "@bitwarden/web-vault/app/layouts/secrets-manager-logo"; +import { SecretsManagerLogo } from "@bitwarden/components"; import { OrganizationCounts } from "../models/view/counts.view"; import { ProjectService } from "../projects/project.service"; diff --git a/libs/components/src/anon-layout/anon-layout.component.ts b/libs/components/src/anon-layout/anon-layout.component.ts index ee3a7ca7bee..45e7f3973a9 100644 --- a/libs/components/src/anon-layout/anon-layout.component.ts +++ b/libs/components/src/anon-layout/anon-layout.component.ts @@ -10,7 +10,8 @@ import { EnvironmentService } from "@bitwarden/common/platform/abstractions/envi import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { IconModule, Icon } from "../icon"; -import { BitwardenLogo, BitwardenShield } from "../icon/icons"; +import { BitwardenLogo } from "../icon/icons"; +import { BitwardenShield } from "../icon/logos"; import { SharedModule } from "../shared"; import { TypographyModule } from "../typography"; diff --git a/libs/components/src/icon/icons/bitwarden-shield.icon.ts b/libs/components/src/icon/icons/bitwarden-shield.icon.ts deleted file mode 100644 index 7abeaf40e3c..00000000000 --- a/libs/components/src/icon/icons/bitwarden-shield.icon.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { svgIcon } from "../icon"; - -export const BitwardenShield = svgIcon` - - - -`; diff --git a/libs/components/src/icon/icons/index.ts b/libs/components/src/icon/icons/index.ts index b68be2bac9a..69fac7d644e 100644 --- a/libs/components/src/icon/icons/index.ts +++ b/libs/components/src/icon/icons/index.ts @@ -1,5 +1,4 @@ export * from "./bitwarden-logo.icon"; -export * from "./bitwarden-shield.icon"; export * from "./extension-bitwarden-logo.icon"; export * from "./lock.icon"; export * from "./generator"; diff --git a/libs/components/src/icon/index.ts b/libs/components/src/icon/index.ts index 8f29234dbc5..4f797326be3 100644 --- a/libs/components/src/icon/index.ts +++ b/libs/components/src/icon/index.ts @@ -1,3 +1,4 @@ export * from "./icon.module"; export * from "./icon"; export * as Icons from "./icons"; +export { AdminConsoleLogo, PasswordManagerLogo, SecretsManagerLogo } from "./logos"; diff --git a/libs/components/src/icon/logos/bitwarden/admin-console.ts b/libs/components/src/icon/logos/bitwarden/admin-console.ts new file mode 100644 index 00000000000..673cf9642c8 --- /dev/null +++ b/libs/components/src/icon/logos/bitwarden/admin-console.ts @@ -0,0 +1,7 @@ +import { svgIcon } from "../../icon"; + +const AdminConsoleLogo = svgIcon` + +`; + +export default AdminConsoleLogo; diff --git a/libs/components/src/icon/logos/bitwarden/index.ts b/libs/components/src/icon/logos/bitwarden/index.ts new file mode 100644 index 00000000000..e786eb90e78 --- /dev/null +++ b/libs/components/src/icon/logos/bitwarden/index.ts @@ -0,0 +1,4 @@ +export { default as AdminConsoleLogo } from "./admin-console"; +export { default as BitwardenShield } from "./shield"; +export { default as PasswordManagerLogo } from "./password-manager"; +export { default as SecretsManagerLogo } from "./secrets-manager"; diff --git a/libs/components/src/icon/logos/bitwarden/password-manager.ts b/libs/components/src/icon/logos/bitwarden/password-manager.ts new file mode 100644 index 00000000000..37b62c5dbc2 --- /dev/null +++ b/libs/components/src/icon/logos/bitwarden/password-manager.ts @@ -0,0 +1,7 @@ +import { svgIcon } from "../../icon"; + +const PasswordManagerLogo = svgIcon` + +`; + +export default PasswordManagerLogo; diff --git a/libs/components/src/icon/logos/bitwarden/secrets-manager.ts b/libs/components/src/icon/logos/bitwarden/secrets-manager.ts new file mode 100644 index 00000000000..bcba5f71d1a --- /dev/null +++ b/libs/components/src/icon/logos/bitwarden/secrets-manager.ts @@ -0,0 +1,7 @@ +import { svgIcon } from "../../icon"; + +const SecretsManagerLogo = svgIcon` + +`; + +export default SecretsManagerLogo; diff --git a/libs/components/src/icon/logos/bitwarden/shield.ts b/libs/components/src/icon/logos/bitwarden/shield.ts new file mode 100644 index 00000000000..15fe6dddf48 --- /dev/null +++ b/libs/components/src/icon/logos/bitwarden/shield.ts @@ -0,0 +1,7 @@ +import { svgIcon } from "../../icon"; + +const BitwardenShield = svgIcon` + +`; + +export default BitwardenShield; diff --git a/libs/components/src/icon/logos/index.ts b/libs/components/src/icon/logos/index.ts new file mode 100644 index 00000000000..07a8a739289 --- /dev/null +++ b/libs/components/src/icon/logos/index.ts @@ -0,0 +1 @@ +export * from "./bitwarden"; diff --git a/libs/components/src/layout/layout.stories.ts b/libs/components/src/layout/layout.stories.ts index e495367f78d..7ab0ffc7ce9 100644 --- a/libs/components/src/layout/layout.stories.ts +++ b/libs/components/src/layout/layout.stories.ts @@ -55,207 +55,15 @@ export const WithContent: Story = { template: /* HTML */ ` - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + Hello world! @@ -277,77 +85,15 @@ export const Secondary: Story = { template: /* HTML */ ` - - - - - - - - - - - - - - - - - - - + + + + + + + + + Hello world! diff --git a/libs/components/src/navigation/nav-base.component.ts b/libs/components/src/navigation/nav-base.component.ts index 9b222c9434f..dc3084509a5 100644 --- a/libs/components/src/navigation/nav-base.component.ts +++ b/libs/components/src/navigation/nav-base.component.ts @@ -55,16 +55,6 @@ export abstract class NavBaseComponent { matrixParams: "ignored", }; - /** - * If this item is used within a tree, set `variant` to `"tree"` - */ - @Input() variant: "default" | "tree" = "default"; - - /** - * Depth level when nested inside of a `'tree'` variant - */ - @Input() treeDepth = 0; - /** * If `true`, do not change styles when nav item is active. */ diff --git a/libs/components/src/navigation/nav-divider.component.html b/libs/components/src/navigation/nav-divider.component.html index 64e43aeab4e..2d8e1dfa24b 100644 --- a/libs/components/src/navigation/nav-divider.component.html +++ b/libs/components/src/navigation/nav-divider.component.html @@ -1,3 +1,3 @@ @if (sideNavService.open$ | async) { -
+
} diff --git a/libs/components/src/navigation/nav-group.component.html b/libs/components/src/navigation/nav-group.component.html index cbb270ad070..6a9ee4c0ab9 100644 --- a/libs/components/src/navigation/nav-group.component.html +++ b/libs/components/src/navigation/nav-group.component.html @@ -6,8 +6,6 @@ [route]="route" [relativeTo]="relativeTo" [routerLinkActiveOptions]="routerLinkActiveOptions" - [variant]="variant" - [treeDepth]="treeDepth" (mainContentClicked)="handleMainContentClicked()" [ariaLabel]="ariaLabel" [hideActiveStyles]="parentHideActiveStyles" @@ -16,9 +14,7 @@ - - @if (variant === "tree") { - - - - } - @if (variant !== "tree") { - - } + diff --git a/libs/components/src/navigation/nav-group.component.ts b/libs/components/src/navigation/nav-group.component.ts index 5346a583e37..b52f9fcd202 100644 --- a/libs/components/src/navigation/nav-group.component.ts +++ b/libs/components/src/navigation/nav-group.component.ts @@ -1,6 +1,5 @@ import { CommonModule } from "@angular/common"; import { - AfterContentInit, booleanAttribute, Component, ContentChildren, @@ -29,7 +28,7 @@ import { SideNavService } from "./side-nav.service"; ], imports: [CommonModule, NavItemComponent, IconButtonModule, I18nPipe], }) -export class NavGroupComponent extends NavBaseComponent implements AfterContentInit { +export class NavGroupComponent extends NavBaseComponent { @ContentChildren(NavBaseComponent, { descendants: true, }) @@ -80,18 +79,6 @@ export class NavGroupComponent extends NavBaseComponent implements AfterContentI this.setOpen(!this.open); } - /** - * - For any nested NavGroupComponents or NavItemComponents, increment the `treeDepth` by 1. - */ - private initNestedStyles() { - if (this.variant !== "tree") { - return; - } - [...this.nestedNavComponents].forEach((navGroupOrItem) => { - navGroupOrItem.treeDepth += 1; - }); - } - protected handleMainContentClicked() { if (!this.sideNavService.open) { if (!this.route) { @@ -103,8 +90,4 @@ export class NavGroupComponent extends NavBaseComponent implements AfterContentI } this.mainContentClicked.emit(); } - - ngAfterContentInit(): void { - this.initNestedStyles(); - } } diff --git a/libs/components/src/navigation/nav-group.stories.ts b/libs/components/src/navigation/nav-group.stories.ts index 19fe3764852..b30acc63c72 100644 --- a/libs/components/src/navigation/nav-group.stories.ts +++ b/libs/components/src/navigation/nav-group.stories.ts @@ -111,31 +111,6 @@ export const HideEmptyGroups: StoryObj = { - render: (args) => ({ - props: args, - template: /*html*/ ` - - - - - - - - - - - - - - - - - - `, - }), -}; - export const Secondary: StoryObj = { render: (args) => ({ props: args, diff --git a/libs/components/src/navigation/nav-item.component.html b/libs/components/src/navigation/nav-item.component.html index f86f7e2c6d7..15fcc74e1f9 100644 --- a/libs/components/src/navigation/nav-item.component.html +++ b/libs/components/src/navigation/nav-item.component.html @@ -1,113 +1,77 @@ - -
+
+ @let open = sideNavService.open$ | async; + @if (open || icon) {
-
-
- -
- -
+
+ + + + +
+ + @if (open) { + {{ text }} + } +
+
+ + + + + + + + + + + + + -
-
- - - - - -
- {{ text }} -
-
+ + + - - - - - - - - - - - - - - - -
- + @if (open) { +
+ +
+ }
-
- + } +
diff --git a/libs/components/src/navigation/nav-logo.component.html b/libs/components/src/navigation/nav-logo.component.html index a6169315333..40dbe8189d6 100644 --- a/libs/components/src/navigation/nav-logo.component.html +++ b/libs/components/src/navigation/nav-logo.component.html @@ -1,23 +1,19 @@ -@if (sideNavService.open) { -
- - - -
-} -@if (!sideNavService.open) { - -} + diff --git a/libs/components/src/navigation/nav-logo.component.ts b/libs/components/src/navigation/nav-logo.component.ts index 724406eeed5..8c40ea0dc79 100644 --- a/libs/components/src/navigation/nav-logo.component.ts +++ b/libs/components/src/navigation/nav-logo.component.ts @@ -1,23 +1,23 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore - +import { CommonModule } from "@angular/common"; import { Component, Input } from "@angular/core"; import { RouterLinkActive, RouterLink } from "@angular/router"; import { Icon } from "../icon"; import { BitIconComponent } from "../icon/icon.component"; +import { BitwardenShield } from "../icon/logos"; -import { NavItemComponent } from "./nav-item.component"; import { SideNavService } from "./side-nav.service"; @Component({ selector: "bit-nav-logo", templateUrl: "./nav-logo.component.html", - imports: [RouterLinkActive, RouterLink, BitIconComponent, NavItemComponent], + imports: [CommonModule, RouterLinkActive, RouterLink, BitIconComponent], }) export class NavLogoComponent { /** Icon that is displayed when the side nav is closed */ - @Input() closedIcon = "bwi-shield"; + @Input() closedIcon = BitwardenShield; /** Icon that is displayed when the side nav is open */ @Input({ required: true }) openIcon: Icon; diff --git a/libs/components/src/navigation/side-nav.component.html b/libs/components/src/navigation/side-nav.component.html index 3b77c981be4..124daa776d0 100644 --- a/libs/components/src/navigation/side-nav.component.html +++ b/libs/components/src/navigation/side-nav.component.html @@ -14,6 +14,7 @@ '--color-text-alt2': 'var(--color-text-main)', '--color-background-alt3': 'var(--color-secondary-100)', '--color-background-alt4': 'var(--color-secondary-300)', + '--color-hover-contrast': 'var(--color-hover-default)', } " [cdkTrapFocus]="data.isOverlay" diff --git a/libs/components/src/stories/kitchen-sink/kitchen-sink.stories.ts b/libs/components/src/stories/kitchen-sink/kitchen-sink.stories.ts index d318e1b5f0e..97a782b7302 100644 --- a/libs/components/src/stories/kitchen-sink/kitchen-sink.stories.ts +++ b/libs/components/src/stories/kitchen-sink/kitchen-sink.stories.ts @@ -81,16 +81,18 @@ export const Default: Story = { template: /* HTML */ ` - - - - - + + + + + + + + diff --git a/libs/components/src/tw-theme.css b/libs/components/src/tw-theme.css index 078357491e5..eb5bb469202 100644 --- a/libs/components/src/tw-theme.css +++ b/libs/components/src/tw-theme.css @@ -13,7 +13,7 @@ --color-background: 255 255 255; --color-background-alt: 243 246 249; --color-background-alt2: 23 92 219; - --color-background-alt3: 26 65 172; + --color-background-alt3: 22 55 146; --color-background-alt4: 2 15 102; --color-primary-100: 219 229 246; @@ -56,6 +56,9 @@ --color-text-alt2: 255 255 255; --color-text-code: 192 17 118; + --color-hover-default: rgb(26 65 172 / 0.1); + --color-hover-contrast: rgb(219 229 246 / 0.15); + --color-marketing-logo: 23 93 220; --tw-ring-offset-color: #ffffff; @@ -124,6 +127,9 @@ --color-text-alt2: 255 255 255; --color-text-code: 255 143 208; + --color-hover-default: rgb(170 195 239 / 0.1); + --color-hover-contrast: rgb(26 39 78 / 0.15); + --color-marketing-logo: 255 255 255; --tw-ring-offset-color: #1f242e; diff --git a/libs/components/tailwind.config.base.js b/libs/components/tailwind.config.base.js index c38515cf775..829c812a954 100644 --- a/libs/components/tailwind.config.base.js +++ b/libs/components/tailwind.config.base.js @@ -83,6 +83,10 @@ module.exports = { alt3: rgba("--color-background-alt3"), alt4: rgba("--color-background-alt4"), }, + hover: { + default: "var(--color-hover-default)", + contrast: "var(--color-hover-contrast)", + }, "marketing-logo": rgba("--color-marketing-logo"), illustration: { outline: rgba("--color-illustration-outline"), From c7fc9b88fccc15b93d99f03c60444ab1c7e79204 Mon Sep 17 00:00:00 2001 From: Jason Ng Date: Thu, 3 Jul 2025 17:35:50 -0400 Subject: [PATCH 062/239] [PM-23197] update cipherService to return decCiphers (#15433) * update cipherService to return decCiphers, update input to use signal, refactor observable, update spec --- .../src/vault/services/cipher.service.ts | 2 +- .../new-item-nudge.component.html | 2 +- .../new-item-nudge.component.spec.ts | 59 ++++++++++--------- .../new-item-nudge.component.ts | 53 ++++++++--------- 4 files changed, 57 insertions(+), 59 deletions(-) diff --git a/libs/common/src/vault/services/cipher.service.ts b/libs/common/src/vault/services/cipher.service.ts index b4f79b2467e..a1727fd7a1d 100644 --- a/libs/common/src/vault/services/cipher.service.ts +++ b/libs/common/src/vault/services/cipher.service.ts @@ -383,7 +383,7 @@ export class CipherService implements CipherServiceAbstraction { const decCiphers = await this.getDecryptedCiphers(userId); if (decCiphers != null && decCiphers.length !== 0) { await this.reindexCiphers(userId); - return await this.getDecryptedCiphers(userId); + return decCiphers; } const decrypted = await this.decryptCiphers(await this.getAll(userId), userId); diff --git a/libs/vault/src/cipher-form/components/new-item-nudge/new-item-nudge.component.html b/libs/vault/src/cipher-form/components/new-item-nudge/new-item-nudge.component.html index 5cd1246fd36..58dc181f826 100644 --- a/libs/vault/src/cipher-form/components/new-item-nudge/new-item-nudge.component.html +++ b/libs/vault/src/cipher-form/components/new-item-nudge/new-item-nudge.component.html @@ -1,4 +1,4 @@ - + { let component: NewItemNudgeComponent; + let componentRef: ComponentRef; let fixture: ComponentFixture; let i18nService: MockProxy; - let accountService: MockProxy; let nudgesService: MockProxy; + const accountService: FakeAccountService = mockAccountServiceWith("test-user-id" as UserId); beforeEach(async () => { i18nService = mock({ t: (key: string) => key }); - accountService = mock(); nudgesService = mock(); await TestBed.configureTestingModule({ @@ -37,7 +40,8 @@ describe("NewItemNudgeComponent", () => { beforeEach(() => { fixture = TestBed.createComponent(NewItemNudgeComponent); component = fixture.componentInstance; - component.configType = null; // Set to null for initial state + componentRef = fixture.componentRef; + componentRef.setInput("configType", null); // Set a default type for testing fixture.detectChanges(); }); @@ -46,13 +50,11 @@ describe("NewItemNudgeComponent", () => { }); it("should set nudge title and body for CipherType.Login type", async () => { - component.configType = CipherType.Login; - accountService.activeAccount$ = of({ id: "test-user-id" as UserId } as Account); - jest.spyOn(component, "checkHasSpotlightDismissed").mockResolvedValue(true); - - await component.ngOnInit(); - - expect(component.showNewItemSpotlight).toBe(true); + componentRef.setInput("configType", CipherType.Login); + fixture.detectChanges(); + component.showNewItemSpotlight$.subscribe((value) => { + expect(value).toEqual(true); + }); expect(component.nudgeTitle).toBe("newLoginNudgeTitle"); expect(component.nudgeBody).toBe( "newLoginNudgeBodyOne newLoginNudgeBodyBold newLoginNudgeBodyTwo", @@ -61,39 +63,38 @@ describe("NewItemNudgeComponent", () => { }); it("should set nudge title and body for CipherType.Card type", async () => { - component.configType = CipherType.Card; - accountService.activeAccount$ = of({ id: "test-user-id" as UserId } as Account); - jest.spyOn(component, "checkHasSpotlightDismissed").mockResolvedValue(true); - - await component.ngOnInit(); - - expect(component.showNewItemSpotlight).toBe(true); + componentRef.setInput("configType", CipherType.Card); + fixture.detectChanges(); + component.showNewItemSpotlight$.subscribe((value) => { + expect(value).toEqual(true); + }); expect(component.nudgeTitle).toBe("newCardNudgeTitle"); expect(component.nudgeBody).toBe("newCardNudgeBody"); expect(component.dismissalNudgeType).toBe(NudgeType.NewCardItemStatus); }); it("should not show anything if spotlight has been dismissed", async () => { - component.configType = CipherType.Identity; - accountService.activeAccount$ = of({ id: "test-user-id" as UserId } as Account); - jest.spyOn(component, "checkHasSpotlightDismissed").mockResolvedValue(false); - - await component.ngOnInit(); - - expect(component.showNewItemSpotlight).toBe(false); + componentRef.setInput("configType", CipherType.Identity); + fixture.detectChanges(); + component.showNewItemSpotlight$.subscribe((value) => { + expect(value).toEqual(false); + }); expect(component.dismissalNudgeType).toBe(NudgeType.NewIdentityItemStatus); }); it("should set showNewItemSpotlight to false when user dismisses spotlight", async () => { - component.showNewItemSpotlight = true; + component.showNewItemSpotlight$ = of(true); component.dismissalNudgeType = NudgeType.NewLoginItemStatus; - component.activeUserId = "test-user-id" as UserId; + const activeUserId = "test-user-id" as UserId; + component.activeUserId$ = of(activeUserId); const dismissSpy = jest.spyOn(nudgesService, "dismissNudge").mockResolvedValue(); await component.dismissNewItemSpotlight(); - expect(component.showNewItemSpotlight).toBe(false); - expect(dismissSpy).toHaveBeenCalledWith(NudgeType.NewLoginItemStatus, component.activeUserId); + component.showNewItemSpotlight$.subscribe((value) => { + expect(value).toEqual(false); + }); + expect(dismissSpy).toHaveBeenCalledWith(NudgeType.NewLoginItemStatus, activeUserId); }); }); diff --git a/libs/vault/src/cipher-form/components/new-item-nudge/new-item-nudge.component.ts b/libs/vault/src/cipher-form/components/new-item-nudge/new-item-nudge.component.ts index 79defc271cf..eccf8f65715 100644 --- a/libs/vault/src/cipher-form/components/new-item-nudge/new-item-nudge.component.ts +++ b/libs/vault/src/cipher-form/components/new-item-nudge/new-item-nudge.component.ts @@ -1,6 +1,7 @@ -import { NgIf } from "@angular/common"; -import { Component, Input, OnInit } from "@angular/core"; -import { firstValueFrom } from "rxjs"; +import { AsyncPipe, NgIf } from "@angular/common"; +import { Component, input } from "@angular/core"; +import { toObservable } from "@angular/core/rxjs-interop"; +import { combineLatest, firstValueFrom, map, of, switchMap } from "rxjs"; import { NudgesService, NudgeType } from "@bitwarden/angular/vault"; import { SpotlightComponent } from "@bitwarden/angular/vault/components/spotlight/spotlight.component"; @@ -13,12 +14,17 @@ import { CipherType } from "@bitwarden/sdk-internal"; @Component({ selector: "vault-new-item-nudge", templateUrl: "./new-item-nudge.component.html", - imports: [NgIf, SpotlightComponent], + imports: [NgIf, SpotlightComponent, AsyncPipe], }) -export class NewItemNudgeComponent implements OnInit { - @Input({ required: true }) configType: CipherType | null = null; - activeUserId: UserId | null = null; - showNewItemSpotlight: boolean = false; +export class NewItemNudgeComponent { + configType = input.required(); + activeUserId$ = this.accountService.activeAccount$.pipe(getUserId); + showNewItemSpotlight$ = combineLatest([ + this.activeUserId$, + toObservable(this.configType).pipe(map((cipherType) => this.mapToNudgeType(cipherType))), + ]).pipe( + switchMap(([userId, nudgeType]) => this.nudgesService.showNudgeSpotlight$(nudgeType, userId)), + ); nudgeTitle: string = ""; nudgeBody: string = ""; dismissalNudgeType: NudgeType | null = null; @@ -29,10 +35,8 @@ export class NewItemNudgeComponent implements OnInit { private nudgesService: NudgesService, ) {} - async ngOnInit() { - this.activeUserId = await firstValueFrom(getUserId(this.accountService.activeAccount$)); - - switch (this.configType) { + mapToNudgeType(cipherType: CipherType | null): NudgeType { + switch (cipherType) { case CipherType.Login: { const nudgeBodyOne = this.i18nService.t("newLoginNudgeBodyOne"); const nudgeBodyBold = this.i18nService.t("newLoginNudgeBodyBold"); @@ -40,25 +44,25 @@ export class NewItemNudgeComponent implements OnInit { this.dismissalNudgeType = NudgeType.NewLoginItemStatus; this.nudgeTitle = this.i18nService.t("newLoginNudgeTitle"); this.nudgeBody = `${nudgeBodyOne} ${nudgeBodyBold} ${nudgeBodyTwo}`; - break; + return NudgeType.NewLoginItemStatus; } case CipherType.Card: this.dismissalNudgeType = NudgeType.NewCardItemStatus; this.nudgeTitle = this.i18nService.t("newCardNudgeTitle"); this.nudgeBody = this.i18nService.t("newCardNudgeBody"); - break; + return NudgeType.NewCardItemStatus; case CipherType.Identity: this.dismissalNudgeType = NudgeType.NewIdentityItemStatus; this.nudgeTitle = this.i18nService.t("newIdentityNudgeTitle"); this.nudgeBody = this.i18nService.t("newIdentityNudgeBody"); - break; + return NudgeType.NewIdentityItemStatus; case CipherType.SecureNote: this.dismissalNudgeType = NudgeType.NewNoteItemStatus; this.nudgeTitle = this.i18nService.t("newNoteNudgeTitle"); this.nudgeBody = this.i18nService.t("newNoteNudgeBody"); - break; + return NudgeType.NewNoteItemStatus; case CipherType.SshKey: { const sshPartOne = this.i18nService.t("newSshNudgeBodyOne"); @@ -67,25 +71,18 @@ export class NewItemNudgeComponent implements OnInit { this.dismissalNudgeType = NudgeType.NewSshItemStatus; this.nudgeTitle = this.i18nService.t("newSshNudgeTitle"); this.nudgeBody = `${sshPartOne} ${sshPartTwo}`; - break; + return NudgeType.NewSshItemStatus; } default: throw new Error("Unsupported cipher type"); } - this.showNewItemSpotlight = await this.checkHasSpotlightDismissed( - this.dismissalNudgeType as NudgeType, - this.activeUserId, - ); } async dismissNewItemSpotlight() { - if (this.dismissalNudgeType && this.activeUserId) { - await this.nudgesService.dismissNudge(this.dismissalNudgeType, this.activeUserId as UserId); - this.showNewItemSpotlight = false; + const activeUserId = await firstValueFrom(this.activeUserId$); + if (this.dismissalNudgeType && activeUserId) { + await this.nudgesService.dismissNudge(this.dismissalNudgeType, activeUserId as UserId); + this.showNewItemSpotlight$ = of(false); } } - - async checkHasSpotlightDismissed(nudgeType: NudgeType, userId: UserId): Promise { - return await firstValueFrom(this.nudgesService.showNudgeSpotlight$(nudgeType, userId)); - } } From 03a7530f8b06613ea2faf65c41d40508164d3cc5 Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Mon, 7 Jul 2025 13:27:50 +0200 Subject: [PATCH 063/239] Remove legacy key support form tools code (#15349) --- .../importer/src/importers/bitwarden/bitwarden-json-importer.ts | 2 +- libs/importer/src/services/import.service.ts | 2 +- .../src/services/individual-vault-export.service.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/importer/src/importers/bitwarden/bitwarden-json-importer.ts b/libs/importer/src/importers/bitwarden/bitwarden-json-importer.ts index 4291f7b1ab2..dfc1c9f58e9 100644 --- a/libs/importer/src/importers/bitwarden/bitwarden-json-importer.ts +++ b/libs/importer/src/importers/bitwarden/bitwarden-json-importer.ts @@ -71,7 +71,7 @@ export class BitwardenJsonImporter extends BaseImporter implements Importer { this.organizationId, ); if (keyForDecryption == null) { - keyForDecryption = await this.keyService.getUserKeyWithLegacySupport(); + keyForDecryption = await this.keyService.getUserKey(); } const encKeyValidation = new EncString(results.encKeyValidation_DO_NOT_EDIT); const encKeyValidationDecrypt = await this.encryptService.decryptString( diff --git a/libs/importer/src/services/import.service.ts b/libs/importer/src/services/import.service.ts index 2b9d2e490f7..c9cb325d10b 100644 --- a/libs/importer/src/services/import.service.ts +++ b/libs/importer/src/services/import.service.ts @@ -365,7 +365,7 @@ export class ImportService implements ImportServiceAbstraction { const c = await this.cipherService.encrypt(importResult.ciphers[i], activeUserId); request.ciphers.push(new CipherRequest(c)); } - const userKey = await this.keyService.getUserKeyWithLegacySupport(activeUserId); + const userKey = await this.keyService.getUserKey(activeUserId); if (importResult.folders != null) { for (let i = 0; i < importResult.folders.length; i++) { const f = await this.folderService.encrypt(importResult.folders[i], userKey); 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 214b2d832a4..4d4ef217c66 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 @@ -225,7 +225,7 @@ export class IndividualVaultExportService await Promise.all(promises); - const userKey = await this.keyService.getUserKeyWithLegacySupport(activeUserId); + const userKey = await this.keyService.getUserKey(activeUserId); const encKeyValidation = await this.encryptService.encryptString(Utils.newGuid(), userKey); const jsonDoc: BitwardenEncryptedIndividualJsonExport = { From 2e03b8cbac1876c3e519123ae57481c6916b3b1c Mon Sep 17 00:00:00 2001 From: Nick Krantz <125900171+nick-livefront@users.noreply.github.com> Date: Mon, 7 Jul 2025 08:56:31 -0500 Subject: [PATCH 064/239] [PM-22180] Setup Extension Videos (#15419) * remove placeholder image * add videos for setup extension * add support for mobile viewports * add mobile/responsiveness for setup extension page * add videos from `assets.bitwarden.com` * align with figma for borders and shadow * make text responsive for setup headings * remove period * add tests * add tests for video sequence * force font weight on `h2` * add 8px to bottom margin of video container --- .../add-extension-videos.component.html | 82 +++++++++ .../add-extension-videos.component.spec.ts | 170 ++++++++++++++++++ .../add-extension-videos.component.ts | 146 +++++++++++++++ .../setup-extension.component.html | 17 +- .../setup-extension.component.spec.ts | 1 + .../setup-extension.component.ts | 42 ++++- .../setup-extension-placeholder.png | Bin 788300 -> 0 bytes apps/web/src/locales/en/messages.json | 6 +- apps/web/webpack.config.js | 3 + 9 files changed, 450 insertions(+), 17 deletions(-) create mode 100644 apps/web/src/app/vault/components/setup-extension/add-extension-videos.component.html create mode 100644 apps/web/src/app/vault/components/setup-extension/add-extension-videos.component.spec.ts create mode 100644 apps/web/src/app/vault/components/setup-extension/add-extension-videos.component.ts delete mode 100644 apps/web/src/images/setup-extension/setup-extension-placeholder.png diff --git a/apps/web/src/app/vault/components/setup-extension/add-extension-videos.component.html b/apps/web/src/app/vault/components/setup-extension/add-extension-videos.component.html new file mode 100644 index 00000000000..3764f7d828f --- /dev/null +++ b/apps/web/src/app/vault/components/setup-extension/add-extension-videos.component.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
diff --git a/apps/web/src/app/vault/components/setup-extension/add-extension-videos.component.spec.ts b/apps/web/src/app/vault/components/setup-extension/add-extension-videos.component.spec.ts new file mode 100644 index 00000000000..9f39a3edcac --- /dev/null +++ b/apps/web/src/app/vault/components/setup-extension/add-extension-videos.component.spec.ts @@ -0,0 +1,170 @@ +import { ComponentFixture, fakeAsync, TestBed, tick } from "@angular/core/testing"; +import { By } from "@angular/platform-browser"; +import { provideNoopAnimations } from "@angular/platform-browser/animations"; +import { RouterModule } from "@angular/router"; + +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; + +import { AddExtensionVideosComponent } from "./add-extension-videos.component"; + +describe("AddExtensionVideosComponent", () => { + let fixture: ComponentFixture; + let component: AddExtensionVideosComponent; + + // Mock HTMLMediaElement load to stop the video file from being loaded + Object.defineProperty(HTMLMediaElement.prototype, "load", { + value: jest.fn(), + writable: true, + }); + + const play = jest.fn(() => Promise.resolve()); + HTMLMediaElement.prototype.play = play; + + beforeEach(async () => { + window.matchMedia = jest.fn().mockReturnValue(false); + play.mockClear(); + + await TestBed.configureTestingModule({ + imports: [AddExtensionVideosComponent, RouterModule.forRoot([])], + providers: [ + provideNoopAnimations(), + { provide: I18nService, useValue: { t: (key: string) => key } }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(AddExtensionVideosComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + describe("loading pulse", () => { + it("shows loading spinner when all videos are not loaded", () => { + const loadingSpinners = fixture.debugElement.queryAll(By.css("[data-testid='video-pulse']")); + expect(loadingSpinners.length).toBe(3); + }); + + it("shows all pulses until all videos are loaded", () => { + let loadingSpinners = fixture.debugElement.queryAll(By.css("[data-testid='video-pulse']")); + expect(loadingSpinners.length).toBe(3); + + // Simulate two video loaded + component["videoElements"].get(0)?.nativeElement.dispatchEvent(new Event("loadeddata")); + component["videoElements"].get(1)?.nativeElement.dispatchEvent(new Event("loadeddata")); + + loadingSpinners = fixture.debugElement.queryAll(By.css("[data-testid='video-pulse']")); + + expect(component["numberOfLoadedVideos"]).toBe(2); + expect(loadingSpinners.length).toBe(3); + }); + }); + + describe("window resizing", () => { + beforeEach(() => { + component["numberOfLoadedVideos"] = 3; + fixture.detectChanges(); + }); + + it("shows all videos when window is resized to desktop viewport", fakeAsync(() => { + component["variant"] = "mobile"; + Object.defineProperty(component["document"].documentElement, "clientWidth", { + configurable: true, + value: 1000, + }); + + window.dispatchEvent(new Event("resize")); + + fixture.detectChanges(); + tick(50); + + expect( + Array.from(component["videoElements"]).every( + (video) => video.nativeElement.parentElement?.style.opacity === "1", + ), + ).toBe(true); + })); + + it("shows only the playing video when window is resized to mobile viewport", fakeAsync(() => { + component["variant"] = "desktop"; + // readonly property needs redefining + Object.defineProperty(component["document"].documentElement, "clientWidth", { + value: 500, + }); + + const video1 = component["videoElements"].get(1); + Object.defineProperty(video1!.nativeElement, "paused", { + value: false, + }); + + window.dispatchEvent(new Event("resize")); + + fixture.detectChanges(); + tick(50); + + expect(component["videoElements"].get(0)?.nativeElement.parentElement?.style.opacity).toBe( + "0", + ); + expect(component["videoElements"].get(1)?.nativeElement.parentElement?.style.opacity).toBe( + "1", + ); + expect(component["videoElements"].get(2)?.nativeElement.parentElement?.style.opacity).toBe( + "0", + ); + })); + }); + + describe("video sequence", () => { + let firstVideo: HTMLVideoElement; + let secondVideo: HTMLVideoElement; + let thirdVideo: HTMLVideoElement; + + beforeEach(() => { + component["numberOfLoadedVideos"] = 2; + component["onVideoLoad"](); + + firstVideo = component["videoElements"].get(0)!.nativeElement; + secondVideo = component["videoElements"].get(1)!.nativeElement; + thirdVideo = component["videoElements"].get(2)!.nativeElement; + }); + + it("starts the video sequence when all videos are loaded", fakeAsync(() => { + tick(); + + expect(firstVideo.play).toHaveBeenCalled(); + })); + + it("plays videos in sequence", fakeAsync(() => { + tick(); // let first video play + + play.mockClear(); + firstVideo.onended!(new Event("ended")); // trigger next video + + tick(); + + expect(secondVideo.play).toHaveBeenCalledTimes(1); + + play.mockClear(); + secondVideo.onended!(new Event("ended")); // trigger next video + + tick(); + + expect(thirdVideo.play).toHaveBeenCalledTimes(1); + })); + + it("doesn't play videos again when the user prefers no motion", fakeAsync(() => { + component["prefersReducedMotion"] = true; + + tick(); + firstVideo.onended!(new Event("ended")); + tick(); + secondVideo.onended!(new Event("ended")); + tick(); + + play.mockClear(); + + thirdVideo.onended!(new Event("ended")); // trigger first video again + + tick(); + expect(play).toHaveBeenCalledTimes(0); + })); + }); +}); diff --git a/apps/web/src/app/vault/components/setup-extension/add-extension-videos.component.ts b/apps/web/src/app/vault/components/setup-extension/add-extension-videos.component.ts new file mode 100644 index 00000000000..2420414fc88 --- /dev/null +++ b/apps/web/src/app/vault/components/setup-extension/add-extension-videos.component.ts @@ -0,0 +1,146 @@ +import { CommonModule, DOCUMENT } from "@angular/common"; +import { Component, ViewChildren, QueryList, ElementRef, inject } from "@angular/core"; +import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; +import { debounceTime, fromEvent } from "rxjs"; + +import { JslibModule } from "@bitwarden/angular/jslib.module"; + +@Component({ + selector: "vault-add-extension-videos", + templateUrl: "./add-extension-videos.component.html", + imports: [CommonModule, JslibModule], +}) +export class AddExtensionVideosComponent { + @ViewChildren("video", { read: ElementRef }) protected videoElements!: QueryList< + ElementRef + >; + + private document = inject(DOCUMENT); + + /** Current viewport size */ + protected variant: "mobile" | "desktop" = "desktop"; + + /** Number of videos that have loaded and are ready to play */ + protected numberOfLoadedVideos = 0; + + /** True when the user prefers reduced motion */ + protected prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches; + + /** Returns true when all videos are loaded */ + get allVideosLoaded(): boolean { + return this.numberOfLoadedVideos >= 3; + } + + constructor() { + fromEvent(window, "resize") + .pipe(takeUntilDestroyed(), debounceTime(25)) + .subscribe(() => this.onResize()); + } + + /** Resets the video states based on the viewport width changes */ + onResize(): void { + const oldVariant = this.variant; + this.variant = this.document.documentElement.clientWidth < 768 ? "mobile" : "desktop"; + + // When the viewport changes from desktop to mobile, hide all videos except the one that is playing. + if (this.variant !== oldVariant && this.variant === "mobile") { + this.videoElements.forEach((video) => { + if (video.nativeElement.paused) { + this.hideElement(video.nativeElement.parentElement!); + } else { + this.showElement(video.nativeElement.parentElement!); + } + }); + } + + // When the viewport changes from mobile to desktop, show all videos. + if (this.variant !== oldVariant && this.variant === "desktop") { + this.videoElements.forEach((video) => { + this.showElement(video.nativeElement.parentElement!); + }); + } + } + + /** + * Increment the number of loaded videos. + * When all videos are loaded, start the first one. + */ + protected onVideoLoad() { + this.numberOfLoadedVideos = this.numberOfLoadedVideos + 1; + + if (this.allVideosLoaded) { + void this.startVideoSequence(0); + } + } + + /** Recursive method to start the video sequence. */ + private async startVideoSequence(i: number): Promise { + let index = i; + const endOfVideos = index >= this.videoElements.length; + + // When the user prefers reduced motion, don't play the videos more than once + if (endOfVideos && this.prefersReducedMotion) { + return; + } + + // When the last of the videos has played, loop back to the start + if (endOfVideos) { + this.videoElements.forEach((video) => { + // Reset all videos to the start + video.nativeElement.currentTime = 0; + }); + + // Loop back to the first video + index = 0; + } + + const video = this.videoElements.toArray()[index].nativeElement; + video.onended = () => { + void this.startVideoSequence(index + 1); + }; + + this.mobileTransitionIn(index); + + // Set muted via JavaScript, browsers are respecting autoplay consistently over just the HTML attribute + video.muted = true; + await video.play(); + } + + /** For mobile viewports, fades the current video out and the next video in. */ + private mobileTransitionIn(index: number): void { + // When the viewport is above the tablet breakpoint, all videos are shown at once. + // No transition is needed. + if (this.isAboveTabletBreakpoint()) { + return; + } + + const currentParent = this.videoElements.toArray()[index].nativeElement.parentElement!; + const previousIndex = index === 0 ? this.videoElements.length - 1 : index - 1; + + const previousParent = this.videoElements.toArray()[previousIndex].nativeElement.parentElement!; + + // Fade out the previous video + this.hideElement(previousParent, true); + + // Fade in the current video + this.showElement(currentParent, true); + } + + /** Returns true when the viewport width is 768px or above. */ + private isAboveTabletBreakpoint(): boolean { + const width = this.document.documentElement.clientWidth; + return width >= 768; + } + + /** Visually hides the given element. */ + private hideElement(element: HTMLElement, transition = false): void { + element.style.transition = transition ? "opacity 0.5s linear" : ""; + element.style.opacity = "0"; + } + + /** Visually shows the given element. */ + private showElement(element: HTMLElement, transition = false): void { + element.style.transition = transition ? "opacity 0.5s linear" : ""; + element.style.opacity = "1"; + } +} diff --git a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.html b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.html index fc2b1bc60cb..3b9ec19fd34 100644 --- a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.html +++ b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.html @@ -6,16 +6,13 @@ >
-

{{ "setupExtensionPageTitle" | i18n }}

-

{{ "setupExtensionPageDescription" | i18n }}

-
- - -
+

+ {{ "setupExtensionPageTitle" | i18n }} +

+

+ {{ "setupExtensionPageDescription" | i18n }} +

+
{ navigate.mockClear(); openExtension.mockClear(); getFeatureFlag.mockClear().mockResolvedValue(true); + window.matchMedia = jest.fn().mockReturnValue(false); await TestBed.configureTestingModule({ imports: [SetupExtensionComponent, RouterModule.forRoot([])], diff --git a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.ts b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.ts index 839572f3a30..9ee8e189627 100644 --- a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.ts +++ b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.ts @@ -1,5 +1,5 @@ -import { NgIf } from "@angular/common"; -import { Component, DestroyRef, inject, OnInit } from "@angular/core"; +import { DOCUMENT, NgIf } from "@angular/common"; +import { Component, DestroyRef, inject, OnDestroy, OnInit } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { Router, RouterModule } from "@angular/router"; import { pairwise, startWith } from "rxjs"; @@ -23,6 +23,7 @@ import { VaultIcons } from "@bitwarden/vault"; import { WebBrowserInteractionService } from "../../services/web-browser-interaction.service"; import { AddExtensionLaterDialogComponent } from "./add-extension-later-dialog.component"; +import { AddExtensionVideosComponent } from "./add-extension-videos.component"; const SetupExtensionState = { Loading: "loading", @@ -35,15 +36,24 @@ type SetupExtensionState = UnionOfValues; @Component({ selector: "vault-setup-extension", templateUrl: "./setup-extension.component.html", - imports: [NgIf, JslibModule, ButtonComponent, LinkModule, IconModule, RouterModule], + imports: [ + NgIf, + JslibModule, + ButtonComponent, + LinkModule, + IconModule, + RouterModule, + AddExtensionVideosComponent, + ], }) -export class SetupExtensionComponent implements OnInit { +export class SetupExtensionComponent implements OnInit, OnDestroy { private webBrowserExtensionInteractionService = inject(WebBrowserInteractionService); private configService = inject(ConfigService); private router = inject(Router); private destroyRef = inject(DestroyRef); private platformUtilsService = inject(PlatformUtilsService); private dialogService = inject(DialogService); + private document = inject(DOCUMENT); protected SetupExtensionState = SetupExtensionState; protected PartyIcon = VaultIcons.Party; @@ -56,8 +66,21 @@ export class SetupExtensionComponent implements OnInit { /** Reference to the add it later dialog */ protected dialogRef: DialogRef | null = null; + private viewportContent: string | null = null; async ngOnInit() { + // It is not be uncommon for users to hit this page from smaller viewports. + // There are global styles that set a min-width for the page which cause it to render poorly. + // Remove them here. + // https://github.com/bitwarden/clients/blob/main/apps/web/src/scss/base.scss#L6 + this.document.body.style.minWidth = "auto"; + + const viewportMeta = this.document.querySelector('meta[name="viewport"]'); + + // Save the current viewport content to reset it when the component is destroyed + this.viewportContent = viewportMeta?.getAttribute("content") ?? null; + viewportMeta?.setAttribute("content", "width=device-width, initial-scale=1.0"); + await this.conditionallyRedirectUser(); this.webStoreUrl = getWebStoreUrl(this.platformUtilsService.getDevice()); @@ -83,6 +106,17 @@ export class SetupExtensionComponent implements OnInit { }); } + ngOnDestroy(): void { + // Reset the body min-width when the component is destroyed + this.document.body.style.minWidth = ""; + + if (this.viewportContent !== null) { + this.document + .querySelector('meta[name="viewport"]') + ?.setAttribute("content", this.viewportContent); + } + } + /** Conditionally redirects the user to the vault upon landing on the page. */ async conditionallyRedirectUser() { const isFeatureEnabled = await this.configService.getFeatureFlag( diff --git a/apps/web/src/images/setup-extension/setup-extension-placeholder.png b/apps/web/src/images/setup-extension/setup-extension-placeholder.png deleted file mode 100644 index 03a6d8951c01924b20d9e3c52d35d0456ae4ede9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 788300 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 nlX(VT~LJ|WfU9AH3^B7gkCFDTFz@~KbL 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 z⋙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≀hBDBf1d1YzW@7f)Xa>zL~9ax|{K?Wc1U49z* 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

#B6&u|u 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 z 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 z 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%0Du!MrOpF7sf@;bUH1Yd|OY#zf-4TA-! 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

bb2IjozVCgUKB=i)MeU?#r> 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Ŏj1=aIkkTpEnAZ) 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 Date: Mon, 7 Jul 2025 09:26:34 -0500 Subject: [PATCH 065/239] Refactor `PendingSecurityTasks` to `RefreshSecurityTasks` (#15021) - Allows for more general use case of security task notifications --- libs/common/src/enums/notification-type.enum.ts | 2 +- .../src/vault/tasks/services/default-task.service.spec.ts | 4 ++-- libs/common/src/vault/tasks/services/default-task.service.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/common/src/enums/notification-type.enum.ts b/libs/common/src/enums/notification-type.enum.ts index 6d731253ce3..d362ffc841a 100644 --- a/libs/common/src/enums/notification-type.enum.ts +++ b/libs/common/src/enums/notification-type.enum.ts @@ -29,5 +29,5 @@ export enum NotificationType { Notification = 20, NotificationStatus = 21, - PendingSecurityTasks = 22, + RefreshSecurityTasks = 22, } diff --git a/libs/common/src/vault/tasks/services/default-task.service.spec.ts b/libs/common/src/vault/tasks/services/default-task.service.spec.ts index d90889cf113..a1f9872266e 100644 --- a/libs/common/src/vault/tasks/services/default-task.service.spec.ts +++ b/libs/common/src/vault/tasks/services/default-task.service.spec.ts @@ -365,7 +365,7 @@ describe("Default task service", () => { const subscription = service.listenForTaskNotifications(); const notification = { - type: NotificationType.PendingSecurityTasks, + type: NotificationType.RefreshSecurityTasks, } as NotificationResponse; mockNotifications$.next([notification, userId]); @@ -390,7 +390,7 @@ describe("Default task service", () => { const subscription = service.listenForTaskNotifications(); const notification = { - type: NotificationType.PendingSecurityTasks, + type: NotificationType.RefreshSecurityTasks, } as NotificationResponse; mockNotifications$.next([notification, "other-user-id" as UserId]); diff --git a/libs/common/src/vault/tasks/services/default-task.service.ts b/libs/common/src/vault/tasks/services/default-task.service.ts index 5858ba832d5..35a7561d63d 100644 --- a/libs/common/src/vault/tasks/services/default-task.service.ts +++ b/libs/common/src/vault/tasks/services/default-task.service.ts @@ -152,7 +152,7 @@ export class DefaultTaskService implements TaskService { return this.notificationService.notifications$.pipe( filter( ([notification, userId]) => - notification.type === NotificationType.PendingSecurityTasks && + notification.type === NotificationType.RefreshSecurityTasks && filterByUserIds.includes(userId), ), map(([, userId]) => userId), From a6ae7d23f7323a7dadb6455d21436ab0d4f64fc5 Mon Sep 17 00:00:00 2001 From: Bryan Cunningham Date: Mon, 7 Jul 2025 11:28:38 -0400 Subject: [PATCH 066/239] [CL-686] updated hover states (#15463) --- .../platform/popup/layout/popup-tab-navigation.component.html | 2 +- libs/components/src/button/button.component.ts | 4 +--- libs/components/src/item/item.component.ts | 2 +- libs/components/src/menu/menu-item.directive.ts | 2 +- libs/components/src/table/row.directive.ts | 2 +- libs/components/src/toggle-group/toggle.component.ts | 2 +- 6 files changed, 6 insertions(+), 8 deletions(-) diff --git a/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.html b/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.html index 1170725a4b7..0a52518b250 100644 --- a/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.html +++ b/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.html @@ -7,7 +7,7 @@

Qps#nxX>YAs0(XABFa%WM)zC;y(?dhOGAV zNF>afFZy073+MX-qgC07`xeYJ-~jZetYmKg0!5f7&!)ev`76H%C5f7f2fseO2h|w% zc}i^o_ybk@tm;kGO2eEybDGYd1QHsE41cg{;M!qQ>Q0z@Z`oX-|Q^|UnJJO}zi$Yb| zpVsWB6kZ$s_A>-~`*i$@!HDknhf3)RodchBjm&nWxXPSuQmn3dt9BO3M3x<&`p}2S z$l^#_WiOFX%s1+VS-)O^^pOvwU~1D93D~W=puebg6DA>M0}O3a+nnp|$vSN;*>3D&yXA0Y}& z_cNPF*MvGipBgjRd@?6p~C0FCx6ESUJZK?gBGQK zyk<7E6gr9b(zEdkuKyJ_cBdu?=j*~$#LtJnDp#zOk31i59uxQTb@ zW4R8Z2(~Ip823~obcd>lk6it%CxIJIj+7G)X3Q-=X1iRl!lGNPN*fM1>Mu?2HgOH}Thp=1^)DoNVCH4u+W7xD!^~dnJw=P` z@)lVVIir0=|Ku6~`ck3upE%Q*+po+EpdRS2P3N5xP5OBhv$ccFrOv*9qB-GAvHDuk zz(LHv*iiwLO;OoQ&ezdkOJEOW%otnyG1wn?t4N13)q)~<#G(GIfIUHTj4U0e8B1W5 z4Q*hMPPn*Zzs-*so4-NYOgM)^_hq%qUYAh|Y;uDsO=Nqg1E?H0mmF`)Urw?wk}4vZ_+%V&cB08{lN}qR$A?w==(0DGn4;kRURCZ(D`xvL0$hNAxZ!=Zuwc zMO5n$pTt!ysv*%cd+yK&p=qm)K9MEtl12khPgj4vp^~_rOXb{^_VrGLE{xHf)a5#k zRY04djIQk-UH!hgE+njw$p?Az6xOAqdYfPVJrrBzEUsXKt(W>SALAhwmlgC6yY+(E zZc(M2>zlHCTT4jxu7$wY3Zt09ZTVIcdAWjRsvD$_*!ub?lo+@zHj@e12xasZImALx zFVXb4AVrgh&gR%Fb;R3ITWr+0sCU|x4V?J{RqFX0e?l3|fOL%`_D}ttW5%NAJOG3S zaA+wkrH7o!x|V5*ibiwJGzja0e}w+Y^k^x;o8BR@7Na>`j?UT5vxDL8k@Jy;&r zAm(&igh?8Q(v@aCIsF7_tL=K<+!;hqyys?MN&)k1 zv@%t>AgiJ2qtlnQjji@)HC9YJXC1rG2rTlpumV=s>`0qd82|4VY+N2uQU>Lzm%)VH zGxpWVFr78H$1U{ML4(`#6@3AOF()g6hv=`tx9+V)*4a(XMA!HpOZ-$y5)rz#9>dPn zD^AO8wkJ%=LmQ)h*qH@=xI_4&k<)CXTU9w1mFAH@Dw-GnOhMO>mR_Uv^eI<`yazEq zBVy^K`qZt+RJBUPb^3vfJxljd*3 zPc*wpRg!ZbUE5}YFmep;A7U-_>CPkKBUk?tSb_;*dTYtxcMmRjtkq3?D->vZjMmvFn(ly*w2?p^7g?{`w9L za7wGDCv}&z_){5>wqQck4%Trbsc{Y#y$1gN&tZ{!Vi!pqy{qY zE=u(&OoqbuB+oBdU*~M_#+m<`9w7Q|aC$0rZI{{@fn3wAH#Yr8+&(v*9q?6>IKwS@ z5~600k=qqyQa(Bti|i3-e#!G1^QrN+`;bk_q`_S-8n=^YZI3x+{-oFz$zcOxBl&s1 z#sLOaoV5&Rg4yp?Jy~rOW|QLhwzSv3ZeQC=Ci6-|=^NcXkIqIlXwZ4WEViX7g;llG zr<;?6q%C=$Rd4C_<}di2dpRa@PTNHThnr|N!Qhw^=<%-A%rh;WZpYDjgvhcMvV1O{4>z(9eoo&yCdv6!b)1c)T zTLhjx4`ckj{04JNJfqZ_MG!m0mRZC-_9Nh4Z6gTMT%ZEgd|9?T#G0NHO?H{k&r}2> z7X1Z&XkhPz>b-9zTd+}A3W!sEhpYUs<}VW(|;zc3For z1rUx_xMicy?*LwhK)O(igrX_p9`$#)1BU#7wi-s#?k)e(l}aTmgelY!0PNbMOF@<> zq#;j*A}4?K64&5?)BI6d1@*B8=;d#{7be)6CBrpQ(tqy*Z4F;lQ0t(mBNWn+Q~%qa zzvYarJPR#$$T^6+8?6NNK6Kqm*qVc23z^!#6UuNsc9Z3Xlqq?jA@M2UFVG0+YcwLg zNHF=kV~hi0jH0%jP(3l>q^WQz=%v-uA&yqVr}Mq=Kt_6b_^?we?2HCoTj0GL zyC9o*(^;5TE;x6hdPi3(iB@iM$P2fk* zJZoLeJ&0TD6}(HTPn^h9qHB)KwB%_K4~(}@-x7dmr@Ry54|oS=6XiC@ zLkp6w?&7F$X^Nu621P3AYR#k`O0P=lPuey4I%E4_we)tTRR)Tt=QR{X&9keirli%i zg|%K{1NR`~e1gQ&3TkFhc9r5|eEYZSsVBmdf?vCkLr_I0;?JK4THLeHR=t(u8Ds>k zx=YY?>1ODfdWxRT?}#r6yF$s)F%KI@Kg4|;xU#dvEYU6|PwHWkf1Oak+{CE@hFrH* z+NISsd&gs<#(HO9%?cjXN#i~?uWgVJ_h)PLL4I6!-@_4gH;SNaha!F*t|e6Q5@RY- zE&ZVwXO07Y`ycy4hqozX8D;H|<~U8=fgMWED$RjHm9SpYnwaW{EJ{>J-BV#qrj*lg z;5@gK6>C{T9+WuT=?^VAEJbP6_1aHAamN~!-{z6C(Gg!CZ%RpjCra|xVW;drW*8W_ zC#SL@H{u0(_q?65DCHfWn~RT}zk74E)TEse`o4p{7=*_wyUuo6Z&t~cEcD=dig{eg zYB*;NX@SZ*O^w5pFr?{MZQC$Sqe)Jq7Y8=wk+5vN~C zO%3_vFOEnWilRF(3}Q0HUeUScEk5K+drT{2m7bT5oB$lkDg|`zwdzxB{(4!#bvTfT z%6(f#c6(HX8odWouIQ#HI@iCa(OLpPQ(^lsHq>l^APk-JkCFkJ&v|FIL zzeXNcPPVl7PO4wIKakXOT#1m%HmPcSHV-6EH3gL3-ms)oM7O6=}4#IF0hBlq;bBz>-!%w$p3x>h|hdv`t;pjia`vk3DIyNcqtS z(AGVvA$Yp*RNSg4U?75v8=|QM&_i{PWR-H`+O0m2bNpd+uiuHK+;+{}ex4a0Lk0u=-Qd-D=4 zh+=%Od^|)-`i8uYN|6|Yd4F4CzK7Ntv3Rn%{z(0~`y1(uw>d8!hyP?jkB601gW)AP z{zR=M!?K_~y}C_`gL`&ED+@0wRx4%WCiW04nrRp9hnU6lLMZXxFGO z$wVNRDS_c~-!?*48y?Q!xr6}d95B+0pit{WbngDuAA{~6vu>I%1dH}~HT&L1uLLOm zw9dL&H#TxJi4Vtt4Y(q1l|BA=6{wKS!U|VqgfKqpeYu&pURyy;2#6H@O!qY}2d!|! zRz)Q6KQr#Iv{ARakk+orzgML0zCcu}Iu1l9o_-#H)q z_#a_2QEl-7>54r2?>Cj%Vbd``8nu*N6ondAMn21yKEt8vPh7)w*=UoDXzqd^Jv>m} zzMhiDX=n97>a|dxg5<=Daa~U9;2qh`;LTg(ubK~}+D%UL1rD9M7He&SUYJ4>J!!r+ zz_6cYq3@<8cBLHeIzSzPlWUb3z1OfqwD@oWYVrG@qXSSEIjkhF$Y$hti52poRLHE7 zzy}nKy{c~*#k^)w3$z20+L%&N4aOz$+Y`gqXpMo2`vR? z4MsYq>BZ9!F8J*<3n)=|;-~ArE~2lftqq3kALi3GGxJ!%w>JEUiS!1ra*2--Dis^Q z7A{raT1!HCCjvM+W@N!%c>nA19d0$|-@dG5U{BatW|$B-@;0X7c+Vnd zI(63Ef5xp&z-uv5Kw~l;;l4{#^wDa7lIgF|J=Nc_Q=HE7c zd_TP3j@O1d8hnyGCbmPY%UMR|b;Jx;#cKdEObZp#M+mb%MUC44VkiFMnvhnu41?*B zsy0DI14?s7tP(~O>&@gI-p)HDGst~;p?SH=+tPGmdP(nl=;4=ma* zBG}NLLS?<=h1Dg4dDBd>DZK|TzvulQMQ0w!5DH=L zoO93I_gO-6<&L?<%x!LxQ0Cs;$}#snbMLp`zx#L3_Iy6?(n+{(F^@{4z@#%6coKo$LaZq1e~FO&AzzwANL4hU#o3TbFTr)$aqM$VyUz+x z4N44nv``~)JG=7x!Fp!gKE76=d4^b`8M4px2e5>A#RLl6`}(zk=EahOEmALRWB*A( z^Lo>2#>hC|jeOyB8CKj;(y}uQc?HXlkJ(OI^i}(rXOA=%jkL*>9}aRn3wmd;kFU~l zeEqA(->~m~nveeBvS}kqJV(03^LPI32P+;pt<#R{1yi$)L(e(uuHHCkKRAz=Hoo+p zH>k)awt#Lx}U%Ck6uDYsyb4mOp1#oM%YLPbjg_v7wArZMVA-;0hI(+~< zI?Cj3Mit(0z!M(h{F5M=Yg1K6_`^3$PI|_F3A7yFcN40{ujeUv!DXgi=uo0D828im zZwV>cAAE=V;5$BJc83riYst+U%X^&lR~H;bRnuQ%;$SblfV7t@50TMvTG>79iOjJVJ+6~s04iVv7wu9y?!LbU+$AQm>3-}lY^sfxi)-X=z=p+ z{eIrGF55EK#ivmITgw6xp=%$HZ;H%!En6tL*3j(B9kxj^4Kq8*A4-^wGrQC!rYm(D zizhzh$WrXHJKr%CKJL_e|AIHlLDF=k#;1Ma>gyyV*ZZ<@6GbspRSDLUey^@PbEbgfb+N7qI53>@B>&dXsNP8q0y2`7tfW4>ARfx;kl zBi?$kmpHQG$Xi%ITGW4>6qLvV?BI3{ipEmn-bRhKde*DjHNExwL3Jqcz>|SDEo{7} zvUgnQQKnp2GE(VO=Tub3yCsE={8Z)cHcpdj?Di2mHVY)a^*Ie? zsUkmL-C2v5rk0Y(T;ciKIv22^mA_mwU^_rB*4`6$eN#vO&&M7HS8RrKvpK&B`zEhVYN=F{uWD?!CR6G@G#QuGHQs)~V`pR9-pbnt z+Z+CsK|9mg%60q(B{NyJkv$pkrZP+A7zQ5iB&~Wurv>vp)De z@{`$RLQwW1xsAxlMqS^o!Y)hox1gvsOet)*^?N-(Uo^MpP}fapS?m}=us6QsGw-hg z(P-Xh9U4!PUL97ME2Jiw&i4^4q7}uZENMOnm0#S96N>oO=CSQ*zzEK|wvkW8KQ!xJ zG*vYmV8HYOoZ&G~DYno2Q=aC>e+ygrgLClDO)y!Tig)ydeax=%4b|d&4~%CLoGlxv zxE74{3~JWG2+c-T9uH-|a8993PrBBxCD%#vrTK zS%vj+*>AKT7SiTRzJfh_aep+M?cOtJ+0nUn8bjUa!^GYtI^zAc-0!W)RY;yH@9+;} zdLfX%O~o5V+`LDE^@$*XFZFj-x(%es{hX~@xW&pWP@MIp z%(*{_3Z{+|gKATNiG9}JH7wwfIRq^;g4f;311>N{gw2uh0gTAJs!DJYJjA~Q5h`V% zVdxglqp^*QV&K{o8*~5+-C)M2mhV5Qr?HC`rC3a3fZtWiiE&@rG(Y!JsEV#e%Ws|- zlYcjD4c~N@B@227CbFue^BOqWi$`+Fo`mW18lU_}lPmIL^mecQW4{Ie)+d%hCRLgl z_LanKXe7UPOe9~ogc)w|U08eX^UL=R7;opz=Sv0^zoDjz zj_R#hu|bKc%_nb>j96+M(M%3HRYg+=maF#)^?u!<>3`yoET@pdWjwD665#A{E?ydc zSGkd|a#-v-f7UWc>9t)3ecmw1ZNM8D8#Z+?XI=%V!`@cCjdtd+EWbSw`er6=;;E4( zN(==Ttf1sbR31eI4go?d-z(z+JAx#kk!jG%U4M&FR#xF0`Az?XKy@6oPQ~o_(-??` zX>=BFRsjpjj%VkWWc&Ws%<{omw3xR4?~R0}(?3muB=RQqk_qBZ;y7Q@x%91OJ?3Gf zIRfI%Px=iPcFwcgY0R6S?2-RcPLL7Hlg&F_YC!E!OglD>876ugD%#I^4+A1?==i1+30?VO{P)QQ(0X^`2;3oHw+WIJ+t_9ZUn zP$&3wbeC0Wk9Ak+xZzUt*!+^7-1#ys+2sMYQTN8`=|LLlv?usH;qO5%8It|^czA%W zKdCq2Z!p_*{x0~} z^>!WDSSrY9t%-2b0cc?dru+>(lC$u9S=$3$@rG$GSQtcP1Z@An=E zM5?XSvbcW+S%o9uyQ^2*x;Uqyf6GYa$nZv!GQ6IL#>Z1+xP93pqSin+;{}?ld&1f< zr-1tCalP5E-3ITJY>URby0C>Q!M6-z>J}dG8&VmUob_%H)Wr6z9EJnyi|&GRaPbO% zXAnsk2fJ<>0b=x@5H+GkZe!HbzxG*g`%EnjuL@mwL3Fa7s;#v#!TYX%0Z_Q>DApXp zP3ZEScgcoIMgm6y2@6%Zg%^tOhp@C@1#n0mBm-nL^Wok+r7953o2inPABUkeN$!2_ zZ8TXTmr9u})D}W?P>7$(6iF1@Di*gz^?lRH4mtDmUs>FBgoQgkKThr{23kYuwbJ;; z;pNj`Pv_Q5QoA9Pm))hrM1cs4hWAQ=^YH}V#0t92`TXxHmw`>$WDI{7dGDu|mMBXB z)_N|C$2UyZxjIRtBB{81HuLnkL#(Yn@b>=pMqy;M3V4=t#jPEGdezxuWm;4TQXAP| z+0GAc#Wf^|B`~i$ZwbSO9O;y!@uos(D zKKu^G!_KkWNGDBh6ZuiKwfcIRzID*2Rf#XXm9BNHkI=d~m4$_)d7M;IY0p;*{$k~G za03C!KTGtsYFwC-yJ(R&&zg4aKE@Zn@$nX+vFPT6#>NmnkbW-!U2D1tp5_W&8o6SW z{u<7qf0wl6PY}Esu(_W}-eZA;@?1VB+NJhc%)UY%7gq|$1}`(5@xK7Sh>$v+N;zBk z@4Ioye+=^K>x;K?32QBRpK4eE+*Wdr5ek3$nqq3{B7;^&GpbL*w>*^Td7q={IxN#* zpGM-)0y2X$s@&8O8+t)8+#?NS^|js8BV<521(@d)BTlEX4Pcm-!b+T*uL zTcz2bw8D?HV5JEe%P2jPH+v%YnL3A>FE>MSai%NIdl*q4vPj64nWC~d9=x3WrNUjc zrocJrIy~67d@EYr`|JPnZXdPQz>T=7$RoL?dHMCdr@%06#JD${FW=fvT$gyR|1%D; zypY>uLyuo$!~A*7f?z!H60fNf;GwOZg)nJ`~ji zTHUm+(nYuaBG69;F@XCmg^x7NvZmB!FMJ@lR)q5e)i-46HRA~9zu7DjZkG%u6|;Lc z=PvMd2>ao|b)(^d_+Wt~cNyKRM^A{j`^kPiSj2Djbl!O7yc@(~{NPA%%8R_-BCJ($ z{B)g8Up(MG_z^4|8Qya{YRLP5=EI?LJE~48HGJ#Vy#oCC-p&4ZTRA8Io4+e%!-BT6 z#21tQDrL?huIk-bc|g74TM+TQqNSvFdz=jrU)4RMs8DV(rMH^ejGU?i*b-Kyq;QRY?+lg}n!LPg-s(btjN3yl4Z zZCG9IytHfLD0iz=WJ~3$F%WC1@cFhI#wx%~1C?Cd4D}{6P^L<6^G+qsd@_*oGvhPB zJP0t#`mnX+u8O;hI-KtSlt9#hYT+3R2N)X&3%E?aU#^Pg8-@+`hGVt=6XEDxRcRoR zwW9I!stBs4`DGXwfS<$HD?mN*~}{Y74Zya`a^5u_JZeW%bA+T zckyIf>umCcYCEMC`ya4gvffIz+*-=xyWs*FY1-~HjMIz3Q?jrH5654>K&N(bW?BUw zu3EsYrLpmqkA6h4vo&|Orx3ErgG^D%Xp=V;!(KAK$#YdZ6@VX&W}O*?V}N%C@cdDt z#&2S)0Mw-7Y65e13=&b`Zb)wx;%tDjc!+XzH`>rzMJp!d!rJk=_|G@@fkUb!A|l+*4=)z4k6CvM;b}J?r|Trx$ntROh-xJ zvRCPxE%H`^e4|khO7JBQ=$Nsn%3l?W5jLfxVvnRM%un})>h6CSa7QI9f@z%BN7JHN&j8`}KBSXz@7$mA36zy6A~;Yuf``i>gV z7cX%G#B-y+TLjv<(h&UWR_KkS|6Fq>4!e+-;XBqVslYI3r-AAlA^&HkON z#rNjTT31qs9NonEv18blZjQ?|9=7ssH4Y^@Rk|y8I4|lsDfKm~<~c}Um$g#Ct~cz) zH09EsJ2%lmG)h!&oxcjb>o;=0PL7k)(zp85T0WD;N#0DOJZbs5!>4ByCN=+S#f68->0bX+viyf@yhC|ln)IhVx`;_KfsNkDikp>Iiiljo>@@pn8 zvK4(3540yg;twNUB6e)yDW}%R81rtr4SnXRZL}A)LYOGs%VFb(%~X;JvlSqz)f+fQ zdhaRg9?vyK2sm$1*Q4aDV{DV6^6UaAiRy^~P3LgV?EX7jx1VpdJ1;U1P7bjJ{@+v630hCul~0QcH7672Lkx3+LiX1eKhW|y z6&)(o=iLij3^?3d>_t4K0$nynJtfFbw4d(rklj6w$#Xjw+*=rwvSe~W@h`U4Xde6H|2-+qrV9(Q)Xo635$PQhfum-+T>AMJv0?kO? z-!(NfcCPerv9uo?-0&CEX`wmZh>mH21m_0{+E|L(hyQrk>ghM=^~n$BRt|Cl3t90@ zmIU;uzb__8;{}#|J?ev%s%WI~q3dXQ`EPzfu^<6n;O$L2_TL}s=i@XJE2*j!(cn92 zROd6l{43^6X1{gPg=AjgOCzvK@lW)WEMN7Ru?VmJ-4l#eK5#Q-f}rd~Pr_df)CDUZj1Kddok5>>T#Uynb_zk=h&n(>{pGQJQ>u~?t~ zo$%dm_~aR{nh+~s+U3heGv=&fCrcid%*cg=2V}?0#82yO``ubd<&N4oqZfVuKiWQxD!h)pM}%wjsmU|1+TtS#3roWs zFtMfUf!luW>)Tn7e>d&_prBf2PNQ|oX)~7PS(V>hhTg9IgRA+@jh8UMi)Ff#RUWWH zh8`n2-%VRsX#Y)&+lRMW(Wl-;MfWwQgTD1oJ0D2;10PZ}f*5fc;5e?AK_iA9+&>V} z$Lr&p%+*{{6s%jMj8nVICRo$x0L$7Whv zf6-2-qF(T~_QNg)12oFoPb>6CA8DD)D}ehVccud2qxTn;?#!l!RH$KuK*n%M*C0U( z#<`jOstK*&Zvrg7MR-*D-PtQXgo$w#kkopm51yDMk6Nchz45|d2TNHT z__Q>BP5w8N?hf#+C3KjM;g5iY2Hl*;^^hOi=q)5203zChx92AqV2l8^dd#od8dam2Jr`6Wr*gw)+U<_Op3F)t~L1Dj^E)aUYvy$(Y9SZ{%^!ByC&C>yw_G z^G^2m=YuWH&Fl|^zDni>@clb{qfuYEHMVEB13lULwI%acHv56k5mVb~3Tmi*>ryrI z7(Y+ByQ>3;gdN3jcI^B^4S5%Y_f8=;CD^%wf9Jzm^se90CX|z3>7-8wPlvhm<}YSw zyCkBzYX+h^gwvR>-aCJp1`DNqRM?QK513YKYujHIA9baK|GlOfkMX^VU7n2t{v#{L z%TV;OMA7Zjb;I`S^?56E3ck>I{JQD=R|&}m_pP%Pl}G>NiD~^mEq=rKKjmUOVc4-! zr@Gc23k?6f;r@}>5DO(k*5>qM#m3PdIWtfE2r6Nf|7LX8YLutgjngZ{*#?=vr4wJ- z?cUe!DQv#dqJq4+-)~slBPh1uCHY)E37d>!0Yp<61s}g%qo-@?VyT+^pfp| z0b<^*Ty|jILi~UJ&!2S=CTOCaL$K$(tC< z0n-wuGWo#=_>qzPG%db}=>Hrl_PO9&1*dC#fn-ttU`}Tfj}-cRNvo~E!6q5kBR$(P zoe$btQ(t_fq?H*WN`&MVRjjSesE>SX@d>(bgLBZnD{1o!7j8}cOmuJG>n~KtQb#(! z?6R;C80Eb7s8tzs>*b4*zBfYpld~OX}?w4+lzKsz^JW6s*#IgYo zxW0ov$AI6a)^-DGDcUa_U)`W{oe^+S*3Psh?G@Gweu6;eRw{xR7rCIB{oH@}JiejGf z7RzY-QO*`S1Y>tq_XS-Rk+;tPW>;k_R7vy&iR6IiRMv-qIQZe3T+ z6P3aV?~*MASVVA7ylvd;Ufw9*z~eAxE!Q>O8q)Ew+UHI4GY*6i3gTG8q5xf+y*HeUN{mPkppdbVR4;(Bl)ltGk34zT) zs26;y+{mO4VG4a#D2g&C&Mp5NU0N9zzx^l7pc8xt_Il1a+1Gw^HKSL3*yfJq`^}Jf z^Jnayu@Fv}sX<)YD76{l~dxcIUPicp~zQxh1<*eYG;j~bvq4DWYozs%ibE!3a zrwh{2k{T#t!5AjGJk!hVwB?sUhz2KxRK}q#%)5#bD+q-f=*>bmhI)JSwd{`iUd|A8 zPs?YxS{jN5vpOWY^W|DWdAE!6C3;boJD7+%zkM9PbBs7XawQM;b)G-zlQ27Q4L-74 zOD9vRTdF78$l2iWax*orWzk1Y-L(b$5CSYUqRs4uwRm~v;D|XPiLN|0sxE5ze%2RrJB@$T3w-p5+{L#L4e3) z$-OBHZ965bB@%=97Oq9|U7e)P!C}hyF)Fv=4)&& z`STwH_k4{{v^ZK6H^$zj-cP&CYg(0lcr#;lvEY`EzRqolOg|&NnXJ63{trekZfnu?-1a2+9v;Amv<7_s(|cmAy%Rifz8z50Is{$+i7Mnt%%987LkNbs4v033I% zLd<7Dp_V10oQ21-*X(+C&X`K1?O*>^o!3zLv=RfZKugzY5PU38pItOEPmDCe)K@HL$06U+oAq>Vo=zNDz9t}DQNzF2-3)s96MomW&IZSP@#{A#o6Y@Y zRddq@FT>3(Z>!Y%^vj_IISW)`p4{_-J|-R1*(3Uu-i4?xo>0PAe%5th8rkAXS6Zk`To;V*yv z?q=QERGrB8Oqw%po5xY5B8+*ByD!gfzcRAy2?$LLPwTq7h`oA{LAHIY;Z>SNua9^& z_|V!aS%GQ@&GVj>@zOK@p@(D{)iB+9Y}Z| z*xe#(sHE}1rB0^l$fL6T3_%VnnzbHa#Iv1&NrO2Q@Iny5e{mdGxKY{0(lcSogGeZR zMhLj(pGIgtWoZ^18v3($xO(j4Az*%&AfKAj>EUD|)LdWa|7d@nVtSem`qf1h=lFeW zWA&l9pQ3~JFNgYL6slN0ZR28sgfyRAEYws*#M6x}u&DpAzIM;+axrgbDSP9{lwHj2 zF>$2OWQ{8~JhG-zTleUW)3)_-gg?#3o?<+YMHhvKHFYkGI`#740*EKr~(7q zSC>2G3RP;)w-$?~JgX)7!;YZ-;9Ur~Z1cckD)#&O9SNGWRXb!;g6gdGW14R*R0@f_ zQl-CN_A2AsZ4OwMf}B)g8P6W!9CPJ#QKi@# z0-d&-Av0qTVQ~v3RRh_i{?^zz6yn=Kii_n2)xO%=(1sK>D?zC(rj#@^8pR@}JrI z7@SgRAIROl@4mGo0I1@GVv}NC)wQ8TKEKSGIPaxFRd^9qBn%zoki5}sxFT_MTi*X#b3MH~mq(lz13KWqabC!iI4ufPune~4Ez`{v3!t<0WNoGY#1YG$2{UKRtl$D}6+!4Ir-=F#Cqb}?Q1o|uyM>Iyc`o?eRa{b96_*i5gAdzn= z|J0#5Hr+;3nt8kluMG9&MERpDdR)+Z&92G=E`QMPYv@C;)z>1oCjg(UQzxYHf27e6}uMN6#ToqU7$3ODG>yS#G??5-E% zp9@~~@lw@Z-}taW03`i>IK!(fp^FAcq-1~HR5h(|NDR#MosYJZ>n&*;?R%H}+;-x- z`F^%(4--Gl^!Acs$ML1c7a!v0yAb}$2gl|?CmfB7Rw0_~5;NX}3^pp4_V={&hlLG` zz|Q4zlj9CvyIr#XXp)=d?S&*A*ArRy%RE)U;(^Yxe`b0iYaE~5pO`{DUvilKB+OIG zpGp;<<@~}B#|nM@R7azp#@Iuf_d+L1I*?bp!R}DvznQR`Mb9-LJn;gn)Fgvnf@~ar z)p%WzWnw2guV&AXvuP1{tv>k=p&CUg`Mx6WzDJ`58S1VTnvfg;PW};1k%# zR#pCRo1WfAig}m#;9K-j?YoNW&`c^Rc#N%B&xbod$J8%f3)pG>Q%t^%HYuhacfJP}%zl93{o#VFoUFLb^%s=$giBZmwdvOoku)Y^nOQ@&nkqhmUVq|{2|_W4UX~( zmm9#4>4vK-V8=(*I^Fk((!WT$vo13K{J)A)B`3I9$yA=k;$=iLr++O$o|))p&{d-W zVXKReYrXOe(b-aZj+zMRa-v_^PMc6adzhB9rAWAQ0$71Xb9k)8#4D?k2@(4zD1xy* zuL3$x$y8W`e;>X#`mvys4OD**|2xFAY9j((7hbur+7`jg1>OQCB&lKeIG4C9tfs{h z#h?F_281ymae%Xa^n9$)z=c(WUo^&Q=|w%-M~!N;@&_7hS}%6K>X~?D52}|%P^!d} za?4b7K$ZpXKH(f5&BOh#p5Y4eo0!Sxa0s?4yb^>YtYxsn3p*zguO&Eto^-+ZGmw;?|Ejf4Y3e;-3y7*7mGQSm z0$y=uS2gT>*n)II+<%;=A+V3p=VnKH!;*&!y>$3Qpz?TIyk|~ef$J~8lj%0b%rx9X zXumdguY~mtwAP_`PiBLw4HUo-8YcCtNvAHK7Uqfz_T>~p?1?m*iuPAl1Ywf2G+xqMmeGiTkts7!0BR>wBhMhiDxd-)%|hb)0X3{F@iWc3SeD;T^>5 zueIlCc=|efInYY_&fG&uSG$U_&ZRf80)OcA0hnxJ2nc0%xB@tCrk7V5Uh&?|Si!uW zCdGx#JEiy87Ui5c!h9jdqVQOj+^~6G49O74lyW6DOAm#^_e%?1!6w_!H0Kw7r1Y{F zpGJja4uP0NH3h_ZWU0>FIgSU8O1*lE)%_C~;jw={!ebU~B9_&etB@h6xj^g9JbI;* zZSEpZ(&s#V?SfC?$+XRaPz?1?Up2=5FF&Q_pgzB{UcJitA)$b0v1IwKxmwFnYKtgP zW4dS?y<{6z_0{Jx-h7P=Tz%|ocBK6z=|$6aVHL=W=dx} z8#|V>A1JfdVToA!7jB`Mu1Tk!_t|tPzGXd+ZGs%<%Dg4J`3%{A}PJ?hW$WWP&6)BCKQhcj@#^}e^@8>I*SIU8v4HZ;;2e~*wXWlp=1wDzRydyup{S&AI~+jAc;GTi-X2yuGl<@P;8H# zBREvdNcS4(Q%9NzmACf=s`#L5*uR~rIl;uGiGf{wb|gOA4Is+Fa(UuqTOF|JB*S9b zGC#$6)*M*xx|n&^ie2*0g|7B(PZS0C#NVV~AZ zVvluk-2E62#BeV)%=FQP!4!1olp5h`UY~jk)_uhbVMX)R*=4kO9=DjI5ZtSgawWAFvLNh_#E?VI^oO%iZj&2UaF>VTt^5JBQ;|I9G($06IyTOm*S)#ruw&erE{(V<#b2-WD*7}-uO}(@el@rYDz+-1EWt?WVomG{7j9$O@9G> z?Ncqu#6$qcQVP3+-&}v21^Kgd)7ZCSzb{xI%48}!zg(`w6G3%kO>hB0d(r#X! zoWX8vcGSnrT5mwg?aU!ile25f%QX!SmEnP4dwBJ4RBmL@`szpnqgxGkh0!CeC$Br@ zikhVLq-bMm3e=T)jd;bH5DHM{jLP!FvH#N7*Bz{rD~qH^Qv+76C0_l`^Al@R-9r_-|*kIzVg8+je+e$?TSFLEO_I5W8A`3f(FoKFzt`e-zFx$f(AIC{OKZ! zcAny9iiL^Ud9Ucws8^`^6tbGak`-JqIPUP%B?a= z8rP%q={D$6Fu`;#@#WO>$<7Dxx!FN9LYY2q*OlcFnS%godZSlEe>-V0cgR9sM;xXE$B11JvH1ydE+|Jg;z~ z34(KBj0}|sK@L-Q23oqUYl!s-a4!&U(Ym2&?P@!SSI;8Iynu%`h$vGMtpAdAdB7pn_?`$H(X}hAXi`4zt=!WSi? z>(N;RWrOvE211g><^>VC(7kz9HIS_}&ROt9o4Y?1?0sIRRVIkq22RI}^_-yH_Ono@ zt!L-(!slCg?ms7S$`6fICPgqNsn7G~; zDve3_XADbHc|M?(kbgyxlz*x;PLn3a_bKJNO=00l_*;d73o037NkLe8JV)f{0p<^2zxE zyR+syxK?Mzmoe5Uu%96em5~sHNI1lH4hTO#ypUZ+4@t}U*5XBuq)^a=V3SwuS}mQE zm?V!SS;~Gn89^f_j0m}c1O(hLzx(^xmeSB&l>rb9n zzf-F-(5oD4YZqTiWcGv^IbQAQw#F$4deFIJ>KGHDu=G}y@slUL>i@;MM^!{$Jc1P| z6pPir{Z2Fqly`NRw5q``-iTFL_LhyPtW!Vhw;V;x)wWGcYZuN81fU`x!g4B^!JXU7 z!&c^^zf@&$#tXjMB%y=|3+)CYnfP%#VS_^dIeru~R)f}`sw%R?r2WHxC?a~;=;l}#S};=GbBVoo;vhv$Vxp6w+*k!LV7F`au+QP}$L-T? zF4TiFeS%InOtGRcjW1gIvOXn}YPK=4|7m2#ng%0%MBul`uq`7}WX8K|+=^C$LBF)zD`JKiDb9&O68BK?&Pc_6cZmfkd zZoJCu+h}I8{OsW|VX2%&aKDur`0`cSTd7!?Z;6-hRt4Tgy)?AISm19s(|yvG5c%*h z_A>b`w>6TWW~Oll{f8*pa4gdFQlx^}&z!<({Ewwxk%oXFLCGC7yILx>3cvsq= zO-Ko;yYccrEjoLyG`8jvefDQmcn;+iv^3Vt(HqaUL;f%RH4lF1CAspF#@RgI#5d=+ z;~!!QamK>6(wp#6Yo10j5kC0zKrOu?H>+yInyq7PQt%>{<7vYz0_g1G zv=$$~y-|!SXKlTeZ|2=`=Jf9CLp$FuuHmj&=Je|DArzKpM*8yW+DF3LW|V2z@?bDL z#~09a1evv?ukBS+*qLnyI*0cRAie0qU2}sx5-PWY5}ecGru>bJS8Lv=BP>k(8Yr;X zN?HvPQ1&%2sfT-|kib%%AYY{`DKdT3`bD8ew{G(--9s(W8b?=IEP6kX%?Hwct043; zp{~Vaon(dM2|p2UZ1*;wxluiN{*704$oHp6K3-QbL&?)y{(i(W5T~lWlIqq^rfuh^ z(;7RIM^JY3v$J2eP?-p^qq~jWR}dJMZ-wP|WSx7vT{?y>%x{!s{~VZeJ>7MN{j&0( zJ7FOBsg!5Q+c&`DK&I~xP{j>^m(`tYS-N4|V9GNZ59Lverre=|Ki`{H!_A>J(rOig zKjQs(w1tCb&l#LPTSh0sJvMUNeKHZFO^uyw$Pa$j3a;o(JFmH#!(rKdYP<)%$*39U z6^*vc4f{^SwantQ1{&Ieb+fbWRstS;7P?>kZ_Qwe5t}Wtg)FZX-=CQ^hxr>Fi~Wrr zV~SeUs7lnTl_cF27miQ7L(II=bK+UU4Y@O-A|w^=1FwEivi!QNY0T9))o)gh5mLv^ z3+cIbD@8&u{HLFiyuxs2A@S)Z$pjQWnJigK();m9H2xYmMB>`Dd`2U0bL7nd^~e?f zPufVYQraA+-q*YV&y2jBdF4M04F`@D3XVQ>19?V6&&*V2H9H$T1CKHMR7ZwLhp#TQ znQMk z>!#d$-tk6hCA;Yg{cjdi*HhGEnK@xE4V&jxdZOaHUgDyP->j=1-3T$@-U~LBQ4(3b z^%Zma_HyIjl}o(bim2Zl^8N=g(NV7#X^ktvraufw!ZDICA7>N8U~R*t*eUAyO1%AJ zZ}8RW3e6c31IAp%5Zkb2c3l+Q&Y~*3fzbUGt`CgB{_v1Fj`Q8@({FT>>WECTe)oV7 zL$rn;>+GXnwA>V%sO%NE+-UT9>~;-Ud7`8zb$4X{6fxjW^$HUa0F()6%UE)K_|Q$A zq<$>#8W9T+`#NsMC&zME*X#V!P>1zBZNO%!d)GC$-fL-RlYFF~>Cuqi)ElmCB z-&E(?FMldGj)Dh+QudopDImbzDv9BsG^yrrk|_G%BNep9OP|~8{0F)0MUPr}Rb+;O z^%b4ZK;Wd!ZOyXS36Zv#2z`;n}_x)4!7>US-Hn^ zK9t*Otpkbw8M%Jcz9Nl^ns#Z8>y;mEB|%6{W4MDIf9^h#`I%GjZEo@s|KDYl53Oli zK)Q3!*lru?LeMnm@}R$g#yMN=4$*aa{=u@2?osj4VqXrlJqVQJyTWn&OGD}9a)k2I zxC`v`lGM%xuB ze;JzlVJ4$RJvMxT)R0bR6LinS#B8Nqt!?Q=qnUVbRZ0{TAiC3+G4 z>o)eFs#rnRiek+eE$3vL@IOml-Tr{Ne;vDGlF+tT{{y--*=jey``_;YFW!d!Bi zB|11Q^(eFo|NYgQgio86@7vPK=m-iKv>_)g$)KE`$0Fib>9XnnWU}%2F~Q8RzfRv} z*1S1hs(zlBC8bl>&mBS3!p}@z4wTld5gcsTGS!1m|6^|F577a=S)9?Fe%ED?;w{_5 zEC(-a^PGEO2>Z}nMICeRG2Hw)XsMOWZS--H+?`po>qV%Wa&>K@h}H4vT#c(v%~ryA zYszt}KwcI$@TX>}g6v^)p z7v{`|GR`z3`TmlQ6XC=N*1IQ&5vv~S_`hR}Csf(cpO#j(W{@93Ys0r*`$D(AIWZhy zP6seHM|!LHk^riDqGArq!G|zK@k1XmnvdyXg&A^qtXJSW9UdPV}(mISTyy?%-Kli;zy*>PNo}5LR^7 z58i-h^92NArrJoOw`KUR`d~FG_31i#`t}l7TjNwIB)@NK=J3kU0Ms4}(Acy>x7hAq z!QT<^_`Bjl7yEyV&k4MKb5RmV8dJ!ZSDc-!Ax@X{;b>V2my&6@BcxBAYYLHl=7*6r zW=n-p$)~-R1Q=Tz6-Cwa&R6FABL(xG-BdfBpzoXOek|;A6bqvLJvQ*=VL6=T-|znc zJwd|0K%NPmbP}#~EOeUs!ifG2Eheq#{Onfs%CkT^O)^iUljwzm+g1F-~w>AAGq=f#|x#n2|G z&fQZY?ETMx_Z+|spk^k}mS z8wERQyYRd&h&vm!2V04twterw=G8QI-s_Q1d;%VP@B@G@Y;=0wdg&6}e#afOVJo_&_)HrVg8)9=Mu5A7m%(Ss1?GO|k^8#;y=oqNyo&r+GwBa07m zac(7Y5kxNh^Og>~$e{1Fgl$Pziad5?+1r7ZGX9$x7Hw33T58b#t?A3jqqPG;-nG~T z)w5g-EJR~J3wEeBsG*xbH`sgEcWspU-Sf4>o zMgC^bmX*&8^Tv9+{q7YE!L-jVxPc?MfAvfs?W1mM-|bCHLZyV10Ml;&`)CU@Y@v&7 ze(6%XfcJ*uoX0NgHY<;wZY?&LVb2Y=7JH$qV5@e(U~_iB zTkKrqIWA%gbbsv1<04%Hm<6-L;8o;>6s`GB z&jK#L$mgp<2jwxBaB?;-&%aCl+feOmZYZG6e_pu!%%DLJrIT(Ifx#LpEx(o9+REBq z0#ovG?PVVvr)3{{(V?^UED^yN4XWSy+?F5IcCAfMV;+kwaS2KY3$^QWp4Eje*xlYJ zU2HKnWzDSqZ>8Mp$^=L>^|qyaree$I!R7;gdUOr*y80TdVWVzm*c7{z-t1xD$@5Y7 zLaBZGh~Th~=dqS`&K;g>=GqVa;19x^-~1-(8|}mwe$jsh_uY3d{ICD)N8toBjpR^U z_13q(m7?@Z)IIQb@l_8z0C!Fc2l{=*#YGHs$(`?+R;75!w8-$S-}+s1Zo`8S%mbbwB-uJ$0`(%t__W;l_ z`yk&GtTwQcJppW_wmmdU2M@G=gk8=l3!xVrCo*G$CC<*f2SDbs;}r0r_9O0I0>Gdd zl@rBQcy6!}&t3b_(euH{gq2sTOZ#k;)g{|b^6K<_pS;d&RNAvAfU{BgKx_ccM&-Jf zLOiF9vO!!;FsEVz=(g{(pZn~9wf$*J9lG_AUVMsgi*esFx3^p1tSh@nVbWLsTdMguWqKxaPo2ea6 zSFKa-_gb*nM%}MK=?+ZyLE2Sb!yarFyVBLlBfueb^%wS1kUG$+>{gd7U7K`K#FBD} zo^P<_+}~frv^O#_J!j0h@*H(dZa{F5yhe>cpW7&nz+AKgP*YtQ8>SZa_x|wmYV~}^^W0Cv zo!NmM*sMI3y7~)ys_e8;9veW{e(tja#YTxd+V2vkj$_25rK?7jAM#!5*(mzx2OV4? zelDHB$7d$-?SV7+v8u^H^pwv%laY>6CLwHEkxtL2CWv({(J zj4-yisu`Cao5fC(!{F=cSM0uyxu+`>?6J^|oE;HLyE;A!>;p8CRVFqQ639jXLcYTXrpSo$|D|Cm(&jAvLJ`|D9@urjQ{D! zu1()Pj*92+@0Mg`O_BTfP2-Xvm|=mkOEvr{6W3I0{A0V0llXki&!;gT zFAO~Q)(E#<2=K>8T=#$J;IcTJ88EZ>flCIlvtr(k?~Zl<$6WUW2(JAoaNE`C=dMc; z?!GNf4zx5ah;aFcIIOv}3UEdx$}GOOX7=IpbPoW|`o=w}gl;mS$MRQM&Xdx~w4Y6V zfoz)08|>+K%i5?t-z8_GO0-~8<54%0*C2w=9QqARl8tQLo_685ckpuAavSVu52iiL zK`|~IN6MHm*lWcROOCIgi=FMFZ3$#t@Y3k>x@|H@uw{tB;@#0+`u6u_yI2)=(sd^` z*B(4J?ySL9qTZqMJMX}@i*7Vm&ix4S=$`EZ6r#u3yja+cEwmXD7=eG+U3bH?&t4&W zbnV(zD#i1zcfA|#zyBqrfBeBH{SSWVLlmKJ9oCmFU4pwN=l`W!Z*8FP>(9&G$-ojW zUc5+|27mTve^#D_b2p6sfB4~t%jF-P791{5nDF~?a&kiDd~`lcGT@$X>F(*<$p6C8 z1YKC3%1dQ)ZlmSZfo^HG^AK6G@O$!TvFjM!V)OE-@7U=3K0WsB?%G3b)RG<_Y6s}t z_8la{XAkxzJFwS&+P*`ZP4p?-D7oi`ZBz)YjdFIt+y0piJHQSs*&u!1p>$RGQC?_! z5+4M6<)vh$BIkbXde|Y1bd71B3CHZ> z&{_bCK^T>-PzpBtJZm(f!?w%VEo~rE$|osPm)=*6hPDf?g0*M-0pCeV&Va#07qUdu|pHvog`6+u|FkF}E0UHCNsa=*Pgm_Yz%u*uY+|edn6? zwGSIVrpie2*cR+spC3EyfW_RAFU1yoyI$t(0Ap(hDAq=K{jz%OWovFPVfOc~u9WLr zxrbv$Q9@5^xhG!qmKvdn(yYYkbPX{zHC>6)Zm z2^AF}M(Ttjk&}pGRH#o5C{~+-6R0y@%o?;#c`oHG=zSXb*(c}Ox> z(o0LWs+U>A1-tV|wY)jM=TZOZS2P0DB~U8&ah5as<+Yx@M-YE_+26?P(g zAL(6=%e!a^nkuh+%xnG^x?+ngvX8mtIXX32zUI1whsCDtbrWB!OJOFDx?h3r15xO1 zuvzRD8)y8S8F|!ih;mNl(diOBAR26aJHWb<44v)f%T*>&SG_#qHJgpR_b`{&ij8d) z%VVa9OzvBq%`3q!fjdRdRc0*RZFJ&D^QtI|Wsf|Kb&PRu2@Vv%MP{-_v|=>Tg38?l zIGOAQM!T2AH!M4p64kPgVKq7FkKhdTa@>~4-x6Sg3jny7hV~I1-_y0YsD1G`!|@S1 z+A}`@i z_dh$m=9Onz#x5M;qC4vvF1VxJ!36+%_Z3H|o`KodByjKn0;WNkE-l$8JKkwWWrvM}{yZN#9Lu?8 zBxR7jeaxbo)~xOYrr@zu|6R+sF4eBrAQ-Jv?(1z25_p33v>kT&SYa`ff&1&0@&-b;$J+@sntMdX~37grkAiMVDuxljrjIPtY zHnLya$#yLSBkjYcGNIT&c)CQ_!gIxrbai#giEjGslLg~9yx}Y0r7yi7e&k1f1U~%X z55v3P^-gO4`mg_OYJcr(UrS|p9((LDqV@Y9e2^AkweROY|M~DapYu8JWv_od%a4px zPfyR9EIvP1#dmwKa5z9A! z^Ebo4|M&l%N(Gg%p=7<;$YzSZFWUN$o%gUHhpvN*C_6?*_XI zoTiKk)@u=l%kh>a@pYOwV(Su`seM6>o~ zyDS~EO@KqF5j5(A3p@`j9rMfWPQR=5-A$T9?$oZg206@AG;_v&dkkSl*U^2XyL$q7Y_NMTg+jM{_*^1keIT4nc)BXKDA;lbTe8@4ZZcIocAu70YK8Ae%Tal>1Bi-k|6U59@~k{R z2VL=hE5q{)ht;N^wJ++5!IloFT`xwjsa+rALAtbr4f3wq^>M!)NM>J>JvJ&XVS~f= zQqXqgxtB-P<9#-2pnAu#!5%`bU2k~~&VGg^UCO&{)Jz^1uzMTT&~=|Kb?CZNUI837 z*tw?)((%aZ`3_z3-zCx|XhdQV=>a+Q7!cBjuv#2^JnWp6aQ#woA z@$tIY7>)eN(vGq>3~TdUGPUbzJUAE!=DZd-ZGH(0b;^T8(b~QnY@EJ4!t6+}}HmQ*= z>kmzEJZ&FgAT}k1c?UdhQV5mjGwdCnD>jRLpDuOj zt~}pk2PgwAEZ5bydnI^muz(F<*+!L2f{r}SZB%W~#)+wOw{2p_{yRT#m1^Z*zA}tB7_0Jj`Rc;$-+c){HfPS*H+jksJwPBYC6L`VEK@Ios7Y~*_#g@G{{rl4L4Gngj2%QF+IAN!x`w&;|^ArhK3tI%XJ? zmRHg-g)Cx6sab6fOGzz3p%Is{eRvZjm0df@Mp&+M9-wBCf_c6Mn)K@4H}@m(7x0+=olx|z@yl9Uh0<9v!FdR*lH1*p;?cvO&#+fHT})Am9E*e2X}wd zpS?eFy={%c?b21QPww7=UFD+JZs_Xy7UggE+}C{ZwBc>+P$<9BGOh?q0ig zjoP;2_(x24-+ebZqQBq^z5qUZS^!XoqNRnUTl!NKiGHCkG1MX zjFm3_-PK0z(k1h5vv#BBGrF30vwipU+}Z){OYP@Qx-Qs(u%zcg7aIFHdG7MXKF{7S z*a~*gaF>cb?6dveM#-}+3YH1!Q*c=QJkPPP32-sPKp`UE877vfR}^ zJ2F5peK%Px=+}oB)@zT98w4&DA2u`9N47`BG4z&s~xa(z=%Td{}s`3GYw?F;up#l9b#$}0EX3EJM?@9BPsF7>f3w0C&!+bgypy0V0=y`SHu?w@f(*!Rh6*kcDm zOZO!^(0%vD4z%sr&<%fm@=BVV_zA9WMdqcQC!Etlbk+bWUNq-m7@&Zd6r|i31adwD zn410|?IYfcOV$HrLS^A8MY2sc0v8;xOwelb(m(f(HQaSufQO#o-F-1qKX0)NA?snm zt|X*&zzj!`$BUY=I>>L3G}wim+}h3=Hh~r((D9E^{`fC07~Fa>!gFpPCM*%|y&X&V z;9`FyqH_twK<}GmGiNFp0lX(bmUirA%(74tWHazoO92vHDTpJP>Zs?*`PUFuk+vj7 zx(#LnbF&yufho8UC6TIjK|0E{9-FOE?W5~w*ra^s44W+a?s_+BM{E*B-e8kJDa~3a z?KwACx^>D8-SQr~(gJ~RSGw-Qrstv*q~GRQg|4AyOWR;1|1LJ*Y>{rR*7uC(!_Wj9 z6$h?a;Ctg6-&p2J?|t9<;79+LABB%U@-PKY;qi`lyaVPkAK?vecmq85xzC0F;UE8F zS_rUCd3xW?DLM45ExCO8GT)C_@OruDTmR}`g}*laeBc8gfIs}hKY&LceT*^=upeB2 z`1WuAcG?TzXMgr*;lT$Vq>@8ghA26wJN{g`a)tWRD1KbLxGGpk7Y$bAE4JYeVVwHg zoSjnXHv7Kdd2Z;A$JMEi$3FQZ-~L z9+({g);^0qcx*dm0-#{G^62Gnv35NiV52&<>wB3h(b);jO2GFXC_uvLT3o34@328W zf9?8cg6Ed775mw<0|uK0L~46u2YT4V4tVS{`?#k z#WqXJ895s1=p5LBp{v#@*Sh6fhiyZ3^=&P1oluyxXIme>!N#e=78^KuRi3L+EAk2s zTh6l-Ho|0DDLHwCnT^stDuxcWy?QQm-I?Onk=LF)_H6%|&^0dD0Z-TR z(Vea-Jl~Z%xR2+eOIng<7J=0)SKNF@ou3rf5J!pA!Gr6iy8FsgEXRS-lT>S22JF6_ zONCTNC`Z{2R9*$6Y_UDKc09Q6+>{PMR@U~dU>k~)Etmo8+1a*W(@1HJ7$$k#GIqtP zeXAp$ORmhZ*S^7(H94$ZvEg%9vI$xb8`G)X988_ESh8ZZs(Np+p(ADrfcx)}tm#`OX3)q)r;t*^!;X->FVF5cVU<09R z+_`5!rE9;vC$ARUGSBC_H0L?g?2V++_jXT!*w_IorxIFhgTbcQRbKb;9G$v-y3ToS z^}LnGIo((u?c}h^W5urWS~DiFoyJAe^^aa2sn-989yy!-P4qkW#S!W&+4Bc$(MR)L z((_}g;Xh7e-wln|j-{qQmSV!bXitC<$8cOK;AAaz^G8W>pWbaF*W>v*t_j=q>4Sgw zCH}^}@h`4;+!fimPEM5Re>%t5h~C%p4Sz!?EJO#{sF>>P%h+Q@S%s@I#>06Y$_UbI zq_SfJ>qEv^{{)wg@!LMo#=m3QluanHFXS?gPtjSA&l;zDux}(_DPthcjWbhH0hQ%! zYI3Kbd%N;b=t*6WNRrvn)c)ze`3Y#J>9P5=YF^s1$}~ap*IP z04cdYgz}&ICrhLd%J|+!MC&4*j?Hw#MCA<~Ik)XlZI?Q6n|8GiP)9e#vE}dQRlymy z65(mF8QWIgA-83N_1@CAVhgpzoqe|qZG>?b8yg#nG!4*3w$k$qcJElyE6HJK`_3F- z)L`q;-C(or+Sg8OhOYFxIL7Q^eGs0|n?cV z3ttFt{Hm{nM;`eEIk3+r=d><>WT7iY;NuTEl>o zkN+56{_>Yk*k1uJc;55MGrhbPx*8e7EQqiC%CDro3qJnHBk;=U8Ayk_Cc0W|U-1=R z0q=hIyQ%CEVt?hUUIn+^dTU)kQKLHj;GPPvn%Xhj0%?WilJI%QW^-mQ6Ad<}OV(hk z{{xJ?p4$$XzV*mCH}W`>H-Mcs%+k3huZ!69UVXN)1G%G1S@qu7s06TRqZAwIrqgq8 zqv*T4WCwJv05ytB6f4r zw_;<{mLQuA9CMyyw^GXOERTGDJ@4VjIl(e^*m?B(w%A;>YBqJ2b1rmWvTZkxt&S&m zW6Mpu#lcRJmgntz(9-nm`L!MPVDI;>JS((qWKFNH^15_Cln9+x2K{@_v1Q;5NQc?8 zwS5>E8_BD58f3gz`-akYt4nR)J-Yfn+ji(4>jb9i!V+C2;%exR zs1@5V^zrrWKsI__c^*nRsXclw%2aKXe&y9JF;x7Q>tScOKKWjrzPg3evjoRS?3e~| zGzXcPwTodaFNx+^9067)-?+~L$i5;-N7|jcI%i4{hw2{A({NEzC(y>3d9vn(@!=9X zyHD1GvhIn+I>NYc$cLy2w_rf$m2# z6gniSX|0Qwvmh>u%|*>>&|y@%;UaFX4y#kd7HcGHgFU61K_UF7b_uW{y2^e91zXM) zJ1zKSI2N9dxs6_KYJoeRBQ~nx4#{peDcZ334I&cs;kdlq33?l7k*)>CvFcL%!y9wzxB8N7XAJ2|NXz;Tvu$$ zgyGNr?8ETuzy4OZIytu=diWuD*-Kvvci(k4eECAPZR26;DMliH?_@G4SU$NbQG+lqah`o;nC(W*@uQfx@~ z7!6$|EvMEguXXp8Zp0Vmc^00>9W~a~s5xwDPDi{w$UiP0+WL{pg>nrtm9_P`@wtekVhAhvq@AWFqX(0E4Ef9Ql9Uhv0kF9#nz!~ z#Wu%I8}3=UNju4_%3~I~JDx+R_2HNI{t#@|PB=RdtxR<6K(n_;nqyz}c=%n9?9azmbU88g1d4mn+Hp<$8!PzK_ZJX;}3q{vVP2RC8Im~XJqdGOqphZriM1zW_i~eZSok>2A*5U|ZJ-6*EsRhpM^No)< z`aPEWeY@5I*P;KseURZ(4;$CjSL_<)ZL#yFTK&HFVdH4zVF$KagWXOP@F4j-TFcoI zwqWQQ99=E8IbDZAYg#YUjqdDXtM%cRc+S`Y^mvZ#SZ{kTb{YK6u+cZL&vV8$?7$WT z`!cpxCg$>5qjI!;jxB^1n-1fvyw0)VGtqI{U^nlk*!kJ>`#rWLx-ILPV3RsHzI}$R z%kw@q&Pv#==fe>9W0N?vzAgduWTMh-8GCD^=5(Fj9XT_#5`gXHVgD`j$NP zbRx(0_0y4^##zRQG7gHSR(*XJ*;Ei}?fNsRT|bnF_ASk?wC4ZWre@_JnNKkrM9y`i z(*Sk9f{a-cGFI72<^b2SiEwShGAj9{aP?F+s}9`vc$S2kD_Q{Ao^E9xx`MNelWflV z!gh4>BUbt@gf-x;o9nz=a1PpjR`@p3BE~e4mTZxc#(0~8mCmzqB1tBn?g6mTu|~;K zkn9j0i;Rq|&~dAKEv#wsO=Fn}7nKM~smw|29u+}sKR&>>XOfv!Sy-m=2on$5IIjSdGG zyRGd_w5Y+ZfmuCl!9AO0r#`zx1Piv1xde-1CnzD5#Yn|osVR$?mJYT(%FEASb%K;(H-ucdV!bd;)Q8=9(>Ui9L|NZcS7rcO;0Z>@?bxF>3v0M4v&`-V@-VW%! z0h}($^P9at#If7818SojX2qu&6+L-WI}p6CDD6V^Sy*`tUY88Eo()pEc{?z(pN412 zVC~r`fH}{7Aa&11HTH9d9YEU~7i>FtY_kNn6v zki)V8C-MX(WhJH(hgZs~+?BK(!G@E>WQ3C)IC=wr-fL}2!H&3{Yr)p?Ji^=#SfnbCA+^zG)NbfjbVZ`giY|&gGM`i)`MH|1 zmP6Q&jfqjjy}Wm02aG%-7Flq^V=%VAu~E>mQ9}22fI64QnH?xM&+R~~>0sp3^==FS7K`=_4o-TXBzHhum+Y`f^57yG^uY;7CB5?$+kH%K@7PdjBkl;``f(f1%P zW2-W;5Bp*Ad_HXZc&@+yC(^a{Aq&s{RIugdujiM?8#C>9iq8O@HZzGSwtPo#rMH7b~PaXilm`Da%+e z2VRh;$s&zmMy@N1-$$&}ACei1@i;)E8>yB({x3n)zk$Si7-*Ty zY_R3BUjg2a&rdZAfyTtrZl0G-J1que+4Q%J8#B?Hu|joh0Jn3w9$q9I1-nlAdCYCG zW!{t!u>~ILmr;f+Fi=UP0Bz0x5N4SrS?*s6-HMG6tSU=>?tIf8hI~p-_VILrjez-V zgW-H|oNu26BZ*v;YccA2{QK*1N8>i+-oFa1*K<5z#} zSK;$M@AKeAFM1Jt_JrfDZ+$B~^2j6bp7*?`>?4537k%*;!{>kg=TjDd_SNILV(ntf zwVX-exz3?etq)&#?&yxc={^t~yg4*uLreFx51Y}w?C88*z_zm3RM(W}Mt2tN0Mr08 zZwL13`9c71*G3sTQ0UgN1G})rC0+71%FCmpYp~e84cdXNkqM}Jt^tsWty@<=guS+X zFI`i+r%F#A_1%)eKC@BA4(#0T#oMS|-z6iD7CVm;5pDJD)Z74o8yQ0^WB{ncNms16 z6CDgvw5S;5jihKCQGG*KLtWZ)Nt2i};#BHFAIV_Tr{`@-&1%NrQ#3YGW4(Ta+w?pf zupQGz6FgAe8b)Z1^|kcP^|npj=u#J&3B8OhR&2qfdB^ z8i9iHIuLef7cY6mPfXQMJmMEg)v2RCE8mjc-Vqvus#!w#Oap8M=1 zYok0}wXS}lYwn~D_Ur&g{06s2g|SfuTdI3h=m4X!1C5Pxse{uG=~Cn@o8WDG#+v^l z)IC*No{xfUydGX3~z1AdCRcVB?TC zCmF0{lN?sTHWs=LLPxHtzLF9QXe+luM~nzQ6P_Opf_3U!=@^BMD3>H}@*RpK6Gs)B z@?5Y*DO-{S8=tSqHWs?BEgd-$dlY$9Y*eOTlHooOz6npOr>My=;I*K z%9$h9(J`tu|7Ua+tY-$>oQ_%Qy|1Tsp(B0ISzgPzlqA>~`HZ4VxzVi+OTtYo8BBCkZp6=fn6Y*@Q~J%}C9Jpdv_zoXN6t=~+H%uiTm2eGZ_JA>y` zW+P^@VQ8$52rHM-z;`^dk^2#A*B`MwZn=~N*RIFx0xk)1LVBL4oof6~{h>T<@f>w& zdj6T*kN2)r??)cPVgIK^23VI)rHsL`lnOXI+fV=j^E}fzVmp>hJ;X}b*IHNqjOawz zQpJYtTg8UwM@NM1Y&u6Qm@T@IbHsWi`xVgqN#ylRZPr@tC) zn$@Q75^S`9&10YSjsFqHl5N-JQ5ysXF}B#CW=z<~+EQLIm|!G_Eu5FGrtgAn343VE zwb}^d8q6jRZyCQ^o}U|Ak8ZHc^8oYUI(3|ap3eZLy zW0nDy@p;t)4@`>yZznsBdk^4uoudBHrd_`dk3RY+ZS0GY{uup__uwO5djI`!&pr2) zjI$YCqd3D4!6uI1C3*C8w{%q=le}7<1GMt$>;M=$&|ovq-m6PHuuVzlRWR$bQcHcG$d)3Q+xh!Q5X;_Z?uPWc|Hs zyAQQd1)FVmGSjmIWnpRoTihX!HozQq&@~&|t^6w=Nt{~;vk((*tc2jg0sz;3l&8y! zvID)Oco^l7%LqVpPg3UP@?_T@V-qRcw3BnCwyV&ZhnLmXat>xa#4yq-=M10zZtf+l zF*>TWhixwcZmsk6gCJ6ThP_R+B?f@Wois<3ZT`s5ZcITtLOW$ z0d(YXk1jP>LYp!f{PTn6jz~t2++(vEqQf3+-_Rc60PL2Fjjn{YG()iiw!MeNv|Gn= z=wJ&A*vKCD=xXg{#}0%Yy5zA8J8b04M!9DVJLEM;-@#)yID)nPFt_Dimpq-amDhdP zY@?(HXci8eWqneHIhSsZgGty9mP>$U#D(DmSFWMcadN^PvvU_0d9b?7(WvK%7JiS` znKoA3BwRe>5)PXUm;73K;DgLk{C*dj07 z;CqiEuTik4Mh18xy6}9%o7Ey6D$f}!{^gYDhzl)|oa(1rrt5Z$f{mYR>Bv|jJE~DW zSJ=Lyz6l%BQFxAYJW{M@BkAwaq)TK6&Z>N(V_$XaWMqdw(hWpDaT>2!k&a1tuGmJa z_lQmDI86PoSr@iqqgG?2zUiE76xY3{#pg8#FVt@Z)IDj$UTT09NT#3t_F03f-<`#; zjLg^YCrdv%vMbIhS`~--oM6f_NPBjjhYXEVmSI-x`t8%Q@SoC>O78^@Ik1UG$EQJz)CJUoTqtOO& znOfixY8mIH{R+l3-%9~f4QlYgNM}<2y*M!qHVxccOFeDHR@#xS7z|=~o;ujH-ADEp z>@m)qi%K zX!n8edfw<#XfrNUUK^e}UD5zEDh(H^Q+>ws4&CrLwb#>zr>D%x9LGmc~du-lD`P%g)GaVasB-tIr(>xE__BP7u5(oIS?{k@#_NsyTcMA_h#fv07ma^WT8yQc8D_2k3 zVUi47cp)a2^f8QFx%J{P+;Wk3DCcy?T7R>Ns_nFI-OFmtYKo@J9Nli6;#~Jx%lG7x z(#j5f0IfHxjy+9Tjq(n>P!WL_E^2-E(7`sk0feS;ScT5#_vR&%b-iPh{be*^BN4Utuf-Y4XBokC`2Ne5(*gh3qqV~oP=qi05yRG^E z>7v_C8)e&bTi3H^`%}k8osZ}3cj;hkz#mzRCVcwYt27YMi~@Cjs{`a_J=DQP@-G7* z$`qO$Y}Ym?@V0k9Tb(aKoL)H_`x(UvW)~Dvv7e>vgB)~!VuxQT&!i48xdPkiw^(cJ zmwSP625Hy6XV^f>VnOw6h0tQB@*JjbDnXIh`M87)40bJ9(ZhyiCsN~d5(h~#*!0;R zTa4vh3hhCo>X@$Lm1>_abOXKLwJTkt(yfP$%->M4!ET;cy4MY8OS`2z*{D?MHlsV! z)i21mbeq$)q5GmdF7UiVch7T+%`Yr_Y@qiq$V4!7=jv`9x-Qb)lxDN-23yPX78~n= zl^NgO!RF{nPEgY~+kS@~<}wjQUUNrY_t^oDZAKSZvIAO*W8jMmc$86wBBwU3=JC8#UJzoF*Ml zt2!ss!p%$XJ%Z1BA=k#nSCy$-9pg!MdM(o=&uBIdW|pJ8KXv&Ejps1qDux>5L8xx# z!2?v9vg-3f=A{cKu%=D2rOvpFD|9?tqDEz|r;clNP?d<(P{-1E3?Y_bSre2LfBYSz{4ZR%0Jq+H ziEQ2*-td)h-}9aapZ!@cgIjL7rLRjW-$o`pHqy0SbnVIGp*%l8CW6tW(9Gp(5Sz!Q z5!rinX`dZ9kGx9zY>!ln4cPHa*bcE#A}?K;u=3ckL16(~?$`nKWsDx%joPSBCtVM) z{mS!TpM8iOxDjm1(|tCoqia37>G9MvS12%uvfe{1zA@3zbNe1<835JME9bT?R;P~-(YIj%Lm5}Ph|{U ze(Jq-AensMDfIhxbkX+gu<_H|`tOR3+UU|)?j_+Wf*TFZ`2LDb>E22}Y>Z!?W3%rD zbs($*(XyZtDmI@{k(z#M{|#NUrM9DM=}+n6uw{!4ijX($bkiK0@?5b~xzb>;rG+}> zg)VxnZZydBXy}#;rD}UeCOprJOcdjBhd|N?fNQ@P_WJ9wZRs;eX~3+*a4MC zZwJb|d7gLdfMB25&mxa_X~j0TQ9Jq;8EPBG6!K=;rtt0Cw7_ zxt{NMH+jC=0kGIq9vAFD4?Dnad7Skf$x?Ti|5$5L#k3OVxp$E ze15buZ4aSo2h*-jBrY~)uxI~Ei!GE7QcYtI<=dT$2xl=z4Uw z0PM%DBafM6BE#G|w({CaY{h0H#dGPwV*~%>Lf06;J-fvg)DAR9Ze+qBDs5Fy!Rc|w z4ivhyx)wa$Ed*-^S_{$GsFvs6MuB^)9X2Z0b1#qe?ojEXGNE?5Rce@}LMnE7Tna@4 z8atpowfp)6`{D=4O)16ONdlTmZ)+0-Ik=(xtk@a>q`mMU;=)2VKeRBy3jprrtjdfi6d&UJ=TDq88%nP+_zKIt-)sLx>#@9V7J&x zyR8-8tD%ndwjDOO0iNePud%*F*Df|kSNvUTfp_bihZ>E)3mef@u^A^{gDs^}BDIUH zCyxWyO2!CcEa`(kdf+oouV05pKJf|o$VWZ`uY29=%Ki3eBL90lN2jloi3XbwloE&Z z47>1DeJHU**AkTId2Z#==@QY+Uo0o}#ZAq6pw%_Yo&wf&-2mQ)HPugbv!sk7jJ98OOw*wLD1fmpfS^?sTVj-3Q z#uSNDByJ2mk<6({<=TvrMjbiI64SfwDjufWa@qxd^vUpmL{S7zMds_F2vLB#QhO#f zv(?67I&r}!?V#91IUJpLG@JkXhpAe%+FCV&+NEfXC=wKqF6ctAvzjy=3xfYz#$Q&TTvi_C@}v|{rTvrClSH~ z*Yu_O@~#m7d1qF0df=$ODc)hlr6Yb9Tq*wmJnWTD9U~@#2h)L_iN+4LaH7Y0AA%9* z80=GzNSk1f85}zr7?E*`q+8dlL)fS{q@ycXXR&>vpI(lr7}`I(k8^461DLzBq3#pM zadMO~e0B_--I(g5nb&`GmCvCv?VhI5MUjX0KzWpl->)AXdu1<3HQe$NF2C>W z9Y;v%5G;k!4TtYoW&CZ_*(Yv&D0Zv3v%}$5fI(IKPuR-g0?@<9nEB413)aqAtHSoc zeX}9Fj5<~gYQ8IBSYT(?y-BC8quv|rI#AgXF9l0(%K`lb&L5c^PXs=>Cw=TCSI;vA zy%XyPxR1NZ<>LAx`FWzV#}mDL?<0Sz+YG{cVI1KOY-Q-lOFDCyX8*C_n7(MGy^1-E zCim^t_MY7lN>Y z9o>jICOCX^n5Yns$b(vbjQ@E+@=~^ULiTQ|y$a_36fYwlNMY8k`u;SF+g{iwVr?DcrElxChPof~*rhYH?OAycCg<26FZt>`%1JjkaZU`5q3L{;s zjl$x$7MRk&yWomA&*eKuhTb$-n`Hw@pAT4fVnA?`W~mN!5B<91=)1xTxDjuYNIY*Yn1-sg*nt->-~ z@VAU!kvPknh^0Y)VsrTc_j_r+y0Pd29T|~&HOFt&sr~xj-iaA_A8zY`8fsVVy7SBk zTDLR)n$I51NQ=vC-|RV@`{6k2V(EIWc$32qzIrz2)7AEYjs?>p4iBBPrHS9+vLLo( zA6Fseud0Gf{B5J5&*%yS=4t`?0;{M2r`Y5 zmx~Qc=;obJrz$IV7PbD}{eLk0A91*dD#2sKYw?3>PeS!ku=i)`XWPa$jLjl~-cJXBuwV=H23+5*eDJlfy?h4Xk^FpCDHz zPFxR(zYl&}Q`%7)cNA);rOjXBKAJlJnBUs^khd8Po%mOlH(8fvYXa}4w+|CjfK~f^ zjjFhFCW??*X=}IfB#PjHRp)vlPF0Na!yrLge`^{kI<*{zgeNVIS-DS-2??>2w8G95phe8M! z>+Z2!!WmO&lF0$;d}pj_|3<+Vjz(($-w;?LKDm`;jc^%K(n%3E`5<8Y5hXqC$!q~V zIT_11E24)!bBZ2mveI5KTR;~DU}wlxcW-knB0?P4L|_875b^_^KGuJQE5bp`#)7H` z3B<&D%D;`E2knkA4j_fkF<~7P*4wOhV#A-(uZ%rZbNLDBVOWI`Vnu7Cy&Kbc`@ftl z#R2j==J2tI-B*(A*70BDz4t$J_+K_8y6yb3OF(}D(7qgvz9eA60E{4E z)k5VvhZJfdK9dNg^_N7Ve=KM#41RF{@Jz9Pp1YWEpNENn?<{H-6_= zznew|_%3D&uze%DJh$)^LV#jwV0m;s+O|Jho57RvX7-S_O~{(H1Mj3Hl)ZPlPCt(V z1%~+gkW_$(>&buBux2m=l**gYqu2uEnB87bXXVaEXgUMVXT<;s>XxmBN}5!EkK z4m!qab9eNLu{>w_Ti@-^ZBa^A$B^x&_`rvr0Dhe+M2}jWi$-w%2UU^r2gHP*HQ(9(dWs-?WbK8G%OWgcp zXXEkiueZTASD|`X{p*#tqyRVkUg1AoR)rj` z*K4UJo&}HC&kx}=!;pZS0{r@}{?>>#G@w{DhpkU2U8chK%VOWm9bhtBMK)>Ed++7# zB5{OBu(bH@&+H+JKQ?kqt$ zRui%Fvqo*VE*503`=R$FOl@b;qG+P1yq-Hc?nKJ@;#-K4GssICV|md$62t&wR+xUk z3P*@$fCipf6~!YrdI7H=&%72|)dMm3-QrJ0SrD$9G2fJU(|o^hs|stLuJNUwY0Iqd z_2UF8i#Le6-Sj8gfvj^+2qU)RM%$Hv4SH9NbNx%zpy$gF)6|~Opch;k|H;jUh%ip6 zzry)*ymFh~?XFjoteIAdd$nHDSIRA=o-MyMg9G=#?`Ubws;e+M*)>r9rfaJ z`!x7=`u;7g z-o}Jml5xjK4IH;JT-*ghkpf$?A1eP_ryF5rvA0#1?U;WkxYgmo_k|UEcCi#F5zaQ8 zM@R}nwBAQbBdo>*OcQ%rA+HlPVsehXE_8n$s4ja)XnVVG14u6MIR~8<6G8fpZ-}|D z%IP-7+4nba;xi=&#IdJ7i{me*$&o92@N?Zr_h0Iu=O+Ioc1a(l$3;i}@ojv3tqOQ} zh^}5E%ItoYOx|S1>d^8A?Ol?5{(V~?a?{9#A8BtzC6Wq3>6{^|kJa3U;Pq^h%#Ig0~!N7VOrA1yj|D?xpwm(vIw{UZ7?h8l{iJBozj(RkG zpb9sl%4zdXwi@R@`n^wFRg7(6Ofc*A8*w<%T^u0!^V)cRnKumbxh$|^n0_VG{jmN} zRCkqdlo^JtX*FT6x~Co9 z6OAg9<0nIr>1{qmcFq^|A68nkFH~2wkX)t#PQ=v<5296qCXJW)G2sM8w7Ob!Hbk+$ zR035Lby-u^bA;bqg{B}qyQZue#Eui|UJF{MjcHDoNRl7Vdbr$Yd-inJ@JyXD48#e0 zvH|tQJ}6UH=ky_muduS039lOY?I4|zwioO)+Fn6n`8>SCV+{n-m>faF!#S7Sg}+}= z8Mkx?OR7fXRXh%9Z(W|9!-x8(mDApL&`%T(V`rvm9p8VL!15lHFJHv2*d)DamYisIFw7&N&{5Or;B2hmig5UA`RN3<;19PmET|r#LNS zmu4hXz#+nmJVh(#yQRQhe^Q}VU4~2+<4?2NGy_=Idb(@W^G@*briv`yXW~H*tJQY< z6a_Lf4qOC!?}-tu|5C)CRco>JPRvsih8@K0c0`CWUYRLXN{doM zpyf0=f&P96$2Irk-adS2T2BVNkeU!L z0`J6Z8(ql`5x+6hSBQH9(M*V1#-9*ynP@^D#q*tNAjbN4CeNwhCw+yl&G1;XTO`X!g%F#3XKNy*9uIT&(W~;RkvwYI4>iKcTub#*ViQKE{X_` zbhJo9hjoKw9(Ojy>?x*M)q_#z?$nDz&#D9e%uNOtxVvqd7n0|A@!os?SsW5OH55% z{Ia63K*+M_my4^&>4_CSQS3h`N#Tx^HH^r|{$+xF!?OJ9 z|^8Z_%$b-P_Lo9G3yP)OE zTY_KkikhV{%rEGgMpxnd@hZb^-s+4w_pj=vF>i$%Cwar62t2p*J;%s z2M>L$Z^Js_yvaSc`>xoHGmI!|eW3jXJ0=(r2Wr0sN;V5B7;-luZtI{O9KC`i2>;nT z+y$h&%93|16qIqbEO1;#=V2h1r)17_^|iA21#<;)9@}g8aOoT053k9}r^JZ8U=8(* zkyFWfSKSxGszp+^fbAr;aw%$u2VtbJxZW2aV9L?8hG#waazgTi-S}C?ryk+=yo}M6 zc>l##rsy~WD62erg1!Vr`GB(Y*xPzG_iq1B9R65rJsYSqh3zCp(V$)CD*GdAs#F$7Y_~d=9A}#bW9+x;jVB9OpmUQ2|@1&RU2OqLE5 zcIi0~7C6m*mKrJmH__`BOLr_jr(!Yqfe-*W0pLp{?6_5OsL+{Z^0cLvujl_JN6oet z$mkWB>En}`Y5V2467>H%IZy0DcBR$r$T-URnaR}_+JNd;|8z3T5f3xoA zp*TkxQ*&{7%j{iPWc)S*2$cZBiS2RvBLv=4KOFPkA|^KgO=YM;q5?QtF(fmL&GmLM zHFHx4R`u|GufwwrMMws-U`vQ`p8*W?Cu?#M{h1iD_$Hp; zzwlTjmX(i$7werEU=Wk<*v;)=*ta;3qVhS)&OWug?3Jbf*+7~~I}fZ3;?+u;FYn}# z_vB!o8dDpwIgN1i?t53n@K1wyd}~U^navs9 z4>CdcA}y9|$alAb_N@bwk)qAMu~*Bl5^R;AVE0`@iQY|m?7BvCha;mA@e^4DQWTpE@XMQ7|UFdgoFOrrg>U91Hzp&`&Ju`|LVqiaF?Cmo>lsC6^X(Gb}PsOkGvHm7%{ja8P%Cb!V>6T5eCF^((imEI8w)% z9c&Shu*@yj-FNRp_peYp;T~P| z7;z)yU>r&cH2_w2?h<@)hEj9f4(Pr7DP?E+4)hvB>tI(<)>7`_B9CmcBC^vcb_v!p zjTyoBcaTF~B+lMNcUuYfQlq{?=$>&|$cwzbk!q6W#%N^D1S@!H(BES^A9sC^re4Lw zrTo~)kA;@Il5R=#7RU?x{V8#ZAl$_otv$9iY6^$mYqiHwgV}~DE|2;552SbVDRuwM zdWrV6RW`}iPcQQdpMB$0HI-+QlfEv5a|-G4nZ?|kk&AqSl%|SAe(680zWM%B!M6e5 zSaE6Zft6r)A?TqDzKgmL4@Bj=BrfqjnC)mf?DL#=F_o#IR4q?3;Q{F6gdSn~GK%Ig z(yvd#w3-jg@!j-3IsNPTnL((oba=oU0qL*eEu67~^=s^j>iFLfLnPNgz=L{T#wC2u zD)AO*%c6!mL_Q^~DC{O5b)y{kf6p^t6$n=r9-{>eg$;^#f{jt~I6{+o#@bMWHJ0=q zG9td^)}Ywj7}0fFVaq~G_6_cjA3b2k-5B-$rqz8Pcy%QzcB4>a()bo}2Rll2LtpNX z=^eHQ{`54Gc?Z6tRUie7eL?j;C$O9}W7}|SNOWazqfB3(v^_YMlISgv$EBg!IEQOW zcX;sZFtVk7!qe$cx|K=021MQdmiL2?5oxl3Yv~`yXjl zg-6T+Yfey-io6l-XxllD#i!RKp?oMCnJ~DIM!v)~V-W}5C zmz$k!+G>?nXmT0Qa1KY3<91R^zE7*X0MX|4@@f20Z8o5z!QG4mBxyIZ-52h`l_mAC z`i0@Zs3+otH4|U3CeY<>S_1n{IV-N9XKXY{&yV7KbLo4wxMm5iP;7`}4-(mw!>n0t zpGRwNw`=B`XApgyx6ireeAdU%farXl(pINI0DjrZ^ip$`6znPiJHeOue9wSFB3t-Y z-pPVn{=vN{bd>_=#H~~LKUU`_MCNWSz$qEH4KfGZjDC!YwAWhax)7nbdumhnH1+E9~S!t_5qF{^S7F+Ic z4==d==F?*e>VCYbtjJtleAAfs3NhkiaYZN@(VVD05B8yW`|BrG=U8QJ?h`u7Z^JFb zBGbB+F5Kg(UmIig(t{?Rl(Zgl+_`Uzd(OMcpoKm+Z+ocVzg{+Ml;t=V=~C?O54 z>06~$s|9p3Srjw`9?wlAr90tGtwdplnK`fEmIv>NBXQNYyeOMTw6S!&Ri%c_Z5k#c zTe5~GO5!6xf_#)NAbL{$74oNodgok?zVYxHP)ov}W!Q5~{V?7pp_CukUP}f!W64z; zD6+9+W?St8Z4p6u79t_72ZqqfU$e?MRmdL4cX=S^#}8Z!>hIz)u71%yd-4Vp?OMAE zp&8%x)>`#kuQnULsvW+1o8oC>k)^_YJ+UHss8eq9>V}IS9x&99z*k6@S7v-Z&U!TI zNtR8#nBY`dunuHB{))rb=SaBjFpQysngO>~jeD~?>n!<=YaqdqV-tf{2ugXf+nMfe zhF&=y^QsCWwMg6yK;({2)<m^wgT3}|lXz+o}9pKFi!=I}c$B+fBX|B0te|O3b zpG3&Xc|;ooMPuRGak&hH@H?xl<3tf~++hN}g>Zajbe(NE-mNV9MO`$u%aH&D|GUKYaD^4;w$TFO zyZ5x*=OdItPE%CbgA|H;M4`p~aoryhmlv-;rliok0YJif(SO~nF3cMb;uZei`^yR9 zJ|NK#7whhx;ktDUDR9#|`91cEvp8=A%G#oDfOR&w=b8zU@z*D+YqGeyL%8gwwLPgg zCZj@I@qgQyX5FT%I*vAr-<<7B{RY#m?zUWbG`i($L}VGH+W)A@gcyjtf$0N%7I=h{ z;!5%G0XgzW(q?6}g=2IOh&j#m*+rtoz~Cy>+C+nu=kn-yU5qv&+#$c~Tltn$`&a%~?Zc0P+iK2WKi{P^xH!|u!yDSi z&kbsD^j{3;QuVLy(t$BSZt#*t(YND8bJqQ#>Kh>`5>cGqdij2JB66NLhVaDT;Csux zOVlmje*);wsPWeqWHEGv1391DTk+!ifp6VY4>V7Vun&qj;I^JMPwZ;1d`hMR;D<9M zp1k6%vM3ySlfdq0-xriObJx?imHYTUU@p(5=8|>Me5} zu$ zyv>6e;7!O2@+q(&2Nc1U_PnzA#M>cA3LUPw%Mb}M$SdTax|Lm?8{w%*I#pT^&*3#nK-+1 zMK>Gf&U#;@1GGAW;|W_bp_8B3sk00te6Jq4^(v!3P@}slY<*Uo!VHf2s6F)KE;teU zs>G~G`kJ0I&J)WD-+u@LAQw_NdHBr8D>B}K;&PXSCh=G^__>Fstd>bkrM*Z$q_ZJ6 zdo6l!Y|ETZ7>6LhV6-t&EHP-BsdLO3%Yx53Ey+Hugs-FpKz9%pWyOU;A4-^zZ@+|do&0A5s+&)mk<4vtgSh6s4(R`{q8=`dqX&f zwK`hhRzpX`b|xSAG`KtBrd4<}%rH%>M`k;A}5|Yf^tt&j{VwpgwBjo6GF*&qQa1xB@S+%%3u6qG0$! zyu}kJG^`lq&#rj>_s5(6PCp5HY`WaJ$x8CKeX}mOIh{-&S3df~C+-#l7ss(!pFgK4 z_=B<4-U8p}emA}ZlCE{L<;h;Ydztt6(F64i$Xg}t+yy5-uBq|hP3 z57(x@c`eUSPdcrIOa7y`xpW&)X=$ZNnYPlBKAM)>4g&%vKZ>{(*(>#qmmb`drIz4I|r;2Iuwe(YMu zg7aXzz;=Ois-`tQ28dozR{Vv1bIOh5cyb4>snH3Bshaix@I1?*Byq_c6?ICFA>(md z_ia0NzfZVnJoFO=QO_bk$KmqtFSk-LpcmR#HFUe)df0u`U5#+G#d$Cv%WBiamWDi^ zZt;Pg>U8CZK9*-VYG_=_O!2J}smFKm{V2Sojlz=u7NeM6Zeo0xbtxiN>TFs5gb!Z4 zxz~D|WApB`ng)*7nA0oCBMR;Q!gs3HS`)&WsXTAHKy~AS{Uc!OGeuAjr>z-ViGf}< z-0qnXJ|f(?KvZtry}E6j;4Zo^-^%T1Z!_neX0m+W*6{3So4&YiY~WoO$ao?k^}uj4 z;Ag16QVwH%)Q(?p1laZb^7-KxqOi}0bsV$8qnVN#x?h{rd!Mlh7BewnL}A1;iX2GVa&VDBYAwYCGK5lT;cw6Ty0*^U1QOrrFwjYl$)*-SR@fL+W4zi=+ouE zyLi)S;|6w)E-=-_x62SPeDg&H*tQ@s-cZ3N?NY*cVh91vW50w`*26gJz7;9?v)UD; z#*4ab>RS~f$>*K6Nyd_nML(mVa>?*Jzg0>2$IEW2I1j#`;d5wBUX0-16RzgIlcv`D zTgQ%Z`QfhENIbL0PKYWM&aZPxL0&RJF4E{kZ>0Thi_N1UF0t0qJJVS~?oy}TSH*Tj zvjDWf5j=pgP~fE-!J(yU`@H2Y6QgV0jRd-cG&bL{02ew$g4m?8(4Yv~tfy(HG6O@C zR~Pt(L4kbmQ?3wD&C8aMGQx1-=7P16KxQoM`SJS6)79mIAyTn9G70>E%^g&A}?e z(;aeeQ}Z!fe935j9{Ras3KzA^tH!hEOEvtR$s36jrD77pg0`7HEqf*7I;8=>f!0&D z4-Cov^^zwwO|*+eCC<`2C}nB#L~NK4uHCdB@7tE*`tQ19_geAU_4n(`-L)tV9pRsk zZJsET{c*|-V!1l{el`8(V!Ppo@B0(qA6}>nOTWbs%0>Hkp&E~4aq_kMz{K^h!IyR( z(Ex;yQ*n_+>|GcG{HyBc?-uI{M&z0X0phiyCPk3QAL%VGi8aN!LMXo*!E3(3lw5(= zVShJ0gE%Z3-vG+8y(j;+zh5@|*9GW^9@<6487HjqNZy&GqH*uraPa^YLvh{!NR@@f zkE@(_yWLnyq`fs@l$pXv>5uB9Sc`QAMC7;)EoNs?q0Ma<_i-?9Bu&lUk@9ytZF39@ zpyyzyo3o)5t%4$D_n+_6HziH;K!$m9&FnjEXS)tsREL2=CRw9vDv26GabQ!4->+`L zwV8lmz+sX5;r%fnn`jKalyBM9y=K~J-nD9Usup;Cd_MhSI%s=(%b>Z?65Nn`m5801&7R!HZ_yWM0KuO&97f;Bb(y-ChJ9yv-I^ZC`_-!9~{e* z#3DJf#h<9Cu6(?-d8sX(w-=G#SQt<16CiFn;bJ}ff+6jzy5g&aTcBmj zSwq#HXu2xyG@a0#{Bmc^F0mwV-8wFB>e60N6jT#YeGh7)_-c!tH;F?&D~hW3LMU#d z9^p`tr(ts7s7NTuE4MXdGYH5s5Pjct3}vrCMdlrd*XIal)w(Jv=-wJ8_cK#YJuX~Q z2utgeCQYSUh2hN~8ngb@FD-WqA5uRl$=6JkUbY@DC97=PsI&I|wRfM|M=PW60KOb^ z6Malqi5^_Ob2w|8-+OmlpvU?UA|20ySz_;C`FvZFv;vphMKAoiui0U$624rwqx&_m z_nDQ}Yt6O%9-ak(v}X@|oq>o)+O4V4SxzS*Jo&;MJ+NblUqt^&J#e6gL&78`1vdrlmQ|+!auPxyJ}{x#3bm$U`5V z{u)I5)8X_z`|V!a$V_BGpQ^Ix%=6(xObK^Nk({&_RS zszYf&0!>DsfpC$-nZuE{2Dm;GchI9{TkHZ#+3D#V(&r zriG@ITI0d#C^=DN7jp>1NPWh|rbNgEM4w_t4+a9w`k&Y-Tv_qfFk6&m4?C8swpBw+ zwn};;)({?;rOU<-pUFA)o`$Z}+EY!k$>JXl*8qC(?DXf)P$^4qTG8O=4!j=?6xw?2 z%3_p1y4O62S1NMjtGa7#6GX{1+n4%95T{Y|LIhQ140K*j)-92W_mB_qu`jKg`wHqA z8N}*un6VqKO?StJ{WX!kBT#rxucD9twM+DMz392f~(;L8Ik`N#wT)kSI#V{jlafLyQ zum8@)w#2hb$AF)^r;Zod7H|S1*ypYn8EsmCsb&Ltd&|FMI5hN*DQ(Q|e~|d={gyK> zlACFi2E5Ds{}}OFtnvS)$FQC{j1?Qx{LZj!r{YTY^jKgoSeZ>ZqdIV{Rimc$PX3Zy zMH6=nd1!lrm;BOz4!#NEi>FuM@WMk`;@ft`s(7p z@BcQcB4Sv@Q@`)dRw@5GTM>>Z8WD@peoS^jPOI5a&(c^>o;TZ8(C?ME*}QP+aT>*a z{r0rgrDNG7c*Ud-`u=413U;b-P2`S(4*_~Cxa4!ou5jP~qI%F!Qg&Q?8;hU21f-bm z)rF?>I?#Q)uT0rj;BwM4PdF-tH7-F#@&josFHb7ei)LTtT@1A{RlNL^;{1Yl^}=nd zp3Dm6YqLoZF1diDMiD#7)^N2y=x>7@n4!n(Sru^xa2l{{?&V>RIJ}W~I^DKC>rA?6 z$9-|{%an{6)-#J1E=fzMLP$f~g^0CwBt%o} zuNBli_A6(DG*yLnu9O_78`M2DD$j)>3E5UeILzd2B7OM+BRMj5EF(exIcw4{-t3m? z&d4-i<@fb}+|=N6c8! zq;!D_R~7V7fD}gh?D(n@hujMg+@EGpBvKr8c}`+>H4rBl zO}F~!M{XUi%B(Z^(v9QJP*yfx%~KDrXPHgH%0}n zip({$yVhF6ZZ;x&82;=^Kz_V`9I!fNq0`&6@_ngAxxU!guO!|bI)P@1Oy2(eep;KtNk&`8!%s~Yzt&L(s$mAImlPP60O7-}1_|2)?_(JlexjCpaLD-MJ{Hba2Lo&$OX%qKd(fw&9GoL^idNvkE3yKngHB6X;Fwo(S{ zk^fnf{7G7NkP*`$rOneG#jFc3Q8JQf25mVTJZzr`N^l@6;Ncn7w|u z@j-{6n!Qt4YOaY-jIELE7Q7UHuHPqEM?Qgdbq&!vA;kAE>Ox+4U%fv$31$f1V|{-I z<-hUZ{36G9{@G>V_H>X~;Lcj$d~IVriqos-?|{_s$l~$qt7Y9zy9DU11f{E+McZv> zgPsvIDNEOrRY77vK0jb_xs$p$kykglgXQJn-L@Y-?@VFeDH0(2ZyS%MEdB$oLf-E zaoPsxWuLzxA?4w_x$~C+5}e%JhS5i^bt1#xsA=)i zlBG@J+o?F{uL)HKrA`2GZS$z|lj0gGz*)tA@ANZz7Fbh|VG)97PSU$@C&< z`!vG_d+k#GI1>GR{57wG?cYTw%qD$F5|;Wzm+RGGW7ne`B-`nTE$4gK04{MWP|E;F zri%AaG23;JuJG)Hz^(h~sxRkWb9d0Z{u@~DVnCAZ7SN-fp|_i;u2FqAs0ZZR4)dLp z`Nb>2Kc@0IEy~(}QYvG7e;wKH^Hn>ga-T|J<#E_j)0oVF`}+)ZzLquO#Swn?iU?P7 z_lIveZTu>DYfy3Hd&1bQMX3~DsOI6L;Phm+f4$D>UzUih;yQO%R3G^>EdT2X0F0XQ z&AktV^f8CwX+HBQETB|N*XJtKX&tp#bIhDB}FXspTrb-M6tdnv^RZsf}gkS7b zC3Y*c2lA_Ztf29AVX+zOC+@>y+}X!(b+`RLcmM|~k05+M`C$RtLwX`>a;+m>wQ}e- zXFZQ}!Pk2W;={n#=VcGQV9K^_K#)6QLfn15K5x^**<63V$w0sJaGRbz<^pT^c1G+P zx2bM%ZjCZ?!dxW6x9iih>L4-@ATwDTBm~x#RrSqU;N(f5tJjm7*W|DNVfB5N1~*aQ zmcFIklpAO#dA$L&ie>g$Qqf~vbaVZ?eO`Qgkz;kD3H!S`@QpxNVpOsKqslKPeE8th z+=7Nlf;KjHnx0>44ThKBX9qe2%UEkhwygDJNPr-t$S?`)qS3kF;qe!SWRpu&Xp)3z z6($lrMQ;j^0gE&gC7VR5^rkQ58?~*&@lnt~O2Un!CC(^Ue-1l-{3^B+~ z57U=4>M`1IU$Y<6P&50BN=XYQp31q>PJD71bdCQ;NnK7Q6ZdjbNYyp&`^|-Yu?0)YUr{;M->6N$zjqHJ=v%+!NF z!l_UHdZ7+D8#jj(Tt>srZ;J+BxHrg}-d6Bn3PilKbg=brV2m1See>U+iLMBuk3abG zV(XPT(Qi_8deG~zHF51Jl0NS(7vBPwe*GSTfksEvu*bF3EC7Jlpk9A_2C5(pxY+i6 z+2~nb3dw70{szQF9v!l0Yb$%dmaxkAZS_A|lD^;Bl|-T!3Y8cd(XBY?%(9 zKGA}z`pg1U7$prQ)7u2jW~sl{I?ck zI6ogRqa8Rv?C&R5__9(E-oSNRS)CGkGS|n~&v8{Px!=3)^Ri*|Z%Y#O{ikf7)^7mv z;0hmaCBCbv1Qj^K=&3PBmYQC2c>J6W<|yQ@cuB9j~TrPnsBY3ix%w$d4}N5}Oj6tWY#Bcqmj_)hc-T zReqJv4rHv_72!Ql?1t6~at~yQ=AT;RF7lA;!)H!}^_VX{|6XZZ^lVtVZW?!f`bDaY zTyaEJ$em4Ly6iPI7|oDysSmpxRNvUpFy~odfm>c!tVag{0ZxuGb^`a9*bB1n@ie9P zQ)BPVk$oU$eIVYAiWg-!oWiYq^SNyIJ{d-Q4-LWQ@cNX&-mBGhXl;9TvUA`J=Jx5P zZVad1jji^D9g`?;l~kE~+*!|}g8__s?+2wHy!-ZYfR9lV|CA=>FE*LU8F{Aaw)CF{ zki@<;`A3h^*^ibCei&f%CTIV}x5AH0Gk)C=4S8M3cQBShtX05mqywtzMQ&rad_Ny9 zCXwM&oGUsTN|LzN>zS%lS*jBt$|TP_tU>U4*7NX_yVTx4`#Qn3$D79aZIAm}fS*?F z*!aX)8E0SOedNvkY0wOy_w1J*EmB*E*xmVAGnaL~t6^%Qq(68as(noIFEI@-!0cMWnfl!fILNoHZpC^Vo{(U`8_zekSaJJSw=AkJ z%WaipT`5Nt%i=nrq7m(qkAJN_9({#);r{+7RHS}Vois!2`7E5+3sHI-KvEHJ^3!XJ zgOxg|$}gDigv9i%W6Zz+e{aH?kFyl=3qOsNq)<0m4TVcp_EDex%o|5#@4nUQN6K!B zvPkL<%P;@fs{QqEObCw+=-lCSG3c(zbE*yz{05Vffh+X>OYF{j7eu|E{8pgvhT=5v zpT8@=;W1M#k|nT$d`jnP&1FO5jTO#%TxE;J2jEFu)vqX@5EN7j=DAdyEutG?Pv2MgaJw}@O@^z&f- z<1?MOnZfOmF>6vqvG2JJ_BlOJ}Z>;2bw;gcqKfW3PlSfzXg)Qr)~?5x3GL&sdbR zTsMy1|33gJLDs%%v4sw{jnK`P&F#@OTe>RUv;>fsN71#^;rTwgt`4;W78^i|&FNaf zX6!%@8yGu~7qAceumQ9@Kc|gavI9yt4P;&9x#-#=T@ALGjS_haMqa&*>gkHNQC+&C z9k@Z;U*vIgdjj<2(a>!suN`bbv7N(4b$PzSM$thF80brp&AlP0dB5RfwgAA<|2){? zMB6N}I=QYck;78z5Cw@ArSlB7wlY4U)U382x-4mR10R5&{^_5l(i?c_MDcI@jlTh3^VMGs zFMi2OXfV58@n&s0XvWQd(P{m6{?7NngAcx+g?1V&|H?1_GQ9T%?}cypOJ6@RZ-762 z-}~U1>ALU#{{KG>tTC$j1uuLd{D1z=-+>Q4_#pg~fAUZ0xgY)L$KZhnUIlObs;{E* zAFuziFXPGZg!%V=@Au%>e(l!?;|D(QL7Mbn)<6_v^1>IqfE9J z`K$i(|GW&I-~avx;h+A~e?nOZzcnp-;3mMrI+DpB`H>%mxBt=G$;tZElTX6;e9!m5 zS5I_Il5&re2E_W4KlzhXYU#lbe25l5#w|}0abS*$_IaQCx#Z~m#&7y2!t$zDJwTJ) zwKHnblsQ4{wp|@EANb%0;n#lkSK*(ufcJm)=X?%r1pT6kU&zCs`PqL-}H^&2%Cwg!{n5w=so<%N{zI4O^at(3hGZM+TcPO z4p?x143!zp3i;9r8)EvJulX8y@rz$v^q6eabS=^pkDvdAUw|hbe;oe9fA|m6g3z;Y z`RU6tXkz<;*ia_k_?2&f+opfNX_Ap*(8Y0pJpZ5nr~iqb_uxb?>=$(c>4VqvsxaFi zbpGRp-&p?Z$tRy8-FW?%zn*mI%O*X%_uhNUB=LK{_y0=^g%_s<4gAoeY@^M<{X-D{ zd;a84X!41)#0e%k@o};2yZ+|iqz!#hH!<4Jsd+pP4uG&BpdiRs-Ai$$7*pSKN*tZPBG{Y&%#Rwd=d2(Vo)Y#U_W^cZxC$^#fcp z0&dPjg9Pe1%QTZ(vf|2sHq%&x7Rv(*~g2E#2z7sNJYF)+H)U=(;WAF6<+A%FB#`HI(N=sP#D!J1=}i zUH}xF8g;1H3jYOLi71i?cwP*JHnNb)q|`B?&Av;a4v0CLUf$KvwbTL^K7i;h$%M2) z8RLP_RTltLp`)yAvb|QGi-RIW4Ft&YYN0GBSGy9*-U-E#Ez6ukC*kH@Ghi0zq^<${d3lkuK-OPROCzpXBTaHM+CtJ>F|PDaqK7 zEceHTe>L)3pRduQ>g3E?4_~%4K``V7TvV6 zL_cQ}RjYbv>1xhxg$0i-Te`Zw^;winEYHXtY$a;eU@H;sJ)Y-W-qV-U=+e!cYjnJR zgNZIgxav>RcCgswZ{+;dHldyJWJXt&34p##IJ)Xkh2TtmYz#KV+F-+Xv+tg3CU+9- z+3|ev*p}qA!*kU&#I{vkD`S;B!xk5Kj)%%4?7#+g?&awUFr({|ye6RuS@OWPJ}UN{ zTWp#Ae!=myu>*RqnM)4lT3rBuCAxZ^sg2UUq&u4ACqA_<>2*hsvZXmURccs!rx~;9p)w9vFu@ zh$|h2w!8_oQX>)QPGxDuNN%P$z@<3{A^P4!chstnGCY zUelF$;2##Thvs90k;;GY2Y&#MfAVp#$6x%5e~}#DDsXx|mI1=!%fI}~sqOo|@B4%| znWA;x_0D&a&fZ=QTW-P{n;`wdE}8t z$XQ5^)yeUQ#tDBu{_&4foqcq$;ywQ02*{C~gXkE2$>dxG<)cLD5*;=ha?HQ=t#2hK z@;l%84siNd4s>kafB*e(--Ol5>?c0)3HXVh_z7~F>!JxRe5ix={qKJt{pj(=H@=aa zq&#WLWrHK!X!+-U?&k={e3NB>Kb&}iC6T`H3%`&jQ+C1xFiRsFMK>(Zb>;5Lv{>=G zzx%u7xP9B(-Uds@J@?#0j`}ye;SKEI9!H}~K+f{t_>H&GA_%s9-sgQDm1;p*!G(r@ z_m-cd1r>W>hQk+s@fX8gcisW<^{=PD(RPCwnjPn90Bz+}bVV~8aPi_df8#euR&fzv z>A>hW#PwCvLK4#}w1Xr5BfR4s@1TX3|Kq2AiX7LuBM2ua7pBFp>+tfIzZ|~ho4=W9 zq6SoO;lH1p9M*4t``h7dlU(6*mkwO~LdQSSSFzCmLmU7rSv-8-v}lI!_@>GE?de&u zoxrWP-8wB!JP*F*TfRl;S{;v%fAW*GK{sMXoxw~M)GhoM7XX4phUv!x9q@SlC#U;x zK@9ce^FRN!#9P!?dj9lml-WQ1(<g2 ze>6Gyf9Bu(o924dC0v-npT}__V4^3=EiN|TA_nR>9`unN#MY|)1Z(?i$&kMNT-GHT zFgtm~=c>H6_EoYF#CB`S9A}tS+dr5AZ}VNsZR((JFZ&TNHKlk&?qdUS9*6@2uU&=y zMC|4~S{)Diy_Nj{C@KjfDr2HZS|rz6B81VdV7438LC>5u!%<9Ya!z67H%9%_^&^&X zEoD7rM@QE;2KnV`c%-Rcf?jJ7qzvhJp=k@k)7~ zl;=PZ<>i|>kw?t17%O(f3Zq1gtGv>fm&aM_Fwo)vZF)IyMn$E2q!LUd zj}-CFQQs=BO2@78T(PAV8}U3=c`S5Yi5;Mg_@dFZvC=&W&(TIn_DHc&NOz2A9}Qit zjY1wbdnrI!w5-^+MjpZOT;(!8NeG9<4K%eNST&BY)W_fHtvu|{4w$f2Aj%P z3Cfk{aVQk?tidMNTJz-PwZUfF&nb^HY~r+C8F|!eH4wz|1Ufu#c$#yI&CBb8JX(1R zR?or6T;QNXkZj1jWTOnWXlzuEu7k=9I9(Fwx|hcw-<%?kVpBo=J_Z}nRh<6zSw5(G zk>}0^^<<)}=Suew=JvDGZuL$VOlI=vbZO;f!r3Ul!ES@i%Hsjpy^RXeZe>On89YzB z*iGN%739D8XTKnIBS*6Uz;+}z-LX4_BWE;9Y!rt~sS9m{UME_-qk33&tj0D4L! zL&nu!E@@=qy!5GBT1KVRg&s6AP=r3z8ta5Dw2^oL+y;>DBMiH+DfVXbN~R+^w15Bi z|6p=x^Q7b@FL?<$b+!D4I;XT`1sT1-H3RY4mT9nO}Kwh(2d>R6d8^6CK0P$NdCIz}T?;)K9&cod388 z@$kbRFN+*s@C9E0_fB{}I4uaAP7c^dKJh5M+YkNF55XR4fC8srDb4XoCAWT)lb?E?>S(8$zSg z_$wwy_5a1*zXx5GT=jwI%G~Fiud2HGA*t1Rqi(5NZwY}k0tpBk`AWvZ%r#Hr@eDRL z8pA~R`rgZ(u;bn#um{KWM40(wCT0i^0d@d3cz}@yV;Bix7)CE7BmsKA)vaeYQn$LR ztE;~6oU=1$uV=2zo%?)Wbu)jM(w3^L&dIZP{&KCAYiF)pkLORuZ`ELE=)K{Fi}W{+ z8GnnLBgBbDnP)xg*|dqh_ul(BY<_z}5e+}{Gd}~*c*Zl}6|a0Hd4WG!#;_Fbq;m!T z{r(SpfDSF*{`R-S@BQBI0T&KY{8};2{YrWTYj^8yd1d z^5KubQ=aw=c+PX52Y>0cf1xt2|NPJYJQ>FESt!r?!h6=Uo<;L%CDA#b`1r>O+i$=5 zx5+4e`*cu+&w1@@UrRL0qAYRTI411>=38!oCr$@E=P^=3bf(|5V2y&?o^%`W6Au7x zyzwF(g6VFLbkIaU`i>sY`VtR?5F5@1JQPy{J)_fj~FjkvdjjTWUr=4>d7gX=tmpD#~?Tzym0IE_~K zf#|FT#9?JRDg>XKnIi}+2fG+*Bky@QRhVq5`B0|htk&X~D{V8LYx_vKu2G(N6QYJK zKITf5?&q{*ECZon1;!Qx8{O})LF7onr2WZzN+TAyV6Q};gj{0>o=em>ZNRv1%Jq## zwIPLr=php43Xm)oPGKGME1yN}h7kcQln8U9s4&F0SR?kj1G+`;NSz zB`oC0A700h5!z=0- z@G{}+lsLMMg|6AjfQ=1QCiEaayY*$3_e3yk!RVe{-*fCL6Dp5hCTMLaGGRQ2EGgKa zs%PNabJ9)AKu&$5)=~&OuWVB-Yca$ajOSx5>#32)%rd~(vXj?P(Xo=(!17PnMGshw zpV47MTe{RzP=^HkK6K=yEZ8{h5u9bN#CIH43&$ z9-SUwr!J`E(|DfSxg_$q;<1gn@SJ9r$RkG;s0=i8H9b&t5L7Zz<_h?^goTVTtgdcS_j1l9 z(%%_!@UuGZnP+tB=U4~VuKV-s`wGG4R^b^3$mvP0zp7nQ zCC{+QJI^1SwAd88>Uzk<=o%b0qf72PL_%1|5AU&s+Ur*JqdEhH13V`UnCm>{YQxd~ z%lf>=rqOX-p3A-3u8wH5UT`)ZPj?*$?W-4fZceg}=h^W^osG=nctIvAc?>1zzhY6Z zaczg7x_(@gM{}go$tIr_o29OD2H4ZEb?1`9rcQpTnLAx<$$4J8-)lsKI{X^8Mkaz{ zTariFL$vbh?VUY6;IY}kWoItM19|{*$yI+)N440T9*7-1VD`}t-Ml;w!k4!FtUBr- z&t)#1rUz!&ygW8~z_1;V$5tl1yn)vPOZsy`_Y)5J+?B@|>ojlB(NVqklACKS-SmKq z=|CD{!SJugBxk>7DS$MT5uiDFkcBOKuqDdX=m+QX6p@s$T3q*N;S2QM@lqQ^6)3n2#RrbNcNQN|4HZ~JZE_LsXvlPl!~8j3GndYBCRdZBkE3L_Q6os5N}gw~@s@xPgVhbdanFsh3UEKvNS7ru~a zhs9R!yO#^N{_!9G5w*YeFaAY%<{i(5C*Jx5<1y0xO>cTrm1+dj`=B@0?a#W47VKaA z!sp1~LA0I>q3G$1M&-{;hVy5J!Q8c}eZh_?#G3a$W0Bd^%@-~$g%#{4(J zJ$HY?q80ErXvDqiuDd9*0#hmBArM}dFF$M;zcS%?{zPLw04Pd^X~#6e-{5uk-FMRn zU-FU{PxQHg_=bjmqzTgTgCG3B)YrZ6CwSm9efJcMs+gX+b1(FEuBrC~;(qg+-%Oa$ zD6aDmY4ME7$bb3L1C%ouqeJk*)G~Pe!E~tg+0T7(I=p$M9RMIdFon^VCLAA~c&py^ znkor-iyrM77Keu!pZ)A-DBTkt*u40~FQx+kJwlwQi^P93a{!O2*o48zV&)Hz=uElVfqOk3gIE*?YG}v z6{5p7oI{uz>`Qdu2W+s%T)Gp@l}?y?DA=Zy4KWyjfrkJ%{`1qn{YFY3UWHr&SW#fT zXhAFg))yPZQhOnYe)bDoT?A@aqsrsnMHBhZLDki$UpI~J*LMRxi=sVr42sE9nS05neMIT;wv^-gJm%AuyycV&9CgdYcg?F$`LtuS&s2Y7!f<@TbAGep zJo{IscMHzZbL%4lebwdHMx5J|Ej<^pAy!J&M>(rGzxFZZ(Z~GSoVyv z?(wj7H8?u%*;9J6IpRF!yPf3O-%uN_1rV#|)z^9jXlx^_)A-LLwiu~z+&ogj_6gg` z)OS*BNatf-+nifz9`h|R9kC|Dc0%)#uuad!&xq}u(ot$F;PZ%%d&&KcJl?a6oTvB4 zKr*m1I&z-!QF7N~AIFqeA9;R6205fl7M_!iQMyiJA!iAs<8)%MI(I}y?XA+0^1tt; zUco?47W6!$q@EnVKuaNH3C}?g?@9Cqp$fwj+(7A(o^@oOzM>4laUPT5rnDc*X z!&*{|P3QfN^Xjh{JJtBXxi&rHipPd@oOn#wk9eLV7S!@L_%)5uHS}6;?{e6FPXYc|Oq*)u`sKzaljN z)<=boh!y#=m$`!Lq0Rb8bdt<_#kx~Eu1Ov&ufEk%5Uf(80;54z8?IwQI!fje%j=e+ zL9AZE*6Gt8R@6ZdSsq0X7#&CEIXYb&DbGotO8ZV^!qxtuIuK6RBd_o?di$G>+OUp7 zJpf8qr|VH4lCDR2%_tM+C~5#@grYkT`$V@ZxV}!2WG+y2(vBhmD5`EOV*JvF@>tOY#~^jS8(b*~;q-TZ8@J zTvB;-^$eEufS1Rv9%!+t9_a8qFJP4DJdfhC^j zc`b#pqX$}^N6+)7Mg<-4i46g<;pg>go>$-WYi};Oxn^`ds~%`{)T%>QO+Bjz0jJKT zMh~>_CA0AYABa<$OyE2dP+6R>?OL7s3$?xg*eM1U&84&{xrB`HW}ib@HsA~{K~Jt2 zepTqi2@QYDi{T@5f8au^y>@bxA;UsB$*RJHvJ{^*ZLDTQ}j_;U$|NZ2xjo!p)Si~{^;xGOZ zyzT98qn!F*o{YrrnGC64nGEKC_wW8)I>)Xhfi-#U)tjFk#M;?AyCzi<@D_Qka<$3k9Kl`&2FP}Ey<3pp5eB`5a zkn^KI`u{esc-$0z==~pnOHX?$Jm;=ENv75Z=8Ecy$4z6#s1)=T$3vhOz34?Wj%VI} z2i1N+Pr#nJnnYYNwm&m-(C#&Tr!1urDJVMNbUpZZjh z34ovbxnGzL7rz4k^S}Njn)7HpdT1Ia9s;0jU~Q3GCVBtbiDp!|2L-?JFYSK>KJ^Lz^PThDPKqrR@Rnz7JLdK(U~qD#?K# z<*KJhtVk(0N5PJ61eTr<9dH5{+ODydR3L+3-&I(HZP?`L$Wc-R z@%_nR%a}3)KTG;FT4*92hk}j0^`t&Q&NI43IYc9#qSx-g>5M9D(-U^K(J0uAuGyvM z!i{TYY)N@8v?01ip{qu`g_X21wyfB2GbVJUR5#K$VV?}2xx@28QZrHA6{Vx_T{$8=TiJH(1(x4h)!_01b1c3df&l;CAxuRIt1x!2kWjD0)qtzEJ4TpH-$ zZR<98iY+V8Q6Exj9KkB`TFEDEnx=8a?B>>BH72s-dD6NLn5M_^+~!s)^IWmhL9ERC z9q9p`*PIRsWrgVo61f;{ZY9|yAZv#VL?ZkzLd|~YA&^O6?x3r%@x%H zvhhW%G>@5%AlReO8R^b45UmbL2yt0Q88+s5F(Al1M;Rh4p~8+)5j&l0(oXkhjkpk_ zl#^HT&JP;xK`}#QSg&+Fy_jRAKLg~su1~C^1}gUJ<#k2R+tS)+pt-}T?6P?hW-;Ki zLq%C%@P00ulYyp6OC_j|wJroQ|--}N69Th3i5#nUc};-!*Qxn; zw61Dwv$-UFTW92{+WbnReM9n|u4b_pMchUeAT zJD<-wm%8%k`#O#1A~ON{^KwZKn65uGmpc0MG;IDIq&lwq?(WPrKbKk^<>eJRGNFBY z=fiBz2#;$0&?y4ke39IDAy$gO!bj}BWOV{YVOj}QV9@FTzL%Rcgei%YN5jzdqy}7j zkah~e$R)gkBL~pn7!`6A&Scm^2`@25*kmg0v=PoFEJs&*KJ+CRHkf128Rlw&iHKgj zXnv)jJ;z@wo9r13Ma5x#(@A zlqq=7;f-Fzd_8EHfGnHJobZiWvD%5}#bcM#6@dg#)_@cGYw zfsELS3$Itd`qfq(*I&ioGi9BpnP zBRUpS#hLuGc>4U z%A27Ieci(Y_kS5K-k|crCxj-Ct`D3mTBIyUKZqAS!SMj+>%ac%>F{MO2Sa$_*f15; z=Rf~Bz`%ru9(oWkz+!Y>{y2_Lf9g|Iv>G>6=<$gMPI#bzJW%|Y=NDxX`K$T6F@OJu zKJ-Bu3wvB4?;o0ERWD5agM54W%fFtYIgIxcZEh_&0vzD@{I77T)>JcajWK6vZ??l#9FXzK8xDy+L12)r|)^S1&@|QtQtp z9fiC6%OxdfE>`V0S1{t`)vx{wlpag3_x|Dg;NEFYQk{d5v0RxBgC3fggU`ic)A;8p zlBNp}tFB&UtjJfC6HF(BslH}cE(ZQ`H989P<-tZ?-@cbSR(>qGybCx>G+(v;4AkIt zKRrJu7X>Ead46Lcx;r>*UiZ@mzj-ftY}sK;P%myO-42R18}@da@l_8#;)47;yZ^Fb zjEt5sk>_a;L!KJ$_`rT;9xZ4f()urG1l9c9RLDJZ7&zsBCj+X~WSQDa-sgcnCpFxe z!OGVJkm9qbd(~Jx?iy^V!bYL1VUTvk76j|aIo0tnSFn*hlNZTK3XP6Ti?A}?q#?zn zUI81H*%JtgAzQJDk+Q;uSVoSp&~znAH`MorJr0GgBj?*5gsv3fLmn-RJ?}NOiqe&h z-lX4TE-2kbF@jqjb4iuL#@tl#*suxR@u&ek?1`tI=Q_4=Bu{I^p$1jWT_1_Z4!fi$ zV`Hu!0E`@sq`APIVUXyEx$S{@m>tg*J9*=X<3*828O!KuCk%C7eZ`i@Q+s9k;wjw@ z@tq;rUz6x2qPe2j07}Y*{a6l2LuPqBsH40*iXIs3 zvzLjMu00(!%Aw+5^)*aK1+V*8rBHbWrw3%7w>-Clm654O7m)Aj6K zTeq`!qu;p8+i}4jb3I?Y=E{`;9p!W_-lFP(Nj{IVe)f(fJcsJE5F1VHm5Squwqqab zj`zK9M+Z6cT#eE4XigZ1QZp??`GWwb(T! z#m0Hv`p5#phQjCW9~!z=UbQ)Qv1O<|f_*zio23q2PsIjM(aq=%&~3*{9eS2{-jj*6 zBol#i(=X8t*J($d=LfK>yoQFZhp?>=$VAYwT`M+uUWF|sm*$bNuTPQJb;k?5qU(A+ z!)823y1Kb^nmkr>t)Xi^MGwFdHgFDR9eG@$D@C$QbhUObkIg(!_AV{yT`C>bq3dZn zs+w!99#Eby(UtZ^vDQ(|TvB6pI>7U5(NWp!sE$19^V;a8aDeAygDrP>K3t=Y>dB+F zQ!4o-dDUmRu^rM;xuXY`c&^UtmBXW4#kv&C@ZZ{ZujT5b0BQ~a$}tKIu|Cn!ywFL& z2dMMv576Y*hbAlspr2zMoTp0S%G%w$`zcwP6EyxCp+X7a*vkYsgl%ZrV~Z^==d7M# z4=y4C{Blo>%D5E?T9>9x?z!hPjDN+27C-TcPr|SK>Ki6Q;$;eN#%FJi&cla3_hlej;mPNc8(IOd&F+|x; zWv9RKcW5NnFd3!a)vFwBpa($ud-SMBBmPy1M!4mc$I+NDz0D^lqjZo$U$`m5P~7|O z`x9A!Gi|X>0~$&x4N0zL-OHnw35?|Up6~fy&~znVnT+zE{oEJe;mHtt>*F5}U%2;P zc<_Ns@UB1jeM-}VhZA@`^w1^Rz$sR66WUa_ScQ^~2-Di2S9om%4e;PY z55wagz6?4CDy8V=63!KVFJ#IvwQe=RWs&O2hC+fBeVf zUB2D!Y0Yrhumyz4HC z&cF-9>@}6p<;z##)A!sn9Z)@Jec?0jnht)x_xrvdZjxN}Dg!Tg;S1pzQy;JTrf;IC z3Y;S-Z+MV_*L&Xkhm*{I$*?OwU-O#3FdZn}UWIt#_3GEWmI^Wd^iTh^^^LSdxyQpP zJ={5Rhg+)Pz3L=Az&k`SKo)+PaY)qwHn~Fp^|pKd3tj}b+sim7=sQ30 zzyHC9D7;@kgCN7Xt1;gSTDQWp+wjk7k^dsG3pQ5nC!X1_qzUT(Hsaljh-N-JR1iwwyShHZ3U}-S}PL@{TKZ$vt1y z1W@eR(VZfILX%@%=q_|q?3A}ZxH?afqmgR5){E-|Zhh(L8o+Yb8;?~c6syT&O?Uc? z20$2GPIbv8?y!;naYa|4He5XydF^8>bsjo>hfv9*%5w&l$IJ#voolhoHI{Goc2*fs zo|DXgn`<(cT6r{{rY6U_U@JV=v535ley-(eu2pksHO#Q_yTD`9XgbnB#Slnf+IA>) zM|{14o*r0ngpZd;ud{}>CIF5tX@pv!^fxmdl}f}!>|v|q6c%G9)3bw)M+UNm_pa=`{8s>C$dLVn@4*uOPE_km&jyllyo9@H3Z;eP>ToFWlCjb3dHu8TKuCo8*&m-yb z;N5sF-+Yfsx-X8sXG86f)3)io-XpjHSBzQ*+Rf1lph^>(n|9y#Y1pB~)*5L-<9WSs zf9yT8>HpEtHN*0S_jre&C2XO2p3&JE0}o*v7O*9FbTYv|=+o7(oPqA-j0DTrV4+R# zjf>D4k9KHyxX|t%U=C|Nc|J`Z0S@pz%)RRY=JHlWx_BOkVmM!#i>K*gc-Of0*um!K%AtGVly;N1Fpr!%la6ZX>U3Vt z`QW{$>8QoN7v!~l{!9-vI_flRs|9Q=&#U>^$U2QBvu02m(POzzjQ|MlKeXt|CEQM5 za@jKpYK3g=YG{%BWDjKCaUcVyJa9VDz#bP`Af|2Cg`5>*5Mrqi=;^cO@YnVho1Gd# zVH9C=1~Frl8lD4txLNIkP{N^ncw8$Ofp-!xn+l2-Iv08`KlAoy z!HqZG0Gi{>7wo{aCRiXB4Xt?LMu|N7wLC;J3Z#d1xibE!wnbeT!ESM zn&KZ;6ih9o|H;X=80euaZg?&Mc`Bx;e%gF6goR%*J(TxO$H)*&BZG2s?|t`82Md>o z=jwfByvm#k1qpQN(q+o!f3n@V!<|4ynx8t+DC_(Pd_eYu>3}3mf1dI5r$c*<<8G3Z zM=S@jUN_!!6Wo6L9qe`J=!ORenC|A8ooC^7{{vrv&r9KHr59p*+EbqbPn+WrsAnD9{m%faa7I}oj9~g9AAlTQ2m zgy&-2XAYF-Jf(GoBhP!b(`XtS)M06=Cscn{Mb@C`etI^_tE4Y!brc!d9etD*elAt@ zUZ9p&Hd02TG2`SJ&)(7HVAJdN8e0ja_V1<9>2^;iuV1xakIfS?IvuWZaXoL~@zO<+ zZsdc_H|B@(4D&{hl%sk}b53)EZz;#R%V9lYKJIm$w>)krPx*=FfgaYD7n*W`uQnt% zRs*2QO|LZo0Ipyj=nyOg9<@*RVcve!b;rAX$y<)~3igukU30Ea-%(EMfolNlN6lF+ zSf{aIE_urZj@a;>D!J>?kiJ@#8UQGcTAzUOmJ3#tOY9qIcz%%l+S7Xs*EO1Nd%HcR z_k`5|7$tZ8uz_9P6aEd2MRI}TSR&^Jr`+{O$GEn71xc|@_nb(c{R^uj!-klQ&Ula= zfO3f!ItI%B&K|v6&Nn)>z1&tXuMVfAg;-9 zNHqW^LL#=7uBZ!6l&**^W1iwI6>G)Z_4xUC$29;L>x3=s>pc4nR(uz&1Iq;Es>eM1 zBCjVzSLS&Xc}2N8zvAe!6Tx=m=$M^+5*?AQK5sd$=cER}c7L*njX!URW*ezdfpi>P z4FHnI71PmbR79zzkhbL6O>~Ts|2<*OWtLBrby|z8O741gE|7figbjHvbs$6rP#&oU zK;m4$N1o@d1^{|$D|U1aK)Mn(%d0PXV7ljOVr&>ef!MEN4FErvCORWwHUo>L~m?YzW(l>8SO@^TFu4 zaXKnAbR5WerOc(E^$LXNcmTha&sZY`<=5y+GQrr6Gs`Q}bw%|8sFp&U>nPL%SOWlc z_S)oiOM2a7MX;M#WPm(SeGPyZrS?Z6dEG><0WiWiJwL1`tP^dvdBK-cM569A(q*6WoyPUv1vjV-)p2cq8ryTf&Pne7i`d6tO!fTt;|z{MlU z>2Mepb5`T$waZOUb1I&ayI!1Nd|rKZ`YP!#6UnakT(!K=ft|GQ9k(9pywDVlG5-t(hixBT!PTL^{cqMJ^mtC!cD=eg@=*p~9YD_uLe>pk{yiLNr2GSpEthHZi8 z*Cem|{UXneu5K=!mb>2cK%=9e!Im36VAvLPRF|%v=N)W|ItuFg8jCz{=aOO*d3>~b zz-y*^*}nHquP1}-S^T0HoLMn6-oAj_~;i8 zokNM{L@CQAo(w!myg^Ht-r9wacw@S@S2@(ddt7E?ROQ_neHcWfR2{vr94f*TLLCkj zOZW)3$r$U+Z|h?q*}u;Hujh=cIOJu65R$FH+i%98UPv8Xr|uJ zcx@_~02?>|d)llYO&hz-U>+1pbIs<;^!Zbt`V@`fcYgPG;Z1LRBi(z64BZ^=&2-w+ z0S0Y2C2E1g%e5XthVxV3<8I?kqWG(6%v{`U}C_qdz|W(GSDDU;IKf z*7Fz6!^IoUPqZusZk=l()ZTS`I4Q>5$sllitg%KPkcN) z{NNMhw3R!@abpC))8&wXa^w1xK-drF_*bwQs&G15=t*94m8U$i@d;c%A-E7XtXnd$ zN2q2_w8BrA2YRfJ7tq`D{J9OMG{|LM;TU(W{s3Y?tjeqC<`T`jq#K8#KTStL(d}p? z$uZ7C2bHHwA(>ry1gLa7UZmSo8)hqqzL<{A-5*=sF8Wcix9_F(Ft1n8VuPG#*mKr{ zW93O5g7?+UyuX5_#L{V@(RS$lNry=o%@ImoX!5F+eB1ncSq$wty$t7I=fg~p{O?KH zk?@#?g61(UjNm{G05m4VQgACjGq!{4S;d4dCa8-K*jU2`5d&K!N|vx>T$g9@Z9P^ zh`#eR075Qw8Y_8KY(*aHngAZ#K(!Pqd6agYYt>w$O%7Q7jKS3a;4~?^9;J~@@|p^^ z5QVN@9z!FqoNf>($NFGvBHe6SyI@UjQ(xpg2^R5KSGsC_jl`)AvqW5gq!h}Y=PCoT zuC3)YgXV|dx;*d4v-2%MJ#y(owqSQyR$W`@Tmk?{m5!?Dx-asGk3b(C9-jBM3uN5) z@A*O2CV~ArAVzg1sJ%b^-%QhB-|E`$dcT5&!?ITiNpgx7CF3?dr$4LxJNUfG0Ntfp zKAabtKDPZR^E1!uwvSi_cMyBlzT~&T{WgbAy@Hfx3(kX->GU0DKPfVMXesNZHH6b^ zDOA`RI#lECVQbqO+O(e9LGKA+Hij14Y<{-bTP#BN%Gsy+eSn5`h)uAB=2-!jd1iea zpsVipyY22?KaMJzMAk|@UY~}|^W2ZM!q(pC`#!+)C7C$OTxxMEU6%B~`~kt{@xg0J zMsl6IUfbeAUm?$VtY7Ow{u`E`m+9EuQH)St~fge5(&boJWLsM|eu{W~{* zM}3~yoc7S6>ykV!VQYRL8Z4oM&2D$t{BL{nJalvr?+y7*i30#QsHG2IofJStk<#ZV z3L=;M{j+;yP^lRdZyfkq3dPbzP@VS~$oPf3B3j%BPO%cCJ%jf!gwpO_(#9hwM6W|% zPR9mNLfCwpe>N@7bIA`+{ksEzb~>T~{P_5a8JeKicV-d6N2mcRS1-#@)jycO8`%qo zJpZYn8&oekyl`{ZzQ54Oi+|=<`E86Pzn8r*1;D-c-b;mb-}|2Tn4wtjhfsK(uW5qk z+1SAK8x|CrdV6E;eXf<=dC>$d;u$?srhALR$)hSk%DX-pt3QXugx~kR&e)XZxx#BN z>t^DHhDXK2A1ZuH7actKgQBM0=9+}8(*|ien82dGSVZ@a|M-tPPi^HScd>H+8V}uE zPD$F!A%reAypVU7AHD=zlOcYl8kF?}6?szW0mY{ZU%o>xH{N7skHSSBm9go#&Ye4| z@ZtSssZ#pnQuccJl z^`IH`1AaG>ag4o8C@-``s$pM*iPDuMOPzv;vmp80**NBMQX@90SHP+A1e>)d!6t5frasn8wYy~r1QHsviB>?~t!NXB(57JEl!VLUej>Xvyb z2O%C?CM;S9Vl8y`@+dqt}$>9m58tUV+h7Ql%+2lwYKq%_U8fITmbGU|4EY;2|p&f+p{JL>f8z4nLbb zs_}Pa>j{r-)WZaE7C6D&^&%4##o*|c4O`IzNwBTrN+R|4JWoXr>=M^ruv!WYT~Py3 zy@Cpx(n@vyNKHyibA+~;b9hE8_g@-&5PIjrJ zX+&BiO?k+x4^6KcqNZ*u&IEiYR3Za(nc|ltCG}*0&a(KryO>V8DpNz>%>eePm&*zud;05;ON zl|y84cr>rup%kCi_9bkVcVDno?Ps9tdI6iq-lLm3?p4@hT`R$R1ozsz*xX*)w|t9i$m3~rHEf-z2BT{zdCaXA zm14_ve)zrcVFk-`X*htb#jZS04R({qP-+6q+5u+RIGrn;ndh5MM8#=zHEbYyK;`ii zJ%BP0W4{i>AstmkgPfJ;y?HJXLrT}dwGXjVw?ybV9?(&Tuz|xioIxHH+e}AYs~&Lj z*u%a#Wv+GUnoGTcMR{!X=cA#kk4}Qqb=2Un(G~OnS{D#=8}7BP9~M&pi8+QA!t`JW z24JTGADq`M5-SuBARfRx=l?F%p)Tg#DGGI)`Z@nsvY4dsksx`Wv*gtcCFlQE6f)(! z%(8%pF7$=k#nYu>gkmqA{7v|sVsGjd^sp(@umI{yUi@N8qjS$a_mF}73!ncy{N?ZX zzr!o@t7tKOv|bf#Q5HME`2LF@`7hwz?|wILNVZ$}&hPv#c;anOgdh6bf18Z_WaDeO z9)hJeGHgoM7-xoR%$JX;X8y+C_#5z_zy9^`z+^PnLU0=GF=l?T1=+md{m*^QbLjrJ zyyY!qME=+R`hT9r_Zf;PKw2 z!c+W%-yKajRl#Ris8J!ZfA^<94L>l^O#8(`z%QD3edn{EO}XuFz4eLk+~++P{{6rI z_wfGdfZ*+Ke>+83pkaa14au|B8cB*p!hmS*Ri9nNMU2j9tt^jb2-WeJk*%F;tASGX zpuGOZZ@vls@lX6C**F1w{mWhkFM8n%;f`lL8*Y2jli{vAp9Rmk>n`}EU-~7u`|i8p zjc()zOf#{*L~gB!Q&qPcsW!UZ7vZ{FmxS@U+bbou;~VGN6`}}z`2sa=%Nt= zbZ|p7DPH=1o@!BB)f0V9kEt3k#J@QxoBoY*Jw9?pWG2mY#!P?4P^E7x`jb8TRQD4$ zr#}(x+ARpQT@6)U9%s7UHZ@H#CiDDrx<5&(ENQ3EL3%H-0Z{81L|K^m_fm_!((N95 z4_hoX0JwjS)VSU^?s~DfYRVtpykjK^Jw(D{<;-I>X70+y7C8ME-m@7>abH?^tyh#2 z7>!lD@KT<0xG2@ep}CydKofW_BbPNwk>?&46*T>b?JJ*SUGqRE!a~@@qnFa+d2Hj} zHZc@wLf*&RPS_Ny6fhk%-#Z%H>5u}`Yen*2rNW%RhE#Go7#VAgy?Fd4X+IKdR1{RA z8t}PBN37+8?{9}~pOd8ciWz#vr(ED-6jm(OE}qs$ zE2Z1sVarC>BiRUyQh0MSXtCfOrxIBex-%Vxt|Mb*gCLqw_wr602wO^EGBK(#GU{fL zv2KP{;kjT3#ReP|rt%mXc~tD^nD1pmd5-P0|lKk0jb?uA>CI*8?=~YdxT;07j)7 zwvQ^Gk$5>;`-*uk#efUXN7)}~tq#W8>VdTsSvIUad31E!NUfy3(*tw}tk?!U^wnq% zk%5#;low$ubWJ@S1?7ED#ej!_imV3qpqRc7^lr({m|+FUM=kUoDuaR6E8=Ao*SMfV zmCO;UtFNvb?9%-NFWqEatR5`xH{pznEnRaQy28T0AN8ecb6Nmp+gm&uZ2k)ROn~B{ zzWn2UdxNdT^QSTX(DpTh7Ro7DD7nYm`UXA+d*uMs+&>#4oPn-q#I}5UaTK%to5Oa9 zme<1b3R~&?Ojf=&BI2=Lx!(!@r61vJS8)(xyt1X_l&g8RS%f;+JRKJ2TKoG2J#ZSXL+xRyuT!44NY@a| z4z0gkyvMa2?y$wC#(%O@nvTry*lZ80Lyi1+a3jeU_TA=42WOG&<*twN2+hl^Ltz_A zVKVOMax9*?xXFr+81!s6VtT>ml6PNI&e+ScWh^pk#YRhyO@FHfFK~*0u;b@(EJ`nw zdIa|9oM+ymn7bB@hFb6yJ>w~@3NBEk2o|{hgQFq-jcG^z@DJZ><9Oclo;MvPJdF%m z8)*3Dt>b>&4PDW=v89}u*)ZO4!wvN8ubGV4_@{kt>L?cVHpg^3Sm5^Fd%s92j_|^T zFB-&g?9aaIxp3oTuzlWLcaq^BbGEB|uy^G<*TTIma1`9@g85KW7dRC_0nsYI&aSUx`;=IF^DdKo<)^V)yS*HCfY zr%i`HPkGXl;7`8vCAc~nUy+yK$JAg-a5MguqI|4+?) zL!9Kn1bXRPnlz68Hak@X$^^8)Ok0J-1@i9K_h066Yz$112<_W1et)-kLmy z2g_BzlKk(OE(hC>ni>G>mFV{UD28YD4&AFaC>fM8<(gkb_L>Ft@*XrrjbOuk@l)Ts z%*M50%^oah_#FkS=GP{y_<3N@RmvB+8t4Gv#PaX5JS9n!VIEYJZ(9x{rY{H^>J;+) zNugfb^Xd+nV#eQwk%K zfk?*N(ddW=0E~?e<_1pRG-l3K&oVF)eW)O_B2TvTY?enf zm@-zzj)x*-G+*(dB+4HC!Li^00_V|BCaBky9Y*fvRGqR6vR8 zi0jDxiRM_BbUAyDG}ZJtTj9AK-tM`8Fv{aT?1ZifuaBPQ@Sdx=OM&)5k)6DDW6A#>7U(*YM~A(_wj{3(TQ{$Mtm_qM zRD$KMU#+fbE~zso$zupz>^`Ee%E2BrwQOgeJ9+HYD=?miVAy(k!05I_*L;TD^(c>u zt&zv2S_-BI_RF;t;1oSzI_eaj;UI)+%8RE7&jEwV| z&htWdUnXL>!ag^hP%ZYnX3NvLZiw4FEQbw*LGrn06KG}Z2%Q}19y`Dy_BNzQ1-iwC z&p@O4-}`%i4}SJ%f0lBsYySIx`Ex%9zyG$k!C(LDe;r==%2$GVm8qfhzx~OdguCy# z2R`wMkAwF%`OfeBPWYP1zTwzwf?#;a%@~7rgehuO)#)L$+QY`p}2TvmZUc(bNCp#f$XJ@A|IqhNnLDDU|mg z4dE)_PkiDNsqijFE8KF+En;-bbm)L7dH(2+{+JFycwBiJi{!2seB`mTS;I{?-T>#0 zj%-YLJ^b(`Do{%WY$qJbqr2|9i~4%o+ulBX`rt&jPtb4PJ&g&+e%mx=j6wjR@7pHY zW8vSAef$#?S@Gm2KbefX-}61+Bi_&*c@;&0{o{C%pVTJaM9+A})8Tuk`@cpG0MwZK zp$~ij-tceUK=*L}JR&RZAyz}AJJxSd^W-3gG3A@(lZUx6TfMr=0ZJ~OfX!UP>yd{a zhA({K3vl%c7iCrh?O%BHtKt9iU;dZ$-8n3fmUuz%hBv$c-u&h_6aVmvZc&N%zUr0V zK+5MCJ@N2*JYw(I!yaN8*x4a6%w|o=)Pyg(HFge2ZpZS@efhXQ}8~pI! z`8#CX$7?%b{?%XkCAjDA&(LB+d5G;__tLK=0|d$^9*TU!H-00@{s%w!L3m&~1pCr7 zkG}RLFQMOS>VhwS`O7qb_f5Dy_OXvvVY3=Cx5Q7}fa<}4wxf=s*G4Ll0(#+GI=5Mw z2Yr@94O)QU=3e9!$Bu_~T9YCM-h_JnXd!Mxomb!VXD%U`mh->SpR2Rz{-(Y4{8!zN zVtup_Lag;(Rx5oki9tsUSCH!v;&kA>q%ZL$?39**4pj7ItQ&YeB!uhsVi~2?K#^xT zY0+>-(iwq`#B|7lx>j=6+via7ZO5o-COH2)ekA{0NrMt}Q|@xtTZlShp-m4LD-W@3 z@Cm8rB_9Q-tYu2>ddUYrvMYpQ+c|8M58kk^BvNH>zbC(F!^Sx%6B!^i&wl2EBr2p` zBBMwjV-A0v=9*7?EP2eS_@v~AkFxkSx=IZI&8tsX-A06dkB9I3OnJG9ZibC%#rd@v zJF;(Q*f^*9m?YXv=(>}+1Ed#%VGDw_U}w7OAuG#7D0CO&C8eq}8R5lz5`Cz2&4Qg0 z{Gh%Lb&aY(`QS^mUC>$!qi9aWCLZn4JpW}a5;>oIkw?i@@8uPmdI!1WSVy{1x&@d2 zy~f5hpnx_}^4a8--4K*+!MvHX(M>mCCXb=yrjO#Wjxv#r=cPtP6mR9Nk+%?7~{FfGe;?a)Kn?*2okBH^IUcR zxL0GyP|0hQ8UPGE+To>M8l@{AibGSU-AC+lBc4A|6`1k`%%hmEw~M#4j>h7)#Evp* z=HN?~70{!WwpGt=+Joz~eQpm}Ub?^c+q~@EoI@Rbf5=mtNAJGZ-^qT_`g8rv+I!bh zd+6lR2RJB~i*%Le=|V6sU{mb5>C5y@^ZeM}?|*+S*!bptyRPNol*?i1Ve`+<4r_o~ zeskydaRGa7Fdmu*z57Fpy_LtNy?yqzXr~#^TlzTp=w7F_LruFLEqz;0osnT|Rz&;8h-GuD=_OW3NuWc*z{aNzzPwnhC3 z&0GsXJmKg1@+@?%+8TMw3p%gWIUZ}~FKQjq&ZV}!b1i+Jr7_GV{-bj~Ts#0!IuH?q z2;YGsMZLMY6#h298TbXiB(I=^g)U`Gp}PA$eN6W}8Va51a>Q>4fktIagM$Wf`lToa zG=ie%^`%P>Pe$#B$@r_`qWCu&TJN8Xhg&hy4dUs7hRE~IkbSz6#P(1K0lcurlqTxU ztWyC!+7Sz4-KiJWv=GMcFI{?wy!**p91Uozl^MQScVs99k4ru@?2>W`lR@}cjQ7dz zHI&A zbh3(hm?zwL3*y&7{2694e2`#C!0W_!&=@k^h&c`*6OXu^kVn@ON~2D{}|&AU^WY7Xvn4co>J@ z;n-AOX%0+t@{va_7ezn)jlWxOj?Az@hg2BdAQ+RJvSZ&!JABT$Ngl6E@;B~F@#OAe z3wmlzUl8-xRdrwJ-32oqg=W#L1)Y^nIM12xalSy9K@0sCy}J(S{zLbfycUHD-6hW{ zy1Yb{)pIKMpH{UWyhI+*X0aL=AH(=+5kG(Fp$J7V;c6wb0cgxr5p$BcJsHF?cm19` zE%x%>kX+w;@fsm-<Ymzx z`X)o)j_buxp^Yt%B`4!N%>F;~aUeH33%SrA>4VTnB=p`V!Yt2vB&gbBXE3(T@oa1a@PCP33jX z5fodU=K~pbIlayx^{Q&R;y6dE39zCl8IMipxxTxOcN}xX9$1mEXPrx-Gne*?eM2c} zcCH_a5f0}zzqXMHADBUQwlk>rvXil|2R#IOhCrjxW14o5{%0vj}h_)IQYAIOG|Dj4p zX0;envUP~o78%4F5$EQZIJM6z4z>nFeMg5*((ZHp>Omx~o^*{={CfVc*qi=`cj?j- z^)eky4keXRn+qIi?43JMQcufW-_1=A2l7HcmYmfdTVBpxzmylcs#kCtws1Ii{j6Sr zcjgr5&KO*}R_Cw-Im4lx)d3zw?)q5L!7gI+bXT4`x@tP&)hXD_;U~}Q5rhSqSj+_; z!oghOhiWNkq)HE4kLQc>x*(5+Ev1eVZJNpJjORUhb=X#oJa%)eFUeyFr_xpH7R_?3 z19Wq&$0clVjd}G?k;gW#{-1X4`t|DcS_+Fg>J++G*klcIs*XB9*E7xYMn^5lL|aQ? zI7JW4=F)JuUO`3Irf;R2VQa>w5v^y{pTmNV+Kc|I=$7-cj_P2ecD3)}^8;Acl1zK; zLspgLYjxTWviz3>NdSy)uzN9tVrXz1`l5rQP%TG{2u+Aaj22EZ3%_gI$I(7ph?@%! zp_D^XJdOJKpj86Yh`kf_Ylp|E1S`JKTBaUF_jBUC(>|3*bpldFr%D{2BU; zhFDY@Klp<`NJdgL!0vWi_}IrjPKMyCS0Awnsz$Q_#ej`Vp_^{L8NTJ4zXd+?na`F{ zO~3ucU;HI_)0^G|PkriB;ihQ}Kk~yr4B!5`*AZSE%S&JSwd7fjQ4M%#@#8=K<3zWY zzx?GCnSj`^ZyXaI4jdm}B_r}Nk4zW(c9HqrERWSG9^p3lI&_ugkl@!$>-=(A3IGJNfo8mw3(L8neuX`8GOOFvM7}0{!C1_aw{ont6_`^T^BYFef2i(Wv_LT@V^9@6pqzW@8-?oWLh-u13`PV~iR{UQ9X|Ld*mKj4&L(ze*mAJ=9kj<)vtav$-+~f@)Y`f%k&$({>pcK7ku_JpMih-YrjTg`uU&# zdEy;LgCI7XhdAfn{q8>?ImNMFxZwtP&9{9Ay!b`WC;1^-O@Gk1|B{!y1m5?)_tAGa zR;2B({_3w%bOXxc3tsp_Du{j0Bq#VHx&8Lr;lBIsqk|MGQinwuvpZ?^+?2U`^<)R< zPIlI;bcg0e$Nvsw&>>SzC|(D+VZ~Y`*f(Byh=K=TKlM{T1;6quze150uYUEn!gHVd zJb1yR6KI1R&Ja3iy8l4vH5yRdyI@Hk+XaN`S6v{q3y4{Gv*`X_xTxuV!4_by`)A>z z8V=gLm!jYy+Ulva9aLPuR}sV9{0(#fjeeEqHUXafBreXl8aB+6J%*~TKx*tKo=@W?X2K4;GNeBk5E&M$*Cao+A;4fuqPqi&Wu5JJw~KB8A$= zOxOm+Cf>wc%Y*M9;zrWFU_1VPZHsHdJ{++pDjq;%ia#<=vNwDd<2hnyY@8N?uo|`t z4YrkGLlHw`CB4u0qZrdUz1b+Wju?Ap>|tf~GMG-&Jf7&9_Sp{i*=ttlR$=3M1VQPF z#z?_N?ErIZQ{VLdmiAIulhqYs!{?5aeq+USO@-$XBY5_lPacbrQc54ehVnoLJ*2CQ zCB#w-gz5!V*aqV{E|%AE)4`r85@3c6R#v}-u}7jiMN6d7=*oqMvHeKW4{3cNDMqdB zO6NVN^uxYDc%F%_Yx=z3i4jQYsxpD;VR9xzEz09+&^2A*Ip7?t@TGO-tIt4bb$Qdsd^>d33ibJjuZ zX|Hsp!{Ls+dTc{vd9AQjI;zkOw`t0AiVlfP8|5h`>GOJk(+?eSdn1p^b9$fSfgt_f z@jUTC6V3abzRy=gFPi6a*u!*_S_)2os*a*mUpvOeo8&wl9Arty7$;fIaOGr2(TbSj z2eIs_$TCL%Zs^crM=2L1B^9=(ouvBWgIA2d;Lq%^V#eP9QX>Ej0FmB5Tdk#_n`-x& z*4fy%e$HID7;~y|y(8HLiy?>Ctv=^JfJWdFokyPMl#(ifwd(;2za5#@lFk?S;OeUf z0OgX182?pZZ%>Oz>Re!u{H=m&ZrzcYx)4Ps4Uf`x3Ui^n6FBL;Z(Su(v$-zoEmWoMG|V%G0LZ zW1i8q;qSFzyO#EuJcim6+T>BOwKAh~DIbpRIEby0rx`ZaZjN2ofNg26=<^;8T|);u z@8!hVufe9an)Vq>WAC;%<9M_>s(topdVuKd`|j|i_xwjo*Q#$fcl4gK=&0GV8$Iw? zum#U^uLqlXzJzV|e8r~nnvy@wpJ6+*j`F;5I?AU!{?odu1Axjq)ybCqU3m<*qzd-! zOj-Kp&hDr`2RQJ9_6nT0^^l@qpP>Guc->Wpk5n&;MoF}N&pxMAO*UMFZq~fe$Fw_W z0DSN(4^BqN&(eYw4VLIBj2EVU!GC{((gZzB26Md7D2W^Mr#5g` z^n$_^KHQb7E|%?LBo~F;D0|E=P{)b{uVJ{-&n5zd7vKL>xus7 zr?G}b)hjg3r2r77n!!J4JZ8`HVXmuQQ0#b^d>uQ?-QZk~Uj^O@qV zcrMD_{~kID4=?nfI(O~}E==;Yrb1_djMzxqkAM7_>NMb=`|p2XlFLU(Ca_M#<;#zN z765F3&|heD*P0UKl}C{edy)k-$~-8>XQUUMa!$X!`Q}@w=wyr80z@d3+}R!RQ1$B)E4n zy5qqgJ_l*yL&d|vS4}y5E&p{_O5Iy4_RHT$W1JT#hq_5cT4FR0&U>WQS0=rr5flDp z*Lxv%UxvLagyluOF8m7g+2#As&HcI4m#4|$x0HKc5B4da^-IDhiVH zd-(3fcJw00>4}Hl6d`lvgmR>#Cx&`2WA6CP^n8pGI62-3a zxxukNH0+_5IMVRwJm&PDuufyglvqd`)JteQMkfuV&2~B{KAC=lbY{Bl$@s_EruWp; zH}eb<#oV>{YqkN>y;S# zMxxo#(T38J9Umv6^J?JqAc*hWgnKoO+rl z!t)%TPx3nPbw~0#7M^2XZJZk$PCJN^e!EG=ux~tAq4YP%^K)F22kFKir)5UPbVFf zFm$|!7>S@dis&ZT@Q?s? z5Xyk@e9zwX$aB1qZhifEM0B|P2$eahFL}%@-*%RR*dR_Znjb#Kx#J09&%B48 zVFS)n&e1b-?1*LO^Xdas*eH6Y$+51v>$M%%__R+7!BQnF-4xqeY!;eA&FB2j3v?xH z9l8cbSC3ukGNY?RA6lwT-LHtV(Gt%Un>r)S=<4%n=X{W^mYZI&Cyh#~bJts)2j#hQ zM4e%4c;3<#U>>QWQRyU)A(-8y$Me|AtH`6$wZ&%gs(M!sg%{}R)3-uPw-72Xal^Jm zS1*qk#qZ|Q*kZ>+;8U>mc%A_&c|3J4_2`ODeVAb)#u;|Q*3i}JJZN2#12O?i*Z?ZJ zwmM3&TkQ|w%c73**qpqo-RCr(_jJ^Z=L_?EQAa8Eo*roFnoH!A>i)H>rEpf=uR5yD z`5zj2Tn+OY6`rn@ZqIeSm!#Mq4PEz*lY;aeW6$g_ktvnaz>=kV`Kk^8yfHB)UdYfV zHFn6$q~utw!ytV4o#oYc?HT%c^>Z$HpM85bv}LICLZ55HasXWWw20Td&;Zun!G>~x z@eAqMKm5c0IT^kG`9J^XWJE=yFVSf-KtACKPkIV;4Fz>pTmmm6}AA;Av{`KVD zjk($J9>j#v7C!w8;<#}-xImA6G>-nwzxg-Wn7i4?qH`{<%5yz5dj9jD5C6yS{oX{o zH^D#t$N!iVDjt-4_OqXb&wS=H~kg=`$s?i<1|-po#f}kANj~6pYJ9^HhTQ)W(>!PGWM7M z@?WNdvcLVee~2P#H2*D=mSsbWwjhq*n8ti*I`F``r?h0l|2dMq*S+p_WcdHD{;MD3 zmrdrJe|pI9z2En}@T`f)IL?oL^rP^5lPstXefXhE@Q$~?9sbH+`70C^@y0j45kByN z4@@}mP~tKdvD=?mQQO?`lfKD71{>VKE5B(`m=fg9yw8aZ4XTHfKF_-24*1ER{7Lwo z-}xOnKtaR*```b5tHXhZVn_q5S0W%d)kk!jaT)iL{_N_0(VvQQCXb!SDzBrCy1Jk5 zZ$k&QAgbmoHf-3Q=k*FacA94$-4D4gTviBOHuACa!gc2q*X5Pn$+I|5nx{6F3PtsH z`O1#h6q7!uf{@!p`O7gEJ{pL2*p6$Efax;=84ZO~l8yf9Ik=mI@SJ7Aw zBYBzvr2^qQwf&J3UTBT7{K3AFUz{60OxU)v?wO2a*v(e@Ml6Jl4Yw&^N)=8wm*}NB zknxbx)8Kvh*|5=@&9E!Bv;)coP1q)4wb;^@y*}vq6M-JN%Bexdz=byRiD09&B-30X zY{1yiBluXcN5f9%#F)}&)LizFyyO`h(j5_DN)$g(gP8Dq`i|t) zuuXKsxk1KH<#{ghigW3h)94hsD$fVwxyq~2t)VOPd~kX|<`NYN-*)I4Dm}p1W0A*Z zo-6i(Es~c$$t%q*!Dc!r6l^B1UPn2)3O3UNij8zi(NTrxERR>W!t-3qD~IvG+V-qk_P!2f92*x`@0YHu7pT{mDF~ zC>`t*i&Iap)5l%p6p)-^YX!GlykVl#2v@Fdset*ISEbemNR(J+Z+yf}#(7*HXyhQ) z55QvVCy>#)@Bu`OXgBs%6b?D{dYQ7FzVy}ae^ zb6dLl&!KluC^hPO-pdtjq&B>@3-g4*k*KX`^mZP>j2O7`7O4pFMn@~UH5p7 zuB{Bf(r2Yvi_P)yOzjP};IKo}-a7269Q0)IEPaPl1{!%i zz;Eg|#?$AL|9wXu+xvTTgyy@MJoTROXyo;j=U4KY^Rm2lbQBzD?_%@(?dSn$upiR> z{!-oF#U4UehnT#D0H^8p%EP~rKY+fDYU%2qx1^)&``KbZo$za&0&qIrd)L7tz`)Bl zh+^iLcTj-zuhO0l{7Q{xb&h_sB6J8HpbDsXP=((bd-*dy3)8&dZ;=N0 z98G6!GJhVd@8q3nPEj z<9#oilTlJt;WKf(h)e0KIr8IBpX?zWa3g}x(oKctf^IL|be}sqKmB$`aF~umWt8t- zdIB7THy19Pr-LPpX2AY9C;T9?w3)uYfi^YRjt5XIBdb~AGrX`3$By*(pV3<_%VIvr z9KM12ypa!Hq@KfG3dlhyh1G7n@g|9WIZwaGi*w?#5gak$Gm&o0caF+nmB9t#6bt?y z$AQno`%pIad-j6B^cUE-=NZZeditpsigH5b6X|}FU}L^T@t$SXir?em7q%hIFscBb zjUJ!)+e*;`&lQ!Cz4JP0Uo1NBwcs%b?$}w_;4^R>_y=*|yuthMe&n_4Uq3(iMHA|G zarIR95`yIme=!0aeyO@=v^r|OxL_lFi*2UOGr;l!>1^1c^IjsEV$+NL0ry(@>gHW# ziF_vM4}Zt?CFnp2H}<0(MB^OS1A6?UsVw%1^ka|%uYKl2TS~RE*E9gr{|1gU!25^D zNdqX=h5R0*Fl4s&lD;JB0Xp%R+YuBMpT&8E?KYlJio4%5xFNgiXU`eu2JlA&ILjdI z=>EzX#>p$>4qXe+>DkEh%<@LqW3<#%L1ZGRJPI~V1w`#S*Rt?Da1M2kt)=UJiRWVA zGz$Tu;K`dM5i7gYq`Kt1Vq;r9mW}5 zBAW_E5x^A{_m+0i-6+R9idK+!8}K%hoe@i3?Xm#}OKnBw>sQd1f&rv5H%Bvq-y@HnK*Q%rP;rbfwTvBYd z)@$fqVLwd|q`H@kGOW@$;7-cmO{2sk#QmCXa^aY2G&Us=?0> zKYW=&if_K|It8njq z_fH1jTj1u&2(9_`bi+Fe-v^QPjqqqiMh7mQmc#?eTM{pvKX3Bw=hDNMFVo-ZHKLIk zZ2T6U%kzz{hCNX@_#kwo9IDgruO1&$njcPW!$x^sV2}|Ac_F(XeCCD8SZ(=^9X2c& zsXRj({mGZULMbq|S05px_>-UfB-R5+cQjn+LSJ->DOi;Okr~8#`N~ze|AC2@`(wB= z(E#)9qj6hhGs;|9n&-z`P7{&kC2`-E?x#)f`6J$h-ZUL>Atu!WDkHtQq+w%3zv<8Y z4}1lF|DErKSNum`4^MyEQ;jd9$RmygX@#<`;p_A=kPYYMX&xh%Rb&}i$zdMy6fu~G zn$YR06lvCt zR*wOI6PsJcD*cBVCi}nYwA$ClAvMO|Cp7R=TFW8VSgk5s{uN^kLkgid9ir6qx zuH|{b=6JpzX`#*0j$k^;=(?ZFqnB4LP>R^uD6FZIB(J`cSIP%(@|cP4%5#;+BCm;L z#;`SXrFZDQ$Ro|Qk?E%Ln#Y1|FEYdL`^@>@6B~^U8`L}poh!fxb~9`px?&nC##ZJz z(G}YT8}XbD0M*EwjmK6KKsMbxmoiytS8LYo`vx1;q!4+edL#?;9I;Vfdp5pBsr`ZN ztfKoI*REkdSEB1X@*8#H>!h1!^R%zj;=CSLYJra_WXiS$VoFH_qDwU8y}VP-mD7o~r?&6*e!)}q4PbTP{PV3nl+>faw<#VSyJDvYq*>p7Y@Tkj zv8CetS07N7Ll{4{=%1~9hvE_A>7K=2;XTkjHt&eEME6xc8~2^AhrxmUf}}rOEDq={w0e zSR4_8*&b>fXSq5N0Ht#xx?>_5@KRpaoyZ_;0Q$!Zts`ig&!~diFuFICxbVIHzSm}p zF^AU#qrKmaEmY9LVq35O+-cSEM>%!H&u9cbf8ho?*`bZXnhyYu==%%yJo7$w*y(w4 zdWXeI@v}eivhfr4SmCTD=CGoZEj13~#tL(c9&L{3d1z$6I6c3eK-DA(e1b)bYBWHj zaq{XhZ79xPIL`}zrMVhb+p%>n^#o9C)V1TM8V*C_1FVMAl^iM{CL9m;Jgi1ILNDv} z+6>ph(X@RTc)~?qZIl-s;+UR;23p+QW1d?4H$`jYl7mqd)KQCF4|34pj0XbpdmX1& z3@tX5592vN{UU7mTwnY$!+!O|m@r|k;nj)A-+2y|RG#O|hG^gontEzke@?OK^M>g; zBN@UThL|R0HEzgoit_5|yLa;1>H*DVr{7Wj;0@-noalRQPjtfrDtq~eVZVI==|?>U zRzvf8_0UAaL&;?(Hd$OMi$yRl;t?b73x5VS}pbDG5cUs*Kbr&96ZpR`QeHY!gBKK_wzb;^w-%!`Xl}&7T zvCJO-oCanjy@B*uVJelt22#>N>WM1GGxEZfLmM*Qa()N#P{;X$2D81~pUF@(ZpGk* zhU)<2wMs=-(fgCCEwX_N3#l@%M$w;a*xMzJ0$N!S)NF@yc<&DL5a&RBlg~C;q{JwX zMJmx-dBfh%lR1sjQ_$F^cFe)99xhQV-MSzQ(^&WUgmmu)u}!^lf)Dl{MvTSNS`Mh_ zUiJt^Q&<``bsBpJmxGmoykL_aXoJN3yurXvG;Pc zv>O8!&js=L%}h5m!zIeiGO*`0j!o%+bR(W|eqQ!k;sbRMY+Ph@G6bS4LPR6z$UF~R zG#GQSpiHf@c!>k+Q}!5k2l~Ww-B7UyJJNfXG&vI=#O$0rvghZa8BLncr z?QFKtc+MVtBqMkLuw{d(I&Sbjhvc#0`PAz!?TKe-_|Bq32s@>}+gEx3XJWRwB-m1t zCDvcgn$=E_-JwSY;^{!wi8R4}nRkzK&;g4FhmkPWG zk~tt5;LmobleK6&D-6<^x$Iy4x*QpRwB2mV?$ozuIRxio$z^v-B5X?qUP)EYz0R(( ze#*oXioy!w>?XODZG8`5-pZO|T_fKqO;i$(%n(XmXxT$lx#{sU=B&=_`AY51`(ATe zs~4^AE!sTg>Ocdsr_;V^%_C9rAlS^SHk7&=n^>Ib6q~k_7p?3c)N_^eA^_znS4TEl z|EptPEcvz-o3;<)BtyDP=^7StR_BF!1%i#=H!Gv7In4lYBzY{+{fgZ@r;+aXj_}w$ zHp#c`u?@;YS4+Y6(m7X-rfP3#d7g!CN+;#H^3@LcB`>3sRz&ZRCk-|nyxT_yi} zbn;&!{<7t!2Y?z|6lai@=eT!v^D?=*ja@yUbXA_`T;vs_-CLfAP)DA$*hLhbhdY~Z z8-}UcMO&*@C^c%fW)ZDYo7#KSsu`nAj2NX9zgkhVR#fdG#7>Obo7iHj6AoRr}#ssN^k)<;HLqXL8gMIC#@m|I^#9k6s^gVuI3p zzAjf8QWv!bq7B}l=mtu!W(Jz4o-+)UEd=LVk#w}YXu*ZWRi1&);J7P zG0|rj>jj>kwHJJ$elgp-)%pn{KX!Q3!lq!8K&$vj)K zKU&Xrl0tj_OB6T!SwkrXYz80Yx8a-^d8H3@@D@W%VOay8p7Us}aP2c=Sdm=bFCM{O z(ig3++N6bXrfQUK4JHF!!Y_)81u>_gE^EDTUFQ$phhrm7Z<6G?ZrmUyzU#f^X`jd1 zcN_|kY8I)p`BQ1=x=S&;=%e+7TH;W`D{drruJ*E4iL zoI4JrZ_}b1r%5hk_fh9y{yH)PkiPvX4f^jY7_nXyIiBQ}3%&OJwHVE7KlNERccBG& zC+DT-jQDG@=j4$MPCmg;>q;LgH2dqNl_il>Xuwt|fn!BrBRTZlrI~(W2iwKVxKAT&_6+0oJ;mdrAxT00pogg@U}jt9 z?5@{Wg02R+4nuRXrCR`uQ|=78%IAIVV5}Uq zvIH=Uo6d*M^I}d~3$pDP?9jURNcN_)yz&mAB(oo=stw4#1s>0-FeqA0>!0tbUM@oH zSVm7or2pC3Y*WtNdD&dbK<{-1_B1ajzZRc`*P%MbyZqU278hSG6TFcNjze_*_Zy<$ zc~K1-{cI&X>#}RA`!w>A6zM+)R%uO7Zw-40f#E_n!e4+D6`y2lbj$$Hd6rb&oIA&j z=UXWiPUa1@1S+AkCH$iV=m#q6hJm#W;f;%Hx}{x|RK{%WDjst*@Jh$Ln$B1Nl|8`M zFVIb$Ea%~=F>Mpsc>)mk4c)L=KRuTgO~2WNj%tsNWbnK{fE$jVk;wKi>k9m6b#N7* zKL5C9E{DE>+A5K_ZlHiy`zI}^fMRai5j+Snd`5DXn?X1C$~Uy%KqWiyR> z%;C<*hN=sj@-Ljf z552$6$TjBT4_qY^l}}2}nFg({Z}XkiY$il^T$pxx>HdZLvH-YG^KhH^H- zFoP3dIJCx)-meeb`MfEWClRM0>l6QV;MG@jLrg5 zjG|s&tm}8oq^1Y|HBB2i|IlrIo~&!N&o0AHyjd^YXO~aQ_X2iS#q(3fB0MRz zcB^f0g|a?DG6I{giM8#SFI(}GZ#Dl3m-talD@IN-qg%!zht3WX(#l>fk$pv>U7+B!u{7|g4ntZNZ#1yVvsI3^tH;sebz%q$tw|fc}TSH zu1(g!dLA#)7*WLM58-mG*qVQdMq|9#U5kR%W({U%ExNZBS{)k3$-E9PrFK4gu3r4; z18;8=1px$z$^P$<$GCsHcd)DM$a+Y<5ZjzaCOwhrDQOdVvtQTuq^fKp#kEJh_m9+I zK}k86u5Bcsz0E4q;Og-i17~h|{eQyQSQ(qHf9Lq0A$&#O1eXH4Pga9^B>LWv<%aSe-3qB|4k z0umlQ#MV@EaSe= zD*W7kxx58EhG1*phcd&js%xJX$;%3oRkpyJP>v9vZ3WS>v`c@iRn$_~j3ZIE^ZGwT zOTHOA7%B##6TrkKbmq_ho^TQ8Pcxqz6DLyQTqKd*;MD|MMRWXjV0wzhN}JxA-r9Tn z;I5g`At$QZZT>1slfKm>(HxU4t5nqVpvY|0R}6R)HJdjuZn~3hr8MTK_#`8U2y-d2 z+08nwKHHGVHPxuUtj*Q=PN`xsR#kZzQ@c}&?cd8kzhA`TMhtPK-b-v$EEoJH@g~pZ zAgIM+e{MA|m+Lm2tQ(OP>>2o5l2vS_;_W+djo>;phv}5{BZJX5YjcT8PC{x1EczLy z8#ZfSjk#2%BRAqOIkP#uQe#il{q$o0eleuOO=Ru$><0wn@=2X-RPJ!T&MG9ti%WWf zu*%D?Ex~mUVJuI zj``kFT7X+eG{tkm`$glCaM7}~nyA}+vhzaw&&>bWN5w!l@Z!8B-{qqPB_5t@xTqG5mSp`#bAs=y-7ee!0UJVD>n zVOXtA82y6QzmRzv^$_jR)b^Vbnc0Gl{M72W{`WYT8pCb&UBc9^sF;Mvb}@|aU6gxH z3w@3EST@MH5GawCm3}aJ8D5Rlef0~)zE{xK`&oOyH+E($ZKFXh^Vyo!okGf6dmk(C zKd^*&vAedaMU-Q4>L|`%7GyOG#-S?N6 ztSP>Z@E4R5X_yWvl&72HlS6x?X;&1)!=0}z{7o&uZJy}lx=QCBM#?DsNSlpC&{zG` zWq^VbTKqTfeaph#G>+NtIryvu0M;L(gFxd-&1pmgME(~IqBxv$jB%pR9c!gzFtF|( z)PClL8D)8+HJfe(r@3}4oniR@kf{jqVgQ#iqRf~tf z>(Cd&G-S~I1}wx2jxfAqe%eo%dzd<~lebi7?z?o|+vqQeUWtBCKCnpBWDcBeooF5nkHCt0wtDT3Z7vfLD{!Fr0Andoysi;@s(9tqB?nvD7RWof zMQB)ZvW_x1r{seAY*~3Dn}aj9jJ&tXl&q0r!{8TYF9=lEC?U2yHrkQ2wib0EiC8$0 zLM~%}*#*v`AO}`E3OJa`o6S=~qtzUku6FgSRF64Fm^XY5%ciyx`2 zNM8TCfMHy!4Ddfjls^>Ty=_g=VKnimM%s;rs)u6hx&j->)nnHcn^2arWbswjQYrpy zPM0%uE|b#z)1%7>bBq0i!Sl#P?tERc?uf6?WYPl@Bl~)t`nUY<-){bE_9r4*iJimE zD$*HUIhGkWHOQ!T52vD`dFCQS#SH?{v2?fqS+kt;hwf&+F*$!2nV`5+`zdB_du@9# z7Iv}v_EohtAfyKY20$Nt#i`jvjjEe}FvCldhWrQrRQwP>uOI_71ikDX8Rz4b$~>N5 z)QY8xr{}@wzvR<-C#nT6IqKyN`v%O&BK`C2!Nq}U3}fbwz?#~6&ABOm6-ZPTU2M{S z=fl$KrK}PU-jnE*dbwq^293aOi+qj{0_)-KKY)=n`9&3HFkKk2jjwnvJ~jS6V@S+I z5nsNPY>Fm9%J1ibp;1;E?iN9xzEhgG@P>C$jFO3F#wQ^yk>#%k4ED@_l?^Z*l$+!U z%Z}$w0Qe~tg=}*H-`F2?c7q@z(PH82C}6f9T>X}>AeQ}6jexH?6Sc3m!tJl4cZ=&a zgwd>6lrkOV%N>F2H))t}p7cd(N&FGJLHDs1BXl2Fskl_fIV`^mo#KzqbFLpYwl%lk z%mk<&eGkwU6?qr7au!7XGdz6=;+-rFta0h?0t_!zY#3=gKNDEeQT(rBzvrFy0#Ywm zfB1{`{4rp-q;i}nd%Iq4M}rS6=l#U=5<}^;6|%O2Sg$($4-{pv$8*8&c#Zp*{F=It zfU^F#g`kBmFU=U-&dg>AkIt{oeqbUI*!Mz)n#<)G+rnkq5%GFE+VBcZ^Ns?D99r1F zqu>mVe~i5otPO?-gC1M%=A?TQk$oJy@v*oG`dHiTUFhKnc)d|EhDh3+sP8jggRZq) z3s*T!K3_+bln)jd1F{H(8sOc(~ZN+$k^Fh=F;-p4Y% zz90BqoIF0{=&))ldHd$wXWWxn!)AZ+0Sghd0$07_w}R@CpBYUqc4bl>r$k|-DD8qv zRj8MF357CSj<=>SU-+sxT#-`F=9yq5BTwgPY7i>T7SU`HvstY|Yq0q=fMVj^)aOBq z`Ia$Dyw_x$aGYx#lPyvYa1>3Kt7!`}>}0sZ(S^i!+0L*FU;2 z8f@v36R{}K1;?S<`wUy^NQTLrs>wU*kN-ZMHcGn6sIJF0W8Y`1UXP#Tw5F&w5=jhZ z0w#cZ$Hs|-dE$tmte3)f&_>~v`RVD&Ly)BTl#r|f=+$}m^0DjYMM3&(PEpg_r#C@L zN$-tK&~H0nc)A5QW8QGDlzP{MdLrc;I|# zHm_v7a^{-SFV%+?ly(D*Oti|pV{;X}GmH(#k#d zO$iTM#Kko_S1pLBJu7K8GV9Ptx~!xMV@*|z%DxPyJ5xk3)L zVmsTZ>qTJ8x=^YFusW*BW*No%(K2i_OA0w2oh$msIxG!17P&-wNIggJ*i|YgT3qgB zQ)%o`1pwX2FrnzfU}#PVeb#|3CgiRpMYR&?x$O-7S7CeyC3kUwzD?KNU6*TLr8kzT z^%Fjg+yh(TbCjtw=tkp$ruWkv#Sb%VMzX$}o-;KRcfp;PN_*|Be9)n;@3A4N<&_%w z!|P*p+2H()FLuqq1*b`5;C`%FQ=13~HT7GOE|?)(J}}xqae$gdCk?w;Wzn0CKpdqb z=8h|S4vFOg&v@`YiRmZrxXLwXiI2Xy7yCScQ{vMpKrsQp zi0oI3R_!DKg)v~F286T0U)&Tg6x_&W3-+fEbWNE(w24iabP>8Dq8TE`mYlx{!ti#S zufOye<0kGm0BlvC-l%A}xPW&=@ec;$P7EiBi_-RNV@ZX1hlq)gmjcnAtI!O@ukgfJ zq*YjsmWB+_=cs-=6j+ zBU;R|xr>Fy*5c(XHnOX?&azj17;;Wo}9&aFKMBR&&!_?!6FDj0U6QCbZ zDnzX=S9+QFp~?hPMBh+^N_E9%qj)6(!h=9#{Z7}C0a!HNLW0E;bSBfs;&MPz3FyBj zwA<8~rS*}6#(Mm{Ak$%SnSn?p5&fkAJBHJ(3CmMuF&|n5;h|bCcTXjr0M4&EznDO# zD{+v@FaCZnPES2^>dA;bNAEXTxXQ!{0x{XvlCgh7LimeL)yyQDJ>r*AWV{%D5(}AX z8NLLRh*Xakh#Hy7;jb@Mejl_6CT({)pDWCLA@{r`;~2FZQS#S#*$wKU#}>hlVCHMhE(%pKt*!V*rH^lLz@F6n3ifk z>G_Q6U|DvS3#?0>dC@mlSjQ-_PxQ9*15Ot0={RiXodp}avzzU)Ml8^_IW#g`C++}@ zCQX%BOrbufKgN4tS4m_KtJC`o&bfG|uu^}blsnQDF)%fT?n9fngch_5OmFAD%5;Fm zR~;~14okoNu_fFK(e<}>Ga)rMF@imK=!9hCT1P><8W-)IuWEi^jZ8Z;XoXfH$)nmt zVH5wIi9cClD}Q*47|avqI}25t1uQ@-Q?&@sIAYW@p``SOlzn!3$v-E*l%8Yl$F@mzy71E(OQrNM11@OGO*yYz8Qpsk2?Y9{^ z&e=h}YicoiYe?$%RqWvvM+OsK^YimgWToF(=KVw7A7G7~q@3p2W*a}Im78zUt7IFM{{bXsE5m$OPkzTUT8xR$ujk}l9r58$hI@jl zO@TfPzMKu)&_iclp$3DApX{>Gbd1_^Q8rWY8CDpY77(7H0ZXVZm#fLp*in=P!o)B| zN}~Pix^~telQDzNSJYMTudI6U*xI5 z@bx@IgW)bFm$JE`ik=vS-l(586o$P#3zxGBI90Z2r=Z1Bz{HqK`YMQ|6T2`PTc&JB zpEG5*o!wJqeL!oA$MUrYTw=QvPE=27=+D9vcegQ_K(y*zH|I4Tq5vrY@O7YI(&4RG z$~Je15G8EqhX+Y&y>@G92jX43Msgem7d6vyne#8l{LT9cT(ULWf~$Nv|GxTyz7UWv zyYcashsneC42tNmRWK!vA90XXn?;VU+p9gF7^Pthr+p<4Dj-4^ZB~scyzT|BL2d&$ z92-Iw4mbQESfKyeV13B^_~rruyLqCGXFg&Kt};2JF?zAm;E>Xmb{I<+rcr<2t@Xu= zIk9>sM?a&jlb=Tki2W$VVxw#Hs4WAtY>^0cK^KJq?rGnZ+rzJu`>%4Udkh@p(69d; z4(^eH+zsvWlV?Q_qQ$BMY6kWqfI;wCtWlJnY88{U^&2O_U;c1hk`4e&lQt*{>jk@k zD=4k)8ErYB@#?cvJ#9wNk)kKD<6>g7H_z^Y>==?d{UFAf;Vy7oI!*^%##i-;ZfAQt ziyq&SPQ?AaM1CHX0@2xmH5m3=b*1s>p}CQw=a`HQ!<|@#pZZ z;}fd`+v|p4595l!vW!mis`oqJzkGLCBVl+k{4kZnippL5?Wis6#j@9hQhjmG6px?U z6IZ{&oPQ5G2jYO=>d6Ps*})&36gLsvm0T+;{Z1jWViiwV|9n_OZp6$&6QTu}M2FAl zBIsNZZ2>}*iafH2H`RbYB-&@|E~@ra)~RjOS05fpVCo$gU=8jaesm+ugXDnQ*5Cgw zM2oqiGw?rsHc#4VCvurYiDcGi-O)Rifs-8&HB=wcQ2h6S5Jc>v0hNAh(iHrWu>r_} zcD!mEb!ux|JpFsMl#WZ>wJt875n0W->9_7e09P~t*IYP@a|qY>-@st_2@n_HSi1cK zeD58s`=s6J%ikj#jIzfq=MI*RK)Y=P1+>S_c{DB}xB822X^RUY_enKy79v(AoQmj= zG;!cAgVj%qBwdmNvin7f4f9(rh(q`bi|yD`aV*i>1wUz?#YPl(cE}1h2scecDb5cmgaB?IGnv5RZh-Qbj2TT2nSAQBvnV;8d5 zU{@I=U3KHH0h#gpavZ`3nSUonUUBamqzA_%`$TDMTj;5Ui0nG5jxRShaqW^F%*78Z zp^}reI1=XC-0g9t6FE#h@rM>@x=-w&WJseJ8(^O530R;4TE>Vwg3rq}%KC~SrPa-C zkzEue4kril=8#DwTSKvuTxjH2D0Ozd;;(0~%-yP^Sh5Rx?pTk4(S&N!Ce=Q9TW*;K zss2|{BLnNnxrp9ax$}2b^JgNm;ht;I-=P7g;mdXQfrG&3d&OwruEhVCkE@_u*d^q{!9R!XR3j^u>z5} zru2FCq_b{3C29wbts&cs-cLu^XQ^pxyoHWNp9IIi{Y}M{TeE3-9=qHY=ZaV?Ows55 zuKpG+_YCudL`opj+)gNtTLewDo3{2q@DoQC?jnQhrtjMW2G26mCbdN*W=29 z#tsw?pZQn(BccN%^cMW~384MvNLzg?rr>Dx?K-7Y#^=lyVK2l4oDxR1lZQUWHki|n z+!c+A#+CgnRbqvkW52b;3!{ewl^mqe5v+Ix=iZ61rZ&oRc{yzL+aktpr*p``K)GWI z<4f4cN&OmhG_57#14V9yj6PHI8J%DAU^i#>-pVns4!d|{4PUT1K2S3r+azAXs@<>S z0k&r!!hBB8`;3-aH|2?;q67d*300aa$qC9CKi_Yyn9Xi zWv7*Smnbrh5o%KJuXCTnGsbei1<+ae0Glg)?YqQ(7Y0Z z8$B&)P_3l2LJN;L6jN@2ANvP-<7s5xQ1qRk5``&6Pv>@=_g3at(XBM{@AC~=vid*j z8HHgCShNOdZGW#`+pJOzwovWnuPKOVXDmoH(FOftZq@HjkyiY-CCbp9r}59XjP%=O zSAc2Nm?TVf@ z?K>e!b4{XVOl`v&SDsq5oJpPaIH23(sb7}a1K+~dY$m6-WFIWm2pN5Ry~0Z<#R~-1 z`%G{d$`m-VLUq`a538jzU!7}mQTqP^V{>Hh?-L-nL_+lcb3N%gyxy519Sg# zO+-Xh@cv|PBVJrjVUa%S^k?PPN)ybA4`kEWh)~LddxJo7I8Hha4E@Qh!~>>FmFQ4| zy*22&QJD>D8v~XTDBJN_L(QxvcB<(p(?3=BCd$|YDGc=GerbuzzmErXRFOGXL{*7n z%B^8@BV$wCPt=OA_Z{Lk7p(qK;677)Kx77q;j{Vczl|2%F$ySb<<8OcE!2?&*#my) zHuAzMD1CF=WmvbB?$U}yY%{TW)l--)`C!bhMaZ;Pmu0m1pn$zcu5|`V-;U@CcK!~s zu`KM%Md4SQjF8(~s8FFMAC6C2rP;JIFEx5W8w}qz?5aGvGq0ha}UcZ*q zsL$O>-7nku-QUV;w4RAR$EqB=;X>ac-WyGFzQazH2|U}MZw$H=%wV9%HdVK*z(khzl@6+pJNDXow~%rWokWE8IWb0ATKzU=$;lWkJnl|}8fJl` zywuG*iVsjdvWH@HKN9rddO+@TW?O5YjinE+Se{Qb9Ng@)*xqPFL0>utsPlv$4TfKv z4198+?Vwkr#c)8mhHM_LjWgndt!^bByb~cFvtR1Ws@nwz@iZ!EZ%&^q z4s_p_ZRwq}VLw>PQUtpLd0@MoMms{;Iu!-)%L~}iF3&0ofDNiaJa5Vq+0SbL*^_?7 zFB|~VQBJfSc6XQ?kSBH?d!B(yM=Ls0jWb469hFYlf$#|mb)UagvvaPk3Nj?&0+95P zgc%a75nVW6Q{XS)^1obCjIT&jmN}0GNs4kM{~Xu8F{p=ZsB2= z8tzwZ!Kl5e1S01$!5bgq#gH$G?elCeR%4>fYrY8w!XF2O3dsly@1sVIUt>5@9?&@m zRQda?+G6u)WVeSrVTh$mcHt^5rPmOt?6?x?;mu>DeRjR;FQ{mCIP@^cp1f7r9Cm>0 zU$392PwQi|wO0Ba_7HP*F#C=2b~X+bM#yWsv4QKfJRt3wnItoLFp1%J^LXrhyr{@$ zE0XE9tfQH+zQc5b=j*Fh$4EcDv%7e?D*%Un+oOuVrDdXdU+F!jBLm=EWr*(n{i;`4 zi8TrO8thIYb=SDVXqip#i#|atV^LrWxXq30+T9{i0Djt5(8I z_8+~l!zv`NOP%7U35TU$K4*{H)`?en$b!Y#*qprxwr4x7#vyWp#uBfQpZ&nLwkz=* zcKGZOlWG_PN7GFVIeIQXZ>Jg*6F%p_4Wcu@>`j>7t~Pu(DH>F6x6p#_!MPp#uP^JsYc1c+PYGHO z19r+3YE<b1xaMD(C*HCX)QAKe@a9Jm7DO9xoXgGhf>;n@_I5cVrkS`z%pHd&|g2 zrj>+b`PtsWnNq>>e++g+v!wdC%)_swtL2_CyxHi{E~?BpR#~P2hhCY`ydiddFS;%J ziQf*8pCvlaCpmSniP0{fW8YEA2Y%JGyyccF@ulb+_+`ApJi^nnmDS>@eYfr{u{Dl; zs{j1UNJXs>btjVrz&i{tK)LjrrP(W<@5e|tt4V{fJXT97G}&E=vq6augyGa*x2I~}3>X)WFl4UCXqE!DkaWZW~EfIMQ|9Cu=P3g~80 z&Gd{-I4^Qf)SFL3*k*pc(VKh466k$zbK--W_zpXA=p_1Z=>PiBU7i;i^q3QruBiRc zAU*K^=r+2;-C6t_)d=2xI+3R@k6BLA|K^;)Jbew}MYnj1{2)-c>kxi$9I~+11 zW?aYeDE-2w>f%~PIlJ8-mK1w`7Nv4ID%xr-COiszRxA=(W%K_46$eu3ZtkX!ExX;2 zq@&C~?TnzeDJn-B8!VsVvsi!JGLqo05#MgI{ds&Rd8M4yP^fk9*1h+S&329|k66<` zeWTZ%L1cUR{xq!swIh&oTUKFtTSP3q*R0mP2O316h-3>CL)c~+9F*=7ptan~mgTc| zItjh%G?xOQFK@G^^8rN;491tL^H&w%^Y}MMedOjb-tfZ?B_K++fMW_0#kPdcIdtt# zkI0Gt+&M<)p6@AE)p5P!V4d7&srVm|^30o6Up(yRa|JmpsSEhA;-l!wd_`q_0ebtP zkf3c{#ZZvs>ojWoZTs(L_-!P)JgUz1B@FkMWS}DR z&DFnZoVbVpZY2U$h*Kf`j5FdMhKnekT-CdKO%rok!fr$FFci|qOPoei5mBYPLMI4+ zH23TAJj%_d7jqeVNGQDVC|aE%>FzGER9lWHx;o*I-dNAi1DMk zPCLMvhNY3x2i|=+3pB4l{YSWy%^hCZB+Sc1XIo89>s4v4y6K{?FdZ}3T3cZY@ctpv z_=i)>MlL_!`fxFuJjPr0Z>#JixpmbMVCnjWYVglJ5!UU$P@=5t@adL+ju@#Gh;DT8 z%d8tl*sFnP3-gWsPHGL621=osGKIkWieBvb$)D*7bL|e|u*;S?8`2jU@24}Ciy)fQ zK)LF-2MDX=n~Hv1)8G^tx_GPP(h7{0 zi=hjveK9w&Z>fJkCHU()-~L5<>W4jdP)O3C-6Hm!J|X2wjIGQpy48Mx|Mg}Rz0$J= zWJg18^}{!rh;h!4Q{`jl&S;>yYYwuL!q*SY9oDRlzU5RBP*Y)8^&0y?aUyq;+~bO6 zQaYB5eL_HMSJfL9?WHA|EOAdN%kA;P0NEL{ zU#O1);coj5o%Ijl=g1u!JeJ0GJl{?1@nd^~+o; zHV!=PTgPaxES;PnZ+?hZU?M~(*#j{_2Fx&EFu00_w)s?Zc@F+8^ND3)QZg7}&cs2! zdP{!9Hx-cirho3>L{2R$moZFgp3}c8-MAN408zVURaDpwTx63iURd4{%F&6!#gB}O z9f_F=?tMf~kVSL(O?~o`21VgC4q4jbvm!lTj5D$i z^zAI%>yb_4oPIWF_@L|;cd4%S&G~)xf?s}$4=bP%s5Z7>f7D)f%UHTo=(ghm)MvcC zBxKMc#KBvm$4nPl%H=SBMxkVmikj^fcXy zCWxj4zw=h5%lk(b2`!M)9Rp}i(I~Qh!WOO#NI(pNJtVLMVMaItV68gqFYZ9 z9tFFQ_y){j=Fcot&thYYUk~)0!0yrTxzX-QDIp|mJYJD(P=ouN*Sxf5hV!NK5uPk@*8)qE+l8b*1V_+4XZ z#)hNNL_b8H1F%FdFnRIxzHlfn_R-Pvy+h@Ymmk(`3RIjU?fD{^Pe^yN%Ckr+^mW9d zzHE^sMxO3{5Ct+A>EwUu6FPXNo=iP;Cek4wKMA9<7Cxg%l4z3cwE|4m&M-b7{)xc4 zAuL-XKEhvO2kdz))MqqooMo%&RX`%HLU%@hn2G{7Z#K-k0>xx_=1wWIld8f)TP4|z z3vH-4q{vkfdPek2KCK8#LMQmX5n6*HQ=D7_$O@3pkvS$sE+aD@ipXe%VETTvOsG7(j z^K)tX#X`X{((rY={0@805t2AbmHg}f{CX&6m%KI5R0%4dLi;Evh9$TqHEGD7w1)qD zk+tpn{}uM#U&nIl*5!OlhFb>d5HT-!_{RcR9Yx&X%a)kS!@t7sdA z_K<_ZL@BGjkE52|R24Cz<6$iNT7Fo=Ai<|BhKk3pjYPut1fLx3oO`#zSk(&EWgn~+ zl|5r(JT~(%{6ogGpz)E3Gws}x5ZoeaIOO~a(EYf0YLcyI;#KdMLCdR9^^ZJQX6qyz zxe&Sf__jJFmpFNpqj^CN;8P$7?aJZ!xv-*|^y{%w$$eYTkh@E&5a1^|8?HudN%<%; z7Ezub2vOV@R`duths4pzeqfy?Bu{mypV%Herq3QKm~nhu=JfDBoN@7p5%9?^VY)NkUH{BY08CDOqgY(uvI#ef}${wN?j1 zK#}eFv5K58Rn?@kBH`&%FN%&36mn^aXeFdRtNORbN)z&Dr&k=etlY{%Gj6Z zgxkuK0b^v5TlPe;InO{I)|cZ(9c-4(qpU=wq&Cj6X27!^@j3oz-csnX1<{hZa9FK& zo;>qTgCn@?0Uc_@{eU=yF&(C2_783F2V_)x1`BCdbqeIodgFI3T3HvZKGAG|qr`Ao zh>1g6vk*AgBfuhtA1!RVI7G2g2HvlHuTdl z%64Ec8PHDX*y$oiLoas!UnBbtFgj1z`lcTa@Z>>iqZ>r)E2eX-%}t z>Whw<`ynX%!EX>cmD$17C)TM_c3q!*Hv?8}Wvm0IcUGIK zEC4i5x+uJNnSHLJH#ZAN_3(NS25Lk?9%~A&5crHq>F(cLHcrO4#0Z16w?iK~$HkPn zNU5JgBSM^DdMEif$qz&Px6iPdB-^cd-_iqm*nZ%ctxR*GJXna~h16dHzu|xKlgTa` zb=f5JBF9S&rld{#i&>TQYJi&jpMfu#J;j5<6;H-vK5o1iLT9J1QKK`SJ6`zZU9GrS z$yTTM%S@CECRPVCUU?_^mIevMES_BQM^S5Ari z4qa!Tsn!CV$S!?h7h}$5Z=Y(?>6LQF&^NQMSBFYqAs|bEcAjVtkZMRnfYiG0yRV!a zpjfV-3)F`yV>0N?KXDzohhbrM#w&hsCDev#f)%b1wc~! z`44Ow;W#0wbqgZf!5q|d&i07cX`%nlz*M`s&VH~+wC{SEy+&VeC8veu%7i!mKYW&s zSkL$XINe_+R#;X^xqSt$ndrBP8suC4>4*LMJhi32WF;pMY6>!-x3hwh3&NgJc(8(Q zoUHMK2=%)xGVZg{JfKO>VhKr6@jzgM>p8KN4Dx;m>r zhwKv1@v4d$Mv@>nE|NHa=meTWbqzp_k6`rHMU={%SL|Gyn`}T^HHN_bbUALMoWhS> zT;+{4)E_&nDG|E&OU+1W6_=Hg$&x)w)(g%s|2ci|NP-rU@Z(K3l=Ia&jvN#@mb-Od zfu%o=`d@KfarJMzh|AU}r`kH@Rr;EuTt9Qcj%w#k1t3`V(Zg;z-J=4cB z9z|{qQ3u0X2RXQ;%~QIzUhmN~7!WIL^N1K)9;_p!^}b^yyEUTKyLPKCF%)g|diV|{ z^09wsdI+l%?;K0;JcnMVX z)P`xTe+K%hgmBuFgWHTTD%r<*rRZU>#-nTBu*+C`nN5{m_-h@r(QK+J~q*6mBfS4qq zJZmStmLJ`o&(t9nvr9%#CLyUCOaw^zsq(_|^ffJ*df}YN4Ej_VV~Y%|`VxzSvT?*x z1+l`%)P-*SghyPX;1Vo*H7@O*sTVN7zyqrwzrIuU^Es9l%Rk}gd!3#o|eWN4C`;%PU4Kg}$jGa_dWtndo1D38QZI2<2D)0HaeD9&d_r$sx*#^2fB zL1!44p9*&%vtCQ>8&vZXl+8fSIfF#7b2Hywp}6d+4Kw=x{h_;Lju^29DsM5~Ak}T% zbB+Ak|DRt;Hj=WH9Q(VJn0;ytx9&qHyX_B(oxbXBygh^h$T`j`fvo$da3l2FcM}%K znCc0cpiJV0?Id*2CGgiJWd)@WH?CB&j)(DT7_hH0+nS>Bm*d3yd&|2O8Gk&FKSVDg zVQ0R-+@7O0!@T;8%;6qr+@WANLS!`9u9~67#WPSGYo;wIQ6=-~>unkNf_pYF4kAI}$fS(G0!kst;3N#+)QQbom%A8GLB{;Z))Gn; z@p~-wi4orm%<9@~B_s~M2C(|29xv{YYMA?C z&m+W!AtusXGF|lc(J#`eWi+9g_I;lXd8v~|A6V3^ybW}Yix!qmnY<+N({)x|v70S_ zmvkQbrLUC@I@JY(@svh~zk$(>>4Tbr*|PeWDPttDWV5L?aN1 z491!(%6u>0d|YWZaXyBK7)DfA{4>!I+a)c^j!aW47S5y^J){^}v>qe7Sy6R`PvX?W z2-`mhB#CvRgpZOYTgEJQ^>qfBPi*pMX8QyM8~Tzr$$nq1kI!+V)xzsLn`n5qP8Eoq z?DRO+)xRjdr!*&yYQ}w~0e7u5YwkWBa4n9{NiO@HFdQ zT!Q(yD0Z{3)cZxanCI>-_l#g#*&C(pTITFJ!Azmm)DmH4<_C2D`b!*iit3`_b!G=7 z{u8DS)`gyv2&a?Iib1RSl;6^UXw3F}|EI3#SziG-2Dvk2Ls!t|5pdZ5%B{K)A_JN? zkMnvdfUpE)U+MSEjMeKj^27Iza)Aw@=SXIZdm5%iS#G7Vo;yk7Zsxdev1h(#+<`7J zUs-mPxnT$o&;uR~r}-n!Htx}nO*`$46tQFvcHhY!cr`MqAp(=)lIv18noXP4kbu<# z+%}&=PL*L2I^Z2$G&lWTY03crfDVb0E!HLcDSgu(HY3i00o8P%*e}Aj7g4mnM`Vht z8Rd)LPRaS@T9HeGmEJIKEr&Q4FF_4sdADeMi1n$uWg+3R*nduQ`&v)2HMXqvFndLx z0QLZiH1rVYW!b^P+16q#Kb*+evd_GfH{R($Jgcv6cHTpz@_aRBv5sT{|0VKkXT`H{ z=!F$rMd%7GF--U+>MbbAZuj4oIP2ua1Y>pKrytnN*|J~JJ=O=q$InFZ>^)vT1sS!? zdx}G?kFB83hopvO|3}evxU>0oVVhD^t+q;xT1B;#S_xgWR%?{nvnWCBk=RAmY;9`S zUNI6 zZqQNE7?X=X{dJQQm>gro+NdIRKd)El2(#bXV?+o;pHZb|%I>tf<&Eyw*Ev9CGn++t ziy`U33l!1bx8B}R3(u;-&Xp@|gz}Mv@Qx}}o<-Nl57ns12db@wU%jMObbIsL60%*) z3tib`aF!6g!=6^>|15k*$A|CtZ*JO=NbzuZm7P}0!0vCQKY6&k#xOiECzfKoUJV~* zRy3CNtjB0gtmmn06a_DZ%Fg14UsmHxdw^%xFlRUaoAN=QxvTiMt^5nnstikC#~SMU z?X~%|tj3V!DElgpKLg*&9W@1N8f@gf^$Zim2UO%mn5kAoOjiupJ&2y$GXb8pIg0YC z#6;JS3-9MLUS(|2ycHTrgw_*2roa*s?6$A=Zo0lysZPsknb8tQal$ZC^T{*pXAMX} z@|$T&0mB5pXxQyJCG2D2?VEENuL}@tiF0jc7$FCVQ}Ov8^(TvpuGo8TP6RD};}jhC zDM;Q8D){ftBX*r6xI({(qioi0YeA*$IO*=d{3mte=(fRe>b+lo9zRIHTUwII%RiC4 z=`g_JNgR2;&SuT_NanZgzTzJ{`m@VNw);VTb;8^q1^3o*N8zr*`zm?rm;~*rH`#dl zWlpQF+2j78>#<4|D*=f$H#BDop6@A)=aq@_#q;f)8o;b1MtA?2GCCF!OzO&2oEz1( zFu<2>_RSvy-AyL6M|?lcpwb^Re?v8qbWA06@Sm0bc0}`)7=B&*QoHn95Pdo4Hzkov zqPB2U7r$GfIN>v`F(44z!Gsoh;j3xP{r8xMF~}qK86dZ`3tpI+r1guP&th^brZkB7 z*<_ERM}#PL^DDCwR_sm1)_p2f+{_2hM7M7pOejOkIPrJ1-4iW_Z?u63Nvsbz%iXM& zG5gk#H`RTs?*KE;zd~doG{$E~^^Od37CgV$@+=@mziv01ALjhD=*ZOehKc)jbA8xL zV3tn|@>bDE;5Z5WPj&?=U*<@Ebt zT@jA#Qsr?uPVnME=n$;Ct=lgy!TS?k^VI%J)2-h5+mMx&>q~; z`ses|tRj&ezciwT%=&gs1K;d`CVlo&T)IfX-}Q>9Rd9biA3a*ClB+i*XmA$DzRtQD zg>OAaBZbv!EoCMF1y$tMRS9d%aJd^w>}PHHCB=SjY6aEEZIh{`sc3{w7v^{w9TMq%X~K{ z`$QtfJb9C}Wv|YTIewxkB70G%v6uF%Et9yOSu+qvk#V`?rEufR5OlKb@zO+(_95gX ziETHsrIY%T0>~KL)~0D?3mG!CiWqMwp7S2b_?`YUr@~xot zCvL^1(vJcl?4vWJAuiviBd+?QhC7u9CpqXU2k0Ih1$}P#`=V3?BRr70(t~xc@Je&( zLIn@pTuVnKKNd2Fx%p-0had{8&oj%75C2oSn(YZ`d5|@2m9cMij(!)e z&jZpL=ET|+091G9v4ZB4rlESh*jM~XNRx8?IK$QO=^l}SoDcpjAFb?S|ANL7TX&=G zomxiU5Elro^?GuW4fnYCaTAY_*Ii!V9vXavfq4jV<-?Sx{J!0sE_|C`60jE7Fo%pr zbBljSqG|Z|j8d=2`Y%;#zc2aA<;6eCd3N>PG}PSbQ?pUz?+mc|Lf9fl__j76B9Ins zM1_#-7h~oDK=K9H!1<>SFTphFf<#?LtV^ABiA@XrW`;{uS;MYV3q6uETlv-7EssQL z^r~_Q9WrcB)LN@(_PH|EEJn>@oc1tO=k#n5_d90RjuS z$Hh_``95M`TVFGJ!Hlaj)uLbAMBw<}bqS91%Iyg_?MoAdR|071 zI`+-auQ;B)27p+YD0T%I%03KMiK$0;#^5CWz-XV*MZ5BFS^iQ$S8s+*O}MLm{V^rX zjEisvdRj*NdOQ}Xx;X=MNxM@Dw-%zo;;>PU^v3?+BM4^3M!7GC_Y=CuaRm09WjH2tc5~V#g%Ikh*s@3LkBI7xz+_|8Y^n9}+=qRGIZ2O>(9RCo0_piOF%JbhR9>~?r8TSH?*e76>s%g2Nh{ob;* zgu;}#e_w}C_r$7h*Q01#5!a3Fm!?8FbF^e)B;cW+xB2r!-_;ebLEuX>&w_5lY@qoa z8aa1o_{VB$v77oYW!+?9?B@-^e_mF@l)I<4&9^{mt}Or=l$F`4_SfyRxbEJ6qtE(| z5&YcCj6m8t{~pZ_!3S16O3^ZmG>AD*{lycdW z;fM}#ztXshz0Md@4&UyWf1&rs`Lf#Av%Ax=lPU*C`_5&{PA*i8*uU%?5&J_7TdB`j z!OD1hddm2q&Hn36U9Y{l5}-V zC~`#isx+)4%#+t&xt2_ORp*cY7Y?6>Onqg7#Z<`}=$~@0wPu+o9~B!q?@$K@6C_Sw z+_p>9SLS_QlUo88lCNAkk&p$w8?bNj4HeV%NBhp?afMpF2LjE?r@`A0hrw=?)!%Fv z;&<~3;e?+wAz$mfZh4i<9!Z*2xR%=7bs;pAL&yKjUx~*R6i|me(Vn@jeEulY?O#%X z#nBnBRvF`2bad>*&;NQ(659h1WskKk{Xnm7-wE(o>1FYoh&67;e$>C_j*X zLH=9Q5)`ye=RB73OAW#G#|Z4AL?@@Q8FPxxyBDAX+hwcUy{)&!a31zV)u3n@OOM<; z$uRK72K@cWK~^JLRvK_+^#rb|U}@$*@TJ@{13U8E@eYR5hC&w40d=lMwfwfv7vFl1 z9I?zE3R`PY;+(P8?CCcQx4qp|E$~LY0?~ERgS<*PSQ>9sB9oDQN^l|xHP+Bv08Z1m?REk%!iU8U@Wdz+%I1|Up-n{1!Z2d?z^p`N21suB$WxY@# z$%O-8=qKJR;G)EEAm3(c?UOZ?0p3H?AbeO*+UH(ahWtMDZ;ez+95d+-)NlZ4Hp@%Y z<0|2HU8pL12v!^^{q@sT(2Ai8t0W>UXvtQT=yOYY;y4_-uke=QDdpRG2P^J=>*I^W zJit}(4t+ds`=J``kwAUDoif0~cA#C(&2&e_Oj!cBlhW&J@6|(6MFF%y1Rg3To%>DOxvl(8BiHyyRz?Woq25D+lT}u$%Linb2@zvAHsMbfp3-vx*)L zzyT%%5U(4n4yr4a(f@v+n9U?4|JW&mT{Ep?vkpG)?1?Em-srvm_^kR<^WHQ&i-Y@B8Zi35xD7TX;4HKILh>$FdF$uY zq`hQ5?>6F4&V+biaf{4H)j7-SIoRR zpe`~Wg&LObPlPWUfX~HR#jXF*|D=mNquitUesg{yr!4_H%ST`{3kN9F^;Rk03%-o( zrG9aBFkZr;Ru46L(F^8;ry*`>wX%Qkx)P6l4DWwew-psM`Qf_B8X6K+w>jg-_umOr zc$#u2@A8uUVo4RcL6!f9>Hf*7<8@yj;ydCS)k@2&V|=?QMc{6?(fL^}>zXFlun(uE zbLe>s05tf3-Rd#C&ZOQtM!NMc198sh1GGDhK!Pl@TNMT z$TPuYOfqMbZ@_>0xd?X~fuerA97$ZBcEM)T z6T_rDi}FT;CQs%W6%+C8-wChaGUJNMuSkME{_=_;?uPHSZO>FS@oYE=WCC^s{Ev4t zrmV=hAZ8X+xNqfB8yw66U!MPc!f(u>0qSIt9L?3SZI)g>tw~f$CR{(0MP6|!(UY-g zVk+Rc42W7PI&QW!`bxOmMm62QeDVKXdU-HzW&hj8Li%TM#p9BqBh1gp#JkCND2T-| zA==R%?F(zH?Pp=Z=jWM%ZIKM0hiT!D^^>CF4<$Yol0B#F$t~753DSd3Q zgx29`I%EQ2x`Nd5N`Dzeoil|}Tu}v2A6s`Grl&}G{k&U8+o?YCAg&)*{-M`~mVPvR zzewA_Nn_QpyWuuv`QV(0tryFoSkpE6`u3b*&*j&015;NdL%?-{+r(d@Iy*v$&y|?T$K*F zVQO;%OWfGp9de*kRr`C+2ARk-x1utsuH}Wr2Z;-q)l7GZBQk*rSasD;u-*>Vl%B*) zFRQbnZ5Mwe-vxTevPf4May>|D1KL08QW8h%8yzsa6LNYI>n1z2w0yB7{kJ`{ljAG8 z{kX-}1eq9;2fBE5HK;1VN%bNn{s_4*QeLh}9n$93f2PgUJd*#4!D*`WlRI_CFyFy- z1^s4jHl*x1rjt%Ngx<{M2ojqk4_<4BKi#iY2M@=N)=fU;3TQo&06&NDNb_z3yX6N` z6O?>5W59O(mwxn}ht*x&?FWuVFCbhB__68U336m~S>^z~Fr(3}<>Sc%8xG=- zk#GzuCc81of6MD5;?60oc96h-?5f=37w1r+YRVnyL|U>&qLE}z`E-vWaeBo>%HS@v zCA#QyorPb9Id~R5XsBu_d$HwJa^=KC5%_C_4VZr?7tWJ7JsW+M98F$)ac-s$c@WyXFy`YCaesMGIr_majX4b9@4E>H8IJ zX4}M)jw(hvwQCqoA2^a)U8Evku0EVzS;OY8{Ybp+ccHPVhsyIJV5sHqc}Oi-*9t{q zhWHkKpEMnZ^;zVB|AyxF$(@$fNCUqSnq~;(1c#qWqbM1hf~TiMc?0BU82pOmYPNqy$~Jt;E*375(7;+`aBHJo6mcx{o2HDQp2)+ z9>%^u3DrkwEta?o>DkwR`FGt6n>l0SG8- zFK2xUE@r{;MzO&PE-de`u27n#REF_35f+Nfk-U}uC7sI48`y-qgcLzil#c(vib=Ml zQy15^6mGXtxe$jP;e9CFRGaOi(CZ-c|MF?Ju9z7sX5Goug`>|I=Wn9+-B5*0( z5-o@R(GR74JfQX^$|q`D-Xn~qFOt)RS1uv5)$TFoVN!iQ(K-~$dYJS(e!!DwwlZgc zfJ1o3`%d2mZV!CXGu6BkO6<~>(srE&WTI+dm3|`=STdHr87!OaL{j*4nP;7S8aA=N z0e~7#5d$oAQt!Z!<}M9KV;FNcQ4r%r>x>s>@$5J1CFIBPXf+AMh~hK(abmYU(|#c& zfKA>k9nhLkH{yQbUywSUC9CFc+|9!rO7AYyhh8Xoh7l_ zJk5mKSm+x9XVNE2CV8CrvA8w+gB|c)!kIduyP1$_b%xU7s@~t=PR1>r$oJM5K0VJQ z8q7@R$s`8+=GFK|etn}Gn^8J2ExLLevlKgv(=`DZe=pO(x83s8x-fxXm7#Y*j9>ddew&l8O|= z++7~P7N=3|r*0MZr-~NYx1RJn8!`CGokWa0&!JD3@MeMNEMF6C!MW7#cW=J)$?d*8 zu{6~Z7Ucm?0Zv3?4dcr`-zd@lPHyo{%W}@Aua1VWNbhAJBUwh#t#_aaF>+ z{?>PBtAr;WA~?;E1iyw}$rk!9kSo2p3}pHD!)8KT+B4mR_;xWLzA_K$Se^G$v(ltJ zi$$TXtk}l9=Xlt)iBSfS^KZYM)k8V1le=|D^M+}f$gKNCfaV&V8eWnG?Da()GpG-? ztu%Ga0X3Y~D$^_Q;p@`)aCp)Bur)9!-j?LA2lxO7rZLf9_f^cJUd^j9t_!RGm=jG9 z?B?LxPH3^8l*Oywj*pt4>2uB-*li#1V+47j!xpyVs+~N5*S@%#QitZrGD$n^q6JlH z&O;L@XJ&O8Ug|wpV+!j<$8R>KKCvgIvhh~FJ8ddrF7pn~ll(aLGuc#KB3v(kVewd{ zuO}SppXM}0c{z9dHyv#;N>2q}tg)ioI_=9&3{4z~0AFWQsKl{MAzYSaJgcZ7yb6`{ zci3rApL@EF5$VunMn7<|xAJrYt*PREN?v@TFd$$c^76xCNg{FNM72W%+hL(<&(#}9 z^A8urZ?Rm%owF+Bn$X9I6~RXCt2V~!YArFgo1Mv&8>1KK5yf^C`7Fvf>&9!=?8s<} zdoUk32in4&i8egQ^~Y7dtP*x<>5f%g%REk02|#?u#X{u=%$;0uCiVH~9iP&JBg~6N zw2~^x&Ra2|I;)2ci4QP0pl?dN7IgSvPx1eMEf!o%TY}P&zZFblTkC9o+Af8#Mla~w zm-9tQbrG%#g*OdhMF{lb`Ce(!X9J>5#8I7ie%208XFz6aL$J%-h8`H=5HBFn*@T=iuVI zeoy+awWVxT78f0l&!JaqToexE4LyCb!ElYV=3M$VGG)fY=uAt&#pd2+Z$zaFA2RcM zla^kIwY}+E^-;VBcN3mJuA8&Szm}vgeHyKHksm=V&hUY3xz($lP~AiM0&L~&GqEjI zIi`eON?(^_#kMw7INL(%Q)}6HXp!*LN3J3FF+X?^fBa8w^tG>|W8`dQk<>hZY76G_ zWQnE*p+`vAh_q6Dj_p#vT2~sCJm^ZsdNf$NGp&I&;k?*IzC+axA_F$enx#48Z~Ahv zk(WK2XXD~2Y$6axs=#Wy`4aE0aCz%Sj1&W{?c&YJWefI?;IRYtIL{hzdb57COTKv*(2HdE)}&!pZl&v|g7JtfFP7BAjE<(=xU$o_W1b=jZGlwGFns?0et*@nzFN}m|FHk|Xm!p{1v0Dl=0vP+)x0ByhJ>6xKT&m-P$9!_NYg+o5 z<@FkHc7-#`S>M~!?eP=OE=|DvkxFl_QP%wQxf?os8lREA{+1|bk`^MD&7f3UK5aG3 zr7}35&LIEPH4X!N2dC=G^!B(nh@FO&3oifaK7F)&e>E3;bKeO!?C^cvkn5+N)guUv zFD4)g@XB?ckIQ0?@7<+lz{{s@CZ}OoLpP?wI4hVv5f2#)s2*m$H?H_}E2Ua`h0m;T zhmXHWgV7ET1~I~Ivl9Oh`Vt}v<#8f^ooly>W~J>h0WzE7l_M4F;>Vh^rQ zJ~NvvXY9r%8$J-H%?=$g=v-BLvnqO=_>TKx*-mAj8gAq6^Lp70^{-}$ z^6+Uf2~#^|d>?A~5e}-b;eO5r`AA8%htjjy;w0Vo=Q(<`>G9)1k%_r94N&o`RDvBU zo-nZuW#%si(S568{WzSG#t`|)jK}P4I!uTtpf|>T^h(D`S}NvSS$q&1n#$2fyT`6r zkinZZmKDmsu1W4BOX`01Xm?CB{r5WC?!YSnh^?frrqpo zjV1gPC;Mh>19|`O5qEd@xn$Bxl>i%@o5lF|3q@^HGqk^R=suvih;np_ew}PSx;vxP zhzulgyWo!_UbO+!c0g%_Eh4BKhdt`kE&q^O%8y}zte1Nf0>p$!dicLycmBPG#hBU! z6~-jq*;IV+iU`4ly(j|Qf^sZxc}6B`uAA4ueX+`5yC`T9liq&bgC=bHkjO?Tv!`@X zBI76v*z9)w(a8*#`<;)4>X6BwS*tjk#PmhgzjpkX+X(eZ?7SA|cJahbN!D$tA9<$F z>_uocI1P%^pm&n#|2%?T?Pa{BSeJTSS#UbIkCQqWbjWExb7&o7#wpJp7Si-O;9TC+JppgMr3c3nYjf-%c@3w+ zB;bV5EtrPm!i-k$)q|(qcL|&-m=le+yBk?8sTR)W&(jL$72nk672wdBOCmNf7W3b)8?C6($}2Y2otnfA zLR;&0(R^L+m-yO?L*LT8%e_InxA~cI(^LZMX7lI}yXXXyuNRh|0j6|%iDe`BQB!KQ zaCykCb(X`ZQ+~!p%g%>Ed=jrg8QeWE9*nO{=y$GJL;f50PPFIA?}_;^>7vKLqHxuM zvm#}Qod=lk$a7>1-)^J@|DbIV@{f%vL%iOx>21)42@iw#>N@ai3a^9?rs*<%W#nU> z%jsE2w%bFkhSg6VcB{*0LZI`+c~b5`+&lfEfI_DrA=*tzztxSh*Q0*m3>q@5b*V>C zOPbKSRd+3gAHy+IzJ@G}swTB4(}QzH`eEO8H$=NxRNvA;I5yMz7y6}eha^Fj74c4o z$6Cso9Vm^gx_lwRD@-TVWFDOh3K91)B+bDSj&xz>wP$#CaE^JN z%^)H+ze2}HDRR^#k!*ccWK=ZB1lpKj)%K|&6K-ttPRc^7iSzG}$^F&866=r7oDEAM zL0k0lDuZmer!`OUE<1TUda&M1fK&hbH5YMft-UJM5OL48kkgN)s+U7c5(hxsYg@V> z!V%Jty5r6Fa_Ghf+-4~smGGnA*GIz=UsCIm$y5JbbhSL@ySj|N>P@{Yz1o?c=l#|2 zYQg>a4Glbj7aub85PqU^u{)}YyCn?Kdj&!r?NZyazIS@6cCv7>)v!6Mwpg+_2oC`S zDF4u`My$;Q;|UjgD^m;Dktc9u+nLR2$2sr;O+PkwLD6@+Ir*yE1$SttYz2%&aDYZ( z-4G2h8m}NqTxvVnITN)ozZ)^XYu>kF1_Qc=EX^w%nZX2VQWlyouk!?tfNe{>8r9o! z2Z+X4p%GvwXok>)71|2=T0P~3q-#Uf$AmCLpp%z|_|att>=#o>LAtCECP>QmZiut1 z;Rf2lbriOA+1@jcf?rr5bIEuQ$tspeP5MIe+x*r`)qeJO!-Lwrx8)1CHQ}t7Yo`}~ zcmAWoTk6GnOQ`n340|yvi$Dnzg)3DpYpWL9V*KUSkt#@J*H}6(|HGF`)f8=tPd4tN z&f;SncWtKLa5=ped9Up+7h8D~wMwjFAG}%NyZwH%S2PR`*8sy^N{=0YwnEvjZ~L}2 z!DZ8hm2z{GT|#1pM^wq+4ks1!sQOgy=DfJAEU!Aa$o%eE%&aAxI{VHho0+un-n^Kn zR>5)4^=zN(9E0C03oe**vbiFFre{ux-@j`7HaO1L&l}!k12r}Daw`Eg56x>PYODtG zy_B#*FvkW=77@n|sakV+v!dRMB6aaq0&zop+2+Zf<8NTXf#a-W^qaepI&oOgzao}k zit`EfRt_PLZhlOKt4T!HZ*~LI~@` z(R1{U+byC8RQkh+Hyz^7eZUPJ=mh_h+^UeER;B<-Ym0i?yJy6Jh5Z+n7atBiXz2YA zg^DG4#dM*%sO0sjmE7O-JJAoh{$0_uYb+rP_cnjMP(FcI*QO}ZyEY1yJEf1)pWH&& z`>>Yf%#Xb5C9?k2ui86 z%roEGZHyW|$8%(p$G!+Fj0?YEIny-xa!AKBPk*e^fYh3bN_wt)h@=LXcv{@z5aOnU ztyG014Kir8y9c*VEFsaLI*lVGcF4iL)%1%$+Y?Ug5x~Gj8@kJK;P(xcnXVx|m-FYf z`(To3l$W^W0+*k<(-yrmaBX;-IXlB5j~lYowjK#ohvc4wJ*~+Z`Ir>jctkp$&|o`U z`jL{Qb9Zxh)^b;|z<=kqd_BIf{}HJ;bbE;J!^Y9^$)JVJMQupyxaw6va%gMdi@3;7 zR;hrfZB7|=2t(-3U)!!`?T2r%>xOH+ggt*psRJ@*F33c&Bkk(MMori6<3E+a%N%k( z{w6$~o7ek%tmpa_f?>?QM`;oKyZ!8fH7m@7r(Jo*&a)Q_TC!XXv2x4$7~I1owU7F< z4-!(|uewNSxRY55_a(}XID=s0ubm{tb~ad#)UP`%M<)^onZV&WCkU-k9RQL5^iu6R zjJpC32p3~!4~xv}>>EU`?pGYO#^fHj7fL$h!&PXqaZ$5w=eH6(p^H4xoSAEN;<6NG80&T zuhylq_NgowL#V5LIHiVv+=)=F)96K^$VOV^6FO72pV^iP)Iyw+Pj?Zy^%2F(mUXTN z6hjgBO&QxGM}%rYR}suZ%Ns%QWyFC~=AelozNZZcbO=juD7(Vtj=#G=2XPYex+fBb z7q~XX%|gC6S4#8NeHQ@D#yX%ze}=D=AqRcEs*_8R58pSAj3KO({2o$%JCnMV1^wgh z(PGwOFZN-@I(!G6{5ei}*hpMQ0gBqqJ>~kFe>bW;)3Q2>3pWgQ;JRlg4=8`eH`djz&Pb5L1Dz7seK@R%eDqS}y!X;jOmZF6WrmCS=udU8L!LnDC5>Ou1}b8b&k7V@(rM1J1sP?>{{hGRbc z3c;jCKQ{+hjz(qsNkNTLWYe=}K5L&WG-azpA82{zb&>d?Ge3#1MWzPo9$WhDsWZ7PRzklELKYUABkV{+m=`C~V0S{N~@qAnmeI9AD zUeDch@x4saYeg4D>K}@=!dmC3Yox(H&4iPdAz3N*_?CoskIV0xFTPf&q~+Onm0(Jn z+!DM0q{Fx2=|?W@7T4-a=(|hazjPYPnX?T879d%xkHsuJgI@ynUnWFJ@${a$VQWXO zYG&IN>9M7Dz%ve>_psJ2$1b^$y}XCBzRK;gG+9`w@idcMYNKe`-H07&a7cCM5&5Nl^~r#5e-b7UU2jwAz;0Mv z%c&pizoo@Jei95g`@V;i=AMwiR*{j+n)aI4K5pmR;OBzI_-IVA%g1QoGkpK?UzeqN zZgQChu(Bvld*%U&G*9)C56~eOo&lBDb}}AU{}TG_kzPGXgLQ?L&mNd8-vbStA!pLD zMTc^KqkFehCiI&TsIF-H{Z5gpT1A9jO`%t?mHU0n3ud$5zk~;LSOJsJw~>H{SJzbY zFTIle1nsmYVeckr9!kDG`-&AM{J5al9N&V^IIc^exi(XS*0^9XfKYSk*>ulnsg~_0 zkk5%SNX>=%6E8bMW4?YS6qeWvAT&eTEq668iLec-T= znm@O6WR@R~z7?=y%1+&@)YAv{%d46TIHY!snLYbGvf!7y_a*1mhW%aGH`?^;JRz6P zD9vRK7`0h1r`yHFP5*(M{XA1^CQn*Fpl_eGF4qd(=9jshZ767lO@U`+AZV8>;E>7r zqUujDtIA4JWvepah!074bQEg-5>HKr-%O zB{p~ECnRnW>pC4gR~C>tSC>PUP3Y`}b!a2z#`P7{XVUv3+b$8T4qkC+{kzT5Ql$+& zFUetvXI-mm-#T$jd?EcTcEXfl_AtL9%=~1g&a&e=4umbjy1+D!sNs46kL3BH)scMO zsBPY$>tdn&O)ZD}UznA+0o|nL?Y5C&ja`MqK^mUic-0VQ&wZ5qnu_gnE6*G=Aa$32 zftNLo4lLJqs5Pdz1sp%Q&XadE*>i=a!?nNHq1bj2_X)NJmK#$bcNUb$pnus2A2ZIG zeDeNGu$n{9Q=*Ravs%;jw?6)0s|L!=+4hlh%brZaN4LiCN ze1=xl@2QP+rqDdY?faojm6BR?={aEwKWV*x`#D1G>GWnk$vEMwB(fuIFX*HmNE6B+`SahLX$dfiHBXK%oOK~{@n^0mtA z_O1|redOtVYd6jbWDpsz_{4tFT%0law5GuFsVL_Dkx2c|JUusYz22)!wKMS=Q?nMj zAGdLyWyOowiW)axl@$}wOF`r8WvQoIE)(K@Q*fK!Hg;I%tUkJg#DJ7O1$S5;S_Xn} z|AhPADPr%W_9>+jX8BxlK4EGL%95(z?~UH^W&}UBHlqWZYuW7P*G>xc0pFb1k|cxr zjfRALQS{9pYt^+l&lpeZcG`PWt;Wlnct~|=RHrj5{7qAs_chS1Ou(YhjKryaqcOa9 z;v_7>Tq|3ws-U)N&_s%sh}YM$As0(~i}azx7iuXkczTf_sbk7xF-el-bJg_FzvYRA zMiX0I8Wuu`4%TIM)v?J@hRTa&65XZ-@>gD2gieZ4ZN911%`45vM|x2?Bj*%nVuT}J z--ejU^IAu01$j?!`Zf8(JcmSiwWm=r52#+aErw)wVP>SiV66b26V}BqqQ28*nwVy& zIK#f!dzuP2|EwR<4X~l4xcx;~Q8gkj+wV5`rEE`wN2IZi!0>x0$Jca(ze%N3S_`Yb z?)4R6V+iL4n{)DysA?y~TA@ji{&E^7W-2OvyZG=CSRmFNAr`GfmwB2i5HvM$lk%~I z@k$@I7&uswA);&MD_QhTQ=sJJH>!?@O||Uh*89Z<&Au&ZlPx(pCDtvb7dE?kEBq4* zlIg#?m|`Dw3pWOB^jYN|??a8DxN z;+or5Lx+3#D6_AhKZo=@yL5|@HsJ=CxH*T+B-mE!P8vo4Z*Em{yjXKN=dKo?Jk^(h zfKw#1PTIqQy<&pOg_~o657x9^l<5gDi6|pyzmp>fN)jN&pfi=L1ToxfAr-%j_?bHm zznAW^!fWhMySM33J9(i-&~jr(BZLAXkc8Mt38%0gQ?N`rHvnR9^>{oKaUeG^!p;oo zqS8k67oL{c`{YinHr8q{JCnsi(Qxf}V^xXjkpxtV0Xl7nwGr|hPqP`tdHPj@?{WB{kM!biIfz4!e*KZ0s2WEtWvC*9GX>bE$}J z10^p1doA_o?U&J89DxsA-CM`5;iIi*hHpY|OuRU|6_*?k1&4&fjqqHf^3l2?5szZ; zVtU{c!AI1-=CO&8zBFC`kYvsWQb2c9WBQGTg0yd&nN=$pU6Cki_l zDht)dk30PzEd&EoAi?pdFGkzZ2 zg6-lV?{7s~7A9DfMzoEd-aHMSP+WS>Lh|1v&h23B;J|n+BD6Xo$aO4$*V~^ph*l|f`sg>`xOF0V97$RV)bkulu`SH= z=cAdw^xr3OcYAzYWm^hfDZUh-+pSw_q@zGc`7?*&axUi*^Va<=snzKBV*Os^WU3b> zp>u-xaO7wm>8Qvg6GwS{Q_W}=gp_^+vp7i3II|R)l zq{+pPRSg}UfsAYzdlqwJ9}Ce>Gueic=uIZ-M)>IlD_gh>C#-LO4Wh|eI(zx#-va=8 zs^7;w`AIsDUa6?xeR~|4%Hx}%m1S4S#Q?R``b$mvb!5IMoBahl&6h6x2_tK?AzBiv z*k?>S{*5~L+5)mIB6qXT;9=FyB?q>#lK=fRt#tf;$%V}&k)`;WuGL%6MgY`?zxxE# z=7ron%imAROhl!W5vQ<4iAuZF-&!u4rcT6+|5k+blG%DvgA+|5vmwE6@znA(qd%>Z zi5vBiaRvagHCAK0nU)P0P`7)i_#9uF*WUNvs_ntG(?fS$)KQc7+HnE)hdOo69fkSz z@fG@0=_`FY%QgGfvE^h>6Z_ft2Bq?ZuTpOVcC@I}E1s-&*4Xe%g9=S~zjR%UcwYzD zMhM%lF$l8Fs+hHG7oI=yvdYl zcOEUj*Xie}gDCTg(h+$9r~UAW?1VtY13Q{M{G|q}El#@g=H#~g0&&XQvN}f=rPwy( z)X&^ZzsZ_m)~e-e;V)7T{Oy8;f9&fFJcv@O8= z7dn1AN7cNsBn3cs?O|F_DE*RVR-?wILd9XaQilkh=MtO1Z_vewTWb3d2VQuY&%SWM z1)girft?^lvFgaBJ4Lg*es>?~-lz*e6JKmOV*j-{VsmY_VUy0WHNB9KSaS`?4_l^% z%v|^5;<@h>teyfJ+*b2RW?hGDkWFts7_Yb6F8|Rwppi_xsv&a92mYmx+9%^)vYVyE zTkOyX;1vHjHr**)>NJcEXJQq&T4Z^W{~Y4>XyFUgb9H$`|`kJzCCUAt|In8hgvU`dpo?bXZ?UNc1K zU;d_BV|2dArndat6S1ndiNT9sbSx zC>@c(a~2-*LmwYe*AsEDf;^07H0r0am}Oh~+RpdfQ!#AA@bRGqPQ-3uf4PlUG=hQW zhHN+OU`&KEgHip%Zog#OitqY9PW*-q%9+05WLp1^RM;o$Ovwo@8g8B&HXig5KZfZP z82X$ZzM{?>t2^bl#_?v;NQb%p4$ZV{8iHE9Xs|A&U-^EJI848AbM?3HAId{UaFj*F zYlt-W(WCMce$CGXr*1D(<*dtIx{#+9Y=44UY?}yP`3p6p*yF&(b1TC*UU|VdW0z!? zgOG`}JLYcGzP)KP4Ke1EQr=j`<=hB!sdj@IiSV3(>z4QU-dj9yjpL5+p6G{5l}(fb zMH+hV_-tX-WUZ4QyR$M)2pTtNSjKVSDUtd~l_zD^>;_0$$mXg3HIhPK{5H=DXv5qW zk|7;S62sGj-PoVj$YBW+eEp{%yH-)Wr1#25u1=KpIofUM{voyf!ESLs9Ky=kWZb(- zy0v_q0Q|F9v`9~~#J5Zr#c_Q-&Fr?k)iyHTSX%~U!Im9SBTT%)UDJ=)&(*ezvH&}% zMmeP06gdURP$B_nuf@8nT{!sVi{4lB8P0l(<47uG-~>n@sqNfU2^RV7 zqz*qC2SM&28A*;2`fAs@lN(&e_cG(lN>dn#ecuy~;ycE`AW;ONI*~{NhSzFP+}G7p zgCZ!;WWi3-C4Kgzqz4FDWN-Id)pi7J?|YZ9L|)fsfUi5v<``LM%?HD`761M}|Ly69 zfc)REuxC%Q&6SbgPJbwMOmU44iX+IJ;N@ut&-6&6L8zrOlfzVKbsEU)G&HD-YuPd+ zengflOjIelEe*s2vhBR(-l!pyb8#PBd#W~&~FVN6-gZKw z9S%#7?Knij+SA{TB!9G}OM8wtEXFC%0QoJ%W=8d&UT)tcG2jnqJixIw8ug4=tgGWz zcXSX`u4_ec`EhDgh?ICtRz++5OUPB`Z4h$^VjexLkWT$Oy|Am7#Dl2%hI82Gb9()U3?8(OK3S=a&wz^$Bi!)n!45g*&ASomM7Rj-lkSE(FZd0+$<>y94Je=c4WNh|+hVM`3H zXX%wucTxeUud^lqw1}tlz}3j&z3i+y;LL5FeRs0BU(4QsW4g;XexxTxqE|`me;l1> zJe&Xf#cf{{ZLONoWmJt)QJdCiDN2XEH$fZ3h?qrHty)Fxs!gmAd(RSTBu1&4mBc85 zSpWO?f0$=^CHMGT=Q`(o+>iaz@S1L-A}Agot4~Z{cf>K!dA=;0U#S>NcPe&Q=K$wP z^bF`})&4D<5ugiMYE)%m!#*5Z9$S<${8qqddD+R{Gm(fItx5K<*1zY+z{dlw(KdqA zN+DkBCCxZOGK}bpg1V9JwUTQjJ+wf!xQ|;FR1QbKP6hBL?bhy_x?QY^ zb_Nry3t1q+QbS7Byk|G(5yo&@<2LNYcsqLyN8zYhCChsodvukK?>%+jBkHz<;q{2? z!_N)x~i`mz=uIF<)m?unn+nnQkVJmZvY>`XsuTM!!ziGEIvJ1L>u1R%>d_ ztEXuIs;cCzk+JwIvHe>s15P)oy<#0-jDS5#?(jzZSf%uul37E=S2n? zOAo68x~$6o^{~l+K`BWuPzKQGp~5@Rl8RHe3jdY!;C%H}$r2}onC{QP@y*i*VW!eWuFxigf3 zq%a-uy74O}h@E`mg6R^7q07!v)|)y~aOa3V5XQ$Aq$?^m$x5@`mA|<$v?Vp4=;^O7Zse z=D4~dHv5j$=daf0!P}aP%gH@sX`QB(l**$FNd*fIEpHhaLgePv%)}qPNcpohQG>Yo z&>s8g#1mJH)No*&&C{g%_6Pcm+Bk@^y-|pN(D4bS<;Z)}!*6!6Hk)wXEsotf22>f2 zlgPVJh2u1TKBX3L9imC*VYJqTd20!kzaw!ma%%;)a|Y@~jUF#~Zv`AOE3)!=mlWS@ zz6N>bPUkT0-0&cmZVSD1@3l$l(bUQ%ng?8|Z4=+QCZsM?s7>YN8E(PMd%UD)cl&p&G&IQ1E6$ovM5aDPP?leA#Y_S}gMw z4Dx&S`+;!%%an4KKj`d%FSAAsrkCg#=)g zSk&p^6&zaK;sjMq)Z1td1~1pR+QPX)g`XG+7=d$^-tZ zJKR#uy&cs@mJed@YiIY7*kNVjF~;lO2XZ;@(A`$ch4o(I9(%1Mm3yh{ss?NKy1Xr) zCPPk(Hmf4_*33Bj`dO}$7_(1JdKTL6A1D3gQ@IC#G>i6g+br0EUU~TH((oRoj`r`F z`dQc=IZJnR&Q{#(@7uiZOQ;At|6}iH+A0cG8!AzjagaN0dBXL=lQ+k}qqoA6Gfldd zA^iTaBKat%EKhIJH#ll<`AE_3k$^%_s0Ktp0(ws&FS64;ch$~%{}bj*UUC%dAQh5p zAIQYXb_YM-{_-&|=4O2!BB{o)xaCG-V7>Lr6&KPcn;xP4;)U>1d+>u>@=yIC2NkHq zu3TYU(F@si292CA5ipf+dG4Jv%8G{Rv(4C>yv;b=ox_#w*pF{#^r&S@ zp^tNoy?V(}lFfHWGeB=$N;bMZJpkduKTs94VN`70KPj{c3b9XJaif2SEF5kR{lJY0+BQEp3^6iiE`S!=5Lq0zvGC)s5H8 znW3?Wzf@>uqGCgU6RMqK?Vd*i3@fzdo1=dwylU3d0QjGFvQ9|HglljjIeL+r>B86F z3vEH*k$(Kd`T=@lS4EI9SW!63J9^#g(Yh=}nbRwKs=@wlZsw5VU(Vz``Y8%2b;S?g5FsHFPEeH33&}S!ChSNhDf))MF)i*F}3UvcuK_PQnX0ft{pW1FA8d*39@3GuT z*c{fVgwsOcJam2~BSB$5_hmMH)(3OkUuC%OB_p~(l4G9Cb9y2M>0HNmFz;AE2ZpyT|R zu(_jGWcK@y-HRLCUuWRlR8LV~8sB!-c?|TXEmOhu9KKF_{1i_Cy~aiyGbMTP#wz_u z{>pUrL2oX*MFmA~os%>@fs`lFW~exZSDLkjFMRx`04^kaz#WG$T^EIfxxKF7haKQG zx%S6uTu-m?s#lpZHMt3z2~+ttw%hZ8pelDImCB$V2lg)^Lp~}v8f1)@-{N^7MB667 zEAT^0?16Goq{m$orjFn2vdv#QeeX==3e-@Zs(UW93)CEv{Cj7HWKH83nLYzy<`6p-iCI`Fs!IVJKqi>2ZAWEo;Y&`l& z$%~l~ZcrUudNRG`UQcq1)S42ArJH@p1lCZcaLc7esc%dMkL^@e{>}H=@Y5m&y^02$ z3Wu61PPnlkcI4iDZu=x)7qj@ z!+sZ<0Dp=m7vIHSj0Lp~*Q_Y2FX&ur(1(z7*Bu&82)`*%Z6)$kPNIYX`74$4ttsLi zWmvp{`{!RQmpzx~I+v3nQvs6YccElI(z9li6iRN0+L9(aG1k|I-uR87r-^8h( zGuyF32KfA%%)la`2XA=>_Um9OQm`j)|E5>_vCj1Vj;GvRvWK^-1Rp){R@tyg=+a@; zU^|Qn&H~niHBGjcqFm6{T0zvdO|n5!#x4Bs)CP2qgJub;CEZ}n+VY14*^S0^t923f1P#b z7Xz4ICwpzZA*T9^=2izcFs?`I9p`_GI|e1FhU_JG30%_0)?`nzdV zcj)hRe)B2lcKDMduDM3_ls_L6y>(Y7Jy~1KqN?^gBt424iJ7$D=bbwB61ocadqzle zee?3TJLdPV@P?-|MMA#uMYNl#F|wHy^vf>or^rc6aDy){z;4w;DcPUh{BZ4+e^l5 zKjPF-B{rZ3SV`HO2Q_k89vDs><=PfrJCy;9RKI>4Rm*^A(d+B<^3SI6j}rV3 z-o`8Et#6z7-_kj906s#v4tRAYZl5;m%%@(XpD-&i^&8zaC`6!c9o)!b-}vVl>vl7A zbg9YR`X!mOj|H?&388{P-B`AV+7lC#oyB4hPP=K+C2g~5_P4vHY@fW%ez;qPBT=K+ zYq;rQ(R$&X_vF?m`}68-lfT-gmeY2MHmH+6#8DrXzCW6>3(7cMv{kj4FBr?RX!}w= zgix=f?P19(`8-k1z4mdGGx?6a1zxG1Kc%m3I@(3e@jPX;WZxE5XK zkbRMF-aM>ra%W&NjcNYH^LXTrru#^*z+}u=mmX+U0dNVdwy&mrDQG2kM#Vhs{ockC z8)$M$@LfcTt4ox5(_rCfKs64qrPz>66MSGdAN^d_-C#;6tM+CIovPHFy<6;tXTm3h zyFyWy0KQj1_XewtdOy+7%O==nkM;(8rAPAHDIKZo@)0+t)6ETFJ#yClyKo$1Y*V;i zxJoV>cw=xLnuE!{)T5ZCyao}(x2VBxRxnv|{Ro+VRM{_Iqj%gelm6}^ znuPLar=A$7FlysOV59pLf9!hjCCyg@Jf-60pWk*KSQ8kQ444OP?{82FxPw^l|9loL z>d2G0zaMw`E59hGRIS|{zr5gAliiS;Z4hNy+vd*vAW!AX$i|50#njGQ!F}$vICz3K zL|ct3o076ce_N;+Kt%0C0md>KQpDI&iaXW{zkF)Ay~pF9mNBZfam~C}9An~MXo6sa zUs;XEDQvtFKL*YBgrV;`&NIBw*|&vV8snTuA83(&YbtbKTb3%Thw5kuH;fTe0)-0} z`iVWWClf*+0@19&oz$cL;KDE5^MB1(6(&yne?aW&v18hi7m>lnODQ8_aK41ulN*Hr z;)(ePp~i<7aVpz|1+1A3lNripE%EUi1Lej%WMyCQ+|JWPp^q&TyHMSOq}w3RMPph&9}Kl7x(XE*4?Q2Yb+iy z)ai?3&ayY?sS{Q(3~WiC(@PNNaeuY+p>oJK-jb=1V_+^j%ZK*`Ge%m#k?^92?GrQs z!^6e5d#(Tk$N>4KMsKx(i+Lm0Ub553pm~b0I8`NQ*K@dPB|-T|j1v6kcD&))4TZUW(E4-(2rJ#( z(P#=8K7Vqc0b3i|Ab*oQQIo*oT@oH1hg}=koMchCr!dY2ao#D)NGR*Vz7&nfDW`ke zeRxUCle*ETRwEi&%HyMWD8VkE&`)zz#A)H6@1Azp2g`M_iAs5rU7!8LR;SJAePQ+n zMS8iT>PUD6=VnTG@DJ7wH&W?aEbkK7|IjyVx~Vg+&J5@Mq2j6e>uquh-+U%7czD<~ zn?Y%<(&Q19#aQuZEQq5^p|78^l*8h83v`wVRW?6neE$y5rK0e$&`Q-t&X_Fa`{J+i zs!W^?dY%pzOGA%->Q&JYVpfAv%YjrJtz4V_#S7j1a$}^!P@;H=w#}?aV!55naDrv* zl9=k5gtBwnmc+xNE23kK`~c@>n~Y!$H+#X>O6EoKqV#-wad+6}{cTLEen+%dl>YsC zXoK?`eC?ByZEOup`xJ_VB*u>knPWHoj37vcQtB>+hmdjfiwjBH)B3kqF<4iBY#+(W zXgg3>PzusKuE(i%H`%?shytGa%P-NLmif8I5Odnq&OmRto>O(v?0drdS-e(v=3O$iIc0CL?y7PG-L3OZ*;omF^BJkY6ftY(Ix;QNShQXY*czAH%2iEsG;qFO zQjQ^5Y@msAw%M@@wH#^n?dgh;<`wrAF|Ui}JJ^6Nf^YJ>&l2ySR86hAVQS5?=_`%% zhFGRohtstzuOFA(ZB)2geloC5UlH7o@K#MEEG}H$2G1OB#XeszlxP+!*r$&2h>P9s zzspBVs*&Me5(rA!vM3Fni9IZuhwU2viFi?+w{JL&2xMkSjhOu(6H*e_r=1r*bPFG z<8I$7>8EzSWCq^?D!(*n66UNY+{a#YGFV0I;-9>$x=G-IqW>;7hdI@ z*CqZsnXu2kL{~ny^Hrz5-zQV9t1iSOE%i`DC#rGRf&rDd%>$M?inu<;+7%nU>zWy5S`zH7H1!Pz^ z1N*EWY1`B04E1(qhBT1JLj89Pt1eF7?O^b8wCIODTu_5}OQfUt_o>z4d0Q-s!j5>2 zm-1A@6YICCGxe992w}Tso?~Mk%B)}zM|W?|K4b9kI%;J?qd47H-j0cMEIM2{8Nh+| zBi-<|@)f2)-kwy@hM3AD4A#Il)^u4-oy!7bvj-4h1A5|<^lsCA@P#qqPKJ@f5m@5< zH~kpk4^Y9`A5iD!04wG>`)(G-eRV!5Q*W>8 zDO}vqEle=W9csYql23Tf)jo1}Bdk9n#L1YxGv`VV`WMM~IUKME$4=GmEbUR_pKp{J zQu#ua_s)I7#c8t=Pfe4k89a)Ena|CwxTxduebjk=8$s0M4 zz8@&s-b?8bJbG9Bk7@ayYckY~i%L#n-@PtA?&BTazDSCjhtD!1~47Uo5e1B++dqo&D^#rwOi@-~Lm0xT?QYl#73(Zs;p#OohNd(Shrrg(16hFj_U)0mc0-Y-(14=lD{R6X8V^9 z!B(&Ig&H-Y^j6DaJ4=cL!ATIqF2d{T;zLH%PZ2W{q#s^!722mibqnWRTKQjQ<&HR# z0q-9B4&yzj{kJi*jS;2k?rHk>edsS3yCV2Pj6N^+=x)-_+T%Zdb;d=D6VDM$WEyyz zIp>uvhKJ~T;A26L>S3+~=VunU*Xi{QY8Ehb9CTXYDv*6P{ax35SKg0lUzd)9IcUm` zy9we|nd_BzrMA7+zJeO$NGb`Y0Mg8bMm_z|hN17P=hbD_d(=byw|1$W0MS~SptyC- z;l8v6`ZG?W+Pj=m5OLSsnmg##gKXyp?N54lSfJP=kKoYMRi><0?s^o`I{9w~E$^90 z^%;b-9JT}*5dP>Nx4QCtBG2DxVecCd7t%I-^^@vP&NOA2z($@m??O@TYC4ym z)!IpI4@x6RmI5E2WXFQolLm7|h1nJU-;tM|aG{D?GLxtI7B~ zenUsi4T^9r_YJI^U9wB_#cEL|TS_{aVaa6%a8o}GG(8$JWF){Nt3vZ-aK3;Iqf}Cky0HIZCfkkD?cZOiYvu_ zrB)3+Q5g03^W$h^s0}|>r63wIqeKq-W+hB0&)u1a*OFY`ABQ1bKt1;zpGpn$Qy+RI*N$qi};Jb1}!wnKKZjE z?K;YD&2;IO+_;-tj2Z@4nYddT_B_11bV`eBqBOs{#j0f7H!(NQe_NPoB41Z8h*y-& z@%~;mDBMccj37PEqBM)E1X9Q&I9YwXZw;a6)-^d6k!Pc+9{sEaA1mJ=P~6}b#c^l5 z@Ps&w^(~Yg&cRrHWn&D56i$i3Co#3!0-%bv#!r?77B34aRz6wfD-GLr$&`-W4HcbO zy;zL3P1el#3224Wn?B(2?oYVSSH6=fIRq-B^n%c{Pwz{NB-7nj(8{iRvS;UGPxLmQs)zm{snPDdEC{V^{a7U&1YGkMnac z%^cKY-6_ugNHe z{kfqFSPJiwLoUvR$)L;SM{_SOL-8H-c zT5biYTDL@215@9JHuq|tou{M|1J%pJYq3j?gw%bzc0K#6OV|A#5hyl6`n@(Gw?P@l zB*m?Oe8k<K3~#%paY&yUvbUJSZP?di*%1-H};hTJp1UVY`34v}cWf0cBV!+qjC{<^lNM+RE6(2fb4=H}d`9liz?>DFItGU{^3VTC0N2dg z1id57V8bmOTYlC03xc;=@$QuK|Macz`PY)F*?MHwFm+0sqcxXlSO+-xHvOtG*cik!*NEW{V_|q1&4VSPw4HdJuQ8gvf zRF{e6*f3=KLo(Lytn=q#QU3Rj9z@<6(2}l)+`yFf^vrgk(5M?Ghq%{PugP(FgnvI$SFcFj`r+UkPv?n>jWZ`A-0FB-57JPunyu_DrmUCRY;% zq!(F09FKmAHE2E<{qtsyexstQQ|qy7zPgR&qpM~~c9flbNbYD~7F<*I5^EpT!gVUM zIeiZ6@j5{%`pqw&dk{a1JP=j4QB%m3*_r8nWlgSW&gAm(^%uVrfDjK?k5JHDMI!`& zvE3=ra!|YnQP1d>(0m(E_~R&8GK+hwIr)*m)_I*V6X#f)Qh8q00YK z+>w?3QPp>yfz}YcM#+sgW*A+zBY867wL9kjA@g>u(Tw7gg@PTY2)+XUOLvMX?ZK5Oe zS$2Xnyk1k`KEyWZ@ekv((5=>e!@OP5s8OMJ7c82V#fBT5!It-ts{4k`O$?yv)%ZT| zh8UhR_wcb<;Tn(>`t#_svRU`ChM{S$iMc-~n?RhH;u2k=yxnDWBzUxDn-Em>g6eM3 zS0i$T9&Act7G`pNtL45T8>wz7{!L$ErLGql?Paw>vnNq$GP|_gP z!|5oqb$|Hq)%J%B<_-IrNsj`Sp{G&I>W^3t^j6a_tKgnA*}^srbQEcOmTp!99&1vl ztU$_3mw~iDk^&}8TwbyQI+$?uUqL+1<(6^T;nd7h68;$S5^_I%4pys?CE6wAf{Y<+ zSqF{?6oNweMzx3jD9%0itUe1Bengk`JQ1&ma11{u%sK@ItQCGf36sfgUn}e$Ihta9 zzth@n6}^<(mJTZju5nJhO)fp+=Hbjd(*dbAJBlEpE?$?~v$ZtQjiRGpsYXm zUG9(w0=_q?!MrUEPuUaNrjLw+##%$o^Sv{!D<`>knr-s&q8fcM@niC6P<&9hbChq2 zyW4L%!jPf^M0JvBwvPWIs8eR=hvT?mh-=n|_ZUOZI%3If)RR*wwJ*=^GUL9V^Myq4 z+u4MsPuf%;_OkkzP@@c^R}e9OkeB{S4cHpVlk}~#GxhBq8%3(jw&y<&czjbvY0M+Q z$0erLx3_}EWmNMv`g1~h!F5Oe38ZsW5gXSRG9}Nd0-5qm$NP*P6qPl>wxl|zCdbVa zl0!mvoZQY#FKa{{y_&W;7wU3cp9e4g%lfzFO_53~8J0dESM}MFd>r&LI3|`@50tbn z1>|}4o5oQ}IJ-Ijqrgd=ZBKEAeSB9T*{_FLI4q^bGa?`Ojw6zH@KrTYan;NM-Z?H| z&6>y0hhUtEP^=#g^^5cBmHA)N>v8eVkM$!jEvZ9Z`yYx6w$hIsR0Pe}cCH1@W$k&0 z-5moS&$Rf5yyUP$7&bKRz7xj^O+z-lCc5+PmjSmM$myTQ%UJ!YXYG?soq7XV|5B>U zotndo&+M4~3m2aS2#;3hbN+{#8>N{R%vtsL#}AQ;)$PQOCNDANxq4N79*?QR3RYf= zY8=n?5w78ILDf+nayifDB{^d&TY=9}hm zWG|+#mm)kBxykjZ1!ou_=(P3NB|LSTU8I&`7}I0o==^DifEPYFYC+*A=v{OTc|XiX z5bwr-@|yo@=Pd2*cCqrS*8kb0ZP|wYKHJEY(-6pu0i<8^*<;iR=ySRQm$y#w*-rQA z+3}clN3inl<9!S!H}%}6-*gmAd*Qb{FSIpx;^(<>3T?TAQi8rY-; z)qUE%V_z;50FNPWV+(*DHPQ`3G*w9KkbXzw}EB~jh!4vUF z4Pj`*K4__JJ*I#o9L zh`2eG9!}pJ00Y%_{SYu)HYCHhJZ>E>90EpPQo#59m*^_JDxmeFAuxRO^g7*Sgt8yb zZ6TuocN-<$HRBjon2RN|ngmeH8AD#_@^$Su3?$GvSdj0c_F4lt<^>3Xn z6{Y_QBsG_;a|eCJ5SG_ZSpG7ZT%@OLw92Yl&YfhbD9zIZcVRR9k)J&Ts{@;U-GAgt zivky>{P=j#rpOW zO#Tn6PMl zb49#(Kw>$$isqsxjvD&9hHH=+*YsC(r-lKJGUh7Tq z9Wmx-(-2rJWim~NdUY423yZ_!s;D@baE>eqe~0Aqw;|L(mX=Sj)rybz1kQkC7UKrB z+8Q_i2hA>LWx};a(ey*yvUtAf-IHVZWR+<_jgsUO5r?pq+hUn4Zu-@64}EVW-8U(< zb&+ zv$ph^7d-Om&85qM^bhe6?ej1pEMLt{-LqRGbnzZ>B$EgbZfeQRnlboyczASCoI&iI zJLv(avGM4~HmS)6*9sf3tU)fwkOLSIqll@ZS#P6k8B}$+vTtx`vCCHBFtvG-TH~e# zBryf`sUX43p>aUvSj0w=T#~n6Ml#V>-R;$`jA}a(furKWK_v&%LF}`~ug>zP^_%H0 zXIIUdgIPeDJ_p2I!yqpk-O`ho>h(f^3mf3S{E=(gU$|3~DQWIb#tviVmy{pcv!_aT zi%eQ(N^AH@UH~ z^8CHtA-H8*o5|j&_bBMqwO4sLgK=-V**ri~y*itD=gX*~(^5PRS@CKdzMef5lzbsIao`quM@()vn<#k=!5 z(ix3;>yqgod%aTKpEO{;|8la0^nMyv=OB0q9H^<}+p^q-MvfdHwu}kRju9%hTTC*2J64k1%JU zr#*h#a(mScdRoOB|>J?bWLwEUYvzA~Pxa3LQ_-y`ih`*9-x>q6V zkLvcT9DD)s=3-Jsdy>D3eOwBA&{GUP|2(`5B`fzWlXweh`j88j1m> zsV~>=v}Hi?|AmEh=Wny)WE=*=zL(ZEbJF&+6!fLTM)hNyOH^gMiJjiK%bJ=t9v1N9 zt|+3?XIRW(kTI-zDaYtA&~TX0X=l-yR+(L0qZZEw38Gq!5C7WDA%QC!sWelxHf|bV z&KhZOGqhV9*OxeA2fEH)iFyg)%HqWIwr_)L80ML&(AsFBp0w~WE-ac>R%Wv(kTAWL z$#2dGri9EQQ3_vnZaMeL-t(zWP)sm+D07jIog}0o!U}(uaKm zpPcY9d}wwAQr>ZZF3aTe#4YsL;ezyLt3DDS`SG7qd=zg{j)yWsRqK1K!T_OgS_B)D zP!^RPsCpIg$|`)UbU=t$tnx9_0`Crr!~`5r6Fd~*07cYw*KmUMeK0}go+}luSKFf| zmmZWFS_#g^w$1JvZZOZ+K0NigH1Q3qFj^sQ5YAIx!Sp;g6~*BeF#RFtzN%d6Yz!YT-vwrbkCgPLBlIr0$6H!njntZw=DMn1u1L zt8+Vu4P1HtA`1z=V}7ug;m05-mQJ+QMkzc0S9~Y-$z6xpMe+ILWbrqPQ58FO>}3mM zxhLe$yLDCVlb^WiR8_Y-Oi{wpp^kFtjuqawn2_?R9=)VvzMA~(1PrD553)p>#%*Gh zxLx`W*D(i2NRhwLJ>;Hhe=tJ}rxs+eqMa4T0%gvae7qEP-&|J*@I>O0+RlK(b3egh zz$xQ0QA|2?qWz17K~0T?JxtoZ1+V{X^UO0>5dvY0io-;Y-8_nQMC|V%V>C-Rv-FS_ zJ5jz)3BVc5Zv?zfa!>%(DAySewaNhnUQKL*cJt521~t~*bx&6;X7qZ4kqnaoKgjV4 z25gX4IP3x8Hh4B^m^2J+Xs0bRUoc0$10#@Oh8qj*R}|7$@3yB6AyRlDg0$$5ZJA?3 zR}#HTzuwbl{Cx>3gv2EsWKQc*0<{~dYrDxQbViZP5)K*jzQKQdE<$a^hl$iCKe!>v1{n!OENs7H zuvmh5kLpXKt-Mu$b;>{21fqS^j>yrML;(Mk*=HQs#fPhX`R=6b)3|T$7pWHr9Ftl+9HdhK8SS*jw`u4;5;( zZEh>fgsEA#`0?Sz%^47`PSu_32-nWE0_FBZz#X$s4S@4tE$nn?001g*wX~t9KbI@( z3WktGBs72B3|cSTj09~05RY3xznaYD$xrR1wU+wWs@+FXmpH#cn>e@6PD|l(KU;zWgM~8fA80 zZ7`zzv1$-m`CRhyFcyl4C~kGx)r<|jhn1u98Rm%Zt~M=IVhop0W3c?lVLVMrJ6W1b z@@O?DDN&tf5r=>NDeIFSzReoI90`tf22t~FF|AUD9Q>kwuIL#jC#%Xwh^KBZmylo{Xu7gQ<_$%+`by zg#YCc5m9k#t#=v+9s&^dkAE$~k#BCmJgZC8ZFfYI6|s#J=}Hmr;Ii_bO>)PJjs1Go zKn-rh-ajJZnZM$d?A#S{ zXWe(H{VZQU_17L=C;_7vBfJb|FfSE0TYLIVgj95Tr6vLxiSgpI;aa8Jg}n(=Z%Ryr zhGg3t%QU_kPkob`6B11US`c>)Jrlyu-(7G zqa=?%5&En5paD0|v2jb7jEjwsi^rE|ljje@wDVRUEDIx+Mrd*(Ts1B(w7;t^?pW$E zwql;SM+m+UCXIx}n>iSF@2GAJbcmftUj`S2oJE%(TdpOMj@xSeuY6EwkXfWJ>PEP{78413GWI1PIB>9$K4L0hXzik-$LOo@`E8qDs=-tJ^kxT zg~1W>KHOw^mceuOQ#O#Ms8sPdoTQX``gZ5Tuk%T{;ltObGN8zAfRo^K&PU8sQ)oNl z1s-;Wh01{YJ3%h^a>Y5JPHlkvAHu>Bl0dk<>-=wJ;$qUC(5Xp~OfMe?3(aSgFj0aM zlznc;3o5EoTxGKhDAl@I9M+N%616iJbl)nr#JqTOOwYbwL%GWJil8IK)l1G01Ml`@ zo-y%XMfB7kaeLu>IgwHOD-BCsi->a6k2ed71KzqT`AQZc;lFBx6zWHjMJ3Uc#a6+K zDlJDifyNJgFo&V0zu)Cib=C)nV_Lo;QCe^$9XMvZFpM`cCiV zlwfu?1Gyy%%anKsRctSIfj=88ys_wxg42hx9#v$VbL){^rY zS7M|~!tiAU@MF7OjXZ)iXfu565jaFh;2w4Lao)%r%Nl(MafdGTz<3<^s86q+SiQc_7SFQfKCYHKuT-%3yCP8##OXh#iw23&3s`K$VG*b zWM;9kx$(}>RSwkfZ85|Oa`T#s2waaMwZ~VM7gxA5aO=8jmxqz(R@%Y~OBSOh3zeO* zbg>IIur01v)k*h<)MbF_l=d^d(B_f4r=~Vm^%7>FCj<<+Al{x)bBpfcwcD$!>kkku zgGqR;7Y38kSE9e~@9gZj+?KL@`|O{7hi>j|gT-CV)r#5duPN%K8*j8`#E-Cwb1_O$ z%ND=CG7q4j0QtHw z_)NNs4*oo1jMhA{e5A6z+00TkWMPA={QTN^=k?R;BOD|PARXd8Ne}N~Y-p;isf*v)6hPDRoc;Jo21sz9+Hp6x6Tp}D(xIhM)k4N!t+mlq z<~K0Zr|EzrZ|&oI5)R|6!U(QW+d#&o#H$P=6LyM}TN`(+berR0N~v8a={EQHge46p`bSkP_aVg8JgYSP&Y}QUrt}U zW3}n=1>fe58yd15q&5y2DiF^GNdWZ_H7EwLS418X^M{YP!9jj5sy(Qt4tT$y3}EcujDdh?8yB!eE?;%EX2aLu|WoNxQW+@KoVob>L!4F zeJ)vOaq>8`4bt_+7VW^e5cSFB@LF^N{rnZ?UMnn*Yn)liZQ5V2sW z=X!Cw)hi)2xCrz#PsM+&aBiCwoz|c_d7=xNKHMK4Q&F5Nv`jF{93e)6j>XS~=WG)e zFASG1hqcc+gY!N+zP|x(5nxTcT-&hrF|X0=e0$MY(S0e-uW&9tJp+B~NZ_&%465 z|DKRUZKB8e((i7~Y+3z1%UB5Y_!ttd=c^Y_6!gQ{yMfhTLdg4~V3jckUgX61*q?Iw zfUwCGG%0t|9WOg9gT8)<2`+f~Wmz}tQ2^@X@ELjd2WybVhR;m!y08%9Svr{P{JyW0gxB2s%_3DGc|D))~+SSk?oA{`}+_0>FwUH_v`h1J{}3!vy45-eSwPx zvGb*%;};K$^B>f=4>-{T+rS^1zUK$zcT)de{O&1cuytFT+uQm2$AEQCZaeF9ZIZaWq!8KHUhC6pETcc2Iuk&zze3dc&~o8dbHvj{I9)QGOFQ z?$~m6(#%sqZc2ZM0baJj?>)y6dqi*Vv9c!5PesISPuGnTEp2(>15w7(T*cH~%FGrX~JGG){ zKYxqTx%WjF$4h>^umBFG0vWwvgeBlq_h1jTm@VDW05t)6X5?TZe)T5xaDn@YBTkYs z+ftTqHV)IvkYv3eW4%=1TY#nlsxfW+x8$%V9p)^L5)OYE&ndn_T!Hgdp@F`)3dRRo zH@qS)lgo@NY>Ibh?dD(MKx(&WSmD27mO4*w009o3l93g`1uKAHU(x#D^KkQ@u8b{J z$*TPP-tmAp$ZlT$F@Rc$6FQ@)Cq*#Pvyuxujs@w}_MV(Y1t6ne773vMjiKL8zL@_Q zYi_%Fw|xVSYV2pi-{1197o$kNGYaHNmww^^9Z5q%*4m`73BV($B!1b7?T`!+6{Fl> z8sM@oQx5lr_#Vw0HWNzr-$rdaOfM`gMXp?)U!GiETrLW1*g^+_79%gu))%Ep-0`8z z&BPjeFCWq_xtxz$sMg15LA0(dua4ZIj(D;>`oJ{ijDhWP9-D2QZ^MJvgxbLCA{8tV z{5(^9C2_W3qH4tn6SQ)Qk7xODbXLX}-5bVWFA^P*HTUSJXbl%N>@?8KHHH^b;-h9<5*_9rpVQ_hkkI4RdgrLqaocL%;tXwe|p z6B2N1&I053B^i|+MtoJ}r%gP)^t(pq3v1nle00(FvBS2a#It;VmX(huYC$JcsDtW^ zJ2Lqx>6y#~{Hmp%i;4J(%%t~FN!#tO7JoHr?BXA&CGuicsyK!{E(ylAYhuPM&_$xqQ26@y4h zvh|$Q`wjV)4RlhC0M6ZYpzIMEMuq`2Tn3IgZcyesabRNlz;yJIo_gMqcU>o5wny1I z2BtY-pQ4>*6*EVO4l$}6+PsoW!0^MNiP@V_*kpw$@IYg4pa?vu=1MF3=K#OLa7K0a3eTu8Hwt6^bJB(nNuTx|up9rxXu=2b zGKSASO^QMPAnOA2;3^Mx^<;52u9cJ~+*Nutn(Z3TxHFH7m8LdBXEesh_r%_b2$@ zgE4U2lJ~4v|2$4*6faR{2D|E_0p(9AeH)fNa%tjrm9p)TlD1YH*(6lwYCktfDdx%* z2_fHpb93?I^}#R3f==|fJ6wN{Ku{s?OF*hhyxKStEb;zIHJx>^Dp5K1R3b1-g#W|wx4ue!XH^k| z0X@VH4zJnXrrIoN?PK1sE*5;IGNgSqQ1H0eYY|~eh$uH1MRz|+$5k2;rGI{q>&;o9N57laRso98lkr+vMJvthb`FUItf z-iI$|wGU@ue>bMRZ!JFu_Z{{*J1y;{1RhYe_VH2Zt3}tYwFv-R(twMz-g?!YCJ<`` zICR8*{MwwiXe7IfZRBiO&nNJZu`;+;4G~2Wbql9MaLJ6>g->tAIm%|TH5|Ck&*u^|*=g8$6R;~DQ@_1bo0D;FIxX@Tm2j^RrF2zTW9HVT=lz3J& z@QadpDThCV(Zif?ZoJ*NDPHLbvDECUw1MBkYWMWWTOyY3OQYa(nLg=s`e;4T#tx1t zS3QD2%I1K1i459cRFwH&g@OQ)oiunlGT;emk7tb2tFTdtG?kOL>~vwm~CHS0)g8BUycl)2_R|1pKMWuz^&L1|>v!h&2 z{n*fM8S!d;znzJoRo_8vhK-N!-wJ{B8Po&$W7O;*!rpQ*pn$@UV8w@P6-TQ2Y^xIKAnX^MmWQr{- zoib%xwTP~S)MA(Gk~5x!clHhnAN~SCtK&?NZ-3qtJkLMhbI5f0d{ijt+#`F)|i;5fn{rcdY`y#4XF`?PgK6fs5!{NT+s2@L4N=s&hC`+5u zTIEtJ@81*?zh27+9P2NDo4iSfVXBUknD6^kTT|{L#k)6SJQdR)=3DU)-y&zSF(#no z-g6h#f^lLcaDwj?4jKQ6>0SAq(Nw+7afuFn=`cDa0BwOEln*^gs57jxcRLGne6#ZV z-W+*$`FHoxOW|av@x5gIh+h~co>P5UV((fxY@vL@r&Jp_5G#)>*f1NR3Rl z`iBPaiKRo!(e#+J*4Tnu=JFzYoZ{CzonV8f#dpE}36Y)Z%ekuGsv^lx(}Iq7Wy~r| zC05r;c+}XsO%i3M8m`=SAzUiIIPSyp)O}*Y)4w(0x)PM|JFXi{I$qDPC#fmxtn4TS z1|DNfaQays3A`(ZrAXbWB&C#mQy#+LR8`+07ARzX7XnO&-wG6+33H=7isw2=pvpL@ zR%?R}a`a!9$>zehu!C(U>gfEpdq`vaDp4eps-Vp}73+k{4cu`%UBK96lgb#t?zwg@ zG8td`RjR4F+dgpKuvhj#YS4$c8>|y_@)mcz-RQyO@zm)~3BbUX8lnli|9RN;$_wt^@zVBc+}n^;pluJ)pmSmYF9oxSS>Y zQTr(#f2fG|2;9xhY|`BG_megdDsLek*f}8=-=OBU_!3OVp;PT(HU^GU` zJFv1UKLJ*1124b0&E>lJOT({mqnom??0o#>AX;E;X8;+Fa-WB{suHX#q{?m*ibNDu zHVHfVAJztQ^W+~q`EUw3t4HvS*S!;WdU|=^sHvA$Md{t6*GYrVspI^!UdpG$WCsDJ zV#zT!`Wp_zFRJ_BB37zdOC(m45RVNcjZm2qkAx99GSIAnSfYN&5S4;c0XVtfE&C-c zkxy2TGTUn4(-1 z2kKr~W8TQ)AE2+#c}hI=kQ`<@y~v;9^8O`;h&10MXGSrs7=->m1v|Eor-czyh>_dIz&?fG14Hr^x{x8gS#<9qfD8+alzgN7}y@jgHChSg8%IP8VUrJ!dCQEHqsAH^-0!{n*b+)Q07|;ge zv9=f4%72e^2w7I@#*Jw`)Xbp+zt%GG=6<{5KRk!cNjjX>Oz`o*EKxQFi4qSORG6V% zSdk5K3`}Vo0V!n4;p8cW>h{8fCl>DH18-?`rt)Ns^cIaGJG?iZNj;L42~slZ2g?7B z4NoW;Zuxgq9uaH<^h%+aB3SDC<9qeptB5a63@b)zyCpE}x*53y6#Zy2u{JtW(jZk|XA&Ff1MMZY?!W*J^d?Ez1Uz^6-0d%@J;8_A3{bkNQ`F-R0f2op zMhJBeOM{zDa_T_I0W*48iWe?4S+TttgPiOG^pfH_E|V&BaB*V?B!1TRC={bGYHv1+ z?3T$zNTtGN(`lh}=)8UQJih@XT1R|)oj2e^?*8``M*KXTwZ&A^j%AHzZNtll$dYo0 zSAkC}>~3QfN!op5=Gh6?0-~SnJhbLHYprSiHc1{^P9u{B{MHDGPJB=*#YlmuWP)Qr zHwh?8^bU_Pvb~C`p`n^?)Uzo zaEdyX6KL|=-bJ%mgYIJmPispC5WTvx>fJA3Ee1ZD-N$j_$>qcD@+jLe5REE`RQfNT z2`8o}H>s^rw7@12p@V129(JcN@lvt&c;nHskY(|M4FW*I$3c6USGzG@el#PVYWt-h)=t5=21=4bmbOfLuDjik=R+9BCG=pUsXS*c0R7dMDW+yO7V zE~l4GweYe4nmS(MU`$TIa#W)KH~4$}q5S^c;pA7f4!9K3u=8zw{5y+w$%o>|#}xzo z3!89acvjPA<*j$Wu0b5f6fQ-NDJ?7S9v6R~M7)x?`vU5OO<$WwIJR?>^+y;#ejU_$ zpD;!)u9kx;ZW#)sQXjH8TQAbx_>Q?mJ(u;4)DZa2kX^Djk0>;K=puFK5{yA46y_-s z&EGJq1X<@+b+(v8E0f+P6?s1%sUS!x-kSwnIZEcGSpuMh^<|SLUu#r+v%_ie>i_`IfSm3<9eNm;X->L4GGimP+8eT8nn`}Zf zVNU=023Xc?xAQyWq)FOqu%Hj|ebK_CGMWyjrC^=i!>%ax z-NGRO_b~rvz?)in9jbTSsC)H8K83tO-ffQV^xJ){F7C0s{){x@UaJUNv==NN*CD;1 z8ir{f#S5_zs&1~{qc4M zoozv)#De;R?S=19PWP`*&;E(P3(^)oQcbDUk2A@upMCWv^;Ty7-b<~%YwZzY;Oq)| z(4IE+{Y6#acCZ;z^_j~fXA_OM3@T8s=}o)TL=SGH5xi6RfxNWx_%52yal#YV`>Oxta4R(`>YU9)WXY1XZso_uiDqsQHR^re zE?SpVRf81*)oVIwV&Rx(?s#MV3bL&mCx`}yH2J7fGpfMUZ8jM0&} z(h*v=$f4Mo)_UXXlhgCts}K!OnYLjpOhg zXk(Xbo7JM*`WQDVfw|n`-Rx4AO1@XEF0i3643rw6pUr5i>UNtn|)xFuN@CJybjg#Ex0}yV`nJU7VAuD*q#-zu=rer4v=)G|xU1M0cG~EK7 zr%PDC;e#yM5C-JUG}$$!I%0?M6L>kFp*-|959od!O+^h&rQWm_LIm%l!c87R2d~IS%>i&GR;;id)Kk?X0M+GOYGNCns`CE zku*|)wVI)(GAGuV9(W(cZ6}E+ULOYO@;)|`ZMqUA{2HB_B#X%gKuF=|sF%xLJDtkX zMUD>*;%|S993Z_Vk2oakP$RoB%x|ipk_3t~)hf^9l0^V-@T&^)^8UDvVvF z`)rC0NLg3%QLGPy9EV^uSEgy!zyftSj+AyaXXe_K2g zh?|u(Td2ThHZm&&Gfzd08 zNf)Z<3Yo1_Tsp)u!C~7`l<_>UDo}i|n)hUGj{$mi(+F!OK|}UOY8F1#pG`jwJY;LguUdN-)# zjT5KT@BSg$Aq;`|%8yYD!P$dY7!vlWht9o={x1woP!D$MwrTDj*9GA;?XC690lS>V zeHb=IPrUqH6jw-j;9pdF${D%A&VYd#A}S~IYu)R?2NOT%RtOB+es$SAE!W?Sn-G+f zIJ>(Tn#3q(UvH*h0ESMO6DNN;chOvjxD1Gsax-jf&{Gsa9l|f;S3X8KCptkZzn$%B zCyM2yS-%dW0YUe)TFp}gE?9pxhfz|)AEHOpD&(LR#_{8T`L@nchr(@?eBV4#Y;(Zx zFO5l3aPJ!ewKt^xI!=Rl8yh8&WPfuOstxRA7p~4fkXw2f*|Y`!@G^=oT;Z#~Fjkrn z#7Ueu%9~WfgaPBb!gH2_95ByQ6^Pq~Vc!P7XCM&sBLw_R7xOJl`ryWl8ycKp&d@Oh z=L)Q>PVZA6>bU?}skO6IQ>%mt%=E6d%i+Du@7|T*J_&*cv91zuH%m2z$Muky8;4yg zQ9R#{s0UY0%MX2lL;%ntAO|-c={>b5xdl&t(nK}(;--HKw)ov@onzj_n}=`{MzHJT z`BMJn=`T**7wvxpzq@{B`Uc< z--TjHpcrq#v0(2yeb6g^nYx)B5Ls(Dqul+MRr0-&uS3pwp$7xSZ0x0(@4@pEfS>~y z{n~6QaPr7+olV?8v6n2&i&M;)c+4`FuP~w@mX2Om5R7gE*=TwT^&!T^hC=v$ZAwMt z`t2oK5h!r8R$>u448KTg-P7s(guV_LH*AdST%0CM2OyUTzdI@n{{c9ozH>>TN%w8b z3`tHtgrIG|{z}8->@l%t@iSh5cIIb7-M?*riGMY3Lj)KZ_FdIz3Kc)XH>3X8@%k;n z4U@918)#fk)#AF(J{p-3&gfR}+MmpMe@}JKWdJcurL>v_$wKR!O08}km>Nh>bn_C- zdBsbatl{08MITh}@YcAGg9i&22&VZLoqo^SI00>}&aIvkd4cih4GezkuZv2)}6@xGo9 zy@3ZunvIM~E5P^rvE94biSmmv9p`T=tuz^{bDc3IJhiw6(W=rk52(9&Jw?~4gaZF` z)ut(w30P9%&u?LWbJlc=Hy#sJq~2E^eKn`_3`DnT&XniN&CT}8?z3;T`>grz==F_k zJf7B0qZ+t8X+d#Q+}Ka@d(X}n6}NLTzF}kZs+*uK+6xAo6sXM+Hj*pe2hG+K_pp&= zftN-=ho5|j*ScJ4X*msL3}w1{mM&dMAMAa|dRF-4!D52SITZZX@Q=$X$mO`1lTr{2 zvCO~RqARETkNVcX8U3?H`K>3g#CnlFRR8a#rF5zKr8sBaj6di0BwJOaO${l7A!B(n zg2{iem5mxKYN}!#fAoO{Pr!Y#%B~Ztiq!hrJ4u?PCAKCB|I3@XEISuH9NYdc!;H+v zQxO2$W<#cm5U@3yOK5W|@Q0uX9bL`pHq))Gt9f+*wqpN}@J4SP@P#{APK}a$^?Vz+ z$~PI*U?+FqR2-TP^B3XPct{7~%FT}5rbpSxrZqyPKTZrCg4r`u*cP&t%Pl(JRlLF>?S?r;PH*6$oHEdtAOSwGvgC!U_jXszdE=16dR|UVbE84s!JJc`tSA@0>o`YZ>3*j8WvD7dd{( z*+{0?gz2z3iasJvnZJ<|Hngl z=GxbI0jbGC$AIU2(W4!*WOZf6W5F6tOR@2)(vv@$nNY0{s;N`^iBur*+ajZ3C?^ou zpKWWrj|sPXzBrh6Hv2tUOf_MPnaQbcnY-p)}^I_#KC4^=FS|{zcXv53%Ui_I`>EvIieGl~!+k(_G01Lx1j~hlK zcb>)CNriOt*8ZS_{{QdX;GR0k)X4kS*;SdSyIWV_RFL|6uo-PS!_Q=bD0Bw;j(RS!cc;XdKo2+kiB4w? zxXq#Tc{&$W!fQ07jaESR5XhoP6Jtq=`>DEZnz>Vm-c&|7Hk~VbQf*()|5@C%<3W9Y z`^O@Nqv$)_FNnMIh$zMEV%3UtOV%Adr6RR+#v(NV=%P!2m2qXTmrL&t`-@~pZNV)f zJLL1}jL;%p$}rk&I`T+Adi#4J{pQ1@f;0m#z}EQ^$K-W2it=g9+`8`?p7weqAB8Pv zXD|(zf~$X9C8%%?c)jobta=kzimAs-TMrk%xFlp(Jx(i%8M(TKH)@Ti%jWxy)z z`IM&&Qc_G*!_2SZ+}e%j+BN0`fnrTYPw-5o?B4*!>YLu(8UQF8wRMq_n8g?JGp0RpRZ_~(;Do|9#O)=D0R=vC

} @else { - - {{ "resetPasswordAutoEnrollInviteWarning" | i18n }} - + @if (userType === SetInitialPasswordUserType.OFFBOARDED_TDE_ORG_USER_UNTRUSTED_DEVICE) { +
+ + {{ "loginOnTrustedDeviceOrAskAdminToAssignPassword" | i18n }} + + + } @else { + + {{ "resetPasswordAutoEnrollInviteWarning" | i18n }} + - + + } } diff --git a/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.ts b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.ts index 2de9aaf7b75..27d4c11f692 100644 --- a/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.ts +++ b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.ts @@ -1,6 +1,7 @@ import { CommonModule } from "@angular/common"; import { Component, OnInit } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; +// import { NoAccess } from "libs/components/src/icon/icons"; import { firstValueFrom } from "rxjs"; // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. @@ -30,9 +31,11 @@ import { SyncService } from "@bitwarden/common/platform/sync"; import { UserId } from "@bitwarden/common/types/guid"; import { AnonLayoutWrapperDataService, + ButtonModule, CalloutComponent, DialogService, ToastService, + Icons, } from "@bitwarden/components"; import { I18nPipe } from "@bitwarden/ui-common"; @@ -46,7 +49,7 @@ import { @Component({ standalone: true, templateUrl: "set-initial-password.component.html", - imports: [CalloutComponent, CommonModule, InputPasswordComponent, I18nPipe], + imports: [ButtonModule, CalloutComponent, CommonModule, InputPasswordComponent, I18nPipe], }) export class SetInitialPasswordComponent implements OnInit { protected inputPasswordFlow = InputPasswordFlow.SetInitialPasswordAuthedUser; @@ -106,6 +109,14 @@ export class SetInitialPasswordComponent implements OnInit { this.masterPasswordService.forceSetPasswordReason$(this.userId), ); + if (this.forceSetPasswordReason === ForceSetPasswordReason.TdeOffboardingUntrustedDevice) { + this.userType = SetInitialPasswordUserType.OFFBOARDED_TDE_ORG_USER_UNTRUSTED_DEVICE; + this.anonLayoutWrapperDataService.setAnonLayoutWrapperData({ + pageTitle: { key: "unableToCompleteLogin" }, + pageIcon: Icons.NoAccess, + }); + } + if (this.forceSetPasswordReason === ForceSetPasswordReason.SsoNewJitProvisionedUser) { this.userType = SetInitialPasswordUserType.JIT_PROVISIONED_MP_ORG_USER; this.anonLayoutWrapperDataService.setAnonLayoutWrapperData({ diff --git a/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.service.abstraction.ts b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.service.abstraction.ts index c167c1675c1..c1f6ba1a5ec 100644 --- a/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.service.abstraction.ts +++ b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.service.abstraction.ts @@ -22,9 +22,15 @@ export const _SetInitialPasswordUserType = { /** * A user in an org that offboarded from trusted device encryption and is now a - * master-password-encryption org + * master-password-encryption org. User is on a trusted device. */ OFFBOARDED_TDE_ORG_USER: "offboarded_tde_org_user", + + /** + * A user in an org that offboarded from trusted device encryption and is now a + * master-password-encryption org. User is on an untrusted device. + */ + OFFBOARDED_TDE_ORG_USER_UNTRUSTED_DEVICE: "offboarded_tde_org_user_untrusted_device", } as const; type _SetInitialPasswordUserType = typeof _SetInitialPasswordUserType; diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 96a95de501e..acb1553387b 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -498,6 +498,7 @@ const safeProviders: SafeProvider[] = [ VaultTimeoutSettingsService, KdfConfigService, TaskSchedulerService, + ConfigService, ], }), safeProvider({ diff --git a/libs/auth/src/common/login-strategies/login.strategy.ts b/libs/auth/src/common/login-strategies/login.strategy.ts index f1b7d236fb7..dc51ce1fa04 100644 --- a/libs/auth/src/common/login-strategies/login.strategy.ts +++ b/libs/auth/src/common/login-strategies/login.strategy.ts @@ -265,8 +265,6 @@ export abstract class LoginStrategy { result.resetMasterPassword = response.resetMasterPassword; - await this.processForceSetPasswordReason(response.forcePasswordReset, userId); - if (response.twoFactorToken != null) { // note: we can read email from access token b/c it was saved in saveAccountInformation const userEmail = await this.tokenService.getEmail(); @@ -278,6 +276,9 @@ export abstract class LoginStrategy { await this.setUserKey(response, userId); await this.setPrivateKey(response, userId); + // This needs to run after the keys are set because it checks for the existence of the encrypted private key + await this.processForceSetPasswordReason(response.forcePasswordReset, userId); + this.messagingService.send("loggedIn"); return result; diff --git a/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts index e5326a7ea97..98142003c6e 100644 --- a/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts @@ -5,10 +5,12 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { AdminAuthRequestStorable } from "@bitwarden/common/auth/models/domain/admin-auth-req-storable"; +import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response"; import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; import { IUserDecryptionOptionsServerResponse } from "@bitwarden/common/auth/models/response/user-decryption-options/user-decryption-options.response"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/key-management/device-trust/abstractions/device-trust.service.abstraction"; import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service"; @@ -19,6 +21,7 @@ import { } from "@bitwarden/common/key-management/vault-timeout"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -26,6 +29,7 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { EncryptedString } from "@bitwarden/common/platform/models/domain/enc-string"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec"; import { CsprngArray } from "@bitwarden/common/types/csprng"; @@ -66,6 +70,7 @@ describe("SsoLoginStrategy", () => { let vaultTimeoutSettingsService: MockProxy; let kdfConfigService: MockProxy; let environmentService: MockProxy; + let configService: MockProxy; let ssoLoginStrategy: SsoLoginStrategy; let credentials: SsoLoginCredentials; @@ -102,6 +107,7 @@ describe("SsoLoginStrategy", () => { vaultTimeoutSettingsService = mock(); kdfConfigService = mock(); environmentService = mock(); + configService = mock(); tokenService.getTwoFactorToken.mockResolvedValue(null); appIdService.getAppId.mockResolvedValue(deviceId); @@ -133,6 +139,7 @@ describe("SsoLoginStrategy", () => { deviceTrustService, authRequestService, i18nService, + configService, accountService, masterPasswordService, keyService, @@ -203,6 +210,45 @@ describe("SsoLoginStrategy", () => { ); }); + describe("given the PM16117_SetInitialPasswordRefactor feature flag is ON", () => { + beforeEach(() => { + configService.getFeatureFlag.mockImplementation(async (flag) => { + if (flag === FeatureFlag.PM16117_SetInitialPasswordRefactor) { + return true; + } + return false; + }); + }); + + describe("given the user does not have the `trustedDeviceOption`, does not have a master password, is not using key connector, does not have a user key, but they DO have a `userKeyEncryptedPrivateKey`", () => { + it("should set the forceSetPasswordReason to TdeOffboardingUntrustedDevice", async () => { + // Arrange + const mockUserDecryptionOptions: IUserDecryptionOptionsServerResponse = { + HasMasterPassword: false, + TrustedDeviceOption: null, + KeyConnectorOption: null, + }; + const tokenResponse = identityTokenResponseFactory(null, mockUserDecryptionOptions); + apiService.postIdentityToken.mockResolvedValue(tokenResponse); + + keyService.userEncryptedPrivateKey$.mockReturnValue( + of("userKeyEncryptedPrivateKey" as EncryptedString), + ); + keyService.hasUserKey.mockResolvedValue(false); + + // Act + await ssoLoginStrategy.logIn(credentials); + + // Assert + expect(masterPasswordService.mock.setForceSetPasswordReason).toHaveBeenCalledTimes(1); + expect(masterPasswordService.mock.setForceSetPasswordReason).toHaveBeenCalledWith( + ForceSetPasswordReason.TdeOffboardingUntrustedDevice, + userId, + ); + }); + }); + }); + describe("Trusted Device Decryption", () => { const deviceKeyBytesLength = 64; const mockDeviceKeyRandomBytes = new Uint8Array(deviceKeyBytesLength).buffer as CsprngArray; diff --git a/libs/auth/src/common/login-strategies/sso-login.strategy.ts b/libs/auth/src/common/login-strategies/sso-login.strategy.ts index 4f5479cd5c4..a48ffd09503 100644 --- a/libs/auth/src/common/login-strategies/sso-login.strategy.ts +++ b/libs/auth/src/common/login-strategies/sso-login.strategy.ts @@ -9,9 +9,11 @@ import { SsoTokenRequest } from "@bitwarden/common/auth/models/request/identity- import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response"; import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; import { HttpStatusCode } from "@bitwarden/common/enums"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/key-management/device-trust/abstractions/device-trust.service.abstraction"; import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { UserId } from "@bitwarden/common/types/guid"; @@ -72,6 +74,7 @@ export class SsoLoginStrategy extends LoginStrategy { private deviceTrustService: DeviceTrustServiceAbstraction, private authRequestService: AuthRequestServiceAbstraction, private i18nService: I18nService, + private configService: ConfigService, ...sharedDeps: ConstructorParameters ) { super(...sharedDeps); @@ -343,13 +346,38 @@ export class SsoLoginStrategy extends LoginStrategy { tokenResponse: IdentityTokenResponse, userId: UserId, ): Promise { - const newSsoUser = tokenResponse.key == null; + const isSetInitialPasswordFlagOn = await this.configService.getFeatureFlag( + FeatureFlag.PM16117_SetInitialPasswordRefactor, + ); - if (!newSsoUser) { - await this.keyService.setPrivateKey( - tokenResponse.privateKey ?? (await this.createKeyPairForOldAccount(userId)), - userId, - ); + if (isSetInitialPasswordFlagOn) { + if (tokenResponse.hasMasterKeyEncryptedUserKey()) { + // User has masterKeyEncryptedUserKey, so set the userKeyEncryptedPrivateKey + // Note: new JIT provisioned SSO users will not yet have a user asymmetric key pair + // and so we don't want them falling into the createKeyPairForOldAccount flow + await this.keyService.setPrivateKey( + tokenResponse.privateKey ?? (await this.createKeyPairForOldAccount(userId)), + userId, + ); + } else if (tokenResponse.privateKey) { + // User doesn't have masterKeyEncryptedUserKey but they do have a userKeyEncryptedPrivateKey + // This is just existing TDE users or a TDE offboarder on an untrusted device + await this.keyService.setPrivateKey(tokenResponse.privateKey, userId); + } + // else { + // User could be new JIT provisioned SSO user in either a MP encryption org OR a TDE org. + // In either case, the user doesn't yet have a user asymmetric key pair, a user key, or a master key + master key encrypted user key. + // } + } else { + // A user that does not yet have a masterKeyEncryptedUserKey set is a new SSO user + const newSsoUser = tokenResponse.key == null; + + if (!newSsoUser) { + await this.keyService.setPrivateKey( + tokenResponse.privateKey ?? (await this.createKeyPairForOldAccount(userId)), + userId, + ); + } } } @@ -389,7 +417,7 @@ export class SsoLoginStrategy extends LoginStrategy { return false; } - // Check for TDE offboarding - user is being offboarded from TDE and needs to set a password + // Check for TDE offboarding - user is being offboarded from TDE and needs to set a password on a trusted device if (userDecryptionOptions.trustedDeviceOption?.isTdeOffboarding) { await this.masterPasswordService.setForceSetPasswordReason( ForceSetPasswordReason.TdeOffboarding, @@ -398,6 +426,39 @@ export class SsoLoginStrategy extends LoginStrategy { return true; } + // If a TDE org user in an offboarding state logs in on an untrusted device, then they will receive their existing userKeyEncryptedPrivateKey from the server, but + // TDE would not have been able to decrypt their user key b/c we don't send down TDE as a valid decryption option, so the user key will be unavilable here for TDE org users on untrusted devices. + // - UserDecryptionOptions.trustedDeviceOption is undefined -- device isn't trusted. + // - UserDecryptionOptions.hasMasterPassword is false -- user doesn't have a master password. + // - UserDecryptionOptions.UsesKeyConnector is undefined. -- they aren't using key connector + // - UserKey is not set after successful login -- because automatic decryption is not available + // - userKeyEncryptedPrivateKey is set after successful login -- this is the key differentiator between a TDE org user logging into an untrusted device and MP encryption JIT provisioned user logging in for the first time. + const isSetInitialPasswordFlagOn = await this.configService.getFeatureFlag( + FeatureFlag.PM16117_SetInitialPasswordRefactor, + ); + + if (isSetInitialPasswordFlagOn) { + const hasUserKeyEncryptedPrivateKey = await firstValueFrom( + this.keyService.userEncryptedPrivateKey$(userId), + ); + const hasUserKey = await this.keyService.hasUserKey(userId); + + // TODO: PM-23491 we should explore consolidating this logic into a flag on the server. It could be set when an org is switched from TDE to MP encryption for each org user. + if ( + !userDecryptionOptions.trustedDeviceOption && + !userDecryptionOptions.hasMasterPassword && + !userDecryptionOptions.keyConnectorOption?.keyConnectorUrl && + hasUserKeyEncryptedPrivateKey && + !hasUserKey + ) { + await this.masterPasswordService.setForceSetPasswordReason( + ForceSetPasswordReason.TdeOffboardingUntrustedDevice, + userId, + ); + return true; + } + } + // Check if user has permission to set password but hasn't yet if ( !userDecryptionOptions.hasMasterPassword && diff --git a/libs/auth/src/common/services/login-strategies/login-strategy.service.spec.ts b/libs/auth/src/common/services/login-strategies/login-strategy.service.spec.ts index 981f5592621..8ddee96dd57 100644 --- a/libs/auth/src/common/services/login-strategies/login-strategy.service.spec.ts +++ b/libs/auth/src/common/services/login-strategies/login-strategy.service.spec.ts @@ -21,6 +21,7 @@ import { VaultTimeoutSettingsService, } from "@bitwarden/common/key-management/vault-timeout"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -75,6 +76,7 @@ describe("LoginStrategyService", () => { let vaultTimeoutSettingsService: MockProxy; let kdfConfigService: MockProxy; let taskSchedulerService: MockProxy; + let configService: MockProxy; let stateProvider: FakeGlobalStateProvider; let loginStrategyCacheExpirationState: FakeGlobalState; @@ -107,6 +109,7 @@ describe("LoginStrategyService", () => { vaultTimeoutSettingsService = mock(); kdfConfigService = mock(); taskSchedulerService = mock(); + configService = mock(); sut = new LoginStrategyService( accountService, @@ -134,6 +137,7 @@ describe("LoginStrategyService", () => { vaultTimeoutSettingsService, kdfConfigService, taskSchedulerService, + configService, ); loginStrategyCacheExpirationState = stateProvider.getFake(CACHE_EXPIRATION_KEY); diff --git a/libs/auth/src/common/services/login-strategies/login-strategy.service.ts b/libs/auth/src/common/services/login-strategies/login-strategy.service.ts index a9b7ef250bc..767d52de370 100644 --- a/libs/auth/src/common/services/login-strategies/login-strategy.service.ts +++ b/libs/auth/src/common/services/login-strategies/login-strategy.service.ts @@ -26,6 +26,7 @@ import { VaultTimeoutSettingsService } from "@bitwarden/common/key-management/va import { PreloginRequest } from "@bitwarden/common/models/request/prelogin.request"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -131,6 +132,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction { protected vaultTimeoutSettingsService: VaultTimeoutSettingsService, protected kdfConfigService: KdfConfigService, protected taskSchedulerService: TaskSchedulerService, + protected configService: ConfigService, ) { this.currentAuthnTypeState = this.stateProvider.get(CURRENT_LOGIN_STRATEGY_KEY); this.loginStrategyCacheState = this.stateProvider.get(CACHE_KEY); @@ -423,6 +425,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction { this.deviceTrustService, this.authRequestService, this.i18nService, + this.configService, ...sharedDeps, ); case AuthenticationType.UserApiKey: diff --git a/libs/common/src/auth/models/domain/force-set-password-reason.ts b/libs/common/src/auth/models/domain/force-set-password-reason.ts index 4a8ec8529cf..9e2069b30d6 100644 --- a/libs/common/src/auth/models/domain/force-set-password-reason.ts +++ b/libs/common/src/auth/models/domain/force-set-password-reason.ts @@ -37,6 +37,15 @@ export enum ForceSetPasswordReason { */ TdeOffboarding, + /** + * Occurs when an org admin switches the org from trusted-device-encryption to master-password-encryption, + * which forces the org user to set an initial password. User must not already have a master password, + * and they must be on an untrusted device. + * + * Calculated on client based on server flags and user state. + */ + TdeOffboardingUntrustedDevice, + /*---------------------------- Change Existing Password -----------------------------*/ diff --git a/libs/common/src/auth/models/response/identity-token.response.ts b/libs/common/src/auth/models/response/identity-token.response.ts index f8c40b41bf0..2d991e9f349 100644 --- a/libs/common/src/auth/models/response/identity-token.response.ts +++ b/libs/common/src/auth/models/response/identity-token.response.ts @@ -17,8 +17,8 @@ export class IdentityTokenResponse extends BaseResponse { tokenType: string; resetMasterPassword: boolean; - privateKey: string; - key?: EncString; + privateKey: string; // userKeyEncryptedPrivateKey + key?: EncString; // masterKeyEncryptedUserKey twoFactorToken: string; kdf: KdfType; kdfIterations: number; @@ -62,4 +62,8 @@ export class IdentityTokenResponse extends BaseResponse { ); } } + + hasMasterKeyEncryptedUserKey(): boolean { + return Boolean(this.key); + } } From b92879a839263542a3b698040436144685b0691c Mon Sep 17 00:00:00 2001 From: SmithThe4th Date: Tue, 8 Jul 2025 13:52:10 -0400 Subject: [PATCH 079/239] Fix card filter restriction when user belongs to multiple orgs (#15521) --- .../vault-popup-list-filters.service.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts b/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts index 610b099952d..dde11aac5f7 100644 --- a/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts +++ b/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts @@ -266,15 +266,15 @@ export class VaultPopupListFiltersService { readonly cipherTypes$: Observable[]> = this.restrictedItemTypesService.restricted$.pipe( map((restrictedTypes) => { - const restrictedCipherTypes = restrictedTypes.map((r) => r.cipherType); - - return CIPHER_MENU_ITEMS.filter((item) => !restrictedCipherTypes.includes(item.type)).map( - (item) => ({ - value: item.type, - label: this.i18nService.t(item.labelKey), - icon: item.icon, - }), - ); + return CIPHER_MENU_ITEMS.filter((item) => { + const restriction = restrictedTypes.find((r) => r.cipherType === item.type); + // Show if no restriction or if the restriction allows viewing in at least one org + return !restriction || restriction.allowViewOrgIds.length > 0; + }).map((item) => ({ + value: item.type, + label: this.i18nService.t(item.labelKey), + icon: item.icon, + })); }), ); From d1b1b5c57b70e6502b158f15f0f03c7537fe4242 Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Tue, 8 Jul 2025 19:52:32 +0200 Subject: [PATCH 080/239] Remove "require MP on restart option on mac" (#15395) --- apps/desktop/src/app/accounts/settings.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/src/app/accounts/settings.component.html b/apps/desktop/src/app/accounts/settings.component.html index e56615c9122..29480519646 100644 --- a/apps/desktop/src/app/accounts/settings.component.html +++ b/apps/desktop/src/app/accounts/settings.component.html @@ -152,7 +152,7 @@ supportsBiometric && this.form.value.biometric && (userHasMasterPassword || (this.form.value.pin && userHasPinSet)) && - !this.isLinux + this.isWindows " >
From 609ca436931758e49a1e4e10c101ad1b69de4f74 Mon Sep 17 00:00:00 2001 From: SmithThe4th Date: Tue, 8 Jul 2025 13:59:00 -0400 Subject: [PATCH 081/239] [PM-23303] Cards showing in trash (#15517) * Filter out restricted items from all decrypted ciphers * Fixed tests --- .../services/vault-popup-items.service.spec.ts | 13 +++++++++++++ .../popup/services/vault-popup-items.service.ts | 11 ++++++++++- .../vault-popup-list-filters.service.spec.ts | 4 ---- .../services/vault-popup-list-filters.service.ts | 8 +------- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/apps/browser/src/vault/popup/services/vault-popup-items.service.spec.ts b/apps/browser/src/vault/popup/services/vault-popup-items.service.spec.ts index 63cd0d90d05..28bf710ec60 100644 --- a/apps/browser/src/vault/popup/services/vault-popup-items.service.spec.ts +++ b/apps/browser/src/vault/popup/services/vault-popup-items.service.spec.ts @@ -19,6 +19,10 @@ import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherData } from "@bitwarden/common/vault/models/data/cipher.data"; import { LocalData } from "@bitwarden/common/vault/models/data/local.data"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { + RestrictedCipherType, + RestrictedItemTypesService, +} from "@bitwarden/common/vault/services/restricted-item-types.service"; import { InlineMenuFieldQualificationService } from "../../../autofill/services/inline-menu-field-qualification.service"; import { BrowserApi } from "../../../platform/browser/browser-api"; @@ -58,6 +62,11 @@ describe("VaultPopupItemsService", () => { const userId = Utils.newGuid() as UserId; const accountServiceMock = mockAccountServiceWith(userId); + const restrictedItemTypesService = { + restricted$: new BehaviorSubject([]), + isCipherRestricted: jest.fn().mockReturnValue(false), + }; + beforeEach(() => { allCiphers = cipherFactory(10); const cipherList = Object.values(allCiphers); @@ -154,6 +163,10 @@ describe("VaultPopupItemsService", () => { useValue: inlineMenuFieldQualificationServiceMock, }, { provide: PopupViewCacheService, useValue: viewCacheService }, + { + provide: RestrictedItemTypesService, + useValue: restrictedItemTypesService, + }, ], }); diff --git a/apps/browser/src/vault/popup/services/vault-popup-items.service.ts b/apps/browser/src/vault/popup/services/vault-popup-items.service.ts index 20bdbd2eefe..d47abb9e6b3 100644 --- a/apps/browser/src/vault/popup/services/vault-popup-items.service.ts +++ b/apps/browser/src/vault/popup/services/vault-popup-items.service.ts @@ -31,6 +31,7 @@ import { SearchService } from "@bitwarden/common/vault/abstractions/search.servi import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service"; import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service"; import { runInsideAngular } from "../../../platform/browser/run-inside-angular.operator"; import { PopupViewCacheService } from "../../../platform/popup/view-cache/popup-view-cache.service"; @@ -107,9 +108,16 @@ export class VaultPopupItemsService { combineLatest([ Utils.asyncToObservable(() => this.cipherService.getAllDecrypted(userId)), this.cipherService.failedToDecryptCiphers$(userId), + this.restrictedItemTypesService.restricted$.pipe(startWith([])), ]), ), - map(([ciphers, failedToDecryptCiphers]) => [...(failedToDecryptCiphers || []), ...ciphers]), + map(([ciphers, failedToDecryptCiphers, restrictions]) => { + const allCiphers = [...(failedToDecryptCiphers || []), ...ciphers]; + + return allCiphers.filter( + (cipher) => !this.restrictedItemTypesService.isCipherRestricted(cipher, restrictions), + ); + }), ), ), shareReplay({ refCount: true, bufferSize: 1 }), @@ -307,6 +315,7 @@ export class VaultPopupItemsService { private syncService: SyncService, private accountService: AccountService, private ngZone: NgZone, + private restrictedItemTypesService: RestrictedItemTypesService, ) {} applyFilter(newSearchText: string) { diff --git a/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.spec.ts b/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.spec.ts index baa34d7bdbe..1e56fd4d352 100644 --- a/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.spec.ts +++ b/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.spec.ts @@ -486,10 +486,6 @@ describe("VaultPopupListFiltersService", () => { { type: CipherType.SecureNote, collectionIds: [], organizationId: null }, ] as CipherView[]; - beforeEach(() => { - restrictedItemTypesService.restricted$.next([]); - }); - it("filters by cipherType", (done) => { service.filterFunction$.subscribe((filterFunction) => { expect(filterFunction(ciphers)).toEqual([ciphers[0]]); diff --git a/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts b/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts index dde11aac5f7..12d0c445b4c 100644 --- a/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts +++ b/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts @@ -215,10 +215,9 @@ export class VaultPopupListFiltersService { */ filterFunction$: Observable<(ciphers: CipherView[]) => CipherView[]> = combineLatest([ this.filters$, - this.restrictedItemTypesService.restricted$.pipe(startWith([])), ]).pipe( map( - ([filters, restrictions]) => + ([filters]) => (ciphers: CipherView[]) => ciphers.filter((cipher) => { // Vault popup lists never shows deleted ciphers @@ -226,11 +225,6 @@ export class VaultPopupListFiltersService { return false; } - // Check if cipher type is restricted (with organization exemptions) - if (this.restrictedItemTypesService.isCipherRestricted(cipher, restrictions)) { - return false; - } - if (filters.cipherType !== null && cipher.type !== filters.cipherType) { return false; } From d5e7f3bd0406e509b17f2e1abb532fdda29c5cc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9C=A8=20Audrey=20=E2=9C=A8?= Date: Tue, 8 Jul 2025 16:02:14 -0400 Subject: [PATCH 082/239] [PM-23514] add send access storage location (#15523) --- libs/common/src/platform/state/state-definitions.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/common/src/platform/state/state-definitions.ts b/libs/common/src/platform/state/state-definitions.ts index f9e6a5007c7..593a28d04c5 100644 --- a/libs/common/src/platform/state/state-definitions.ts +++ b/libs/common/src/platform/state/state-definitions.ts @@ -155,6 +155,7 @@ export const SEND_DISK = new StateDefinition("encryptedSend", "disk", { export const SEND_MEMORY = new StateDefinition("decryptedSend", "memory", { browser: "memory-large-object", }); +export const SEND_ACCESS_AUTH_MEMORY = new StateDefinition("sendAccessAuth", "memory"); // Vault From 682f1f83d9c211e886d6f05fc557eddb25c4c5c2 Mon Sep 17 00:00:00 2001 From: Bryan Cunningham Date: Tue, 8 Jul 2025 16:13:25 -0400 Subject: [PATCH 083/239] [CL-295] Use aria-disabled on buttons (#15009) * Use aria-disabled for button disabled state * remove import from testing story * use aria-disabled attr on bitLink button * remove unnecessary story attrs * remove disabled attr if on button element * create caprture click util * use caprture click util and fix tests * fix lint errors * fix event type * combine click capture and attr modification * fix lint error. Commit spec changes left out of last commit in error * inject element ref * move aria-disabled styles to common * move disabled logic into util * fix broken async actions stories * fix broken tests asserting disabled attr * have test check for string true vlalue * fix Signal type * fix form-field story import * remove injector left in error * aria-disable icon buttons * update form component css selector to look for aria-disabled buttons * use correct types. pass nativeElement directly * add JSDoc comment for util function --------- Co-authored-by: Will Martin --- .../vault-generator-dialog.component.spec.ts | 18 ++--- .../web-generator-dialog.component.spec.ts | 18 ++--- .../src/async-actions/in-forms.stories.ts | 18 ++++- .../src/async-actions/standalone.stories.ts | 12 +++- .../src/button/button.component.spec.ts | 14 ++-- .../components/src/button/button.component.ts | 41 ++++++++---- .../src/form-field/form-field.component.html | 2 +- .../src/form-field/form-field.stories.ts | 1 + .../src/icon-button/icon-button.component.ts | 67 ++++++++++++------- libs/components/src/link/link.directive.ts | 27 +++++++- .../src/utils/aria-disable-element.ts | 29 ++++++++ libs/components/src/utils/index.ts | 1 + 12 files changed, 175 insertions(+), 73 deletions(-) create mode 100644 libs/components/src/utils/aria-disable-element.ts diff --git a/apps/browser/src/vault/popup/components/vault-v2/vault-generator-dialog/vault-generator-dialog.component.spec.ts b/apps/browser/src/vault/popup/components/vault-v2/vault-generator-dialog/vault-generator-dialog.component.spec.ts index b5d35e2005e..b65138dac3a 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/vault-generator-dialog/vault-generator-dialog.component.spec.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/vault-generator-dialog/vault-generator-dialog.component.spec.ts @@ -76,10 +76,8 @@ describe("VaultGeneratorDialogComponent", () => { component.onValueGenerated("test-password"); fixture.detectChanges(); - const button = fixture.debugElement.query( - By.css("[data-testid='select-button']"), - ).nativeElement; - expect(button.disabled).toBe(false); + const button = fixture.debugElement.query(By.css("[data-testid='select-button']")); + expect(button.attributes["aria-disabled"]).toBe(undefined); }); it("should disable the button if no value has been generated", () => { @@ -90,10 +88,8 @@ describe("VaultGeneratorDialogComponent", () => { generator.algorithmSelected.emit({ useGeneratedValue: "Use Password" } as any); fixture.detectChanges(); - const button = fixture.debugElement.query( - By.css("[data-testid='select-button']"), - ).nativeElement; - expect(button.disabled).toBe(true); + const button = fixture.debugElement.query(By.css("[data-testid='select-button']")); + expect(button.attributes["aria-disabled"]).toBe("true"); }); it("should disable the button if no algorithm is selected", () => { @@ -104,10 +100,8 @@ describe("VaultGeneratorDialogComponent", () => { generator.valueGenerated.emit("test-password"); fixture.detectChanges(); - const button = fixture.debugElement.query( - By.css("[data-testid='select-button']"), - ).nativeElement; - expect(button.disabled).toBe(true); + const button = fixture.debugElement.query(By.css("[data-testid='select-button']")); + expect(button.attributes["aria-disabled"]).toBe("true"); }); it("should update button text when algorithm is selected", () => { diff --git a/apps/web/src/app/vault/components/web-generator-dialog/web-generator-dialog.component.spec.ts b/apps/web/src/app/vault/components/web-generator-dialog/web-generator-dialog.component.spec.ts index 085a3d0d4b0..afb32738901 100644 --- a/apps/web/src/app/vault/components/web-generator-dialog/web-generator-dialog.component.spec.ts +++ b/apps/web/src/app/vault/components/web-generator-dialog/web-generator-dialog.component.spec.ts @@ -70,10 +70,8 @@ describe("WebVaultGeneratorDialogComponent", () => { generator.valueGenerated.emit("test-password"); fixture.detectChanges(); - const button = fixture.debugElement.query( - By.css("[data-testid='select-button']"), - ).nativeElement; - expect(button.disabled).toBe(false); + const button = fixture.debugElement.query(By.css("[data-testid='select-button']")); + expect(button.attributes["aria-disabled"]).toBe(undefined); }); it("should disable the button if no value has been generated", () => { @@ -84,10 +82,8 @@ describe("WebVaultGeneratorDialogComponent", () => { generator.algorithmSelected.emit({ useGeneratedValue: "Use Password" } as any); fixture.detectChanges(); - const button = fixture.debugElement.query( - By.css("[data-testid='select-button']"), - ).nativeElement; - expect(button.disabled).toBe(true); + const button = fixture.debugElement.query(By.css("[data-testid='select-button']")); + expect(button.attributes["aria-disabled"]).toBe("true"); }); it("should disable the button if no algorithm is selected", () => { @@ -98,10 +94,8 @@ describe("WebVaultGeneratorDialogComponent", () => { generator.valueGenerated.emit("test-password"); fixture.detectChanges(); - const button = fixture.debugElement.query( - By.css("[data-testid='select-button']"), - ).nativeElement; - expect(button.disabled).toBe(true); + const button = fixture.debugElement.query(By.css("[data-testid='select-button']")); + expect(button.attributes["aria-disabled"]).toBe("true"); }); it("should close with selected value when confirmed", () => { diff --git a/libs/components/src/async-actions/in-forms.stories.ts b/libs/components/src/async-actions/in-forms.stories.ts index 857a23227f5..7f51a8bdad2 100644 --- a/libs/components/src/async-actions/in-forms.stories.ts +++ b/libs/components/src/async-actions/in-forms.stories.ts @@ -13,6 +13,7 @@ import { IconButtonModule } from "../icon-button"; import { InputModule } from "../input/input.module"; import { I18nMockService } from "../utils/i18n-mock.service"; +import { AsyncActionsModule } from "./async-actions.module"; import { BitActionDirective } from "./bit-action.directive"; import { BitSubmitDirective } from "./bit-submit.directive"; import { BitFormButtonDirective } from "./form-button.directive"; @@ -40,6 +41,13 @@ const template = ` @Component({ selector: "app-promise-example", template, + imports: [ + AsyncActionsModule, + ButtonModule, + FormFieldModule, + IconButtonModule, + ReactiveFormsModule, + ], }) class PromiseExampleComponent { formObj = this.formBuilder.group({ @@ -77,6 +85,13 @@ class PromiseExampleComponent { @Component({ selector: "app-observable-example", template, + imports: [ + AsyncActionsModule, + ButtonModule, + FormFieldModule, + IconButtonModule, + ReactiveFormsModule, + ], }) class ObservableExampleComponent { formObj = this.formBuilder.group({ @@ -109,7 +124,6 @@ export default { title: "Component Library/Async Actions/In Forms", decorators: [ moduleMetadata({ - declarations: [PromiseExampleComponent, ObservableExampleComponent], imports: [ BitSubmitDirective, BitFormButtonDirective, @@ -120,6 +134,8 @@ export default { ButtonModule, IconButtonModule, BitActionDirective, + PromiseExampleComponent, + ObservableExampleComponent, ], providers: [ { diff --git a/libs/components/src/async-actions/standalone.stories.ts b/libs/components/src/async-actions/standalone.stories.ts index d6f7f978bd5..542825eb17a 100644 --- a/libs/components/src/async-actions/standalone.stories.ts +++ b/libs/components/src/async-actions/standalone.stories.ts @@ -9,6 +9,7 @@ import { ValidationService } from "@bitwarden/common/platform/abstractions/valid import { ButtonModule } from "../button"; import { IconButtonModule } from "../icon-button"; +import { AsyncActionsModule } from "./async-actions.module"; import { BitActionDirective } from "./bit-action.directive"; const template = /*html*/ ` @@ -20,6 +21,8 @@ const template = /*html*/ ` @Component({ template, selector: "app-promise-example", + imports: [AsyncActionsModule, ButtonModule, IconButtonModule], + standalone: true, }) class PromiseExampleComponent { statusEmoji = "🟡"; @@ -36,6 +39,7 @@ class PromiseExampleComponent { @Component({ template, selector: "app-action-resolves-quickly", + imports: [AsyncActionsModule, ButtonModule, IconButtonModule], }) class ActionResolvesQuicklyComponent { statusEmoji = "🟡"; @@ -53,6 +57,7 @@ class ActionResolvesQuicklyComponent { @Component({ template, selector: "app-observable-example", + imports: [AsyncActionsModule, ButtonModule, IconButtonModule], }) class ObservableExampleComponent { action = () => { @@ -63,6 +68,7 @@ class ObservableExampleComponent { @Component({ template, selector: "app-rejected-promise-example", + imports: [AsyncActionsModule, ButtonModule, IconButtonModule], }) class RejectedPromiseExampleComponent { action = async () => { @@ -76,13 +82,15 @@ export default { title: "Component Library/Async Actions/Standalone", decorators: [ moduleMetadata({ - declarations: [ + imports: [ + ButtonModule, + IconButtonModule, + BitActionDirective, PromiseExampleComponent, ObservableExampleComponent, RejectedPromiseExampleComponent, ActionResolvesQuicklyComponent, ], - imports: [ButtonModule, IconButtonModule, BitActionDirective], providers: [ { provide: ValidationService, diff --git a/libs/components/src/button/button.component.spec.ts b/libs/components/src/button/button.component.spec.ts index 6ddbc172803..1651b6cf12a 100644 --- a/libs/components/src/button/button.component.spec.ts +++ b/libs/components/src/button/button.component.spec.ts @@ -34,23 +34,25 @@ describe("Button", () => { expect(buttonDebugElement.nativeElement.disabled).toBeFalsy(); }); - it("should be disabled when disabled is true", () => { + it("should be aria-disabled and not html attribute disabled when disabled is true", () => { testAppComponent.disabled = true; fixture.detectChanges(); - - expect(buttonDebugElement.nativeElement.disabled).toBeTruthy(); + expect(buttonDebugElement.attributes["aria-disabled"]).toBe("true"); + expect(buttonDebugElement.nativeElement.disabled).toBeFalsy(); // Anchor tags cannot be disabled. }); - it("should be disabled when attribute disabled is true", () => { - expect(disabledButtonDebugElement.nativeElement.disabled).toBeTruthy(); + it("should be aria-disabled not html attribute disabled when attribute disabled is true", () => { + fixture.detectChanges(); + expect(disabledButtonDebugElement.attributes["aria-disabled"]).toBe("true"); + expect(disabledButtonDebugElement.nativeElement.disabled).toBeFalsy(); }); it("should be disabled when loading is true", () => { testAppComponent.loading = true; fixture.detectChanges(); - expect(buttonDebugElement.nativeElement.disabled).toBeTruthy(); + expect(buttonDebugElement.attributes["aria-disabled"]).toBe("true"); }); }); diff --git a/libs/components/src/button/button.component.ts b/libs/components/src/button/button.component.ts index 011360db867..671b1dfb96d 100644 --- a/libs/components/src/button/button.component.ts +++ b/libs/components/src/button/button.component.ts @@ -1,10 +1,21 @@ import { coerceBooleanProperty } from "@angular/cdk/coercion"; import { NgClass } from "@angular/common"; -import { Input, HostBinding, Component, model, computed, input } from "@angular/core"; +import { + Input, + HostBinding, + Component, + model, + computed, + input, + ElementRef, + inject, + Signal, +} from "@angular/core"; import { toObservable, toSignal } from "@angular/core/rxjs-interop"; import { debounce, interval } from "rxjs"; import { ButtonLikeAbstraction, ButtonType, ButtonSize } from "../shared/button-like.abstraction"; +import { ariaDisableElement } from "../utils"; const focusRing = [ "focus-visible:tw-ring-2", @@ -52,7 +63,7 @@ const buttonStyles: Record = { providers: [{ provide: ButtonLikeAbstraction, useExisting: ButtonComponent }], imports: [NgClass], host: { - "[attr.disabled]": "disabledAttr()", + "[attr.aria-disabled]": "disabledAttr()", }, }) export class ButtonComponent implements ButtonLikeAbstraction { @@ -69,27 +80,28 @@ export class ButtonComponent implements ButtonLikeAbstraction { "focus:tw-outline-none", ] .concat(this.block ? ["tw-w-full", "tw-block"] : ["tw-inline-block"]) - .concat(buttonStyles[this.buttonType ?? "secondary"]) .concat( this.showDisabledStyles() || this.disabled() ? [ - "disabled:tw-bg-secondary-300", - "disabled:hover:tw-bg-secondary-300", - "disabled:tw-border-secondary-300", - "disabled:hover:tw-border-secondary-300", - "disabled:!tw-text-muted", - "disabled:hover:!tw-text-muted", - "disabled:tw-cursor-not-allowed", - "disabled:hover:tw-no-underline", + "aria-disabled:!tw-bg-secondary-300", + "hover:tw-bg-secondary-300", + "aria-disabled:tw-border-secondary-300", + "hover:tw-border-secondary-300", + "aria-disabled:!tw-text-muted", + "hover:!tw-text-muted", + "aria-disabled:tw-cursor-not-allowed", + "hover:tw-no-underline", + "aria-disabled:tw-pointer-events-none", ] : [], ) + .concat(buttonStyles[this.buttonType ?? "secondary"]) .concat(buttonSizeStyles[this.size() || "default"]); } protected disabledAttr = computed(() => { const disabled = this.disabled() != null && this.disabled() !== false; - return disabled || this.loading() ? true : null; + return disabled || this.loading() ? true : undefined; }); /** @@ -138,4 +150,9 @@ export class ButtonComponent implements ButtonLikeAbstraction { ); disabled = model(false); + private el = inject(ElementRef); + + constructor() { + ariaDisableElement(this.el.nativeElement, this.disabledAttr as Signal); + } } diff --git a/libs/components/src/form-field/form-field.component.html b/libs/components/src/form-field/form-field.component.html index c4fd018b3ba..ccea0546f3a 100644 --- a/libs/components/src/form-field/form-field.component.html +++ b/libs/components/src/form-field/form-field.component.html @@ -46,7 +46,7 @@
= { const disabledStyles: Record = { contrast: [ - "disabled:tw-opacity-60", - "disabled:hover:tw-border-transparent", - "disabled:hover:tw-bg-transparent", + "aria-disabled:tw-opacity-60", + "aria-disabled:hover:tw-border-transparent", + "aria-disabled:hover:tw-bg-transparent", ], main: [ - "disabled:!tw-text-secondary-300", - "disabled:hover:tw-border-transparent", - "disabled:hover:tw-bg-transparent", + "aria-disabled:!tw-text-secondary-300", + "aria-disabled:hover:tw-border-transparent", + "aria-disabled:hover:tw-bg-transparent", ], muted: [ - "disabled:!tw-text-secondary-300", - "disabled:hover:tw-border-transparent", - "disabled:hover:tw-bg-transparent", + "aria-disabled:!tw-text-secondary-300", + "aria-disabled:hover:tw-border-transparent", + "aria-disabled:hover:tw-bg-transparent", ], primary: [ - "disabled:tw-opacity-60", - "disabled:hover:tw-border-primary-600", - "disabled:hover:tw-bg-primary-600", + "aria-disabled:tw-opacity-60", + "aria-disabled:hover:tw-border-primary-600", + "aria-disabled:hover:tw-bg-primary-600", ], secondary: [ - "disabled:tw-opacity-60", - "disabled:hover:tw-border-text-muted", - "disabled:hover:tw-bg-transparent", - "disabled:hover:!tw-text-muted", + "aria-disabled:tw-opacity-60", + "aria-disabled:hover:tw-border-text-muted", + "aria-disabled:hover:tw-bg-transparent", + "aria-disabled:hover:!tw-text-muted", ], danger: [ - "disabled:!tw-text-secondary-300", - "disabled:hover:tw-border-transparent", - "disabled:hover:tw-bg-transparent", - "disabled:hover:!tw-text-secondary-300", + "aria-disabled:!tw-text-secondary-300", + "aria-disabled:hover:tw-border-transparent", + "aria-disabled:hover:tw-bg-transparent", + "aria-disabled:hover:!tw-text-secondary-300", ], light: [ - "disabled:tw-opacity-60", - "disabled:hover:tw-border-transparent", - "disabled:hover:tw-bg-transparent", + "aria-disabled:tw-opacity-60", + "aria-disabled:hover:tw-border-transparent", + "aria-disabled:hover:tw-bg-transparent", ], unstyled: [], }; @@ -163,7 +173,7 @@ const sizes: Record = { ], imports: [NgClass], host: { - "[attr.disabled]": "disabledAttr()", + "[attr.aria-disabled]": "disabledAttr()", }, }) export class BitIconButtonComponent implements ButtonLikeAbstraction, FocusableElement { @@ -233,5 +243,10 @@ export class BitIconButtonComponent implements ButtonLikeAbstraction, FocusableE return this.elementRef.nativeElement; } - constructor(private elementRef: ElementRef) {} + private elementRef = inject(ElementRef); + + constructor() { + const element = this.elementRef.nativeElement; + ariaDisableElement(element, this.disabledAttr as Signal); + } } diff --git a/libs/components/src/link/link.directive.ts b/libs/components/src/link/link.directive.ts index ad9c94b7831..1a653fd1c83 100644 --- a/libs/components/src/link/link.directive.ts +++ b/libs/components/src/link/link.directive.ts @@ -1,4 +1,14 @@ -import { Input, HostBinding, Directive } from "@angular/core"; +import { + Input, + HostBinding, + Directive, + inject, + ElementRef, + input, + booleanAttribute, +} from "@angular/core"; + +import { ariaDisableElement } from "../utils"; export type LinkType = "primary" | "secondary" | "contrast" | "light"; @@ -58,6 +68,11 @@ const commonStyles = [ "before:tw-transition", "focus-visible:before:tw-ring-2", "focus-visible:tw-z-10", + "aria-disabled:tw-no-underline", + "aria-disabled:tw-pointer-events-none", + "aria-disabled:!tw-text-secondary-300", + "aria-disabled:hover:!tw-text-secondary-300", + "aria-disabled:hover:tw-no-underline", ]; @Directive() @@ -89,9 +104,19 @@ export class AnchorLinkDirective extends LinkDirective { selector: "button[bitLink]", }) export class ButtonLinkDirective extends LinkDirective { + private el = inject(ElementRef); + + disabled = input(false, { transform: booleanAttribute }); + @HostBinding("class") get classList() { return ["before:-tw-inset-y-[0.25rem]"] .concat(commonStyles) .concat(linkStyles[this.linkType] ?? []); } + + constructor() { + super(); + + ariaDisableElement(this.el.nativeElement, this.disabled); + } } diff --git a/libs/components/src/utils/aria-disable-element.ts b/libs/components/src/utils/aria-disable-element.ts new file mode 100644 index 00000000000..f7e02f2cdd1 --- /dev/null +++ b/libs/components/src/utils/aria-disable-element.ts @@ -0,0 +1,29 @@ +import { Signal, effect } from "@angular/core"; +import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; +import { fromEvent } from "rxjs"; + +/** + * a11y helper util used to `aria-disable` elements as opposed to using the HTML `disabled` attr. + * - Removes HTML `disabled` attr and replaces it with `aria-disabled="true"` + * - Captures click events and prevents them from propagating + */ +export function ariaDisableElement(element: HTMLElement, isDisabled: Signal) { + effect(() => { + if (element.hasAttribute("disabled") || isDisabled()) { + // Remove native disabled and set aria-disabled. Capture click event + element.removeAttribute("disabled"); + + element.setAttribute("aria-disabled", "true"); + } + }); + + fromEvent(element, "click") + .pipe(takeUntilDestroyed()) + .subscribe((event: Event) => { + if (isDisabled()) { + event.stopPropagation(); + event.preventDefault(); + return false; + } + }); +} diff --git a/libs/components/src/utils/index.ts b/libs/components/src/utils/index.ts index afadd6b3b41..91fa71cf0e0 100644 --- a/libs/components/src/utils/index.ts +++ b/libs/components/src/utils/index.ts @@ -1,2 +1,3 @@ +export * from "./aria-disable-element"; export * from "./function-to-observable"; export * from "./i18n-mock.service"; From cee4e6c4c73614de1d0c3428685938b789f4ae7b Mon Sep 17 00:00:00 2001 From: Jared McCannon Date: Wed, 9 Jul 2025 07:59:39 -0500 Subject: [PATCH 084/239] This is unused and can be removed. (#15487) --- .../abstractions/organization-user-api.service.ts | 7 ------- .../services/default-organization-user-api.service.ts | 11 ----------- 2 files changed, 18 deletions(-) diff --git a/libs/admin-console/src/common/organization-user/abstractions/organization-user-api.service.ts b/libs/admin-console/src/common/organization-user/abstractions/organization-user-api.service.ts index 3186bdaa84b..ff422231a12 100644 --- a/libs/admin-console/src/common/organization-user/abstractions/organization-user-api.service.ts +++ b/libs/admin-console/src/common/organization-user/abstractions/organization-user-api.service.ts @@ -37,13 +37,6 @@ export abstract class OrganizationUserApiService { }, ): Promise; - /** - * Retrieve a list of groups Ids the specified organization user belongs to - * @param organizationId - Identifier for the user's organization - * @param id - Organization user identifier - */ - abstract getOrganizationUserGroups(organizationId: string, id: string): Promise; - /** * Retrieve full details of all users that belong to the specified organization. * This is only accessible to privileged users, if you need a simple listing of basic details, use diff --git a/libs/admin-console/src/common/organization-user/services/default-organization-user-api.service.ts b/libs/admin-console/src/common/organization-user/services/default-organization-user-api.service.ts index 7289f41d7e7..c16fba258ec 100644 --- a/libs/admin-console/src/common/organization-user/services/default-organization-user-api.service.ts +++ b/libs/admin-console/src/common/organization-user/services/default-organization-user-api.service.ts @@ -48,17 +48,6 @@ export class DefaultOrganizationUserApiService implements OrganizationUserApiSer return new OrganizationUserDetailsResponse(r); } - async getOrganizationUserGroups(organizationId: string, id: string): Promise { - const r = await this.apiService.send( - "GET", - "/organizations/" + organizationId + "/users/" + id + "/groups", - null, - true, - true, - ); - return r; - } - async getAllUsers( organizationId: string, options?: { From 489cbd4856c08699d074840248b555220e2c717f Mon Sep 17 00:00:00 2001 From: Vijay Oommen Date: Wed, 9 Jul 2025 08:18:16 -0500 Subject: [PATCH 085/239] [PM-21652] Notify At Risk Ciphers to change passwords (#14785) --- .../access-intelligence/critical-applications.component.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/critical-applications.component.ts b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/critical-applications.component.ts index 765d979bbe6..fcca568da6e 100644 --- a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/critical-applications.component.ts +++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/critical-applications.component.ts @@ -144,8 +144,10 @@ export class CriticalApplicationsComponent implements OnInit { const apps = this.dataSource.data; const cipherIds = apps .filter((_) => _.atRiskPasswordCount > 0) - .flatMap((app) => app.atRiskMemberDetails.map((member) => member.cipherId)); + .flatMap((app) => app.atRiskCipherIds); + const distinctCipherIds = Array.from(new Set(cipherIds)); + const tasks: CreateTasksRequest[] = distinctCipherIds.map((cipherId) => ({ cipherId: cipherId as CipherId, type: SecurityTaskType.UpdateAtRiskCredential, From e7d5cde1057133f24f9133852bf891976ee9cfdc Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Wed, 9 Jul 2025 16:52:47 +0200 Subject: [PATCH 086/239] [BEEEP/PM-22958] Update russh version, and add sessionbind information (#14602) * Update russh version, and add sessionbind information * Cargo fmt * Clean up to fix lint * Attempt to fix windows * Use expect instead of unwrap * Fix cargo toml --- apps/desktop/desktop_native/Cargo.lock | 159 +++++++++++++++++- apps/desktop/desktop_native/Cargo.toml | 2 +- .../desktop_native/core/src/ssh_agent/mod.rs | 75 +++++++-- .../core/src/ssh_agent/peerinfo/models.rs | 16 +- .../desktop_native/core/src/ssh_agent/unix.rs | 4 +- .../core/src/ssh_agent/windows.rs | 4 +- apps/desktop/desktop_native/napi/src/lib.rs | 3 +- 7 files changed, 241 insertions(+), 22 deletions(-) diff --git a/apps/desktop/desktop_native/Cargo.lock b/apps/desktop/desktop_native/Cargo.lock index eadd75e5981..d02ffb9b026 100644 --- a/apps/desktop/desktop_native/Cargo.lock +++ b/apps/desktop/desktop_native/Cargo.lock @@ -377,6 +377,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.22.1" @@ -427,11 +433,17 @@ checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "bitwarden-russh" version = "0.1.0" -source = "git+https://github.com/bitwarden/bitwarden-russh.git?rev=3d48f140fd506412d186203238993163a8c4e536#3d48f140fd506412d186203238993163a8c4e536" +source = "git+https://github.com/bitwarden/bitwarden-russh.git?rev=a641316227227f8777fdf56ac9fa2d6b5f7fe662#a641316227227f8777fdf56ac9fa2d6b5f7fe662" dependencies = [ "anyhow", "byteorder", + "ecdsa", + "ed25519-dalek", "futures", + "p256", + "p384", + "p521", + "rsa", "russh-cryptovec", "ssh-encoding", "ssh-key", @@ -707,6 +719,18 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -750,6 +774,7 @@ dependencies = [ "fiat-crypto", "rustc_version", "subtle", + "zeroize", ] [[package]] @@ -1018,6 +1043,20 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + [[package]] name = "ed25519" version = "2.2.3" @@ -1036,8 +1075,32 @@ checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", + "serde", "sha2", + "signature", "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", ] [[package]] @@ -1122,6 +1185,16 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "fiat-crypto" version = "0.2.9" @@ -1274,6 +1347,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -1342,6 +1416,17 @@ dependencies = [ "scroll", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -2112,6 +2197,44 @@ dependencies = [ "log", ] +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p521" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" +dependencies = [ + "base16ct", + "ecdsa", + "elliptic-curve", + "primeorder", + "rand_core 0.6.4", + "sha2", +] + [[package]] name = "parking" version = "2.2.1" @@ -2348,6 +2471,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro-crate" version = "3.3.0" @@ -2504,6 +2636,16 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "rsa" version = "0.9.6" @@ -2640,6 +2782,20 @@ dependencies = [ "sha2", ] +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "security-framework" version = "3.1.0" @@ -2854,6 +3010,7 @@ dependencies = [ "num-bigint-dig", "rand_core 0.6.4", "rsa", + "sec1", "sha2", "signature", "ssh-cipher", diff --git a/apps/desktop/desktop_native/Cargo.toml b/apps/desktop/desktop_native/Cargo.toml index b1516ecfbca..1aa6f784ec7 100644 --- a/apps/desktop/desktop_native/Cargo.toml +++ b/apps/desktop/desktop_native/Cargo.toml @@ -16,7 +16,7 @@ argon2 = "=0.5.3" ashpd = "=0.11.0" base64 = "=0.22.1" bindgen = "=0.72.0" -bitwarden-russh = { git = "https://github.com/bitwarden/bitwarden-russh.git", rev = "3d48f140fd506412d186203238993163a8c4e536" } +bitwarden-russh = { git = "https://github.com/bitwarden/bitwarden-russh.git", rev = "a641316227227f8777fdf56ac9fa2d6b5f7fe662" } byteorder = "=1.5.0" bytes = "=1.10.1" cbc = "=0.1.2" diff --git a/apps/desktop/desktop_native/core/src/ssh_agent/mod.rs b/apps/desktop/desktop_native/core/src/ssh_agent/mod.rs index 63348904e46..33076071a1b 100644 --- a/apps/desktop/desktop_native/core/src/ssh_agent/mod.rs +++ b/apps/desktop/desktop_native/core/src/ssh_agent/mod.rs @@ -3,10 +3,14 @@ use std::sync::{ Arc, }; +use base64::{engine::general_purpose::STANDARD, Engine as _}; use tokio::sync::Mutex; use tokio_util::sync::CancellationToken; -use bitwarden_russh::ssh_agent::{self, Key}; +use bitwarden_russh::{ + session_bind::SessionBindResult, + ssh_agent::{self, SshKey}, +}; #[cfg_attr(target_os = "windows", path = "windows.rs")] #[cfg_attr(target_os = "macos", path = "unix.rs")] @@ -20,8 +24,8 @@ pub mod peerinfo; mod request_parser; #[derive(Clone)] -pub struct BitwardenDesktopAgent { - keystore: ssh_agent::KeyStore, +pub struct BitwardenDesktopAgent { + keystore: ssh_agent::KeyStore, cancellation_token: CancellationToken, show_ui_request_tx: tokio::sync::mpsc::Sender, get_ui_response_rx: Arc>>, @@ -40,8 +44,47 @@ pub struct SshAgentUIRequest { pub is_forwarding: bool, } -impl ssh_agent::Agent for BitwardenDesktopAgent { - async fn confirm(&self, ssh_key: Key, data: &[u8], info: &peerinfo::models::PeerInfo) -> bool { +#[derive(Clone)] +pub struct BitwardenSshKey { + pub private_key: Option, + pub name: String, + pub cipher_uuid: String, +} + +impl SshKey for BitwardenSshKey { + fn name(&self) -> &str { + &self.name + } + + fn public_key_bytes(&self) -> Vec { + if let Some(ref private_key) = self.private_key { + private_key + .public_key() + .to_bytes() + .expect("Cipher private key is always correctly parsed") + } else { + Vec::new() + } + } + + fn private_key(&self) -> Option> { + if let Some(ref private_key) = self.private_key { + Some(Box::new(private_key.clone())) + } else { + None + } + } +} + +impl ssh_agent::Agent + for BitwardenDesktopAgent +{ + async fn confirm( + &self, + ssh_key: BitwardenSshKey, + data: &[u8], + info: &peerinfo::models::PeerInfo, + ) -> bool { if !self.is_running() { println!("[BitwardenDesktopAgent] Agent is not running, but tried to call confirm"); return false; @@ -63,10 +106,11 @@ impl ssh_agent::Agent for BitwardenDesktopAgent { }; println!( - "[SSH Agent] Confirming request from application: {}, is_forwarding: {}, namespace: {}", + "[SSH Agent] Confirming request from application: {}, is_forwarding: {}, namespace: {}, host_key: {}", info.process_name(), info.is_forwarding(), namespace.clone().unwrap_or_default(), + STANDARD.encode(info.host_key()) ); let mut rx_channel = self.get_ui_response_rx.lock().await.resubscribe(); @@ -117,19 +161,24 @@ impl ssh_agent::Agent for BitwardenDesktopAgent { false } - async fn set_is_forwarding( + async fn set_sessionbind_info( &self, - is_forwarding: bool, + session_bind_info_result: &SessionBindResult, connection_info: &peerinfo::models::PeerInfo, ) { - // is_forwarding can only be added but never removed from a connection - if is_forwarding { - connection_info.set_forwarding(is_forwarding); + match session_bind_info_result { + SessionBindResult::Success(session_bind_info) => { + connection_info.set_forwarding(session_bind_info.is_forwarding); + connection_info.set_host_key(session_bind_info.host_key.clone()); + } + SessionBindResult::SignatureFailure => { + println!("[BitwardenDesktopAgent] Session bind failure: Signature failure"); + } } } } -impl BitwardenDesktopAgent { +impl BitwardenDesktopAgent { pub fn stop(&self) { if !self.is_running() { println!("[BitwardenDesktopAgent] Tried to stop agent while it is not running"); @@ -170,7 +219,7 @@ impl BitwardenDesktopAgent { .expect("Cipher private key is always correctly parsed"); keystore.0.write().expect("RwLock is not poisoned").insert( public_key_bytes, - Key { + BitwardenSshKey { private_key: Some(private_key), name: name.clone(), cipher_uuid: cipher_id.clone(), diff --git a/apps/desktop/desktop_native/core/src/ssh_agent/peerinfo/models.rs b/apps/desktop/desktop_native/core/src/ssh_agent/peerinfo/models.rs index 35a5a508263..fad535cb80e 100644 --- a/apps/desktop/desktop_native/core/src/ssh_agent/peerinfo/models.rs +++ b/apps/desktop/desktop_native/core/src/ssh_agent/peerinfo/models.rs @@ -1,15 +1,16 @@ -use std::sync::{atomic::AtomicBool, Arc}; +use std::sync::{atomic::AtomicBool, Arc, Mutex}; /** * Peerinfo represents the information of a peer process connecting over a socket. * This can be later extended to include more information (icon, app name) for the corresponding application. */ -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct PeerInfo { uid: u32, pid: u32, process_name: String, is_forwarding: Arc, + host_key: Arc>>, } impl PeerInfo { @@ -19,6 +20,7 @@ impl PeerInfo { pid, process_name, is_forwarding: Arc::new(AtomicBool::new(false)), + host_key: Arc::new(Mutex::new(Vec::new())), } } @@ -28,6 +30,7 @@ impl PeerInfo { pid: 0, process_name: "Unknown application".to_string(), is_forwarding: Arc::new(AtomicBool::new(false)), + host_key: Arc::new(Mutex::new(Vec::new())), } } @@ -52,4 +55,13 @@ impl PeerInfo { self.is_forwarding .store(value, std::sync::atomic::Ordering::Relaxed); } + + pub fn set_host_key(&self, host_key: Vec) { + let mut host_key_lock = self.host_key.lock().expect("Mutex is not poisoned"); + *host_key_lock = host_key; + } + + pub fn host_key(&self) -> Vec { + self.host_key.lock().expect("Mutex is not poisoned").clone() + } } diff --git a/apps/desktop/desktop_native/core/src/ssh_agent/unix.rs b/apps/desktop/desktop_native/core/src/ssh_agent/unix.rs index ed297a9002f..05d07cfee46 100644 --- a/apps/desktop/desktop_native/core/src/ssh_agent/unix.rs +++ b/apps/desktop/desktop_native/core/src/ssh_agent/unix.rs @@ -15,9 +15,9 @@ use tokio_util::sync::CancellationToken; use crate::ssh_agent::peercred_unix_listener_stream::PeercredUnixListenerStream; -use super::{BitwardenDesktopAgent, SshAgentUIRequest}; +use super::{BitwardenDesktopAgent, BitwardenSshKey, SshAgentUIRequest}; -impl BitwardenDesktopAgent { +impl BitwardenDesktopAgent { pub async fn start_server( auth_request_tx: tokio::sync::mpsc::Sender, auth_response_rx: Arc>>, diff --git a/apps/desktop/desktop_native/core/src/ssh_agent/windows.rs b/apps/desktop/desktop_native/core/src/ssh_agent/windows.rs index bc63ef552b7..aeb20aefd66 100644 --- a/apps/desktop/desktop_native/core/src/ssh_agent/windows.rs +++ b/apps/desktop/desktop_native/core/src/ssh_agent/windows.rs @@ -11,9 +11,9 @@ use std::{ use tokio::sync::Mutex; use tokio_util::sync::CancellationToken; -use super::{BitwardenDesktopAgent, SshAgentUIRequest}; +use super::{BitwardenDesktopAgent, BitwardenSshKey, SshAgentUIRequest}; -impl BitwardenDesktopAgent { +impl BitwardenDesktopAgent { pub async fn start_server( auth_request_tx: tokio::sync::mpsc::Sender, auth_response_rx: Arc>>, diff --git a/apps/desktop/desktop_native/napi/src/lib.rs b/apps/desktop/desktop_native/napi/src/lib.rs index fb80ec451a4..49f653d4809 100644 --- a/apps/desktop/desktop_native/napi/src/lib.rs +++ b/apps/desktop/desktop_native/napi/src/lib.rs @@ -166,6 +166,7 @@ pub mod clipboards { pub mod sshagent { use std::sync::Arc; + use desktop_core::ssh_agent::BitwardenSshKey; use napi::{ bindgen_prelude::Promise, threadsafe_function::{ErrorStrategy::CalleeHandled, ThreadsafeFunction}, @@ -174,7 +175,7 @@ pub mod sshagent { #[napi] pub struct SshAgentState { - state: desktop_core::ssh_agent::BitwardenDesktopAgent, + state: desktop_core::ssh_agent::BitwardenDesktopAgent, } #[napi(object)] From 9f1531a1b27a8871f77402b11880c94a6f3b441c Mon Sep 17 00:00:00 2001 From: Jordan Aasen <166539328+jaasen-livefront@users.noreply.github.com> Date: Wed, 9 Jul 2025 08:37:38 -0700 Subject: [PATCH 087/239] [PM-22375] - [Vault] [Clients] Sort My Items collection to the top of Vault collection filters (#15332) * WIP - default collection sorting * apply filtering to popup list filters service. * add tests. add feature flag checks * finalize my items collection filters * fix type error * re-add service * re-add comment * remove unused code * fix sorting logic * shorten variable name to fit one line * fix error * fix more errors * abstract logic to vault filter service * fix test * export sort as function instead of adding to class * fix more tests * add collator arg * remove ts-ignore. fix type errors * remove optional param * fix vault filter service --- .../browser/src/background/main.background.ts | 2 + .../src/popup/services/services.module.ts | 2 + .../vault-popup-list-filters.service.spec.ts | 40 ++++++++++ .../vault-popup-list-filters.service.ts | 75 +++++++++++-------- .../vault/services/vault-filter.service.ts | 6 ++ .../vault-filter/vault-filter.service.ts | 3 + .../services/vault-filter.service.spec.ts | 62 ++++++++++++++- .../services/vault-filter.service.ts | 54 ++++++++----- apps/web/src/locales/en/messages.json | 3 + .../services/vault-filter.service.ts | 58 +++++++++++--- 10 files changed, 244 insertions(+), 61 deletions(-) diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index c6d68a9f047..16149ea0fb3 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -918,6 +918,8 @@ export default class MainBackground { this.policyService, this.stateProvider, this.accountService, + this.configService, + this.i18nService, ); this.vaultSettingsService = new VaultSettingsService(this.stateProvider); diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 9f79cf42553..d70418137f8 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -404,6 +404,8 @@ const safeProviders: SafeProvider[] = [ PolicyService, StateProvider, AccountServiceAbstraction, + ConfigService, + I18nServiceAbstraction, ], }), safeProvider({ diff --git a/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.spec.ts b/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.spec.ts index 1e56fd4d352..e530046a971 100644 --- a/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.spec.ts +++ b/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.spec.ts @@ -5,12 +5,14 @@ import { BehaviorSubject, skipWhile } from "rxjs"; import { CollectionService, CollectionView } from "@bitwarden/admin-console/common"; import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; +import * as vaultFilterSvc from "@bitwarden/angular/vault/vault-filter/services/vault-filter.service"; 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 { 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 { ProductTierType } from "@bitwarden/common/billing/enums"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { StateProvider } from "@bitwarden/common/platform/state"; import { mockAccountServiceWith } from "@bitwarden/common/spec"; @@ -31,6 +33,14 @@ import { VaultPopupListFiltersService, } from "./vault-popup-list-filters.service"; +const configService = { + getFeatureFlag$: jest.fn(() => new BehaviorSubject(true)), +} as unknown as ConfigService; + +jest.mock("@bitwarden/angular/vault/vault-filter/services/vault-filter.service", () => ({ + sortDefaultCollections: jest.fn(), +})); + describe("VaultPopupListFiltersService", () => { let service: VaultPopupListFiltersService; let _memberOrganizations$ = new BehaviorSubject([]); @@ -138,6 +148,10 @@ describe("VaultPopupListFiltersService", () => { provide: RestrictedItemTypesService, useValue: restrictedItemTypesService, }, + { + provide: ConfigService, + useValue: configService, + }, ], }); @@ -399,6 +413,29 @@ describe("VaultPopupListFiltersService", () => { done(); }); }); + + it("calls vaultFilterService.sortDefaultCollections", (done) => { + const collections = [ + { id: "1234", name: "Default Collection", organizationId: "org1" }, + { id: "5678", name: "Shared Collection", organizationId: "org2" }, + ] as CollectionView[]; + + const orgs = [ + { id: "org1", name: "Organization 1" }, + { id: "org2", name: "Organization 2" }, + ] as Organization[]; + + createSeededVaultPopupListFiltersService(orgs, collections, [], {}); + + service.collections$.subscribe(() => { + expect(vaultFilterSvc.sortDefaultCollections).toHaveBeenCalledWith( + collections, + orgs, + i18nService.collator, + ); + done(); + }); + }); }); describe("folders$", () => { @@ -573,6 +610,8 @@ describe("VaultPopupListFiltersService", () => { const seededOrganizations: Organization[] = [ { id: MY_VAULT_ID, name: "Test Org" } as Organization, + { id: "org1", name: "Default User Collection Org 1" } as Organization, + { id: "org2", name: "Default User Collection Org 2" } as Organization, ]; const seededCollections: CollectionView[] = [ { @@ -752,6 +791,7 @@ function createSeededVaultPopupListFiltersService( accountServiceMock, viewCacheServiceMock, restrictedItemTypesServiceMock, + configService, ); }); diff --git a/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts b/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts index 12d0c445b4c..a936aaf86d9 100644 --- a/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts +++ b/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts @@ -6,6 +6,7 @@ import { debounceTime, distinctUntilChanged, filter, + from, map, Observable, shareReplay, @@ -17,6 +18,7 @@ import { import { CollectionService, CollectionView } from "@bitwarden/admin-console/common"; import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; import { DynamicTreeNode } from "@bitwarden/angular/vault/vault-filter/models/dynamic-tree-node.model"; +import { sortDefaultCollections } from "@bitwarden/angular/vault/vault-filter/services/vault-filter.service"; 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 { PolicyType } from "@bitwarden/common/admin-console/enums"; @@ -24,6 +26,8 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga 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 { 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 { @@ -181,6 +185,7 @@ export class VaultPopupListFiltersService { private accountService: AccountService, private viewCacheService: ViewCacheService, private restrictedItemTypesService: RestrictedItemTypesService, + private configService: ConfigService, ) { this.filterForm.controls.organization.valueChanges .pipe(takeUntilDestroyed()) @@ -424,39 +429,47 @@ export class VaultPopupListFiltersService { /** * Collection array structured to be directly passed to `ChipSelectComponent` */ - collections$: Observable[]> = combineLatest([ - this.filters$.pipe( - distinctUntilChanged( - (previousFilter, currentFilter) => - // Only update the collections when the organizationId filter changes - previousFilter.organization?.id === currentFilter.organization?.id, + collections$: Observable[]> = + this.accountService.activeAccount$.pipe( + getUserId, + switchMap((userId) => + combineLatest([ + this.filters$.pipe( + distinctUntilChanged((prev, curr) => prev.organization?.id === curr.organization?.id), + ), + this.collectionService.decryptedCollections$, + this.organizationService.memberOrganizations$(userId), + this.configService.getFeatureFlag$(FeatureFlag.CreateDefaultLocation), + ]), ), - ), - this.collectionService.decryptedCollections$, - ]).pipe( - map(([filters, allCollections]) => { - const organizationId = filters.organization?.id ?? null; - // When the organization filter is selected, filter out collections that do not belong to the selected organization - const collections = - organizationId === null - ? allCollections - : allCollections.filter((c) => c.organizationId === organizationId); + map(([filters, allCollections, orgs, defaultVaultEnabled]) => { + const orgFilterId = filters.organization?.id ?? null; + // When the organization filter is selected, filter out collections that do not belong to the selected organization + const filtered = orgFilterId + ? allCollections.filter((c) => c.organizationId === orgFilterId) + : allCollections; - return collections; - }), - switchMap(async (collections) => { - const nestedCollections = await this.collectionService.getAllNested(collections); - - return new DynamicTreeNode({ - fullList: collections, - nestedList: nestedCollections, - }); - }), - map((collections) => - collections.nestedList.map((c) => this.convertToChipSelectOption(c, "bwi-collection-shared")), - ), - shareReplay({ refCount: true, bufferSize: 1 }), - ); + if (!defaultVaultEnabled) { + return filtered; + } + return sortDefaultCollections(filtered, orgs, this.i18nService.collator); + }), + switchMap((collections) => { + return from(this.collectionService.getAllNested(collections)).pipe( + map( + (nested) => + new DynamicTreeNode({ + fullList: collections, + nestedList: nested, + }), + ), + ); + }), + map((tree) => + tree.nestedList.map((c) => this.convertToChipSelectOption(c, "bwi-collection-shared")), + ), + shareReplay({ bufferSize: 1, refCount: true }), + ); /** Organizations, collection, folders filters. */ allFilters$ = combineLatest([this.organizations$, this.collections$, this.folders$]); diff --git a/apps/browser/src/vault/services/vault-filter.service.ts b/apps/browser/src/vault/services/vault-filter.service.ts index f8b22f2f88f..f33e8e1c130 100644 --- a/apps/browser/src/vault/services/vault-filter.service.ts +++ b/apps/browser/src/vault/services/vault-filter.service.ts @@ -6,6 +6,8 @@ import { VaultFilterService as BaseVaultFilterService } from "@bitwarden/angular import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { 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"; @@ -25,6 +27,8 @@ export class VaultFilterService extends BaseVaultFilterService { policyService: PolicyService, stateProvider: StateProvider, accountService: AccountService, + configService: ConfigService, + i18nService: I18nService, ) { super( organizationService, @@ -34,6 +38,8 @@ export class VaultFilterService extends BaseVaultFilterService { policyService, stateProvider, accountService, + configService, + i18nService, ); this.vaultFilter.myVaultOnly = false; this.vaultFilter.selectedOrganizationId = null; diff --git a/apps/web/src/app/admin-console/organizations/collections/vault-filter/vault-filter.service.ts b/apps/web/src/app/admin-console/organizations/collections/vault-filter/vault-filter.service.ts index f4b6f41fab6..dc05248d7ba 100644 --- a/apps/web/src/app/admin-console/organizations/collections/vault-filter/vault-filter.service.ts +++ b/apps/web/src/app/admin-console/organizations/collections/vault-filter/vault-filter.service.ts @@ -5,6 +5,7 @@ import { CollectionAdminView, CollectionService } from "@bitwarden/admin-console import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { StateProvider } from "@bitwarden/common/platform/state"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; @@ -34,6 +35,7 @@ export class VaultFilterService extends BaseVaultFilterService implements OnDest stateProvider: StateProvider, collectionService: CollectionService, accountService: AccountService, + configService: ConfigService, ) { super( organizationService, @@ -44,6 +46,7 @@ export class VaultFilterService extends BaseVaultFilterService implements OnDest stateProvider, collectionService, accountService, + configService, ); } diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.spec.ts b/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.spec.ts index 59aa169481e..2154ecff1b7 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.spec.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.spec.ts @@ -5,13 +5,20 @@ import { import { FakeSingleUserState } from "@bitwarden/common/../spec/fake-state"; import { FakeStateProvider } from "@bitwarden/common/../spec/fake-state-provider"; import { mock, MockProxy } from "jest-mock-extended"; -import { firstValueFrom, ReplaySubject } from "rxjs"; +import { firstValueFrom, of, ReplaySubject } from "rxjs"; -import { CollectionService, CollectionView } from "@bitwarden/admin-console/common"; +import { + CollectionService, + CollectionType, + CollectionTypes, + CollectionView, +} from "@bitwarden/admin-console/common"; +import * as vaultFilterSvc from "@bitwarden/angular/vault/vault-filter/services/vault-filter.service"; 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 { PolicyType } from "@bitwarden/common/admin-console/enums"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; +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 { UserId } from "@bitwarden/common/types/guid"; @@ -23,6 +30,10 @@ import { COLLAPSED_GROUPINGS } from "@bitwarden/common/vault/services/key-state/ import { VaultFilterService } from "./vault-filter.service"; +jest.mock("@bitwarden/angular/vault/vault-filter/services/vault-filter.service", () => ({ + sortDefaultCollections: jest.fn(() => []), +})); + describe("vault filter service", () => { let vaultFilterService: VaultFilterService; @@ -39,6 +50,7 @@ describe("vault filter service", () => { let organizationDataOwnershipPolicy: ReplaySubject; let singleOrgPolicy: ReplaySubject; let stateProvider: FakeStateProvider; + let configService: MockProxy; const mockUserId = Utils.newGuid() as UserId; let accountService: FakeAccountService; @@ -54,6 +66,7 @@ describe("vault filter service", () => { stateProvider = new FakeStateProvider(accountService); i18nService.collator = new Intl.Collator("en-US"); collectionService = mock(); + configService = mock(); organizations = new ReplaySubject(1); folderViews = new ReplaySubject(1); @@ -62,6 +75,7 @@ describe("vault filter service", () => { organizationDataOwnershipPolicy = new ReplaySubject(1); singleOrgPolicy = new ReplaySubject(1); + configService.getFeatureFlag$.mockReturnValue(of(true)); organizationService.memberOrganizations$.mockReturnValue(organizations); folderService.folderViews$.mockReturnValue(folderViews); collectionService.decryptedCollections$ = collectionViews; @@ -82,8 +96,10 @@ describe("vault filter service", () => { stateProvider, collectionService, accountService, + configService, ); collapsedGroupingsState = stateProvider.singleUser.getFake(mockUserId, COLLAPSED_GROUPINGS); + organizations.next([]); }); describe("collapsed filter nodes", () => { @@ -285,6 +301,40 @@ describe("vault filter service", () => { const c3 = c1.children[0]; expect(c3.parent.node.id).toEqual("id-1"); }); + + it.only("calls sortDefaultCollections with the correct args", async () => { + const storedOrgs = [ + createOrganization("id-defaultOrg1", "org1"), + createOrganization("id-defaultOrg2", "org2"), + ]; + organizations.next(storedOrgs); + + const storedCollections = [ + createCollectionView("id-2", "Collection 2", "org test id"), + createCollectionView("id-1", "Collection 1", "org test id"), + createCollectionView( + "id-3", + "Default User Collection - Org 2", + "id-defaultOrg2", + CollectionTypes.DefaultUserCollection, + ), + createCollectionView( + "id-4", + "Default User Collection - Org 1", + "id-defaultOrg1", + CollectionTypes.DefaultUserCollection, + ), + ]; + collectionViews.next(storedCollections); + + await firstValueFrom(vaultFilterService.collectionTree$); + + expect(vaultFilterSvc.sortDefaultCollections).toHaveBeenCalledWith( + storedCollections, + storedOrgs, + i18nService.collator, + ); + }); }); }); @@ -312,11 +362,17 @@ describe("vault filter service", () => { return folder; } - function createCollectionView(id: string, name: string, orgId: string): CollectionView { + function createCollectionView( + id: string, + name: string, + orgId: string, + type?: CollectionType, + ): CollectionView { const collection = new CollectionView(); collection.id = id; collection.name = name; collection.organizationId = orgId; + collection.type = type || CollectionTypes.SharedCollection; return collection; } }); diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.ts b/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.ts index b6548564ec9..f326034e806 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.ts @@ -18,12 +18,15 @@ import { CollectionService, CollectionView, } from "@bitwarden/admin-console/common"; +import { sortDefaultCollections } from "@bitwarden/angular/vault/vault-filter/services/vault-filter.service"; 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 { 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 { getUserId } from "@bitwarden/common/auth/services/account.service"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { SingleUserState, StateProvider } from "@bitwarden/common/platform/state"; import { UserId } from "@bitwarden/common/types/guid"; @@ -104,8 +107,14 @@ export class VaultFilterService implements VaultFilterServiceAbstraction { }), ); - collectionTree$: Observable> = this.filteredCollections$.pipe( - map((collections) => this.buildCollectionTree(collections)), + collectionTree$: Observable> = combineLatest([ + this.filteredCollections$, + this.memberOrganizations$, + this.configService.getFeatureFlag$(FeatureFlag.CreateDefaultLocation), + ]).pipe( + map(([collections, organizations, defaultCollectionsFlagEnabled]) => + this.buildCollectionTree(collections, organizations, defaultCollectionsFlagEnabled), + ), ); cipherTypeTree$: Observable> = this.buildCipherTypeTree(); @@ -123,6 +132,7 @@ export class VaultFilterService implements VaultFilterServiceAbstraction { protected stateProvider: StateProvider, protected collectionService: CollectionService, protected accountService: AccountService, + protected configService: ConfigService, ) {} async getCollectionNodeFromTree(id: string) { @@ -227,31 +237,39 @@ export class VaultFilterService implements VaultFilterServiceAbstraction { : storedCollections; } - protected buildCollectionTree(collections?: CollectionView[]): TreeNode { + protected buildCollectionTree( + collections?: CollectionView[], + orgs?: Organization[], + defaultCollectionsFlagEnabled?: boolean, + ): TreeNode { const headNode = this.getCollectionFilterHead(); if (!collections) { return headNode; } const nodes: TreeNode[] = []; - collections - .sort((a, b) => this.i18nService.collator.compare(a.name, b.name)) - .forEach((c) => { - const collectionCopy = new CollectionView() as CollectionFilter; - collectionCopy.id = c.id; - collectionCopy.organizationId = c.organizationId; - collectionCopy.icon = "bwi-collection-shared"; - if (c instanceof CollectionAdminView) { - collectionCopy.groups = c.groups; - collectionCopy.assigned = c.assigned; - } - const parts = - c.name != null ? c.name.replace(/^\/+|\/+$/g, "").split(NestingDelimiter) : []; - ServiceUtils.nestedTraverse(nodes, 0, parts, collectionCopy, null, NestingDelimiter); - }); + + if (defaultCollectionsFlagEnabled) { + collections = sortDefaultCollections(collections, orgs, this.i18nService.collator); + } + + collections.forEach((c) => { + const collectionCopy = new CollectionView() as CollectionFilter; + collectionCopy.id = c.id; + collectionCopy.organizationId = c.organizationId; + collectionCopy.icon = "bwi-collection-shared"; + if (c instanceof CollectionAdminView) { + collectionCopy.groups = c.groups; + collectionCopy.assigned = c.assigned; + } + const parts = c.name != null ? c.name.replace(/^\/+|\/+$/g, "").split(NestingDelimiter) : []; + ServiceUtils.nestedTraverse(nodes, 0, parts, collectionCopy, null, NestingDelimiter); + }); + nodes.forEach((n) => { n.parent = headNode; headNode.children.push(n); }); + return headNode; } diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index ba5e4841e3d..bc2e49e85cd 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -864,6 +864,9 @@ "me": { "message": "Me" }, + "myItems": { + "message": "My items" + }, "myVault": { "message": "My vault" }, 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 3317f0c9002..fea57743055 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 @@ -1,17 +1,22 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore import { Injectable } from "@angular/core"; import { firstValueFrom, from, map, mergeMap, Observable, switchMap, take } from "rxjs"; // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // eslint-disable-next-line no-restricted-imports -import { CollectionService, CollectionView } from "@bitwarden/admin-console/common"; +import { + CollectionService, + CollectionTypes, + CollectionView, +} 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 { 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 { getUserId } from "@bitwarden/common/auth/services/account.service"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { SingleUserState, StateProvider } from "@bitwarden/common/platform/state"; import { UserId } from "@bitwarden/common/types/guid"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; @@ -40,6 +45,8 @@ export class VaultFilterService implements DeprecatedVaultFilterServiceAbstracti protected policyService: PolicyService, protected stateProvider: StateProvider, protected accountService: AccountService, + protected configService: ConfigService, + protected i18nService: I18nService, ) {} async storeCollapsedFilterNodes( @@ -103,12 +110,20 @@ export class VaultFilterService implements DeprecatedVaultFilterServiceAbstracti async buildCollections(organizationId?: string): Promise> { const storedCollections = await this.collectionService.getAllDecrypted(); - let collections: CollectionView[]; - if (organizationId != null) { - collections = storedCollections.filter((c) => c.organizationId === organizationId); - } else { - collections = storedCollections; + const orgs = await this.buildOrganizations(); + const defaulCollectionsFlagEnabled = await this.configService.getFeatureFlag( + FeatureFlag.CreateDefaultLocation, + ); + + let collections = + organizationId == null + ? storedCollections + : storedCollections.filter((c) => c.organizationId === organizationId); + + if (defaulCollectionsFlagEnabled) { + collections = sortDefaultCollections(collections, orgs, this.i18nService.collator); } + const nestedCollections = await this.collectionService.getAllNested(collections); return new DynamicTreeNode({ fullList: collections, @@ -145,7 +160,7 @@ export class VaultFilterService implements DeprecatedVaultFilterServiceAbstracti folderCopy.id = f.id; folderCopy.revisionDate = f.revisionDate; const parts = f.name != null ? f.name.replace(/^\/+|\/+$/g, "").split(NestingDelimiter) : []; - ServiceUtils.nestedTraverse(nodes, 0, parts, folderCopy, null, NestingDelimiter); + ServiceUtils.nestedTraverse(nodes, 0, parts, folderCopy, undefined, NestingDelimiter); }); return nodes; } @@ -158,3 +173,28 @@ export class VaultFilterService implements DeprecatedVaultFilterServiceAbstracti return ServiceUtils.getTreeNodeObjectFromList(folders, id) as TreeNode; } } + +/** + * Sorts collections with default user collections at the top, sorted by organization name. + * Remaining collections are sorted by name. + * @param collections - The list of collections to sort. + * @param orgs - The list of organizations to use for sorting default user collections. + * @returns Sorted list of collections. + */ +export function sortDefaultCollections( + collections: CollectionView[], + orgs: Organization[] = [], + collator: Intl.Collator, +): CollectionView[] { + const sortedDefaultCollectionTypes = collections + .filter((c) => c.type === CollectionTypes.DefaultUserCollection) + .sort((a, b) => { + const aName = orgs.find((o) => o.id === a.organizationId)?.name ?? a.organizationId; + const bName = orgs.find((o) => o.id === b.organizationId)?.name ?? b.organizationId; + return collator.compare(aName, bName); + }); + return [ + ...sortedDefaultCollectionTypes, + ...collections.filter((c) => c.type !== CollectionTypes.DefaultUserCollection), + ]; +} From 09fb74679dd42c9794fe6df2677f14bc9e7dedf6 Mon Sep 17 00:00:00 2001 From: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> Date: Wed, 9 Jul 2025 11:53:16 -0500 Subject: [PATCH 088/239] [PM-21912] Require userID for KeyService's hasUserKey (#14890) * Update keyService hasUserKey to require userId and remove unused/duplicate methods * Update lock component consumer * Update send commands to pass in userId * update SSO login to pass in userID * Update bw serve to pass in userID * remove unneeded method from electron-key.service --- .../extension-lock-component.service.spec.ts | 8 ---- apps/cli/src/oss-serve-configurator.ts | 8 +++- .../src/tools/send/commands/get.command.ts | 6 ++- .../src/tools/send/commands/list.command.ts | 6 ++- apps/cli/src/tools/send/send.program.ts | 3 ++ .../key-management/electron-key.service.ts | 4 -- .../login-strategies/sso-login.strategy.ts | 2 +- .../send/services/send.service.abstraction.ts | 2 +- .../tools/send/services/send.service.spec.ts | 17 +++++-- .../src/tools/send/services/send.service.ts | 4 +- .../src/lock/components/lock.component.ts | 2 +- .../src/abstractions/key.service.ts | 19 ++------ libs/key-management/src/key.service.spec.ts | 45 +++++++++---------- libs/key-management/src/key.service.ts | 15 +------ 14 files changed, 66 insertions(+), 75 deletions(-) diff --git a/apps/browser/src/key-management/lock/services/extension-lock-component.service.spec.ts b/apps/browser/src/key-management/lock/services/extension-lock-component.service.spec.ts index 86781474b67..0ae0997fe4b 100644 --- a/apps/browser/src/key-management/lock/services/extension-lock-component.service.spec.ts +++ b/apps/browser/src/key-management/lock/services/extension-lock-component.service.spec.ts @@ -12,7 +12,6 @@ import { VaultTimeoutSettingsService } from "@bitwarden/common/key-management/va import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { UserId } from "@bitwarden/common/types/guid"; import { - KeyService, BiometricsService, BiometricsStatus, BiometricStateService, @@ -35,7 +34,6 @@ describe("ExtensionLockComponentService", () => { let biometricsService: MockProxy; let pinService: MockProxy; let vaultTimeoutSettingsService: MockProxy; - let keyService: MockProxy; let routerService: MockProxy; let biometricStateService: MockProxy; @@ -45,7 +43,6 @@ describe("ExtensionLockComponentService", () => { biometricsService = mock(); pinService = mock(); vaultTimeoutSettingsService = mock(); - keyService = mock(); routerService = mock(); biometricStateService = mock(); @@ -72,10 +69,6 @@ describe("ExtensionLockComponentService", () => { provide: VaultTimeoutSettingsService, useValue: vaultTimeoutSettingsService, }, - { - provide: KeyService, - useValue: keyService, - }, { provide: BrowserRouterService, useValue: routerService, @@ -375,7 +368,6 @@ describe("ExtensionLockComponentService", () => { vaultTimeoutSettingsService.isBiometricLockSet.mockResolvedValue( mockInputs.hasBiometricEncryptedUserKeyStored, ); - keyService.hasUserKeyStored.mockResolvedValue(mockInputs.hasBiometricEncryptedUserKeyStored); platformUtilsService.supportsSecureStorage.mockReturnValue( mockInputs.platformSupportsSecureStorage, ); diff --git a/apps/cli/src/oss-serve-configurator.ts b/apps/cli/src/oss-serve-configurator.ts index 875b8cc7507..14e6ace3b34 100644 --- a/apps/cli/src/oss-serve-configurator.ts +++ b/apps/cli/src/oss-serve-configurator.ts @@ -3,6 +3,7 @@ import * as koaMulter from "@koa/multer"; import * as koaRouter from "@koa/router"; import * as koa from "koa"; +import { firstValueFrom, map } from "rxjs"; import { ConfirmCommand } from "./admin-console/commands/confirm.command"; import { ShareCommand } from "./admin-console/commands/share.command"; @@ -170,6 +171,7 @@ export class OssServeConfigurator { this.serviceContainer.searchService, this.serviceContainer.encryptService, this.serviceContainer.apiService, + this.serviceContainer.accountService, ); this.sendEditCommand = new SendEditCommand( this.serviceContainer.sendService, @@ -182,6 +184,7 @@ export class OssServeConfigurator { this.serviceContainer.sendService, this.serviceContainer.environmentService, this.serviceContainer.searchService, + this.serviceContainer.accountService, ); this.sendRemovePasswordCommand = new SendRemovePasswordCommand( this.serviceContainer.sendService, @@ -414,7 +417,10 @@ export class OssServeConfigurator { this.processResponse(res, Response.error("You are not logged in.")); return true; } - if (await this.serviceContainer.keyService.hasUserKey()) { + const userId = await firstValueFrom( + this.serviceContainer.accountService.activeAccount$.pipe(map((account) => account?.id)), + ); + if (await this.serviceContainer.keyService.hasUserKey(userId)) { return false; } this.processResponse(res, Response.error("Vault is locked.")); diff --git a/apps/cli/src/tools/send/commands/get.command.ts b/apps/cli/src/tools/send/commands/get.command.ts index 1b3a8f6c500..2d6cc93c781 100644 --- a/apps/cli/src/tools/send/commands/get.command.ts +++ b/apps/cli/src/tools/send/commands/get.command.ts @@ -4,6 +4,8 @@ import { OptionValues } from "commander"; import { firstValueFrom } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; @@ -22,6 +24,7 @@ export class SendGetCommand extends DownloadCommand { private searchService: SearchService, encryptService: EncryptService, apiService: ApiService, + private accountService: AccountService, ) { super(encryptService, apiService); } @@ -77,7 +80,8 @@ export class SendGetCommand extends DownloadCommand { return await send.decrypt(); } } else if (id.trim() !== "") { - let sends = await this.sendService.getAllDecryptedFromState(); + const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)); + let sends = await this.sendService.getAllDecryptedFromState(activeUserId); sends = this.searchService.searchSends(sends, id); if (sends.length > 1) { return sends; diff --git a/apps/cli/src/tools/send/commands/list.command.ts b/apps/cli/src/tools/send/commands/list.command.ts index f611cb3f5dc..d3cb73e9b21 100644 --- a/apps/cli/src/tools/send/commands/list.command.ts +++ b/apps/cli/src/tools/send/commands/list.command.ts @@ -1,5 +1,7 @@ import { firstValueFrom } from "rxjs"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; import { SearchService } from "@bitwarden/common/vault/abstractions/search.service"; @@ -13,10 +15,12 @@ export class SendListCommand { private sendService: SendService, private environmentService: EnvironmentService, private searchService: SearchService, + private accountService: AccountService, ) {} async run(cmdOptions: Record): Promise { - let sends = await this.sendService.getAllDecryptedFromState(); + const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)); + let sends = await this.sendService.getAllDecryptedFromState(activeUserId); const normalizedOptions = new Options(cmdOptions); if (normalizedOptions.search != null && normalizedOptions.search.trim() !== "") { diff --git a/apps/cli/src/tools/send/send.program.ts b/apps/cli/src/tools/send/send.program.ts index 6af714cb786..cbeda188a99 100644 --- a/apps/cli/src/tools/send/send.program.ts +++ b/apps/cli/src/tools/send/send.program.ts @@ -128,6 +128,7 @@ export class SendProgram extends BaseProgram { this.serviceContainer.sendService, this.serviceContainer.environmentService, this.serviceContainer.searchService, + this.serviceContainer.accountService, ); const response = await cmd.run(options); this.processResponse(response); @@ -193,6 +194,7 @@ export class SendProgram extends BaseProgram { this.serviceContainer.searchService, this.serviceContainer.encryptService, this.serviceContainer.apiService, + this.serviceContainer.accountService, ); const response = await cmd.run(id, options); this.processResponse(response); @@ -253,6 +255,7 @@ export class SendProgram extends BaseProgram { this.serviceContainer.searchService, this.serviceContainer.encryptService, this.serviceContainer.apiService, + this.serviceContainer.accountService, ); const cmd = new SendEditCommand( this.serviceContainer.sendService, diff --git a/apps/desktop/src/key-management/electron-key.service.ts b/apps/desktop/src/key-management/electron-key.service.ts index 8a6fbfa085f..0f5555167c0 100644 --- a/apps/desktop/src/key-management/electron-key.service.ts +++ b/apps/desktop/src/key-management/electron-key.service.ts @@ -51,10 +51,6 @@ export class ElectronKeyService extends DefaultKeyService { ); } - override async hasUserKeyStored(keySuffix: KeySuffixOptions, userId?: UserId): Promise { - return super.hasUserKeyStored(keySuffix, userId); - } - override async clearStoredUserKey(keySuffix: KeySuffixOptions, userId: UserId): Promise { await super.clearStoredUserKey(keySuffix, userId); } diff --git a/libs/auth/src/common/login-strategies/sso-login.strategy.ts b/libs/auth/src/common/login-strategies/sso-login.strategy.ts index a48ffd09503..8b60e42f03e 100644 --- a/libs/auth/src/common/login-strategies/sso-login.strategy.ts +++ b/libs/auth/src/common/login-strategies/sso-login.strategy.ts @@ -266,7 +266,7 @@ export class SsoLoginStrategy extends LoginStrategy { ); } - if (await this.keyService.hasUserKey()) { + if (await this.keyService.hasUserKey(userId)) { // Now that we have a decrypted user key in memory, we can check if we // need to establish trust on the current device await this.deviceTrustService.trustDeviceIfRequired(userId); diff --git a/libs/common/src/tools/send/services/send.service.abstraction.ts b/libs/common/src/tools/send/services/send.service.abstraction.ts index 0cf951e4197..f586e39a755 100644 --- a/libs/common/src/tools/send/services/send.service.abstraction.ts +++ b/libs/common/src/tools/send/services/send.service.abstraction.ts @@ -54,7 +54,7 @@ export abstract class SendService implements UserKeyRotationDataProvider Promise; + getAllDecryptedFromState: (userId: UserId) => Promise; } export abstract class InternalSendService extends SendService { diff --git a/libs/common/src/tools/send/services/send.service.spec.ts b/libs/common/src/tools/send/services/send.service.spec.ts index 777bc54f299..d2a2d5dd9b5 100644 --- a/libs/common/src/tools/send/services/send.service.spec.ts +++ b/libs/common/src/tools/send/services/send.service.spec.ts @@ -467,10 +467,21 @@ describe("SendService", () => { }); }); - it("getAllDecryptedFromState", async () => { - const sends = await sendService.getAllDecryptedFromState(); + describe("getAllDecryptedFromState", () => { + it("returns already decrypted sends in state", async () => { + const sends = await sendService.getAllDecryptedFromState(mockUserId); - expect(sends[0]).toMatchObject(testSendViewData("1", "Test Send")); + expect(sends[0]).toMatchObject(testSendViewData("1", "Test Send")); + }); + + it("throws if no decrypted sends in state and there is no userKey", async () => { + decryptedState.nextState(null); + keyService.hasUserKey.mockResolvedValue(false); + + await expect(sendService.getAllDecryptedFromState(mockUserId)).rejects.toThrow( + "No user key found.", + ); + }); }); describe("getRotatedData", () => { diff --git a/libs/common/src/tools/send/services/send.service.ts b/libs/common/src/tools/send/services/send.service.ts index 2556fa2e908..623ab7c4a7b 100644 --- a/libs/common/src/tools/send/services/send.service.ts +++ b/libs/common/src/tools/send/services/send.service.ts @@ -199,14 +199,14 @@ export class SendService implements InternalSendServiceAbstraction { return response; } - async getAllDecryptedFromState(): Promise { + async getAllDecryptedFromState(userId: UserId): Promise { let decSends = await this.stateProvider.getDecryptedSends(); if (decSends != null) { return decSends; } decSends = []; - const hasKey = await this.keyService.hasUserKey(); + const hasKey = await this.keyService.hasUserKey(userId); if (!hasKey) { throw new Error("No user key found."); } diff --git a/libs/key-management-ui/src/lock/components/lock.component.ts b/libs/key-management-ui/src/lock/components/lock.component.ts index cd731629b48..3d5951a5ac4 100644 --- a/libs/key-management-ui/src/lock/components/lock.component.ts +++ b/libs/key-management-ui/src/lock/components/lock.component.ts @@ -249,7 +249,7 @@ export class LockComponent implements OnInit, OnDestroy { private async handleActiveAccountChange(activeAccount: Account) { // this account may be unlocked, prevent any prompts so we can redirect to vault - if (await this.keyService.hasUserKeyInMemory(activeAccount.id)) { + if (await this.keyService.hasUserKey(activeAccount.id)) { return; } diff --git a/libs/key-management/src/abstractions/key.service.ts b/libs/key-management/src/abstractions/key.service.ts index 452d3e02436..bbe0dd50f3d 100644 --- a/libs/key-management/src/abstractions/key.service.ts +++ b/libs/key-management/src/abstractions/key.service.ts @@ -138,24 +138,13 @@ export abstract class KeyService { userId: string, ): Promise; - /** - * Determines whether the user key is available for the given user. - * @param userId The desired user. If not provided, the active user will be used. If no active user exists, the method will return false. - * @returns True if the user key is available - */ - abstract hasUserKey(userId?: UserId): Promise; /** * Determines whether the user key is available for the given user in memory. - * @param userId The desired user. If not provided, the active user will be used. If no active user exists, the method will return false. - * @returns True if the user key is available + * @param userId The desired user. If null or undefined, will return false. + * @returns True if the user key is available, returns false otherwise. */ - abstract hasUserKeyInMemory(userId?: string): Promise; - /** - * @param keySuffix The desired version of the user's key to check - * @param userId The desired user - * @returns True if the provided version of the user key is stored - */ - abstract hasUserKeyStored(keySuffix: KeySuffixOptions, userId?: string): Promise; + abstract hasUserKey(userId: UserId): Promise; + /** * Generates a new user key * @throws Error when master key is null and there is no active user diff --git a/libs/key-management/src/key.service.spec.ts b/libs/key-management/src/key.service.spec.ts index 1fc998dc131..7d7ac99898d 100644 --- a/libs/key-management/src/key.service.spec.ts +++ b/libs/key-management/src/key.service.spec.ts @@ -148,39 +148,25 @@ describe("keyService", () => { }); }); - describe.each(["hasUserKey", "hasUserKeyInMemory"])(`%s`, (methodName: string) => { + describe("hasUserKey", () => { let mockUserKey: UserKey; - let method: (userId?: UserId) => Promise; beforeEach(() => { const mockRandomBytes = new Uint8Array(64) as CsprngArray; mockUserKey = new SymmetricCryptoKey(mockRandomBytes) as UserKey; - method = - methodName === "hasUserKey" - ? keyService.hasUserKey.bind(keyService) - : keyService.hasUserKeyInMemory.bind(keyService); }); + test.each([null as unknown as UserId, undefined as unknown as UserId])( + "returns false when userId is %s", + async (userId) => { + expect(await keyService.hasUserKey(userId)).toBe(false); + }, + ); + it.each([true, false])("returns %s if the user key is set", async (hasKey) => { stateProvider.singleUser.getFake(mockUserId, USER_KEY).nextState(hasKey ? mockUserKey : null); - expect(await method(mockUserId)).toBe(hasKey); + expect(await keyService.hasUserKey(mockUserId)).toBe(hasKey); }); - - it("returns false when no active userId is set", async () => { - accountService.activeAccountSubject.next(null); - expect(await method()).toBe(false); - }); - - it.each([true, false])( - "resolves %s for active user id when none is provided", - async (hasKey) => { - stateProvider.activeUserId$ = of(mockUserId); - stateProvider.singleUser - .getFake(mockUserId, USER_KEY) - .nextState(hasKey ? mockUserKey : null); - expect(await method()).toBe(hasKey); - }, - ); }); describe("getUserKeyWithLegacySupport", () => { @@ -410,6 +396,19 @@ describe("keyService", () => { }); }); + describe("makeSendKey", () => { + const mockRandomBytes = new Uint8Array(16) as CsprngArray; + it("calls keyGenerationService with expected hard coded parameters", async () => { + await keyService.makeSendKey(mockRandomBytes); + + expect(keyGenerationService.deriveKeyFromMaterial).toHaveBeenCalledWith( + mockRandomBytes, + "bitwarden-send", + "send", + ); + }); + }); + describe("clearStoredUserKey", () => { describe("input validation", () => { const invalidUserIdTestCases = [ diff --git a/libs/key-management/src/key.service.ts b/libs/key-management/src/key.service.ts index eae52a2ba87..a8e75123b85 100644 --- a/libs/key-management/src/key.service.ts +++ b/libs/key-management/src/key.service.ts @@ -198,16 +198,7 @@ export class DefaultKeyService implements KeyServiceAbstraction { return userKey; } - async hasUserKey(userId?: UserId): Promise { - userId ??= await firstValueFrom(this.stateProvider.activeUserId$); - if (userId == null) { - return false; - } - return await this.hasUserKeyInMemory(userId); - } - - async hasUserKeyInMemory(userId?: UserId): Promise { - userId ??= await firstValueFrom(this.stateProvider.activeUserId$); + async hasUserKey(userId: UserId): Promise { if (userId == null) { return false; } @@ -215,10 +206,6 @@ export class DefaultKeyService implements KeyServiceAbstraction { return (await firstValueFrom(this.stateProvider.getUserState$(USER_KEY, userId))) != null; } - async hasUserKeyStored(keySuffix: KeySuffixOptions, userId?: UserId): Promise { - return (await this.getKeyFromStorage(keySuffix, userId)) != null; - } - async makeUserKey(masterKey: MasterKey | null): Promise<[UserKey, EncString]> { if (masterKey == null) { const userId = await firstValueFrom(this.stateProvider.activeUserId$); From b62f6c7eb5cf0ff7d05b8d6b785711f74c28b2ca Mon Sep 17 00:00:00 2001 From: SmithThe4th Date: Wed, 9 Jul 2025 13:24:58 -0400 Subject: [PATCH 089/239] Fixed from json conversion for encyrpted key (#15536) --- libs/common/src/vault/models/view/attachment.view.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/common/src/vault/models/view/attachment.view.ts b/libs/common/src/vault/models/view/attachment.view.ts index 57a1deaedb9..d943d21367d 100644 --- a/libs/common/src/vault/models/view/attachment.view.ts +++ b/libs/common/src/vault/models/view/attachment.view.ts @@ -45,7 +45,8 @@ export class AttachmentView implements View { static fromJSON(obj: Partial>): AttachmentView { const key = obj.key == null ? null : SymmetricCryptoKey.fromJSON(obj.key); - return Object.assign(new AttachmentView(), obj, { key: key }); + const encryptedKey = obj.encryptedKey == null ? undefined : new EncString(obj.encryptedKey); + return Object.assign(new AttachmentView(), obj, { key: key, encryptedKey: encryptedKey }); } /** From 90b71972793648e90e1ae43acd958ecb0a413470 Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Wed, 9 Jul 2025 21:38:33 +0200 Subject: [PATCH 090/239] [PM-20210] Expand badge API (#14801) * feat: scaffold new badge service structure * feat: add state override * feat: add priority-based override * feat: implement state clearing * feat: add docs to badge service functions * feat: add support for setting icon * feat: implement unsetting * feat: implement setting text * feat: add support for setting background * fix: default icon * feat: clean up old update-badge * feat: save state using StateProvider * feat: migrate auth status badge updating * feat: migrate autofill badge updating * fix: auto set to default values * chore: woops, clean up copy-pasta * fix: lint and types * chore: nit updates from PR review * feat: remove ability to send in arbitrary icons * feat: move init to separate function * fix: wrong import * fix: typing issues * fix: try again to fix typing issues * feat: scaffold tests for new tabId-specific states * feat: add diffence util function * feat: add support for limiting state to tabId * feat: re-implement autofill badge updater to only update when a tab actually changes * feat[wip]: always set all tabs when changing the general state * feat[wip]: implement general states for mutliple open tabs * feat[wip]: implement fully working multi-tab functionality * feat: optimize api calls * feat: adjust storage * chore: clean up old code * chore: remove unused log service * chore: minor tweaks * fix: types * fix: race condition causing wrong icon on startup The service assumes that the first emission from the state will be an empty one and discards it (techincally it just doesn't act on it because pairwise requires a minimum two emissions). This caused issues when a service is able to update the state before the observable got a change to properly initialize. To fix this we simply force an empty emission before anything else, that way we will always react to the emission from the state provider (because that would end up being the second emission). We then use distinctUntilChanged to avoid unecessarily acting on an empty state. --- .../auth-status-badge-updater.service.ts | 56 ++ .../background/tabs.background.spec.ts | 8 - .../autofill/background/tabs.background.ts | 2 - .../autofill-badge-updater.service.ts | 163 +++++ .../browser/src/background/main.background.ts | 38 +- .../src/background/runtime.background.ts | 3 - .../src/platform/badge/array-utils.spec.ts | 17 + .../browser/src/platform/badge/array-utils.ts | 16 + .../src/platform/badge/badge-browser-api.ts | 119 ++++ .../src/platform/badge/badge.service.spec.ts | 562 ++++++++++++++++++ .../src/platform/badge/badge.service.ts | 182 ++++++ apps/browser/src/platform/badge/consts.ts | 9 + apps/browser/src/platform/badge/icon.ts | 21 + apps/browser/src/platform/badge/priority.ts | 7 + apps/browser/src/platform/badge/state.ts | 32 + .../badge/test/mock-badge-browser-api.ts | 21 + .../src/platform/browser/browser-api.ts | 2 +- .../src/platform/listeners/update-badge.ts | 217 ------- .../src/platform/state/state-definitions.ts | 3 + 19 files changed, 1237 insertions(+), 241 deletions(-) create mode 100644 apps/browser/src/auth/services/auth-status-badge-updater.service.ts create mode 100644 apps/browser/src/autofill/services/autofill-badge-updater.service.ts create mode 100644 apps/browser/src/platform/badge/array-utils.spec.ts create mode 100644 apps/browser/src/platform/badge/array-utils.ts create mode 100644 apps/browser/src/platform/badge/badge-browser-api.ts create mode 100644 apps/browser/src/platform/badge/badge.service.spec.ts create mode 100644 apps/browser/src/platform/badge/badge.service.ts create mode 100644 apps/browser/src/platform/badge/consts.ts create mode 100644 apps/browser/src/platform/badge/icon.ts create mode 100644 apps/browser/src/platform/badge/priority.ts create mode 100644 apps/browser/src/platform/badge/state.ts create mode 100644 apps/browser/src/platform/badge/test/mock-badge-browser-api.ts delete mode 100644 apps/browser/src/platform/listeners/update-badge.ts diff --git a/apps/browser/src/auth/services/auth-status-badge-updater.service.ts b/apps/browser/src/auth/services/auth-status-badge-updater.service.ts new file mode 100644 index 00000000000..4205ebc665d --- /dev/null +++ b/apps/browser/src/auth/services/auth-status-badge-updater.service.ts @@ -0,0 +1,56 @@ +import { mergeMap, of, switchMap } from "rxjs"; + +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; +import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; + +import { BadgeService } from "../../platform/badge/badge.service"; +import { BadgeIcon } from "../../platform/badge/icon"; +import { BadgeStatePriority } from "../../platform/badge/priority"; +import { Unset } from "../../platform/badge/state"; + +const StateName = "auth-status"; + +export class AuthStatusBadgeUpdaterService { + constructor( + private badgeService: BadgeService, + private accountService: AccountService, + private authService: AuthService, + ) { + this.accountService.activeAccount$ + .pipe( + switchMap((account) => + account + ? this.authService.authStatusFor$(account.id) + : of(AuthenticationStatus.LoggedOut), + ), + mergeMap(async (authStatus) => { + switch (authStatus) { + case AuthenticationStatus.LoggedOut: { + await this.badgeService.setState(StateName, BadgeStatePriority.High, { + icon: BadgeIcon.LoggedOut, + backgroundColor: Unset, + text: Unset, + }); + break; + } + case AuthenticationStatus.Locked: { + await this.badgeService.setState(StateName, BadgeStatePriority.High, { + icon: BadgeIcon.Locked, + backgroundColor: Unset, + text: Unset, + }); + break; + } + case AuthenticationStatus.Unlocked: { + await this.badgeService.setState(StateName, BadgeStatePriority.Low, { + icon: BadgeIcon.Unlocked, + }); + break; + } + } + }), + ) + .subscribe(); + } +} diff --git a/apps/browser/src/autofill/background/tabs.background.spec.ts b/apps/browser/src/autofill/background/tabs.background.spec.ts index 4473eb452f3..635ab8504a1 100644 --- a/apps/browser/src/autofill/background/tabs.background.spec.ts +++ b/apps/browser/src/autofill/background/tabs.background.spec.ts @@ -73,7 +73,6 @@ describe("TabsBackground", () => { triggerWindowOnFocusedChangedEvent(10); await flushPromises(); - expect(mainBackground.refreshBadge).toHaveBeenCalled(); expect(mainBackground.refreshMenu).toHaveBeenCalled(); expect(overlayBackground.updateOverlayCiphers).toHaveBeenCalled(); }); @@ -91,7 +90,6 @@ describe("TabsBackground", () => { triggerTabOnActivatedEvent({ tabId: 10, windowId: 20 }); await flushPromises(); - expect(mainBackground.refreshBadge).toHaveBeenCalled(); expect(mainBackground.refreshMenu).toHaveBeenCalled(); expect(overlayBackground.updateOverlayCiphers).toHaveBeenCalled(); }); @@ -127,7 +125,6 @@ describe("TabsBackground", () => { triggerTabOnReplacedEvent(10, 20); await flushPromises(); - expect(mainBackground.refreshBadge).toHaveBeenCalled(); expect(mainBackground.refreshMenu).toHaveBeenCalled(); expect(overlayBackground.updateOverlayCiphers).toHaveBeenCalled(); }); @@ -160,7 +157,6 @@ describe("TabsBackground", () => { triggerTabOnUpdatedEvent(focusedWindowId, { status: "loading" }, tab); await flushPromises(); - expect(mainBackground.refreshBadge).not.toHaveBeenCalled(); expect(mainBackground.refreshMenu).not.toHaveBeenCalled(); expect(overlayBackground.updateOverlayCiphers).not.toHaveBeenCalled(); }); @@ -170,7 +166,6 @@ describe("TabsBackground", () => { triggerTabOnUpdatedEvent(focusedWindowId, { status: "loading" }, tab); await flushPromises(); - expect(mainBackground.refreshBadge).not.toHaveBeenCalled(); expect(mainBackground.refreshMenu).not.toHaveBeenCalled(); expect(overlayBackground.updateOverlayCiphers).not.toHaveBeenCalled(); }); @@ -180,7 +175,6 @@ describe("TabsBackground", () => { triggerTabOnUpdatedEvent(focusedWindowId, { status: "loading" }, tab); await flushPromises(); - expect(mainBackground.refreshBadge).not.toHaveBeenCalled(); expect(mainBackground.refreshMenu).not.toHaveBeenCalled(); expect(overlayBackground.updateOverlayCiphers).not.toHaveBeenCalled(); }); @@ -190,7 +184,6 @@ describe("TabsBackground", () => { triggerTabOnUpdatedEvent(focusedWindowId, { status: "loading" }, tab); await flushPromises(); - expect(mainBackground.refreshBadge).not.toHaveBeenCalled(); expect(mainBackground.refreshMenu).not.toHaveBeenCalled(); }); @@ -205,7 +198,6 @@ describe("TabsBackground", () => { triggerTabOnUpdatedEvent(focusedWindowId, { status: "loading" }, tab); await flushPromises(); - expect(mainBackground.refreshBadge).toHaveBeenCalled(); expect(mainBackground.refreshMenu).toHaveBeenCalled(); expect(overlayBackground.updateOverlayCiphers).toHaveBeenCalled(); }); diff --git a/apps/browser/src/autofill/background/tabs.background.ts b/apps/browser/src/autofill/background/tabs.background.ts index c093f1a3b00..4d520680980 100644 --- a/apps/browser/src/autofill/background/tabs.background.ts +++ b/apps/browser/src/autofill/background/tabs.background.ts @@ -102,7 +102,6 @@ export default class TabsBackground { this.main.onUpdatedRan = true; await this.notificationBackground.checkNotificationQueue(tab); - await this.main.refreshBadge(); await this.main.refreshMenu(); this.main.messagingService.send("tabChanged"); }; @@ -122,7 +121,6 @@ export default class TabsBackground { */ private updateCurrentTabData = async () => { await Promise.all([ - this.main.refreshBadge(), this.main.refreshMenu(), this.overlayBackground.updateOverlayCiphers(false), ]); diff --git a/apps/browser/src/autofill/services/autofill-badge-updater.service.ts b/apps/browser/src/autofill/services/autofill-badge-updater.service.ts new file mode 100644 index 00000000000..42cb8886216 --- /dev/null +++ b/apps/browser/src/autofill/services/autofill-badge-updater.service.ts @@ -0,0 +1,163 @@ +import { combineLatest, distinctUntilChanged, mergeMap, of, Subject, switchMap } from "rxjs"; + +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { BadgeSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/badge-settings.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { UserId } from "@bitwarden/common/types/guid"; +import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; + +import { BadgeService } from "../../platform/badge/badge.service"; +import { BadgeStatePriority } from "../../platform/badge/priority"; +import { BrowserApi } from "../../platform/browser/browser-api"; + +const StateName = (tabId: number) => `autofill-badge-${tabId}`; + +export class AutofillBadgeUpdaterService { + private tabReplaced$ = new Subject<{ addedTab: chrome.tabs.Tab; removedTabId: number }>(); + private tabUpdated$ = new Subject(); + private tabRemoved$ = new Subject(); + + constructor( + private badgeService: BadgeService, + private accountService: AccountService, + private cipherService: CipherService, + private badgeSettingsService: BadgeSettingsServiceAbstraction, + private logService: LogService, + ) { + const cipherViews$ = this.accountService.activeAccount$.pipe( + switchMap((account) => (account?.id ? this.cipherService.cipherViews$(account?.id) : of([]))), + ); + + combineLatest({ + account: this.accountService.activeAccount$, + enableBadgeCounter: + this.badgeSettingsService.enableBadgeCounter$.pipe(distinctUntilChanged()), + ciphers: cipherViews$, + }) + .pipe( + mergeMap(async ({ account, enableBadgeCounter, ciphers }) => { + if (!account) { + return; + } + + const tabs = await BrowserApi.tabsQuery({}); + for (const tab of tabs) { + if (!tab.id) { + continue; + } + + if (enableBadgeCounter) { + await this.setTabState(tab, account.id); + } else { + await this.clearTabState(tab.id); + } + } + }), + ) + .subscribe(); + + combineLatest({ + account: this.accountService.activeAccount$, + enableBadgeCounter: this.badgeSettingsService.enableBadgeCounter$, + replaced: this.tabReplaced$, + ciphers: cipherViews$, + }) + .pipe( + mergeMap(async ({ account, enableBadgeCounter, replaced }) => { + if (!account || !enableBadgeCounter) { + return; + } + + await this.clearTabState(replaced.removedTabId); + await this.setTabState(replaced.addedTab, account.id); + }), + ) + .subscribe(); + + combineLatest({ + account: this.accountService.activeAccount$, + enableBadgeCounter: this.badgeSettingsService.enableBadgeCounter$, + tab: this.tabUpdated$, + ciphers: cipherViews$, + }) + .pipe( + mergeMap(async ({ account, enableBadgeCounter, tab }) => { + if (!account || !enableBadgeCounter) { + return; + } + + await this.setTabState(tab, account.id); + }), + ) + .subscribe(); + + combineLatest({ + account: this.accountService.activeAccount$, + enableBadgeCounter: this.badgeSettingsService.enableBadgeCounter$, + tabId: this.tabRemoved$, + ciphers: cipherViews$, + }) + .pipe( + mergeMap(async ({ account, enableBadgeCounter, tabId }) => { + if (!account || !enableBadgeCounter) { + return; + } + + await this.clearTabState(tabId); + }), + ) + .subscribe(); + } + + init() { + BrowserApi.addListener(chrome.tabs.onReplaced, async (addedTabId, removedTabId) => { + const newTab = await BrowserApi.getTab(addedTabId); + if (!newTab) { + this.logService.warning( + `Tab replaced event received but new tab not found (id: ${addedTabId})`, + ); + return; + } + + this.tabReplaced$.next({ + removedTabId, + addedTab: newTab, + }); + }); + BrowserApi.addListener(chrome.tabs.onUpdated, (_, changeInfo, tab) => { + if (changeInfo.url) { + this.tabUpdated$.next(tab); + } + }); + BrowserApi.addListener(chrome.tabs.onRemoved, (tabId, _) => this.tabRemoved$.next(tabId)); + } + + private async setTabState(tab: chrome.tabs.Tab, userId: UserId) { + if (!tab.id) { + this.logService.warning("Tab event received but tab id is undefined"); + return; + } + + const ciphers = tab.url ? await this.cipherService.getAllDecryptedForUrl(tab.url, userId) : []; + const cipherCount = ciphers.length; + + if (cipherCount === 0) { + await this.clearTabState(tab.id); + return; + } + + const countText = cipherCount > 9 ? "9+" : cipherCount.toString(); + await this.badgeService.setState( + StateName(tab.id), + BadgeStatePriority.Default, + { + text: countText, + }, + tab.id, + ); + } + + private async clearTabState(tabId: number) { + await this.badgeService.clearState(StateName(tabId)); + } +} diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 16149ea0fb3..3f29151a1b7 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -242,6 +242,7 @@ import { VaultExportServiceAbstraction, } from "@bitwarden/vault-export-core"; +import { AuthStatusBadgeUpdaterService } from "../auth/services/auth-status-badge-updater.service"; import { OverlayNotificationsBackground as OverlayNotificationsBackgroundInterface } from "../autofill/background/abstractions/overlay-notifications.background"; import { OverlayBackground as OverlayBackgroundInterface } from "../autofill/background/abstractions/overlay.background"; import { AutoSubmitLoginBackground } from "../autofill/background/auto-submit-login.background"; @@ -261,16 +262,18 @@ import { BrowserFido2UserInterfaceService, } from "../autofill/fido2/services/browser-fido2-user-interface.service"; import { AutofillService as AutofillServiceAbstraction } from "../autofill/services/abstractions/autofill.service"; +import { AutofillBadgeUpdaterService } from "../autofill/services/autofill-badge-updater.service"; import AutofillService from "../autofill/services/autofill.service"; import { InlineMenuFieldQualificationService } from "../autofill/services/inline-menu-field-qualification.service"; import { SafariApp } from "../browser/safariApp"; import { BackgroundBrowserBiometricsService } from "../key-management/biometrics/background-browser-biometrics.service"; import VaultTimeoutService from "../key-management/vault-timeout/vault-timeout.service"; +import { DefaultBadgeBrowserApi } from "../platform/badge/badge-browser-api"; +import { BadgeService } from "../platform/badge/badge.service"; import { BrowserApi } from "../platform/browser/browser-api"; import { flagEnabled } from "../platform/flags"; import { IpcBackgroundService } from "../platform/ipc/ipc-background.service"; import { IpcContentScriptManagerService } from "../platform/ipc/ipc-content-script-manager.service"; -import { UpdateBadge } from "../platform/listeners/update-badge"; /* eslint-disable no-restricted-imports */ import { ChromeMessageSender } from "../platform/messaging/chrome-message.sender"; /* eslint-enable no-restricted-imports */ @@ -421,6 +424,10 @@ export default class MainBackground { ipcContentScriptManagerService: IpcContentScriptManagerService; ipcService: IpcService; + badgeService: BadgeService; + authStatusBadgeUpdaterService: AuthStatusBadgeUpdaterService; + autofillBadgeUpdaterService: AutofillBadgeUpdaterService; + onUpdatedRan: boolean; onReplacedRan: boolean; loginToAutoFill: CipherView = null; @@ -444,7 +451,6 @@ export default class MainBackground { constructor() { // Services const lockedCallback = async (userId: UserId) => { - await this.refreshBadge(); await this.refreshMenu(true); if (this.systemService != null) { await this.systemService.clearPendingClipboard(); @@ -1363,6 +1369,16 @@ export default class MainBackground { this.authService, this.logService, ); + + this.badgeService = new BadgeService( + this.stateProvider, + new DefaultBadgeBrowserApi(this.platformUtilsService), + ); + this.authStatusBadgeUpdaterService = new AuthStatusBadgeUpdaterService( + this.badgeService, + this.accountService, + this.authService, + ); } async bootstrap() { @@ -1437,10 +1453,10 @@ export default class MainBackground { await this.initOverlayAndTabsBackground(); await this.ipcService.init(); + this.badgeService.startListening(); return new Promise((resolve) => { setTimeout(async () => { - await this.refreshBadge(); await this.fullSync(false); this.backgroundSyncService.init(); this.notificationsService.startListening(); @@ -1455,10 +1471,6 @@ export default class MainBackground { }); } - async refreshBadge() { - await new UpdateBadge(self, this).run(); - } - async refreshMenu(forLocked = false) { if (!chrome.windows || !chrome.contextMenus) { return; @@ -1530,7 +1542,6 @@ export default class MainBackground { await switchPromise; if (userId == null) { - await this.refreshBadge(); await this.refreshMenu(); await this.updateOverlayCiphers(); this.messagingService.send("goHome"); @@ -1547,7 +1558,6 @@ export default class MainBackground { this.messagingService.send("locked", { userId: userId }); } else { this.messagingService.send("unlocked", { userId: userId }); - await this.refreshBadge(); await this.refreshMenu(); await this.updateOverlayCiphers(); await this.syncService.fullSync(false); @@ -1640,7 +1650,6 @@ export default class MainBackground { // eslint-disable-next-line @typescript-eslint/no-floating-promises BrowserApi.sendMessage("updateBadge"); } - await this.refreshBadge(); await this.mainContextMenuHandler?.noAccess(); await this.systemService.clearPendingClipboard(); await this.processReloadService.startProcessReload(this.authService); @@ -1805,6 +1814,14 @@ export default class MainBackground { (password) => this.addPasswordToHistory(password), ); + this.autofillBadgeUpdaterService = new AutofillBadgeUpdaterService( + this.badgeService, + this.accountService, + this.cipherService, + this.badgeSettingsService, + this.logService, + ); + this.tabsBackground = new TabsBackground( this, this.notificationBackground, @@ -1813,6 +1830,7 @@ export default class MainBackground { await this.overlayBackground.init(); await this.tabsBackground.init(); + await this.autofillBadgeUpdaterService.init(); } generatePassword = async (): Promise => { diff --git a/apps/browser/src/background/runtime.background.ts b/apps/browser/src/background/runtime.background.ts index 54fb8326cfb..1e7a0140022 100644 --- a/apps/browser/src/background/runtime.background.ts +++ b/apps/browser/src/background/runtime.background.ts @@ -256,7 +256,6 @@ export default class RuntimeBackground { // @TODO these need to happen last to avoid blocking `tabSendMessageData` above // The underlying cause exists within `cipherService.getAllDecrypted` via // `getAllDecryptedForUrl` and is anticipated to be refactored - await this.main.refreshBadge(); await this.main.refreshMenu(false); await this.autofillService.setAutoFillOnPageLoadOrgPolicy(); @@ -280,7 +279,6 @@ export default class RuntimeBackground { case "syncCompleted": if (msg.successfully) { setTimeout(async () => { - await this.main.refreshBadge(); await this.main.refreshMenu(); }, 2000); await this.configService.ensureConfigFetched(); @@ -304,7 +302,6 @@ export default class RuntimeBackground { case "editedCipher": case "addedCipher": case "deletedCipher": - await this.main.refreshBadge(); await this.main.refreshMenu(); break; case "bgReseedStorage": { diff --git a/apps/browser/src/platform/badge/array-utils.spec.ts b/apps/browser/src/platform/badge/array-utils.spec.ts new file mode 100644 index 00000000000..3f41019f02e --- /dev/null +++ b/apps/browser/src/platform/badge/array-utils.spec.ts @@ -0,0 +1,17 @@ +import { difference } from "./array-utils"; + +describe("array-utils", () => { + describe("difference", () => { + it.each([ + [new Set([1, 2, 3]), new Set([]), new Set([1, 2, 3]), new Set([])], + [new Set([]), new Set([1, 2, 3]), new Set([]), new Set([1, 2, 3])], + [new Set([1, 2, 3]), new Set([2, 3, 5]), new Set([1]), new Set([5])], + [new Set([1, 2, 3]), new Set([1, 2, 3]), new Set([]), new Set([])], + ])("returns elements that are unique to each set", (A, B, onlyA, onlyB) => { + const [resultA, resultB] = difference(A, B); + + expect(resultA).toEqual(onlyA); + expect(resultB).toEqual(onlyB); + }); + }); +}); diff --git a/apps/browser/src/platform/badge/array-utils.ts b/apps/browser/src/platform/badge/array-utils.ts new file mode 100644 index 00000000000..699006e6153 --- /dev/null +++ b/apps/browser/src/platform/badge/array-utils.ts @@ -0,0 +1,16 @@ +/** + * Returns the difference between two sets. + * @param a First set + * @param b Second set + * @returns A tuple containing two sets: + * - The first set contains elements unique to `a`. + * - The second set contains elements unique to `b`. + * - If an element is present in both sets, it will not be included in either set. + */ +export function difference(a: Set, b: Set): [Set, Set] { + const intersection = new Set([...a].filter((x) => b.has(x))); + a = new Set([...a].filter((x) => !intersection.has(x))); + b = new Set([...b].filter((x) => !intersection.has(x))); + + return [a, b]; +} diff --git a/apps/browser/src/platform/badge/badge-browser-api.ts b/apps/browser/src/platform/badge/badge-browser-api.ts new file mode 100644 index 00000000000..9febaf8d39c --- /dev/null +++ b/apps/browser/src/platform/badge/badge-browser-api.ts @@ -0,0 +1,119 @@ +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; + +import { BrowserApi } from "../browser/browser-api"; + +import { BadgeIcon, IconPaths } from "./icon"; + +export interface RawBadgeState { + tabId?: string; + text: string; + backgroundColor: string; + icon: BadgeIcon; +} + +export interface BadgeBrowserApi { + setState(state: RawBadgeState, tabId?: number): Promise; + getTabs(): Promise; +} + +export class DefaultBadgeBrowserApi implements BadgeBrowserApi { + private badgeAction = BrowserApi.getBrowserAction(); + private sidebarAction = BrowserApi.getSidebarAction(self); + + constructor(private platformUtilsService: PlatformUtilsService) {} + + async setState(state: RawBadgeState, tabId?: number): Promise { + await Promise.all([ + state.backgroundColor !== undefined ? this.setIcon(state.icon, tabId) : undefined, + this.setText(state.text, tabId), + state.backgroundColor !== undefined + ? this.setBackgroundColor(state.backgroundColor, tabId) + : undefined, + ]); + } + + async getTabs(): Promise { + return (await BrowserApi.tabsQuery({})).map((tab) => tab.id).filter((tab) => tab !== undefined); + } + + private setIcon(icon: IconPaths, tabId?: number) { + return Promise.all([this.setActionIcon(icon, tabId), this.setSidebarActionIcon(icon, tabId)]); + } + + private setText(text: string, tabId?: number) { + return Promise.all([this.setActionText(text, tabId), this.setSideBarText(text, tabId)]); + } + + private async setActionIcon(path: IconPaths, tabId?: number) { + if (!this.badgeAction?.setIcon) { + return; + } + + if (this.useSyncApiCalls) { + await this.badgeAction.setIcon({ path, tabId }); + } else { + await new Promise((resolve) => this.badgeAction.setIcon({ path, tabId }, resolve)); + } + } + + private async setSidebarActionIcon(path: IconPaths, tabId?: number) { + if (!this.sidebarAction?.setIcon) { + return; + } + + if ("opr" in self && BrowserApi.isManifestVersion(3)) { + // setIcon API is currenly broken for Opera MV3 extensions + // https://forums.opera.com/topic/75680/opr-sidebaraction-seticon-api-is-broken-access-to-extension-api-denied?_=1738349261570 + // The API currently crashes on MacOS + return; + } + + if (this.isOperaSidebar(this.sidebarAction)) { + await new Promise((resolve) => + (this.sidebarAction as OperaSidebarAction).setIcon({ path, tabId }, () => resolve()), + ); + } else { + await this.sidebarAction.setIcon({ path, tabId }); + } + } + + private async setActionText(text: string, tabId?: number) { + if (this.badgeAction?.setBadgeText) { + await this.badgeAction.setBadgeText({ text, tabId }); + } + } + + private async setSideBarText(text: string, tabId?: number) { + if (!this.sidebarAction) { + return; + } + + if (this.isOperaSidebar(this.sidebarAction)) { + this.sidebarAction.setBadgeText({ text, tabId }); + } else if (this.sidebarAction) { + // Firefox + const title = `Bitwarden${Utils.isNullOrEmpty(text) ? "" : ` [${text}]`}`; + await this.sidebarAction.setTitle({ title, tabId }); + } + } + + private async setBackgroundColor(color: string, tabId?: number) { + if (this.badgeAction && this.badgeAction?.setBadgeBackgroundColor) { + await this.badgeAction.setBadgeBackgroundColor({ color, tabId }); + } + if (this.sidebarAction && this.isOperaSidebar(this.sidebarAction)) { + this.sidebarAction.setBadgeBackgroundColor({ color, tabId }); + } + } + + private get useSyncApiCalls() { + return this.platformUtilsService.isFirefox() || this.platformUtilsService.isSafari(); + } + + private isOperaSidebar( + action: OperaSidebarAction | FirefoxSidebarAction, + ): action is OperaSidebarAction { + return action != null && (action as OperaSidebarAction).setBadgeText != null; + } +} diff --git a/apps/browser/src/platform/badge/badge.service.spec.ts b/apps/browser/src/platform/badge/badge.service.spec.ts new file mode 100644 index 00000000000..2a7ba2ce392 --- /dev/null +++ b/apps/browser/src/platform/badge/badge.service.spec.ts @@ -0,0 +1,562 @@ +import { Subscription } from "rxjs"; + +import { FakeAccountService, FakeStateProvider } from "@bitwarden/common/spec"; + +import { RawBadgeState } from "./badge-browser-api"; +import { BadgeService } from "./badge.service"; +import { DefaultBadgeState } from "./consts"; +import { BadgeIcon } from "./icon"; +import { BadgeStatePriority } from "./priority"; +import { BadgeState, Unset } from "./state"; +import { MockBadgeBrowserApi } from "./test/mock-badge-browser-api"; + +describe("BadgeService", () => { + let badgeApi: MockBadgeBrowserApi; + let stateProvider: FakeStateProvider; + let badgeService!: BadgeService; + + let badgeServiceSubscription: Subscription; + + beforeEach(() => { + badgeApi = new MockBadgeBrowserApi(); + stateProvider = new FakeStateProvider(new FakeAccountService({})); + + badgeService = new BadgeService(stateProvider, badgeApi); + }); + + afterEach(() => { + badgeServiceSubscription?.unsubscribe(); + }); + + describe("calling without tabId", () => { + const tabId = 1; + + describe("given a single tab is open", () => { + beforeEach(() => { + badgeApi.tabs = [1]; + badgeServiceSubscription = badgeService.startListening(); + }); + + // This relies on the state provider to auto-emit + it("sets default values on startup", async () => { + expect(badgeApi.generalState).toEqual(DefaultBadgeState); + }); + + it("sets provided state when no other state has been set", async () => { + const state: BadgeState = { + text: "text", + backgroundColor: "color", + icon: BadgeIcon.Locked, + }; + + await badgeService.setState("state-name", BadgeStatePriority.Default, state); + + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(badgeApi.generalState).toEqual(state); + expect(badgeApi.specificStates[tabId]).toEqual(state); + }); + + it("sets default values when none are provided", async () => { + // This is a bit of a weird thing to do, but I don't think it's something we need to prohibit + const state: BadgeState = {}; + + await badgeService.setState("state-name", BadgeStatePriority.Default, state); + + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(badgeApi.generalState).toEqual(DefaultBadgeState); + expect(badgeApi.specificStates[tabId]).toEqual(DefaultBadgeState); + }); + + it("merges states when multiple same-priority states have been set", async () => { + await badgeService.setState("state-1", BadgeStatePriority.Default, { text: "text" }); + await badgeService.setState("state-2", BadgeStatePriority.Default, { + backgroundColor: "#fff", + }); + await badgeService.setState("state-3", BadgeStatePriority.Default, { + icon: BadgeIcon.Locked, + }); + + await new Promise((resolve) => setTimeout(resolve, 0)); + const expectedState: RawBadgeState = { + text: "text", + backgroundColor: "#fff", + icon: BadgeIcon.Locked, + }; + expect(badgeApi.generalState).toEqual(expectedState); + expect(badgeApi.specificStates[tabId]).toEqual(expectedState); + }); + + it("overrides previous lower-priority state when higher-priority state is set", async () => { + await badgeService.setState("state-1", BadgeStatePriority.Low, { + text: "text", + backgroundColor: "#fff", + icon: BadgeIcon.Locked, + }); + await badgeService.setState("state-2", BadgeStatePriority.Default, { + text: "override", + }); + await badgeService.setState("state-3", BadgeStatePriority.High, { + backgroundColor: "#aaa", + }); + + await new Promise((resolve) => setTimeout(resolve, 0)); + const expectedState: RawBadgeState = { + text: "override", + backgroundColor: "#aaa", + icon: BadgeIcon.Locked, + }; + expect(badgeApi.generalState).toEqual(expectedState); + expect(badgeApi.specificStates[tabId]).toEqual(expectedState); + }); + + it("removes override when a previously high-priority state is cleared", async () => { + await badgeService.setState("state-1", BadgeStatePriority.Low, { + text: "text", + backgroundColor: "#fff", + icon: BadgeIcon.Locked, + }); + await badgeService.setState("state-2", BadgeStatePriority.Default, { + text: "override", + }); + await badgeService.clearState("state-2"); + + await new Promise((resolve) => setTimeout(resolve, 0)); + const expectedState: RawBadgeState = { + text: "text", + backgroundColor: "#fff", + icon: BadgeIcon.Locked, + }; + expect(badgeApi.generalState).toEqual(expectedState); + expect(badgeApi.specificStates[tabId]).toEqual(expectedState); + }); + + it("sets default values when all states have been cleared", async () => { + await badgeService.setState("state-1", BadgeStatePriority.Low, { + text: "text", + backgroundColor: "#fff", + icon: BadgeIcon.Locked, + }); + await badgeService.setState("state-2", BadgeStatePriority.Default, { + text: "override", + }); + await badgeService.setState("state-3", BadgeStatePriority.High, { + backgroundColor: "#aaa", + }); + await badgeService.clearState("state-1"); + await badgeService.clearState("state-2"); + await badgeService.clearState("state-3"); + + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(badgeApi.generalState).toEqual(DefaultBadgeState); + expect(badgeApi.specificStates[tabId]).toEqual(DefaultBadgeState); + }); + + it("sets default value high-priority state contains Unset", async () => { + await badgeService.setState("state-1", BadgeStatePriority.Low, { + text: "text", + backgroundColor: "#fff", + icon: BadgeIcon.Locked, + }); + await badgeService.setState("state-3", BadgeStatePriority.High, { + icon: Unset, + }); + + await new Promise((resolve) => setTimeout(resolve, 0)); + const expectedState: RawBadgeState = { + text: "text", + backgroundColor: "#fff", + icon: DefaultBadgeState.icon, + }; + expect(badgeApi.generalState).toEqual(expectedState); + expect(badgeApi.specificStates[tabId]).toEqual(expectedState); + }); + + it("ignores medium-priority Unset when high-priority contains a value", async () => { + await badgeService.setState("state-1", BadgeStatePriority.Low, { + text: "text", + backgroundColor: "#fff", + icon: BadgeIcon.Locked, + }); + await badgeService.setState("state-3", BadgeStatePriority.Default, { + icon: Unset, + }); + await badgeService.setState("state-3", BadgeStatePriority.High, { + icon: BadgeIcon.Unlocked, + }); + + await new Promise((resolve) => setTimeout(resolve, 0)); + const expectedState: RawBadgeState = { + text: "text", + backgroundColor: "#fff", + icon: BadgeIcon.Unlocked, + }; + expect(badgeApi.generalState).toEqual(expectedState); + expect(badgeApi.specificStates[tabId]).toEqual(expectedState); + }); + }); + + describe("given multiple tabs are open", () => { + const tabIds = [1, 2, 3]; + + beforeEach(() => { + badgeApi.tabs = tabIds; + badgeServiceSubscription = badgeService.startListening(); + }); + + it("sets default values for each tab on startup", async () => { + expect(badgeApi.generalState).toEqual(DefaultBadgeState); + for (const tabId of tabIds) { + expect(badgeApi.specificStates[tabId]).toEqual(DefaultBadgeState); + } + }); + + it("sets state for each tab when no other state has been set", async () => { + const state: BadgeState = { + text: "text", + backgroundColor: "color", + icon: BadgeIcon.Locked, + }; + + await badgeService.setState("state-name", BadgeStatePriority.Default, state); + + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(badgeApi.generalState).toEqual(state); + expect(badgeApi.specificStates).toEqual({ + 1: state, + 2: state, + 3: state, + }); + }); + }); + }); + + describe("calling with tabId", () => { + describe("given a single tab is open", () => { + const tabId = 1; + + beforeEach(() => { + badgeApi.tabs = [tabId]; + badgeServiceSubscription = badgeService.startListening(); + }); + + it("sets provided state when no other state has been set", async () => { + const state: BadgeState = { + text: "text", + backgroundColor: "color", + icon: BadgeIcon.Locked, + }; + + await badgeService.setState("state-name", BadgeStatePriority.Default, state, tabId); + + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(badgeApi.generalState).toEqual(DefaultBadgeState); + expect(badgeApi.specificStates[tabId]).toEqual(state); + }); + + it("sets default values when none are provided", async () => { + // This is a bit of a weird thing to do, but I don't think it's something we need to prohibit + const state: BadgeState = {}; + + await badgeService.setState("state-name", BadgeStatePriority.Default, state, tabId); + + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(badgeApi.generalState).toEqual(DefaultBadgeState); + expect(badgeApi.specificStates[tabId]).toEqual(DefaultBadgeState); + }); + + it("merges tabId specific state with general states", async () => { + await badgeService.setState("general-state", BadgeStatePriority.Default, { text: "text" }); + await badgeService.setState( + "specific-state", + BadgeStatePriority.Default, + { + backgroundColor: "#fff", + }, + tabId, + ); + await badgeService.setState("general-state-2", BadgeStatePriority.Default, { + icon: BadgeIcon.Locked, + }); + + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(badgeApi.generalState).toEqual({ + ...DefaultBadgeState, + text: "text", + icon: BadgeIcon.Locked, + }); + expect(badgeApi.specificStates[tabId]).toEqual({ + text: "text", + backgroundColor: "#fff", + icon: BadgeIcon.Locked, + }); + }); + + it("merges states when multiple same-priority states with the same tabId have been set", async () => { + await badgeService.setState("state-1", BadgeStatePriority.Default, { text: "text" }, tabId); + await badgeService.setState( + "state-2", + BadgeStatePriority.Default, + { + backgroundColor: "#fff", + }, + tabId, + ); + await badgeService.setState( + "state-3", + BadgeStatePriority.Default, + { + icon: BadgeIcon.Locked, + }, + tabId, + ); + + await new Promise((resolve) => setTimeout(resolve, 0)); + const expectedState: RawBadgeState = { + text: "text", + backgroundColor: "#fff", + icon: BadgeIcon.Locked, + }; + expect(badgeApi.generalState).toEqual(DefaultBadgeState); + expect(badgeApi.specificStates[tabId]).toEqual(expectedState); + }); + + it("overrides previous lower-priority state when higher-priority state with the same tabId is set", async () => { + await badgeService.setState( + "state-1", + BadgeStatePriority.Low, + { + text: "text", + backgroundColor: "#fff", + icon: BadgeIcon.Locked, + }, + tabId, + ); + await badgeService.setState( + "state-2", + BadgeStatePriority.Default, + { + text: "override", + }, + tabId, + ); + await badgeService.setState( + "state-3", + BadgeStatePriority.High, + { + backgroundColor: "#aaa", + }, + tabId, + ); + + await new Promise((resolve) => setTimeout(resolve, 0)); + const expectedState: RawBadgeState = { + text: "override", + backgroundColor: "#aaa", + icon: BadgeIcon.Locked, + }; + expect(badgeApi.generalState).toEqual(DefaultBadgeState); + expect(badgeApi.specificStates[tabId]).toEqual(expectedState); + }); + + it("overrides lower-priority tab-specific state when higher-priority general state is set", async () => { + await badgeService.setState( + "state-1", + BadgeStatePriority.Low, + { + text: "text", + backgroundColor: "#fff", + icon: BadgeIcon.Locked, + }, + tabId, + ); + await badgeService.setState("state-2", BadgeStatePriority.Default, { + text: "override", + }); + await badgeService.setState("state-3", BadgeStatePriority.High, { + backgroundColor: "#aaa", + }); + + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(badgeApi.generalState).toEqual({ + text: "override", + backgroundColor: "#aaa", + icon: DefaultBadgeState.icon, + }); + expect(badgeApi.specificStates[tabId]).toEqual({ + text: "override", + backgroundColor: "#aaa", + icon: BadgeIcon.Locked, + }); + }); + + it("removes override when a previously high-priority state with the same tabId is cleared", async () => { + await badgeService.setState( + "state-1", + BadgeStatePriority.Low, + { + text: "text", + backgroundColor: "#fff", + icon: BadgeIcon.Locked, + }, + tabId, + ); + await badgeService.setState( + "state-2", + BadgeStatePriority.Default, + { + text: "override", + }, + tabId, + ); + await badgeService.clearState("state-2"); + + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(badgeApi.generalState).toEqual(DefaultBadgeState); + expect(badgeApi.specificStates[tabId]).toEqual({ + text: "text", + backgroundColor: "#fff", + icon: BadgeIcon.Locked, + }); + }); + + it("sets default state when all states with the same tabId have been cleared", async () => { + await badgeService.setState( + "state-1", + BadgeStatePriority.Low, + { + text: "text", + backgroundColor: "#fff", + icon: BadgeIcon.Locked, + }, + tabId, + ); + await badgeService.setState( + "state-2", + BadgeStatePriority.Default, + { + text: "override", + }, + tabId, + ); + await badgeService.setState( + "state-3", + BadgeStatePriority.High, + { + backgroundColor: "#aaa", + }, + tabId, + ); + await badgeService.clearState("state-1"); + await badgeService.clearState("state-2"); + await badgeService.clearState("state-3"); + + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(badgeApi.generalState).toEqual(DefaultBadgeState); + expect(badgeApi.specificStates[tabId]).toEqual(DefaultBadgeState); + }); + + it("sets default value when high-priority state contains Unset", async () => { + await badgeService.setState( + "state-1", + BadgeStatePriority.Low, + { + text: "text", + backgroundColor: "#fff", + icon: BadgeIcon.Locked, + }, + tabId, + ); + await badgeService.setState( + "state-3", + BadgeStatePriority.High, + { + icon: Unset, + }, + tabId, + ); + + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(badgeApi.generalState).toEqual(DefaultBadgeState); + expect(badgeApi.specificStates[tabId]).toEqual({ + text: "text", + backgroundColor: "#fff", + icon: DefaultBadgeState.icon, + }); + }); + + it("ignores medium-priority Unset when high-priority contains a value", async () => { + await badgeService.setState( + "state-1", + BadgeStatePriority.Low, + { + text: "text", + backgroundColor: "#fff", + icon: BadgeIcon.Locked, + }, + tabId, + ); + await badgeService.setState( + "state-3", + BadgeStatePriority.Default, + { + icon: Unset, + }, + tabId, + ); + await badgeService.setState( + "state-3", + BadgeStatePriority.High, + { + icon: BadgeIcon.Unlocked, + }, + tabId, + ); + + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(badgeApi.generalState).toEqual(DefaultBadgeState); + expect(badgeApi.specificStates[tabId]).toEqual({ + text: "text", + backgroundColor: "#fff", + icon: BadgeIcon.Unlocked, + }); + }); + }); + + describe("given multiple tabs are open", () => { + const tabIds = [1, 2, 3]; + + beforeEach(() => { + badgeApi.tabs = tabIds; + badgeServiceSubscription = badgeService.startListening(); + }); + + it("sets tab-specific state for provided tab and general state for the others", async () => { + const generalState: BadgeState = { + text: "general-text", + backgroundColor: "general-color", + icon: BadgeIcon.Unlocked, + }; + const specificState: BadgeState = { + text: "tab-text", + icon: BadgeIcon.Locked, + }; + + await badgeService.setState("general-state", BadgeStatePriority.Default, generalState); + await badgeService.setState( + "tab-state", + BadgeStatePriority.Default, + specificState, + tabIds[0], + ); + + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(badgeApi.generalState).toEqual(generalState); + expect(badgeApi.specificStates).toEqual({ + [tabIds[0]]: { ...specificState, backgroundColor: "general-color" }, + [tabIds[1]]: generalState, + [tabIds[2]]: generalState, + }); + }); + }); + }); +}); diff --git a/apps/browser/src/platform/badge/badge.service.ts b/apps/browser/src/platform/badge/badge.service.ts new file mode 100644 index 00000000000..d48150ac516 --- /dev/null +++ b/apps/browser/src/platform/badge/badge.service.ts @@ -0,0 +1,182 @@ +import { + defer, + distinctUntilChanged, + filter, + map, + mergeMap, + pairwise, + startWith, + Subscription, + switchMap, +} from "rxjs"; + +import { + BADGE_MEMORY, + GlobalState, + KeyDefinition, + StateProvider, +} from "@bitwarden/common/platform/state"; + +import { difference } from "./array-utils"; +import { BadgeBrowserApi, RawBadgeState } from "./badge-browser-api"; +import { DefaultBadgeState } from "./consts"; +import { BadgeStatePriority } from "./priority"; +import { BadgeState, Unset } from "./state"; + +interface StateSetting { + priority: BadgeStatePriority; + state: BadgeState; + tabId?: number; +} + +const BADGE_STATES = new KeyDefinition(BADGE_MEMORY, "badgeStates", { + deserializer: (value: Record) => value ?? {}, +}); + +export class BadgeService { + private states: GlobalState>; + + constructor( + private stateProvider: StateProvider, + private badgeApi: BadgeBrowserApi, + ) { + this.states = this.stateProvider.getGlobal(BADGE_STATES); + } + + /** + * Start listening for badge state changes. + * Without this the service will not be able to update the badge state. + */ + startListening(): Subscription { + const initialSetup$ = defer(async () => { + const openTabs = await this.badgeApi.getTabs(); + await this.badgeApi.setState(DefaultBadgeState); + for (const tabId of openTabs) { + await this.badgeApi.setState(DefaultBadgeState, tabId); + } + }); + + return initialSetup$ + .pipe( + switchMap(() => this.states.state$), + startWith({}), + distinctUntilChanged(), + map((states) => new Set(states ? Object.values(states) : [])), + pairwise(), + map(([previous, current]) => { + const [removed, added] = difference(previous, current); + return { states: current, removed, added }; + }), + filter(({ removed, added }) => removed.size > 0 || added.size > 0), + mergeMap(async ({ states, removed, added }) => { + const changed = [...removed, ...added]; + const changedTabIds = new Set( + changed.map((s) => s.tabId).filter((tabId) => tabId !== undefined), + ); + const onlyTabSpecificStatesChanged = changed.every((s) => s.tabId != undefined); + if (onlyTabSpecificStatesChanged) { + // If only tab-specific states changed then we only need to update those specific tabs. + for (const tabId of changedTabIds) { + const newState = this.calculateState(states, tabId); + await this.badgeApi.setState(newState, tabId); + } + return; + } + + // If there are any general states that changed then we need to update all tabs. + const openTabs = await this.badgeApi.getTabs(); + const generalState = this.calculateState(states); + await this.badgeApi.setState(generalState); + for (const tabId of openTabs) { + const newState = this.calculateState(states, tabId); + await this.badgeApi.setState(newState, tabId); + } + }), + ) + .subscribe(); + } + + /** + * Inform badge service of a new state that the badge should reflect. + * + * This will merge the new state with any existing states: + * - If the new state has a higher priority, it will override any lower priority states. + * - If the new state has a lower priority, it will be ignored. + * - If the name of the state is already in use, it will be updated. + * - If the state has a `tabId` set, it will only apply to that tab. + * - States with `tabId` can still be overridden by states without `tabId` if they have a higher priority. + * + * @param name The name of the state. This is used to identify the state and will be used to clear it later. + * @param priority The priority of the state (higher numbers are higher priority, but setting arbitrary numbers is not supported). + * @param state The state to set. + * @param tabId Limit this badge state to a specific tab. If this is not set, the state will be applied to all tabs. + */ + async setState(name: string, priority: BadgeStatePriority, state: BadgeState, tabId?: number) { + await this.states.update((s) => ({ ...s, [name]: { priority, state, tabId } })); + } + + /** + * Clear the state with the given name. + * + * This will remove the state from the badge service and clear it from the badge. + * If the state is not found, nothing will happen. + * + * @param name The name of the state to clear. + */ + async clearState(name: string) { + await this.states.update((s) => { + const newStates = { ...s }; + delete newStates[name]; + return newStates; + }); + } + + private calculateState(states: Set, tabId?: number): RawBadgeState { + const sortedStates = [...states].sort((a, b) => a.priority - b.priority); + + let filteredStates = sortedStates; + if (tabId !== undefined) { + // Filter out states that are not applicable to the current tab. + // If a state has no tabId, it is considered applicable to all tabs. + // If a state has a tabId, it is only applicable to that tab. + filteredStates = sortedStates.filter((s) => s.tabId === tabId || s.tabId === undefined); + } else { + // If no tabId is provided, we only want states that are not tab-specific. + filteredStates = sortedStates.filter((s) => s.tabId === undefined); + } + + const mergedState = filteredStates + .map((s) => s.state) + .reduce>((acc: Partial, state: BadgeState) => { + const newState = { ...acc }; + + for (const k in state) { + const key = k as keyof BadgeState & keyof RawBadgeState; + setStateValue(newState, state, key); + } + + return newState; + }, DefaultBadgeState); + + return { + ...DefaultBadgeState, + ...mergedState, + }; + } +} + +/** + * Helper value to modify the state variable. + * TS doesn't like it when this is being doine inline. + */ +function setStateValue( + newState: Partial, + state: BadgeState, + key: Key, +) { + if (state[key] === Unset) { + delete newState[key]; + } else if (state[key] !== undefined) { + newState[key] = state[key] as RawBadgeState[Key]; + } +} diff --git a/apps/browser/src/platform/badge/consts.ts b/apps/browser/src/platform/badge/consts.ts new file mode 100644 index 00000000000..67cb4b1035b --- /dev/null +++ b/apps/browser/src/platform/badge/consts.ts @@ -0,0 +1,9 @@ +import { RawBadgeState } from "./badge-browser-api"; +import { BadgeIcon } from "./icon"; +import { BadgeState } from "./state"; + +export const DefaultBadgeState: RawBadgeState & BadgeState = { + text: "", + backgroundColor: "#294e5f", + icon: BadgeIcon.LoggedOut, +}; diff --git a/apps/browser/src/platform/badge/icon.ts b/apps/browser/src/platform/badge/icon.ts new file mode 100644 index 00000000000..d6dcdcc5f7d --- /dev/null +++ b/apps/browser/src/platform/badge/icon.ts @@ -0,0 +1,21 @@ +export const BadgeIcon = { + LoggedOut: { + 19: "/images/icon19_gray.png", + 38: "/images/icon38_gray.png", + } as IconPaths, + Locked: { + 19: "/images/icon19_locked.png", + 38: "/images/icon38_locked.png", + } as IconPaths, + Unlocked: { + 19: "/images/icon19.png", + 38: "/images/icon38.png", + } as IconPaths, +} as const satisfies Record; + +export type BadgeIcon = (typeof BadgeIcon)[keyof typeof BadgeIcon]; + +export type IconPaths = { + 19: string; + 38: string; +}; diff --git a/apps/browser/src/platform/badge/priority.ts b/apps/browser/src/platform/badge/priority.ts new file mode 100644 index 00000000000..6870e571e6a --- /dev/null +++ b/apps/browser/src/platform/badge/priority.ts @@ -0,0 +1,7 @@ +export const BadgeStatePriority = { + Low: 0, + Default: 100, + High: 200, +} as const; + +export type BadgeStatePriority = (typeof BadgeStatePriority)[keyof typeof BadgeStatePriority]; diff --git a/apps/browser/src/platform/badge/state.ts b/apps/browser/src/platform/badge/state.ts new file mode 100644 index 00000000000..0731ad81f41 --- /dev/null +++ b/apps/browser/src/platform/badge/state.ts @@ -0,0 +1,32 @@ +import { BadgeIcon } from "./icon"; + +export const Unset = Symbol("Unset badge state"); +export type Unset = typeof Unset; + +export type BadgeState = { + /** + * The text to display in the badge. + * If this is set to `Unset`, any text set by a lower priority state will be cleared. + * If this is set to `undefined`, a lower priority state may be used. + * If no lower priority state is set, no text will be displayed. + */ + text?: string | Unset; + + /** + * The background color of the badge. + * This should be a 3 or 6 character hex color code (e.g. `#f00` or `#ff0000`). + * If this is set to `Unset`, any color set by a lower priority state will be cleared/ + * If this is set to `undefined`, a lower priority state may be used. + * If no lower priority state is set, the default color will be used. + */ + backgroundColor?: string | Unset; + + /** + * The icon to display in the badge. + * This should be a URL to an image file. + * If this is set to `Unset`, any icon set by a lower priority state will be cleared. + * If this is set to `undefined`, a lower priority state may be used. + * If no lower priority state is set, the default icon will be used. + */ + icon?: Unset | BadgeIcon; +}; diff --git a/apps/browser/src/platform/badge/test/mock-badge-browser-api.ts b/apps/browser/src/platform/badge/test/mock-badge-browser-api.ts new file mode 100644 index 00000000000..19bde1e1fd8 --- /dev/null +++ b/apps/browser/src/platform/badge/test/mock-badge-browser-api.ts @@ -0,0 +1,21 @@ +import { BadgeBrowserApi, RawBadgeState } from "../badge-browser-api"; + +export class MockBadgeBrowserApi implements BadgeBrowserApi { + specificStates: Record = {}; + generalState?: RawBadgeState; + tabs: number[] = []; + + setState(state: RawBadgeState, tabId?: number): Promise { + if (tabId !== undefined) { + this.specificStates[tabId] = state; + } else { + this.generalState = state; + } + + return Promise.resolve(); + } + + getTabs(): Promise { + return Promise.resolve(this.tabs); + } +} diff --git a/apps/browser/src/platform/browser/browser-api.ts b/apps/browser/src/platform/browser/browser-api.ts index 4ef72fa0077..d0bdaa504b3 100644 --- a/apps/browser/src/platform/browser/browser-api.ts +++ b/apps/browser/src/platform/browser/browser-api.ts @@ -437,7 +437,7 @@ export class BrowserApi { * @param event - The event in which to add the listener to. * @param callback - The callback you want registered onto the event. */ - static addListener unknown>( + static addListener any>( event: chrome.events.Event, callback: T, ) { diff --git a/apps/browser/src/platform/listeners/update-badge.ts b/apps/browser/src/platform/listeners/update-badge.ts deleted file mode 100644 index c168ae44f3c..00000000000 --- a/apps/browser/src/platform/listeners/update-badge.ts +++ /dev/null @@ -1,217 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { firstValueFrom } from "rxjs"; - -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; -import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; -import { getOptionalUserId } from "@bitwarden/common/auth/services/account.service"; -import { BadgeSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/badge-settings.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; - -import MainBackground from "../../background/main.background"; -import IconDetails from "../../vault/background/models/icon-details"; -import { BrowserApi } from "../browser/browser-api"; - -export type BadgeOptions = { - tab?: chrome.tabs.Tab; - windowId?: number; -}; - -export class UpdateBadge { - private authService: AuthService; - private badgeSettingsService: BadgeSettingsServiceAbstraction; - private cipherService: CipherService; - private accountService: AccountService; - private badgeAction: typeof chrome.action | typeof chrome.browserAction; - private sidebarAction: OperaSidebarAction | FirefoxSidebarAction; - private win: Window & typeof globalThis; - private platformUtilsService: PlatformUtilsService; - - constructor(win: Window & typeof globalThis, services: MainBackground) { - this.badgeAction = BrowserApi.getBrowserAction(); - this.sidebarAction = BrowserApi.getSidebarAction(self); - this.win = win; - - this.badgeSettingsService = services.badgeSettingsService; - this.authService = services.authService; - this.cipherService = services.cipherService; - this.accountService = services.accountService; - this.platformUtilsService = services.platformUtilsService; - } - - async run(opts?: { tabId?: number; windowId?: number }): Promise { - const authStatus = await this.authService.getAuthStatus(); - - await this.setBadgeBackgroundColor(); - - switch (authStatus) { - case AuthenticationStatus.LoggedOut: { - await this.setLoggedOut(); - break; - } - case AuthenticationStatus.Locked: { - await this.setLocked(); - break; - } - case AuthenticationStatus.Unlocked: { - const tab = await this.getTab(opts?.tabId, opts?.windowId); - await this.setUnlocked({ tab, windowId: tab?.windowId }); - break; - } - } - } - - async setLoggedOut(): Promise { - await this.setBadgeIcon("_gray"); - await this.clearBadgeText(); - } - - async setLocked() { - await this.setBadgeIcon("_locked"); - await this.clearBadgeText(); - } - - private async clearBadgeText() { - const tabs = await BrowserApi.getActiveTabs(); - if (tabs != null) { - tabs.forEach(async (tab) => { - if (tab.id != null) { - await this.setBadgeText("", tab.id); - } - }); - } - } - - async setUnlocked(opts: BadgeOptions) { - await this.setBadgeIcon(""); - - const enableBadgeCounter = await firstValueFrom(this.badgeSettingsService.enableBadgeCounter$); - if (!enableBadgeCounter) { - return; - } - - const activeUserId = await firstValueFrom( - this.accountService.activeAccount$.pipe(getOptionalUserId), - ); - if (!activeUserId) { - return; - } - - const ciphers = await this.cipherService.getAllDecryptedForUrl(opts?.tab?.url, activeUserId); - let countText = ciphers.length == 0 ? "" : ciphers.length.toString(); - if (ciphers.length > 9) { - countText = "9+"; - } - await this.setBadgeText(countText, opts?.tab?.id); - } - - setBadgeBackgroundColor(color = "#294e5f") { - if (this.badgeAction?.setBadgeBackgroundColor) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.badgeAction.setBadgeBackgroundColor({ color }); - } - if (this.isOperaSidebar(this.sidebarAction)) { - this.sidebarAction.setBadgeBackgroundColor({ color }); - } - } - - setBadgeText(text: string, tabId?: number) { - this.setActionText(text, tabId); - this.setSideBarText(text, tabId); - } - - async setBadgeIcon(iconSuffix: string, windowId?: number) { - const options: IconDetails = { - path: { - 19: "/images/icon19" + iconSuffix + ".png", - 38: "/images/icon38" + iconSuffix + ".png", - }, - }; - if (windowId && this.platformUtilsService.isFirefox()) { - options.windowId = windowId; - } - - await this.setActionIcon(options); - await this.setSidebarActionIcon(options); - } - - private setActionText(text: string, tabId?: number) { - if (this.badgeAction?.setBadgeText) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.badgeAction.setBadgeText({ text, tabId }); - } - } - - private setSideBarText(text: string, tabId?: number) { - if (this.isOperaSidebar(this.sidebarAction)) { - this.sidebarAction.setBadgeText({ text, tabId }); - } else if (this.sidebarAction) { - // Firefox - const title = `Bitwarden${Utils.isNullOrEmpty(text) ? "" : ` [${text}]`}`; - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.sidebarAction.setTitle({ title, tabId }); - } - } - - private async setActionIcon(options: IconDetails) { - if (!this.badgeAction?.setIcon) { - return; - } - - if (this.useSyncApiCalls) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.badgeAction.setIcon(options); - } else { - await new Promise((resolve) => this.badgeAction.setIcon(options, () => resolve())); - } - } - - private async setSidebarActionIcon(options: IconDetails) { - if (!this.sidebarAction?.setIcon) { - return; - } - - if ("opr" in this.win && BrowserApi.isManifestVersion(3)) { - // setIcon API is currenly broken for Opera MV3 extensions - // https://forums.opera.com/topic/75680/opr-sidebaraction-seticon-api-is-broken-access-to-extension-api-denied?_=1738349261570 - // The API currently crashes on MacOS - return; - } - - if (this.isOperaSidebar(this.sidebarAction)) { - await new Promise((resolve) => - (this.sidebarAction as OperaSidebarAction).setIcon(options, () => resolve()), - ); - } else { - await this.sidebarAction.setIcon(options); - } - } - - private async getTab(tabId?: number, windowId?: number) { - return ( - (await BrowserApi.getTab(tabId)) ?? - (windowId - ? await BrowserApi.tabsQueryFirst({ active: true, windowId }) - : await BrowserApi.tabsQueryFirst({ active: true, currentWindow: true })) ?? - (await BrowserApi.tabsQueryFirst({ active: true, lastFocusedWindow: true })) ?? - (await BrowserApi.tabsQueryFirst({ active: true })) - ); - } - - private get useSyncApiCalls() { - return this.platformUtilsService.isFirefox() || this.platformUtilsService.isSafari(); - } - - private isOperaSidebar( - action: OperaSidebarAction | FirefoxSidebarAction, - ): action is OperaSidebarAction { - return action != null && (action as OperaSidebarAction).setBadgeText != null; - } -} diff --git a/libs/common/src/platform/state/state-definitions.ts b/libs/common/src/platform/state/state-definitions.ts index 593a28d04c5..7472520189c 100644 --- a/libs/common/src/platform/state/state-definitions.ts +++ b/libs/common/src/platform/state/state-definitions.ts @@ -106,6 +106,9 @@ export const NEW_WEB_LAYOUT_BANNER_DISK = new StateDefinition("newWebLayoutBanne export const APPLICATION_ID_DISK = new StateDefinition("applicationId", "disk", { web: "disk-local", }); +export const BADGE_MEMORY = new StateDefinition("badge", "memory", { + browser: "memory-large-object", +}); export const BIOMETRIC_SETTINGS_DISK = new StateDefinition("biometricSettings", "disk"); export const CLEAR_EVENT_DISK = new StateDefinition("clearEvent", "disk"); export const CONFIG_DISK = new StateDefinition("config", "disk", { From dac7014cf132ed4216a2b9b0e0bcb02ea2992ccb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 9 Jul 2025 17:00:45 -0400 Subject: [PATCH 091/239] [deps] UI Foundation: Update zone.js to v0.15.1 (#15283) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index bde67319dad..115f7cbf32d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -74,7 +74,7 @@ "tldts": "7.0.1", "ts-node": "10.9.2", "utf-8-validate": "6.0.5", - "zone.js": "0.15.0", + "zone.js": "0.15.1", "zxcvbn": "4.4.2" }, "devDependencies": { @@ -40059,9 +40059,9 @@ } }, "node_modules/zone.js": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.0.tgz", - "integrity": "sha512-9oxn0IIjbCZkJ67L+LkhYWRyAy7axphb3VgE2MBDlOqnmHMPWGYMxJxBYFueFq/JGY2GMwS0rU+UCLunEmy5UA==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.1.tgz", + "integrity": "sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==", "license": "MIT" }, "node_modules/zwitch": { diff --git a/package.json b/package.json index ca84074ff26..be0c53914b8 100644 --- a/package.json +++ b/package.json @@ -210,7 +210,7 @@ "tldts": "7.0.1", "ts-node": "10.9.2", "utf-8-validate": "6.0.5", - "zone.js": "0.15.0", + "zone.js": "0.15.1", "zxcvbn": "4.4.2" }, "overrides": { From ec015bd253aef5d9f455df7fa215379ac945075d Mon Sep 17 00:00:00 2001 From: SmithThe4th Date: Wed, 9 Jul 2025 20:55:16 -0400 Subject: [PATCH 092/239] Fixed stale data after moving anb item to a collection (#15553) --- apps/desktop/src/vault/app/vault/vault-v2.component.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/desktop/src/vault/app/vault/vault-v2.component.ts b/apps/desktop/src/vault/app/vault/vault-v2.component.ts index 2d741944071..2142b5e7a4b 100644 --- a/apps/desktop/src/vault/app/vault/vault-v2.component.ts +++ b/apps/desktop/src/vault/app/vault/vault-v2.component.ts @@ -637,7 +637,15 @@ export class VaultV2Component implements OnInit, OnDestroy, CopyClickListener { const result = await lastValueFrom(dialog.closed); if (result === CollectionAssignmentResult.Saved) { - await this.savedCipher(cipher); + const updatedCipher = await firstValueFrom( + // Fetch the updated cipher from the service + this.cipherService.cipherViews$(this.activeUserId as UserId).pipe( + filter((ciphers) => ciphers != null), + map((ciphers) => ciphers!.find((c) => c.id === cipher.id)), + filter((foundCipher) => foundCipher != null), + ), + ); + await this.savedCipher(updatedCipher); } } From 1f60bcdcc0295fe1b7b666237bca97bbc2fa1ddf Mon Sep 17 00:00:00 2001 From: Patrick-Pimentel-Bitwarden Date: Thu, 10 Jul 2025 09:08:25 -0400 Subject: [PATCH 093/239] feat(change-password): [PM-18720] (#5319) Change Password Implementation for Non Dialog Cases (#15319) * feat(change-password-component): Change Password Update [18720] - Very close to complete. * fix(policy-enforcement): [PM-21085] Fix Bug with Policy Enforcement - Removed temp code to force the state I need to verify correctness. * fix(policy-enforcement): [PM-21085] Fix Bug with Policy Enforcement - Recover account working with change password component. * fix(policy-enforcement): [PM-21085] Fix Bug with Policy Enforcement - Made code more dry. * fix(change-password-component): Change Password Update [18720] - Updates to routing and the extension. Extension is still a wip. * fix(change-password-component): Change Password Update [18720] - Extension routing changes. * feat(change-password-component): Change Password Update [18720] - More extension work * feat(change-password-component): Change Password Update [18720] - Pausing work for now while we wait for product to hear back. * feat(change-password-component): Change Password Update [18720] - Removed duplicated anon layouts. * feat(change-password-component): Change Password Update [18720] - Tidied up code. * feat(change-password-component): Change Password Update [18720] - Small fixes to the styling * feat(change-password-component): Change Password Update [18720] - Adding more content for the routing. * feat(change-password-component): Change Password Update [18720] - Removed circular loop for now. * feat(change-password-component): Change Password Update [18720] - Made comments regarding the change password routing complexities with change-password and auth guard. * feat(change-password-component): Change Password Update [18720] - Undid some changes because they will be conflicts later on. * feat(change-password-component): Change Password Update [18720] - Small directive change. * feat(change-password-component): Change Password Update [18720] - Small changes and added some clarification on where I'm blocked * feat(change-password-component): Change Password Update [18720] - Org invite is seemingly working, found one bug to iron out. * refactor(change-password-component): Change Password Update [18720] - Fixed up policy service to be made more clear. * docs(change-password-component): Change Password Update [18720] - Updated documentation. * refactor(change-password-component): Change Password Update [18720] - Routing changes and policy service changes. * fix(change-password-component): Change Password Update [18720] - Wrapping up changes. * feat(change-password-component): Change Password Update [18720] - Should be working fully * feat(change-password-component): Change Password Update [18720] - Found a bug, working on password policy being present on login. * feat(change-password-component): Change Password Update [18720] - Turned on auth guard on other clients for change-password route. * feat(change-password-component): Change Password Update [18720] - Committing intermediate changes. * feat(change-password-component): Change Password Update [18720] - The master password policy endpoint has been added! Should be working. Testing now. * feat(change-password-component): Change Password Update [18720] - Minor fixes. * feat(change-password-component): Change Password Update [18720] - Undid naming change. * feat(change-password-component): Change Password Update [18720] - Removed comment. * feat(change-password-component): Change Password Update [18720] - Removed unneeded code. * fix(change-password-component): Change Password Update [18720] - Took org invite state out of service and made it accessible. * fix(change-password-component): Change Password Update [18720] - Small changes. * fix(change-password-component): Change Password Update [18720] - Split up org invite service into client specific implementations and have them injected into clients properly * feat(change-password-component): Change Password Update [18720] - Stopping work and going to switch to a new branch to pare down some of the solutions that were made to get this over the finish line * feat(change-password-component): Change Password Update [18720] - Started to remove functionality in the login.component and the password login strategy. * feat(change-password-component): Change Password Update [18720] - Removed more unneded changes. * feat(change-password-component): Change Password Update [18720] - Change password clearing state working properly. * fix(change-password-component): Change Password Update [18720] - Added docs and moved web implementation. * comments(change-password-component): Change Password Update [18720] - Added more notes. * test(change-password-component): Change Password Update [18720] - Added in tests for policy service. * comment(change-password-component): Change Password Update [18720] - Updated doc with correct ticket number. * comment(change-password-component): Change Password Update [18720] - Fixed doc. * test(change-password-component): Change Password Update [18720] - Fixed tests. * test(change-password-component): Change Password Update [18720] - Fixed linting errors. Have more tests to fix. * test(change-password-component): Change Password Update [18720] - Added back in ignore for typesafety. * fix(change-password-component): Change Password Update [18720] - Fixed other type issues. * test(change-password-component): Change Password Update [18720] - Fixed tests. * test(change-password-component): Change Password Update [18720] - Fixed more tests. * test(change-password-component): Change Password Update [18720] - Fixed tiny duplicate code. * fix(change-password-component): Change Password Update [18720] - Fixed desktop component. * fix(change-password-component): Change Password Update [18720] - Removed unused code * fix(change-password-component): Change Password Update [18720] - Fixed locales. * fix(change-password-component): Change Password Update [18720] - Removed tracing. * fix(change-password-component): Change Password Update [18720] - Removed duplicative services module entry. * fix(change-password-component): Change Password Update [18720] - Added comment. * fix(change-password-component): Change Password Update [18720] - Fixed unneeded call in two factor to get user id. * fix(change-password-component): Change Password Update [18720] - Fixed a couple of tiny things. * fix(change-password-component): Change Password Update [18720] - Added comment for later fix. * fix(change-password-component): Change Password Update [18720] - Fixed linting error. * PM-18720 - AuthGuard - move call to get isChangePasswordFlagOn down after other conditions for efficiency. * PM-18720 - PasswordLoginStrategy tests - test new feature flagged combine org invite policies logic for weak password evaluation. * PM-18720 - CLI - fix dep issue * PM-18720 - ChangePasswordComp - extract change password warning up out of input password component * PM-18720 - InputPassword - remove unused dependency. * PM-18720 - ChangePasswordComp - add callout dep * PM-18720 - Revert all anon-layout changes * PM-18720 - Anon Layout - finish reverting changes. * PM-18720 - WIP move of change password out of libs/auth * PM-18720 - Clean up remaining imports from moving change password out of libs/auth * PM-18720 - Add change-password barrel file for better import grouping * PM-18720 - Change Password comp - restore maxWidth * PM-18720 - After merge, fix errors * PM-18720 - Desktop - fix api service import * PM-18720 - NDV - fix routing. * PM-18720 - Change Password Comp - add logout service todo * PM-18720 - PasswordSettings - per feedback, component is already feature flagged behind PM16117_ChangeExistingPasswordRefactor so we can just delete the replaced callout (new text is in change-password comp) * PM-18720 - Routing Modules - properly flag new component behind feature flag. * PM-18720 - SSO Login Strategy - fix config service import since it is now in shared deps from main merge. * PM-18720 - Fix SSO login strategy tests * PM-18720 - Default Policy Service - address AC PR feedback --------- Co-authored-by: Jared Snider Co-authored-by: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com> --- apps/browser/src/_locales/en/messages.json | 9 + apps/browser/src/popup/app-routing.module.ts | 28 ++- apps/desktop/src/app/app-routing.module.ts | 19 +- .../src/app/services/services.module.ts | 5 +- .../login/desktop-login-component.service.ts | 2 +- .../src/auth/set-password.component.ts | 63 +++--- apps/desktop/src/locales/en/messages.json | 9 + .../web-change-password.service.ts | 11 +- .../web-login-decryption-options.service.ts | 6 +- .../login/web-login-component.service.spec.ts | 18 +- .../login/web-login-component.service.ts | 37 +++- .../web-organization-invite.service.ts | 38 ++++ .../web-set-initial-password.service.spec.ts | 14 +- .../web-set-initial-password.service.ts | 6 +- .../web-registration-finish.service.spec.ts | 52 ++--- .../web-registration-finish.service.ts | 13 +- .../web-set-password-jit.service.ts | 6 +- .../accept-organization.component.ts | 37 +++- .../accept-organization.service.spec.ts | 52 +++-- .../accept-organization.service.ts | 62 +----- .../organization-invite.ts | 40 ---- .../src/app/auth/set-password.component.ts | 7 +- .../settings/change-password.component.ts | 33 ++- .../emergency-access-takeover.component.ts | 8 +- .../password-settings.component.html | 1 - .../password-settings.component.ts | 4 +- .../src/app/auth/update-password.component.ts | 7 +- .../complete-trial-initiation.component.ts | 6 +- apps/web/src/app/core/core.module.ts | 26 ++- apps/web/src/app/oss-routing.module.ts | 29 ++- apps/web/src/locales/en/messages.json | 9 + .../components/change-password.component.ts | 8 +- .../auth/components/set-password.component.ts | 46 ++-- .../components/update-password.component.ts | 8 +- .../update-temp-password.component.ts | 8 +- libs/angular/src/auth/guards/auth.guard.ts | 7 +- .../change-password.component.html | 8 + .../change-password.component.ts | 202 ++++++++++++++++++ .../change-password.service.abstraction.ts | 28 ++- .../default-change-password.service.spec.ts | 48 ++++- .../default-change-password.service.ts | 59 ++++- .../change-password/index.ts | 3 + .../src/services/jslib-services.module.ts | 18 +- .../change-password.component.ts | 114 ---------- libs/auth/src/angular/index.ts | 4 - .../input-password.component.html | 2 +- .../input-password.component.ts | 6 +- .../auth/src/angular/login/login.component.ts | 45 +++- .../new-device-verification.component.ts | 36 +++- .../default-set-password-jit.service.spec.ts | 8 +- .../default-set-password-jit.service.ts | 6 +- .../two-factor-auth.component.ts | 22 +- .../auth-request-login.strategy.spec.ts | 4 + .../login-strategies/login.strategy.spec.ts | 6 + .../common/login-strategies/login.strategy.ts | 2 + .../password-login.strategy.spec.ts | 77 ++++++- .../password-login.strategy.ts | 37 +++- .../sso-login.strategy.spec.ts | 2 +- .../login-strategies/sso-login.strategy.ts | 2 - .../user-api-login.strategy.spec.ts | 4 + .../webauthn-login.strategy.spec.ts | 4 + .../common/models/domain/login-credentials.ts | 2 + .../login-strategy.service.ts | 2 +- .../policy/policy.service.abstraction.ts | 19 ++ .../policy/default-policy.service.spec.ts | 146 +++++++++++++ .../services/policy/default-policy.service.ts | 67 ++++++ .../default-organization-invite.service.ts | 26 +++ .../organization-invite-state.ts | 13 ++ .../organization-invite.service.ts | 20 ++ .../organization-invite.ts | 20 ++ 70 files changed, 1301 insertions(+), 495 deletions(-) create mode 100644 apps/web/src/app/auth/core/services/organization-invite/web-organization-invite.service.ts delete mode 100644 apps/web/src/app/auth/organization-invite/organization-invite.ts rename libs/{auth/src/angular => angular/src/auth/password-management}/change-password/change-password.component.html (67%) create mode 100644 libs/angular/src/auth/password-management/change-password/change-password.component.ts rename libs/{auth/src/angular => angular/src/auth/password-management}/change-password/change-password.service.abstraction.ts (56%) rename libs/{auth/src/angular => angular/src/auth/password-management}/change-password/default-change-password.service.spec.ts (77%) rename libs/{auth/src/angular => angular/src/auth/password-management}/change-password/default-change-password.service.ts (50%) create mode 100644 libs/angular/src/auth/password-management/change-password/index.ts delete mode 100644 libs/auth/src/angular/change-password/change-password.component.ts create mode 100644 libs/common/src/auth/services/organization-invite/default-organization-invite.service.ts create mode 100644 libs/common/src/auth/services/organization-invite/organization-invite-state.ts create mode 100644 libs/common/src/auth/services/organization-invite/organization-invite.service.ts create mode 100644 libs/common/src/auth/services/organization-invite/organization-invite.ts diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 957386ba576..ee8cd412625 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -1173,6 +1173,12 @@ "message": "Oh no! We couldn't save this. Try entering the details manually.", "description": "Detailed error message shown when saving login details fails." }, + "changePasswordWarning": { + "message": "After changing your password, you will need to log in with your new password. Active sessions on other devices will be logged out within one hour." + }, + "accountRecoveryUpdateMasterPasswordSubtitle": { + "message": "Change your master password to complete account recovery." + }, "enableChangedPasswordNotification": { "message": "Ask to update existing login" }, @@ -3454,6 +3460,9 @@ "logInRequestSent": { "message": "Request sent" }, + "masterPasswordChanged": { + "message": "Master password saved" + }, "exposedMasterPassword": { "message": "Exposed Master Password" }, diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts index f836f5ffac7..da5a6c43d36 100644 --- a/apps/browser/src/popup/app-routing.module.ts +++ b/apps/browser/src/popup/app-routing.module.ts @@ -15,6 +15,7 @@ import { tdeDecryptionRequiredGuard, unauthGuardFn, } from "@bitwarden/angular/auth/guards"; +import { ChangePasswordComponent } from "@bitwarden/angular/auth/password-management/change-password"; import { SetInitialPasswordComponent } from "@bitwarden/angular/auth/password-management/set-initial-password/set-initial-password.component"; import { canAccessFeature } from "@bitwarden/angular/platform/guard/feature-flag.guard"; import { @@ -331,7 +332,15 @@ const routes: Routes = [ { path: "update-temp-password", component: UpdateTempPasswordComponent, - canActivate: [authGuard], + canActivate: [ + canAccessFeature( + FeatureFlag.PM16117_ChangeExistingPasswordRefactor, + false, + `/change-password`, + false, + ), + authGuard, + ], data: { elevation: 1 } satisfies RouteDataProperties, }, { @@ -555,6 +564,23 @@ const routes: Routes = [ showBackButton: true, } satisfies RouteDataProperties & ExtensionAnonLayoutWrapperData, }, + { + path: "change-password", + data: { + elevation: 1, + hideFooter: true, + } satisfies RouteDataProperties & ExtensionAnonLayoutWrapperData, + children: [ + { + path: "", + component: ChangePasswordComponent, + }, + ], + canActivate: [ + canAccessFeature(FeatureFlag.PM16117_ChangeExistingPasswordRefactor), + authGuard, + ], + }, ], }, { diff --git a/apps/desktop/src/app/app-routing.module.ts b/apps/desktop/src/app/app-routing.module.ts index 42846878d03..0a60478c94d 100644 --- a/apps/desktop/src/app/app-routing.module.ts +++ b/apps/desktop/src/app/app-routing.module.ts @@ -14,6 +14,7 @@ import { tdeDecryptionRequiredGuard, unauthGuardFn, } from "@bitwarden/angular/auth/guards"; +import { ChangePasswordComponent } from "@bitwarden/angular/auth/password-management/change-password"; import { SetInitialPasswordComponent } from "@bitwarden/angular/auth/password-management/set-initial-password/set-initial-password.component"; import { canAccessFeature } from "@bitwarden/angular/platform/guard/feature-flag.guard"; import { featureFlaggedRoute } from "@bitwarden/angular/platform/utils/feature-flagged-route"; @@ -119,7 +120,15 @@ const routes: Routes = [ { path: "update-temp-password", component: UpdateTempPasswordComponent, - canActivate: [authGuard], + canActivate: [ + canAccessFeature( + FeatureFlag.PM16117_ChangeExistingPasswordRefactor, + false, + `/change-password`, + false, + ), + authGuard, + ], }, { path: "remove-password", @@ -340,6 +349,14 @@ const routes: Routes = [ }, } satisfies RouteDataProperties & AnonLayoutWrapperData, }, + { + path: "change-password", + component: ChangePasswordComponent, + canActivate: [ + canAccessFeature(FeatureFlag.PM16117_ChangeExistingPasswordRefactor), + authGuard, + ], + }, ], }, ]; diff --git a/apps/desktop/src/app/services/services.module.ts b/apps/desktop/src/app/services/services.module.ts index 0abd810bd18..4111a62d3b2 100644 --- a/apps/desktop/src/app/services/services.module.ts +++ b/apps/desktop/src/app/services/services.module.ts @@ -382,12 +382,11 @@ const safeProviders: SafeProvider[] = [ provide: SetPasswordJitService, useClass: DesktopSetPasswordJitService, deps: [ - ApiService, - MasterPasswordApiService, - KeyService, EncryptService, I18nServiceAbstraction, KdfConfigService, + KeyService, + MasterPasswordApiService, InternalMasterPasswordServiceAbstraction, OrganizationApiServiceAbstraction, OrganizationUserApiService, diff --git a/apps/desktop/src/auth/login/desktop-login-component.service.ts b/apps/desktop/src/auth/login/desktop-login-component.service.ts index 60e7791b384..d7e7ba0178b 100644 --- a/apps/desktop/src/auth/login/desktop-login-component.service.ts +++ b/apps/desktop/src/auth/login/desktop-login-component.service.ts @@ -84,7 +84,7 @@ export class DesktopLoginComponentService } catch (err) { this.toastService.showToast({ variant: "error", - title: this.i18nService.t("errorOccured"), + title: this.i18nService.t("errorOccurred"), message: this.i18nService.t("ssoError"), }); } diff --git a/apps/desktop/src/auth/set-password.component.ts b/apps/desktop/src/auth/set-password.component.ts index 48b18d7294c..55ad1f48a77 100644 --- a/apps/desktop/src/auth/set-password.component.ts +++ b/apps/desktop/src/auth/set-password.component.ts @@ -4,7 +4,6 @@ import { ActivatedRoute, Router } from "@angular/router"; import { OrganizationUserApiService } from "@bitwarden/admin-console/common"; import { SetPasswordComponent as BaseSetPasswordComponent } from "@bitwarden/angular/auth/components/set-password.component"; import { InternalUserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; @@ -32,52 +31,50 @@ const BroadcasterSubscriptionId = "SetPasswordComponent"; }) export class SetPasswordComponent extends BaseSetPasswordComponent implements OnInit, OnDestroy { constructor( - accountService: AccountService, - masterPasswordService: InternalMasterPasswordServiceAbstraction, - apiService: ApiService, - i18nService: I18nService, - keyService: KeyService, - messagingService: MessagingService, - platformUtilsService: PlatformUtilsService, - policyApiService: PolicyApiServiceAbstraction, - policyService: PolicyService, - router: Router, - masterPasswordApiService: MasterPasswordApiService, - syncService: SyncService, - route: ActivatedRoute, + protected accountService: AccountService, + protected dialogService: DialogService, + protected encryptService: EncryptService, + protected i18nService: I18nService, + protected kdfConfigService: KdfConfigService, + protected keyService: KeyService, + protected masterPasswordApiService: MasterPasswordApiService, + protected masterPasswordService: InternalMasterPasswordServiceAbstraction, + protected messagingService: MessagingService, + protected organizationApiService: OrganizationApiServiceAbstraction, + protected organizationUserApiService: OrganizationUserApiService, + protected platformUtilsService: PlatformUtilsService, + protected policyApiService: PolicyApiServiceAbstraction, + protected policyService: PolicyService, + protected route: ActivatedRoute, + protected router: Router, + protected ssoLoginService: SsoLoginServiceAbstraction, + protected syncService: SyncService, + protected toastService: ToastService, + protected userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction, private broadcasterService: BroadcasterService, private ngZone: NgZone, - organizationApiService: OrganizationApiServiceAbstraction, - organizationUserApiService: OrganizationUserApiService, - userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction, - ssoLoginService: SsoLoginServiceAbstraction, - dialogService: DialogService, - kdfConfigService: KdfConfigService, - encryptService: EncryptService, - toastService: ToastService, ) { super( accountService, - masterPasswordService, + dialogService, + encryptService, i18nService, + kdfConfigService, keyService, + masterPasswordApiService, + masterPasswordService, messagingService, + organizationApiService, + organizationUserApiService, platformUtilsService, policyApiService, policyService, - router, - masterPasswordApiService, - apiService, - syncService, route, - organizationApiService, - organizationUserApiService, - userDecryptionOptionsService, + router, ssoLoginService, - dialogService, - kdfConfigService, - encryptService, + syncService, toastService, + userDecryptionOptionsService, ); } diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index 703b65c35b4..a139c0c712c 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -2407,6 +2407,15 @@ "updateWeakMasterPasswordWarning": { "message": "Your master password does not meet one or more of your organization policies. In order to access the vault, you must update your master password now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour." }, + "changePasswordWarning": { + "message": "After changing your password, you will need to log in with your new password. Active sessions on other devices will be logged out within one hour." + }, + "accountRecoveryUpdateMasterPasswordSubtitle": { + "message": "Change your master password to complete account recovery." + }, + "updateMasterPasswordSubtitle": { + "message": "Your master password does not meet this organization’s requirements. Change your master password to continue." + }, "tdeDisabledMasterPasswordRequired": { "message": "Your organization has disabled trusted device encryption. Please set a master password to access your vault." }, diff --git a/apps/web/src/app/auth/core/services/change-password/web-change-password.service.ts b/apps/web/src/app/auth/core/services/change-password/web-change-password.service.ts index b75aef0f1fc..ed384763241 100644 --- a/apps/web/src/app/auth/core/services/change-password/web-change-password.service.ts +++ b/apps/web/src/app/auth/core/services/change-password/web-change-password.service.ts @@ -1,8 +1,12 @@ -import { ChangePasswordService, DefaultChangePasswordService } from "@bitwarden/auth/angular"; +import { + ChangePasswordService, + DefaultChangePasswordService, +} from "@bitwarden/angular/auth/password-management/change-password"; import { Account } from "@bitwarden/common/auth/abstractions/account.service"; import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { KeyService } from "@bitwarden/key-management"; +import { RouterService } from "@bitwarden/web-vault/app/core"; import { UserKeyRotationService } from "@bitwarden/web-vault/app/key-management/key-rotation/user-key-rotation.service"; export class WebChangePasswordService @@ -14,6 +18,7 @@ export class WebChangePasswordService protected masterPasswordApiService: MasterPasswordApiService, protected masterPasswordService: InternalMasterPasswordServiceAbstraction, private userKeyRotationService: UserKeyRotationService, + private routerService: RouterService, ) { super(keyService, masterPasswordApiService, masterPasswordService); } @@ -31,4 +36,8 @@ export class WebChangePasswordService newPasswordHint, ); } + + async clearDeeplinkState() { + await this.routerService.getAndClearLoginRedirectUrl(); + } } diff --git a/apps/web/src/app/auth/core/services/login-decryption-options/web-login-decryption-options.service.ts b/apps/web/src/app/auth/core/services/login-decryption-options/web-login-decryption-options.service.ts index 3de3ec46457..fb30f04ffc4 100644 --- a/apps/web/src/app/auth/core/services/login-decryption-options/web-login-decryption-options.service.ts +++ b/apps/web/src/app/auth/core/services/login-decryption-options/web-login-decryption-options.service.ts @@ -4,10 +4,10 @@ import { LoginDecryptionOptionsService, DefaultLoginDecryptionOptionsService, } from "@bitwarden/auth/angular"; +import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { RouterService } from "../../../../core/router.service"; -import { AcceptOrganizationInviteService } from "../../../organization-invite/accept-organization.service"; export class WebLoginDecryptionOptionsService extends DefaultLoginDecryptionOptionsService @@ -16,7 +16,7 @@ export class WebLoginDecryptionOptionsService constructor( protected messagingService: MessagingService, private routerService: RouterService, - private acceptOrganizationInviteService: AcceptOrganizationInviteService, + private organizationInviteService: OrganizationInviteService, ) { super(messagingService); } @@ -27,7 +27,7 @@ export class WebLoginDecryptionOptionsService // accepted while being enrolled in admin recovery. So we need to clear // the redirect and stored org invite. await this.routerService.getAndClearLoginRedirectUrl(); - await this.acceptOrganizationInviteService.clearOrganizationInvitation(); + await this.organizationInviteService.clearOrganizationInvitation(); } catch (error) { throw new Error(error); } diff --git a/apps/web/src/app/auth/core/services/login/web-login-component.service.spec.ts b/apps/web/src/app/auth/core/services/login/web-login-component.service.spec.ts index 95ddc74c3c5..4cc06baf32b 100644 --- a/apps/web/src/app/auth/core/services/login/web-login-component.service.spec.ts +++ b/apps/web/src/app/auth/core/services/login/web-login-component.service.spec.ts @@ -10,7 +10,9 @@ import { Policy } from "@bitwarden/common/admin-console/models/domain/policy"; import { ResetPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/reset-password-policy-options"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; +import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service"; import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; @@ -22,7 +24,6 @@ import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legac // FIXME: remove `src` and fix import // eslint-disable-next-line no-restricted-imports import { RouterService } from "../../../../../../../../apps/web/src/app/core"; -import { AcceptOrganizationInviteService } from "../../../organization-invite/accept-organization.service"; import { WebLoginComponentService } from "./web-login-component.service"; @@ -32,7 +33,7 @@ jest.mock("../../../../../utils/flags", () => ({ describe("WebLoginComponentService", () => { let service: WebLoginComponentService; - let acceptOrganizationInviteService: MockProxy; + let organizationInviteService: MockProxy; let logService: MockProxy; let policyApiService: MockProxy; let internalPolicyService: MockProxy; @@ -44,9 +45,10 @@ describe("WebLoginComponentService", () => { let ssoLoginService: MockProxy; const mockUserId = Utils.newGuid() as UserId; let accountService: FakeAccountService; + let configService: MockProxy; beforeEach(() => { - acceptOrganizationInviteService = mock(); + organizationInviteService = mock(); logService = mock(); policyApiService = mock(); internalPolicyService = mock(); @@ -57,12 +59,13 @@ describe("WebLoginComponentService", () => { platformUtilsService = mock(); ssoLoginService = mock(); accountService = mockAccountServiceWith(mockUserId); + configService = mock(); TestBed.configureTestingModule({ providers: [ WebLoginComponentService, { provide: DefaultLoginComponentService, useClass: WebLoginComponentService }, - { provide: AcceptOrganizationInviteService, useValue: acceptOrganizationInviteService }, + { provide: OrganizationInviteService, useValue: organizationInviteService }, { provide: LogService, useValue: logService }, { provide: PolicyApiServiceAbstraction, useValue: policyApiService }, { provide: InternalPolicyService, useValue: internalPolicyService }, @@ -73,6 +76,7 @@ describe("WebLoginComponentService", () => { { provide: PlatformUtilsService, useValue: platformUtilsService }, { provide: SsoLoginServiceAbstraction, useValue: ssoLoginService }, { provide: AccountService, useValue: accountService }, + { provide: ConfigService, useValue: configService }, ], }); service = TestBed.inject(WebLoginComponentService); @@ -84,14 +88,14 @@ describe("WebLoginComponentService", () => { describe("getOrgPoliciesFromOrgInvite", () => { it("returns undefined if organization invite is null", async () => { - acceptOrganizationInviteService.getOrganizationInvite.mockResolvedValue(null); + organizationInviteService.getOrganizationInvite.mockResolvedValue(null); const result = await service.getOrgPoliciesFromOrgInvite(); expect(result).toBeUndefined(); }); it("logs an error if getPoliciesByToken throws an error", async () => { const error = new Error("Test error"); - acceptOrganizationInviteService.getOrganizationInvite.mockResolvedValue({ + organizationInviteService.getOrganizationInvite.mockResolvedValue({ organizationId: "org-id", token: "token", email: "email", @@ -117,7 +121,7 @@ describe("WebLoginComponentService", () => { const resetPasswordPolicyOptions = new ResetPasswordPolicyOptions(); resetPasswordPolicyOptions.autoEnrollEnabled = autoEnrollEnabled; - acceptOrganizationInviteService.getOrganizationInvite.mockResolvedValue({ + organizationInviteService.getOrganizationInvite.mockResolvedValue({ organizationId: "org-id", token: "token", email: "email", diff --git a/apps/web/src/app/auth/core/services/login/web-login-component.service.ts b/apps/web/src/app/auth/core/services/login/web-login-component.service.ts index 36e7143ccd0..cf0adb91144 100644 --- a/apps/web/src/app/auth/core/services/login/web-login-component.service.ts +++ b/apps/web/src/app/auth/core/services/login/web-login-component.service.ts @@ -11,18 +11,21 @@ import { } from "@bitwarden/auth/angular"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; import { Policy } from "@bitwarden/common/admin-console/models/domain/policy"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; +import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; import { RouterService } from "../../../../core/router.service"; -import { AcceptOrganizationInviteService } from "../../../organization-invite/accept-organization.service"; @Injectable() export class WebLoginComponentService @@ -30,7 +33,7 @@ export class WebLoginComponentService implements LoginComponentService { constructor( - protected acceptOrganizationInviteService: AcceptOrganizationInviteService, + protected organizationInviteService: OrganizationInviteService, protected logService: LogService, protected policyApiService: PolicyApiServiceAbstraction, protected policyService: InternalPolicyService, @@ -42,6 +45,7 @@ export class WebLoginComponentService ssoLoginService: SsoLoginServiceAbstraction, private router: Router, private accountService: AccountService, + private configService: ConfigService, ) { super( cryptoFunctionService, @@ -66,8 +70,8 @@ export class WebLoginComponentService return; } - async getOrgPoliciesFromOrgInvite(): Promise { - const orgInvite = await this.acceptOrganizationInviteService.getOrganizationInvite(); + async getOrgPoliciesFromOrgInvite(): Promise { + const orgInvite = await this.organizationInviteService.getOrganizationInvite(); if (orgInvite != null) { let policies: Policy[]; @@ -84,7 +88,7 @@ export class WebLoginComponentService } if (policies == null) { - return; + return undefined; } const resetPasswordPolicy = this.policyService.getResetPasswordPolicyOptions( @@ -95,12 +99,23 @@ export class WebLoginComponentService const isPolicyAndAutoEnrollEnabled = resetPasswordPolicy[1] && resetPasswordPolicy[0].autoEnrollEnabled; - const enforcedPasswordPolicyOptions = await firstValueFrom( - this.accountService.activeAccount$.pipe( - getUserId, - switchMap((userId) => this.policyService.masterPasswordPolicyOptions$(userId, policies)), - ), - ); + let enforcedPasswordPolicyOptions: MasterPasswordPolicyOptions; + + if ( + await this.configService.getFeatureFlag(FeatureFlag.PM16117_ChangeExistingPasswordRefactor) + ) { + enforcedPasswordPolicyOptions = + this.policyService.combinePoliciesIntoMasterPasswordPolicyOptions(policies); + } else { + enforcedPasswordPolicyOptions = await firstValueFrom( + this.accountService.activeAccount$.pipe( + getUserId, + switchMap((userId) => + this.policyService.masterPasswordPolicyOptions$(userId, policies), + ), + ), + ); + } return { policies, diff --git a/apps/web/src/app/auth/core/services/organization-invite/web-organization-invite.service.ts b/apps/web/src/app/auth/core/services/organization-invite/web-organization-invite.service.ts new file mode 100644 index 00000000000..b799358dbae --- /dev/null +++ b/apps/web/src/app/auth/core/services/organization-invite/web-organization-invite.service.ts @@ -0,0 +1,38 @@ +import { firstValueFrom } from "rxjs"; + +import { OrganizationInvite } from "@bitwarden/common/auth/services/organization-invite/organization-invite"; +import { ORGANIZATION_INVITE } from "@bitwarden/common/auth/services/organization-invite/organization-invite-state"; +import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service"; +import { GlobalState, GlobalStateProvider } from "@bitwarden/common/platform/state"; + +export class WebOrganizationInviteService implements OrganizationInviteService { + private organizationInvitationState: GlobalState; + + constructor(private readonly globalStateProvider: GlobalStateProvider) { + this.organizationInvitationState = this.globalStateProvider.get(ORGANIZATION_INVITE); + } + + /** + * Returns the currently stored organization invite + */ + async getOrganizationInvite(): Promise { + return await firstValueFrom(this.organizationInvitationState.state$); + } + + /** + * Stores a new organization invite + * @param invite an organization invite + * @throws if the invite is nullish + */ + async setOrganizationInvitation(invite: OrganizationInvite): Promise { + if (invite == null) { + throw new Error("Invite cannot be null. Use clearOrganizationInvitation instead."); + } + await this.organizationInvitationState.update(() => invite); + } + + /** Clears the currently stored organization invite */ + async clearOrganizationInvitation(): Promise { + await this.organizationInvitationState.update(() => null); + } +} diff --git a/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.spec.ts b/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.spec.ts index b90d0624b3f..b562c54894b 100644 --- a/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.spec.ts +++ b/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.spec.ts @@ -15,6 +15,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; import { SetPasswordRequest } from "@bitwarden/common/auth/models/request/set-password.request"; +import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { KeysRequest } from "@bitwarden/common/models/request/keys.request"; @@ -25,7 +26,6 @@ import { CsprngArray } from "@bitwarden/common/types/csprng"; import { UserId } from "@bitwarden/common/types/guid"; import { MasterKey, UserKey } from "@bitwarden/common/types/key"; import { DEFAULT_KDF_CONFIG, KdfConfigService, KeyService } from "@bitwarden/key-management"; -import { AcceptOrganizationInviteService } from "@bitwarden/web-vault/app/auth/organization-invite/accept-organization.service"; import { RouterService } from "@bitwarden/web-vault/app/core"; import { WebSetInitialPasswordService } from "./web-set-initial-password.service"; @@ -43,7 +43,7 @@ describe("WebSetInitialPasswordService", () => { let organizationApiService: MockProxy; let organizationUserApiService: MockProxy; let userDecryptionOptionsService: MockProxy; - let acceptOrganizationInviteService: MockProxy; + let organizationInviteService: MockProxy; let routerService: MockProxy; beforeEach(() => { @@ -57,7 +57,7 @@ describe("WebSetInitialPasswordService", () => { organizationApiService = mock(); organizationUserApiService = mock(); userDecryptionOptionsService = mock(); - acceptOrganizationInviteService = mock(); + organizationInviteService = mock(); routerService = mock(); sut = new WebSetInitialPasswordService( @@ -71,7 +71,7 @@ describe("WebSetInitialPasswordService", () => { organizationApiService, organizationUserApiService, userDecryptionOptionsService, - acceptOrganizationInviteService, + organizationInviteService, routerService, ); }); @@ -169,9 +169,7 @@ describe("WebSetInitialPasswordService", () => { // Assert expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); - expect(acceptOrganizationInviteService.clearOrganizationInvitation).toHaveBeenCalledTimes( - 1, - ); + expect(organizationInviteService.clearOrganizationInvitation).toHaveBeenCalledTimes(1); }); }); @@ -201,7 +199,7 @@ describe("WebSetInitialPasswordService", () => { // Assert await expect(promise).rejects.toThrow(); expect(masterPasswordApiService.setPassword).not.toHaveBeenCalled(); - expect(acceptOrganizationInviteService.clearOrganizationInvitation).not.toHaveBeenCalled(); + expect(organizationInviteService.clearOrganizationInvitation).not.toHaveBeenCalled(); }); }); }); diff --git a/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.ts b/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.ts index 41e7e8ad4ab..19ddbf5e260 100644 --- a/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.ts +++ b/apps/web/src/app/auth/core/services/password-management/set-initial-password/web-set-initial-password.service.ts @@ -9,12 +9,12 @@ import { InternalUserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; +import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { UserId } from "@bitwarden/common/types/guid"; import { KdfConfigService, KeyService } from "@bitwarden/key-management"; -import { AcceptOrganizationInviteService } from "@bitwarden/web-vault/app/auth/organization-invite/accept-organization.service"; import { RouterService } from "@bitwarden/web-vault/app/core"; export class WebSetInitialPasswordService @@ -32,7 +32,7 @@ export class WebSetInitialPasswordService protected organizationApiService: OrganizationApiServiceAbstraction, protected organizationUserApiService: OrganizationUserApiService, protected userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction, - private acceptOrganizationInviteService: AcceptOrganizationInviteService, + private organizationInviteService: OrganizationInviteService, private routerService: RouterService, ) { super( @@ -78,6 +78,6 @@ export class WebSetInitialPasswordService * as clear the org invite itself that was originally set in state by the AcceptOrganizationComponent. */ await this.routerService.getAndClearLoginRedirectUrl(); - await this.acceptOrganizationInviteService.clearOrganizationInvitation(); + await this.organizationInviteService.clearOrganizationInvitation(); } } diff --git a/apps/web/src/app/auth/core/services/registration/web-registration-finish.service.spec.ts b/apps/web/src/app/auth/core/services/registration/web-registration-finish.service.spec.ts index afaf1bd49d2..e491f95c1b9 100644 --- a/apps/web/src/app/auth/core/services/registration/web-registration-finish.service.spec.ts +++ b/apps/web/src/app/auth/core/services/registration/web-registration-finish.service.spec.ts @@ -9,20 +9,16 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; import { Policy } from "@bitwarden/common/admin-console/models/domain/policy"; import { AccountApiService } from "@bitwarden/common/auth/abstractions/account-api.service"; +import { OrganizationInvite } from "@bitwarden/common/auth/services/organization-invite/organization-invite"; +import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { Utils } from "@bitwarden/common/platform/misc/utils"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; -import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec"; import { CsprngArray } from "@bitwarden/common/types/csprng"; -import { UserId } from "@bitwarden/common/types/guid"; import { MasterKey, UserKey } from "@bitwarden/common/types/key"; import { DEFAULT_KDF_CONFIG, KeyService } from "@bitwarden/key-management"; -import { AcceptOrganizationInviteService } from "../../../organization-invite/accept-organization.service"; -import { OrganizationInvite } from "../../../organization-invite/organization-invite"; - import { WebRegistrationFinishService } from "./web-registration-finish.service"; describe("WebRegistrationFinishService", () => { @@ -30,32 +26,28 @@ describe("WebRegistrationFinishService", () => { let keyService: MockProxy; let accountApiService: MockProxy; - let acceptOrgInviteService: MockProxy; + let organizationInviteService: MockProxy; let policyApiService: MockProxy; let logService: MockProxy; let policyService: MockProxy; let configService: MockProxy; - const mockUserId = Utils.newGuid() as UserId; - let accountService: FakeAccountService; beforeEach(() => { keyService = mock(); accountApiService = mock(); - acceptOrgInviteService = mock(); + organizationInviteService = mock(); policyApiService = mock(); logService = mock(); policyService = mock(); - accountService = mockAccountServiceWith(mockUserId); configService = mock(); service = new WebRegistrationFinishService( keyService, accountApiService, - acceptOrgInviteService, + organizationInviteService, policyApiService, logService, policyService, - accountService, configService, ); }); @@ -76,21 +68,21 @@ describe("WebRegistrationFinishService", () => { }); it("returns null when the org invite is null", async () => { - acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(null); + organizationInviteService.getOrganizationInvite.mockResolvedValue(null); const result = await service.getOrgNameFromOrgInvite(); expect(result).toBeNull(); - expect(acceptOrgInviteService.getOrganizationInvite).toHaveBeenCalled(); + expect(organizationInviteService.getOrganizationInvite).toHaveBeenCalled(); }); it("returns the organization name from the organization invite when it exists", async () => { - acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(orgInvite); + organizationInviteService.getOrganizationInvite.mockResolvedValue(orgInvite); const result = await service.getOrgNameFromOrgInvite(); expect(result).toEqual(orgInvite.organizationName); - expect(acceptOrgInviteService.getOrganizationInvite).toHaveBeenCalled(); + expect(organizationInviteService.getOrganizationInvite).toHaveBeenCalled(); }); }); @@ -106,22 +98,22 @@ describe("WebRegistrationFinishService", () => { }); it("returns null when the org invite is null", async () => { - acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(null); + organizationInviteService.getOrganizationInvite.mockResolvedValue(null); const result = await service.getMasterPasswordPolicyOptsFromOrgInvite(); expect(result).toBeNull(); - expect(acceptOrgInviteService.getOrganizationInvite).toHaveBeenCalled(); + expect(organizationInviteService.getOrganizationInvite).toHaveBeenCalled(); }); it("returns null when the policies are null", async () => { - acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(orgInvite); + organizationInviteService.getOrganizationInvite.mockResolvedValue(orgInvite); policyApiService.getPoliciesByToken.mockResolvedValue(null); const result = await service.getMasterPasswordPolicyOptsFromOrgInvite(); expect(result).toBeNull(); - expect(acceptOrgInviteService.getOrganizationInvite).toHaveBeenCalled(); + expect(organizationInviteService.getOrganizationInvite).toHaveBeenCalled(); expect(policyApiService.getPoliciesByToken).toHaveBeenCalledWith( orgInvite.organizationId, orgInvite.token, @@ -131,13 +123,13 @@ describe("WebRegistrationFinishService", () => { }); it("logs an error and returns null when policies cannot be fetched", async () => { - acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(orgInvite); + organizationInviteService.getOrganizationInvite.mockResolvedValue(orgInvite); policyApiService.getPoliciesByToken.mockRejectedValue(new Error("error")); const result = await service.getMasterPasswordPolicyOptsFromOrgInvite(); expect(result).toBeNull(); - expect(acceptOrgInviteService.getOrganizationInvite).toHaveBeenCalled(); + expect(organizationInviteService.getOrganizationInvite).toHaveBeenCalled(); expect(policyApiService.getPoliciesByToken).toHaveBeenCalledWith( orgInvite.organizationId, orgInvite.token, @@ -151,14 +143,14 @@ describe("WebRegistrationFinishService", () => { const masterPasswordPolicies = [new Policy()]; const masterPasswordPolicyOptions = new MasterPasswordPolicyOptions(); - acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(orgInvite); + organizationInviteService.getOrganizationInvite.mockResolvedValue(orgInvite); policyApiService.getPoliciesByToken.mockResolvedValue(masterPasswordPolicies); policyService.masterPasswordPolicyOptions$.mockReturnValue(of(masterPasswordPolicyOptions)); const result = await service.getMasterPasswordPolicyOptsFromOrgInvite(); expect(result).toEqual(masterPasswordPolicyOptions); - expect(acceptOrgInviteService.getOrganizationInvite).toHaveBeenCalled(); + expect(organizationInviteService.getOrganizationInvite).toHaveBeenCalled(); expect(policyApiService.getPoliciesByToken).toHaveBeenCalledWith( orgInvite.organizationId, orgInvite.token, @@ -225,7 +217,7 @@ describe("WebRegistrationFinishService", () => { keyService.makeUserKey.mockResolvedValue([userKey, userKeyEncString]); keyService.makeKeyPair.mockResolvedValue(userKeyPair); accountApiService.registerFinish.mockResolvedValue(); - acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(null); + organizationInviteService.getOrganizationInvite.mockResolvedValue(null); await service.finishRegistration(email, passwordInputResult, emailVerificationToken); @@ -261,7 +253,7 @@ describe("WebRegistrationFinishService", () => { keyService.makeUserKey.mockResolvedValue([userKey, userKeyEncString]); keyService.makeKeyPair.mockResolvedValue(userKeyPair); accountApiService.registerFinish.mockResolvedValue(); - acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(orgInvite); + organizationInviteService.getOrganizationInvite.mockResolvedValue(orgInvite); await service.finishRegistration(email, passwordInputResult); @@ -297,7 +289,7 @@ describe("WebRegistrationFinishService", () => { keyService.makeUserKey.mockResolvedValue([userKey, userKeyEncString]); keyService.makeKeyPair.mockResolvedValue(userKeyPair); accountApiService.registerFinish.mockResolvedValue(); - acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(null); + organizationInviteService.getOrganizationInvite.mockResolvedValue(null); await service.finishRegistration( email, @@ -338,7 +330,7 @@ describe("WebRegistrationFinishService", () => { keyService.makeUserKey.mockResolvedValue([userKey, userKeyEncString]); keyService.makeKeyPair.mockResolvedValue(userKeyPair); accountApiService.registerFinish.mockResolvedValue(); - acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(null); + organizationInviteService.getOrganizationInvite.mockResolvedValue(null); await service.finishRegistration( email, @@ -381,7 +373,7 @@ describe("WebRegistrationFinishService", () => { keyService.makeUserKey.mockResolvedValue([userKey, userKeyEncString]); keyService.makeKeyPair.mockResolvedValue(userKeyPair); accountApiService.registerFinish.mockResolvedValue(); - acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(null); + organizationInviteService.getOrganizationInvite.mockResolvedValue(null); await service.finishRegistration( email, diff --git a/apps/web/src/app/auth/core/services/registration/web-registration-finish.service.ts b/apps/web/src/app/auth/core/services/registration/web-registration-finish.service.ts index 05b8ab5cb0f..d6f0a27a79c 100644 --- a/apps/web/src/app/auth/core/services/registration/web-registration-finish.service.ts +++ b/apps/web/src/app/auth/core/services/registration/web-registration-finish.service.ts @@ -12,16 +12,14 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; import { Policy } from "@bitwarden/common/admin-console/models/domain/policy"; import { AccountApiService } from "@bitwarden/common/auth/abstractions/account-api.service"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { RegisterFinishRequest } from "@bitwarden/common/auth/models/request/registration/register-finish.request"; +import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { KeyService } from "@bitwarden/key-management"; -import { AcceptOrganizationInviteService } from "../../../organization-invite/accept-organization.service"; - export class WebRegistrationFinishService extends DefaultRegistrationFinishService implements RegistrationFinishService @@ -29,18 +27,17 @@ export class WebRegistrationFinishService constructor( protected keyService: KeyService, protected accountApiService: AccountApiService, - private acceptOrgInviteService: AcceptOrganizationInviteService, + private organizationInviteService: OrganizationInviteService, private policyApiService: PolicyApiServiceAbstraction, private logService: LogService, private policyService: PolicyService, - private accountService: AccountService, private configService: ConfigService, ) { super(keyService, accountApiService); } override async getOrgNameFromOrgInvite(): Promise { - const orgInvite = await this.acceptOrgInviteService.getOrganizationInvite(); + const orgInvite = await this.organizationInviteService.getOrganizationInvite(); if (orgInvite == null) { return null; } @@ -50,7 +47,7 @@ export class WebRegistrationFinishService override async getMasterPasswordPolicyOptsFromOrgInvite(): Promise { // If there's a deep linked org invite, use it to get the password policies - const orgInvite = await this.acceptOrgInviteService.getOrganizationInvite(); + const orgInvite = await this.organizationInviteService.getOrganizationInvite(); if (orgInvite == null) { return null; @@ -115,7 +112,7 @@ export class WebRegistrationFinishService // web specific logic // Org invites are deep linked. Non-existent accounts are redirected to the register page. // Org user id and token are included here only for validation and two factor purposes. - const orgInvite = await this.acceptOrgInviteService.getOrganizationInvite(); + const orgInvite = await this.organizationInviteService.getOrganizationInvite(); if (orgInvite != null) { registerRequest.organizationUserId = orgInvite.organizationUserId; registerRequest.orgInviteToken = orgInvite.token; diff --git a/apps/web/src/app/auth/core/services/set-password-jit/web-set-password-jit.service.ts b/apps/web/src/app/auth/core/services/set-password-jit/web-set-password-jit.service.ts index 62175f1256d..3078b8e3b83 100644 --- a/apps/web/src/app/auth/core/services/set-password-jit/web-set-password-jit.service.ts +++ b/apps/web/src/app/auth/core/services/set-password-jit/web-set-password-jit.service.ts @@ -5,16 +5,16 @@ import { SetPasswordCredentials, SetPasswordJitService, } from "@bitwarden/auth/angular"; +import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service"; import { RouterService } from "../../../../core/router.service"; -import { AcceptOrganizationInviteService } from "../../../organization-invite/accept-organization.service"; export class WebSetPasswordJitService extends DefaultSetPasswordJitService implements SetPasswordJitService { routerService = inject(RouterService); - acceptOrganizationInviteService = inject(AcceptOrganizationInviteService); + organizationInviteService = inject(OrganizationInviteService); override async setPassword(credentials: SetPasswordCredentials) { await super.setPassword(credentials); @@ -22,6 +22,6 @@ export class WebSetPasswordJitService // SSO JIT accepts org invites when setting their MP, meaning // we can clear the deep linked url for accepting it. await this.routerService.getAndClearLoginRedirectUrl(); - await this.acceptOrganizationInviteService.clearOrganizationInvitation(); + await this.organizationInviteService.clearOrganizationInvitation(); } } diff --git a/apps/web/src/app/auth/organization-invite/accept-organization.component.ts b/apps/web/src/app/auth/organization-invite/accept-organization.component.ts index 838a3029711..b60007ca91e 100644 --- a/apps/web/src/app/auth/organization-invite/accept-organization.component.ts +++ b/apps/web/src/app/auth/organization-invite/accept-organization.component.ts @@ -4,13 +4,14 @@ import { Component } from "@angular/core"; import { ActivatedRoute, Params, Router } from "@angular/router"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; +import { OrganizationInvite } from "@bitwarden/common/auth/services/organization-invite/organization-invite"; +import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { BaseAcceptComponent } from "../../common/base.accept.component"; import { AcceptOrganizationInviteService } from "./accept-organization.service"; -import { OrganizationInvite } from "./organization-invite"; @Component({ templateUrl: "accept-organization.component.html", @@ -21,18 +22,19 @@ export class AcceptOrganizationComponent extends BaseAcceptComponent { protected requiredParameters: string[] = ["organizationId", "organizationUserId", "token"]; constructor( - router: Router, - platformUtilsService: PlatformUtilsService, - i18nService: I18nService, - route: ActivatedRoute, - authService: AuthService, + protected router: Router, + protected platformUtilsService: PlatformUtilsService, + protected i18nService: I18nService, + protected route: ActivatedRoute, + protected authService: AuthService, private acceptOrganizationInviteService: AcceptOrganizationInviteService, + private organizationInviteService: OrganizationInviteService, ) { super(router, platformUtilsService, i18nService, route, authService); } async authedHandler(qParams: Params): Promise { - const invite = OrganizationInvite.fromParams(qParams); + const invite = this.fromParams(qParams); const success = await this.acceptOrganizationInviteService.validateAndAcceptInvite(invite); if (!success) { @@ -52,9 +54,9 @@ export class AcceptOrganizationComponent extends BaseAcceptComponent { } async unauthedHandler(qParams: Params): Promise { - const invite = OrganizationInvite.fromParams(qParams); + const invite = this.fromParams(qParams); - await this.acceptOrganizationInviteService.setOrganizationInvitation(invite); + await this.organizationInviteService.setOrganizationInvitation(invite); await this.navigateInviteAcceptance(invite); } @@ -94,4 +96,21 @@ export class AcceptOrganizationComponent extends BaseAcceptComponent { }); return; } + + private fromParams(params: Params): OrganizationInvite | null { + if (params == null) { + return null; + } + + return Object.assign(new OrganizationInvite(), { + email: params.email, + initOrganization: params.initOrganization?.toLocaleLowerCase() === "true", + orgSsoIdentifier: params.orgSsoIdentifier, + orgUserHasExistingUser: params.orgUserHasExistingUser?.toLocaleLowerCase() === "true", + organizationId: params.organizationId, + organizationName: params.organizationName, + organizationUserId: params.organizationUserId, + token: params.token, + }); + } } diff --git a/apps/web/src/app/auth/organization-invite/accept-organization.service.spec.ts b/apps/web/src/app/auth/organization-invite/accept-organization.service.spec.ts index 253328b0c04..2fd869049bb 100644 --- a/apps/web/src/app/auth/organization-invite/accept-organization.service.spec.ts +++ b/apps/web/src/app/auth/organization-invite/accept-organization.service.spec.ts @@ -1,6 +1,5 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { FakeGlobalStateProvider } from "@bitwarden/common/../spec/fake-state-provider"; import { MockProxy, mock } from "jest-mock-extended"; import { BehaviorSubject } from "rxjs"; @@ -15,22 +14,18 @@ import { ResetPasswordPolicyOptions } from "@bitwarden/common/admin-console/mode import { OrganizationKeysResponse } from "@bitwarden/common/admin-console/models/response/organization-keys.response"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; +import { OrganizationInvite } from "@bitwarden/common/auth/services/organization-invite/organization-invite"; +import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; -import { FakeGlobalState } from "@bitwarden/common/spec/fake-state"; import { OrgKey } from "@bitwarden/common/types/key"; -import { DialogService } from "@bitwarden/components"; import { KeyService } from "@bitwarden/key-management"; import { I18nService } from "../../core/i18n.service"; -import { - AcceptOrganizationInviteService, - ORGANIZATION_INVITE, -} from "./accept-organization.service"; -import { OrganizationInvite } from "./organization-invite"; +import { AcceptOrganizationInviteService } from "./accept-organization.service"; describe("AcceptOrganizationInviteService", () => { let sut: AcceptOrganizationInviteService; @@ -43,10 +38,8 @@ describe("AcceptOrganizationInviteService", () => { let logService: MockProxy; let organizationApiService: MockProxy; let organizationUserApiService: MockProxy; + let organizationInviteService: MockProxy; let i18nService: MockProxy; - let globalStateProvider: FakeGlobalStateProvider; - let globalState: FakeGlobalState; - let dialogService: MockProxy; let accountService: MockProxy; beforeEach(() => { @@ -59,10 +52,8 @@ describe("AcceptOrganizationInviteService", () => { logService = mock(); organizationApiService = mock(); organizationUserApiService = mock(); + organizationInviteService = mock(); i18nService = mock(); - globalStateProvider = new FakeGlobalStateProvider(); - globalState = globalStateProvider.getFake(ORGANIZATION_INVITE); - dialogService = mock(); accountService = mock(); sut = new AcceptOrganizationInviteService( @@ -76,8 +67,7 @@ describe("AcceptOrganizationInviteService", () => { organizationApiService, organizationUserApiService, i18nService, - globalStateProvider, - dialogService, + organizationInviteService, accountService, ); }); @@ -103,8 +93,10 @@ describe("AcceptOrganizationInviteService", () => { expect(result).toBe(true); expect(organizationUserApiService.postOrganizationUserAcceptInit).toHaveBeenCalled(); expect(apiService.refreshIdentityToken).toHaveBeenCalled(); - expect(globalState.nextMock).toHaveBeenCalledWith(null); expect(organizationUserApiService.postOrganizationUserAccept).not.toHaveBeenCalled(); + expect(organizationInviteService.getOrganizationInvite).not.toHaveBeenCalled(); + expect(organizationInviteService.setOrganizationInvitation).not.toHaveBeenCalled(); + expect(organizationInviteService.clearOrganizationInvitation).toHaveBeenCalled(); expect(authService.logOut).not.toHaveBeenCalled(); }); @@ -121,13 +113,16 @@ describe("AcceptOrganizationInviteService", () => { expect(result).toBe(false); expect(authService.logOut).toHaveBeenCalled(); - expect(globalState.nextMock).toHaveBeenCalledWith(invite); + expect(organizationInviteService.setOrganizationInvitation).toHaveBeenCalledWith(invite); + expect(organizationInviteService.clearOrganizationInvitation).toHaveBeenCalled(); }); it("clears the stored invite when a master password policy check is required but the stored invite doesn't match the provided one", async () => { const storedInvite = createOrgInvite({ email: "wrongemail@example.com" }); const providedInvite = createOrgInvite(); - await globalState.update(() => storedInvite); + organizationInviteService.getOrganizationInvite.mockReturnValueOnce( + Promise.resolve(storedInvite), + ); policyApiService.getPoliciesByToken.mockResolvedValue([ { type: PolicyType.MasterPassword, @@ -139,7 +134,11 @@ describe("AcceptOrganizationInviteService", () => { expect(result).toBe(false); expect(authService.logOut).toHaveBeenCalled(); - expect(globalState.nextMock).toHaveBeenCalledWith(providedInvite); + expect(organizationInviteService.setOrganizationInvitation).toHaveBeenCalledWith( + providedInvite, + ); + expect(organizationInviteService.getOrganizationInvite).toHaveBeenCalledWith(); + expect(organizationInviteService.clearOrganizationInvitation).toHaveBeenCalled(); }); it("accepts the invitation request when the organization doesn't have a master password policy", async () => { @@ -151,8 +150,10 @@ describe("AcceptOrganizationInviteService", () => { expect(result).toBe(true); expect(organizationUserApiService.postOrganizationUserAccept).toHaveBeenCalled(); expect(apiService.refreshIdentityToken).toHaveBeenCalled(); - expect(globalState.nextMock).toHaveBeenCalledWith(null); expect(organizationUserApiService.postOrganizationUserAcceptInit).not.toHaveBeenCalled(); + expect(organizationInviteService.setOrganizationInvitation).not.toHaveBeenCalled(); + expect(organizationInviteService.getOrganizationInvite).not.toHaveBeenCalled(); + expect(organizationInviteService.clearOrganizationInvitation).toHaveBeenCalled(); expect(authService.logOut).not.toHaveBeenCalled(); }); @@ -165,7 +166,7 @@ describe("AcceptOrganizationInviteService", () => { } as Policy, ]); // an existing invite means the user has already passed the master password policy - await globalState.update(() => invite); + organizationInviteService.getOrganizationInvite.mockReturnValueOnce(Promise.resolve(invite)); policyService.getResetPasswordPolicyOptions.mockReturnValue([ { @@ -179,6 +180,8 @@ describe("AcceptOrganizationInviteService", () => { expect(result).toBe(true); expect(organizationUserApiService.postOrganizationUserAccept).toHaveBeenCalled(); expect(organizationUserApiService.postOrganizationUserAcceptInit).not.toHaveBeenCalled(); + expect(organizationInviteService.getOrganizationInvite).toHaveBeenCalledWith(); + expect(organizationInviteService.clearOrganizationInvitation).toHaveBeenCalled(); expect(authService.logOut).not.toHaveBeenCalled(); }); @@ -202,7 +205,7 @@ describe("AcceptOrganizationInviteService", () => { encryptedString: "encryptedString", } as EncString); - await globalState.update(() => invite); + organizationInviteService.getOrganizationInvite.mockReturnValueOnce(Promise.resolve(invite)); policyService.getResetPasswordPolicyOptions.mockReturnValue([ { @@ -220,6 +223,9 @@ describe("AcceptOrganizationInviteService", () => { ); expect(organizationUserApiService.postOrganizationUserAccept).toHaveBeenCalled(); expect(organizationUserApiService.postOrganizationUserAcceptInit).not.toHaveBeenCalled(); + expect(organizationInviteService.getOrganizationInvite).toHaveBeenCalledTimes(1); + expect(organizationInviteService.getOrganizationInvite).toHaveBeenCalledWith(); + expect(organizationInviteService.clearOrganizationInvitation).toHaveBeenCalled(); expect(authService.logOut).not.toHaveBeenCalled(); }); }); diff --git a/apps/web/src/app/auth/organization-invite/accept-organization.service.ts b/apps/web/src/app/auth/organization-invite/accept-organization.service.ts index c68b174166d..a5f5eb828fa 100644 --- a/apps/web/src/app/auth/organization-invite/accept-organization.service.ts +++ b/apps/web/src/app/auth/organization-invite/accept-organization.service.ts @@ -17,36 +17,17 @@ import { Policy } from "@bitwarden/common/admin-console/models/domain/policy"; import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; +import { OrganizationInvite } from "@bitwarden/common/auth/services/organization-invite/organization-invite"; +import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { - GlobalState, - GlobalStateProvider, - KeyDefinition, - ORGANIZATION_INVITE_DISK, -} from "@bitwarden/common/platform/state"; import { OrgKey } from "@bitwarden/common/types/key"; -import { DialogService } from "@bitwarden/components"; import { KeyService } from "@bitwarden/key-management"; -import { OrganizationInvite } from "./organization-invite"; - -// We're storing the organization invite for 2 reasons: -// 1. If the org requires a MP policy check, we need to keep track that the user has already been redirected when they return. -// 2. The MP policy check happens on login/register flows, we need to store the token to retrieve the policies then. -export const ORGANIZATION_INVITE = new KeyDefinition( - ORGANIZATION_INVITE_DISK, - "organizationInvite", - { - deserializer: (invite) => (invite ? OrganizationInvite.fromJSON(invite) : null), - }, -); - @Injectable() export class AcceptOrganizationInviteService { - private organizationInvitationState: GlobalState; private orgNameSubject: BehaviorSubject = new BehaviorSubject(null); private policyCache: Policy[]; @@ -64,34 +45,9 @@ export class AcceptOrganizationInviteService { private readonly organizationApiService: OrganizationApiServiceAbstraction, private readonly organizationUserApiService: OrganizationUserApiService, private readonly i18nService: I18nService, - private readonly globalStateProvider: GlobalStateProvider, - private readonly dialogService: DialogService, + private readonly organizationInviteService: OrganizationInviteService, private readonly accountService: AccountService, - ) { - this.organizationInvitationState = this.globalStateProvider.get(ORGANIZATION_INVITE); - } - - /** Returns the currently stored organization invite */ - async getOrganizationInvite(): Promise { - return await firstValueFrom(this.organizationInvitationState.state$); - } - - /** - * Stores a new organization invite - * @param invite an organization invite - * @throws if the invite is nullish - */ - async setOrganizationInvitation(invite: OrganizationInvite): Promise { - if (invite == null) { - throw new Error("Invite cannot be null. Use clearOrganizationInvitation instead."); - } - await this.organizationInvitationState.update(() => invite); - } - - /** Clears the currently stored organization invite */ - async clearOrganizationInvitation(): Promise { - await this.organizationInvitationState.update(() => null); - } + ) {} /** * Validates and accepts the organization invitation if possible. @@ -113,7 +69,7 @@ export class AcceptOrganizationInviteService { // Accepting an org invite from existing org if (await this.masterPasswordPolicyCheckRequired(invite)) { - await this.setOrganizationInvitation(invite); + await this.organizationInviteService.setOrganizationInvitation(invite); this.authService.logOut(() => { /* Do nothing */ }); @@ -134,7 +90,7 @@ export class AcceptOrganizationInviteService { ), ); await this.apiService.refreshIdentityToken(); - await this.clearOrganizationInvitation(); + await this.organizationInviteService.clearOrganizationInvitation(); } private async prepareAcceptAndInitRequest( @@ -170,7 +126,7 @@ export class AcceptOrganizationInviteService { ); await this.apiService.refreshIdentityToken(); - await this.clearOrganizationInvitation(); + await this.organizationInviteService.clearOrganizationInvitation(); } private async prepareAcceptRequest( @@ -224,10 +180,10 @@ export class AcceptOrganizationInviteService { (p) => p.type === PolicyType.MasterPassword && p.enabled, ); - let storedInvite = await this.getOrganizationInvite(); + let storedInvite = await this.organizationInviteService.getOrganizationInvite(); if (storedInvite?.email !== invite.email) { // clear stored invites if the email doesn't match - await this.clearOrganizationInvitation(); + await this.organizationInviteService.clearOrganizationInvitation(); storedInvite = null; } // if we don't have an org invite stored, we know the user hasn't been redirected yet to check the MP policy diff --git a/apps/web/src/app/auth/organization-invite/organization-invite.ts b/apps/web/src/app/auth/organization-invite/organization-invite.ts deleted file mode 100644 index 65414113e74..00000000000 --- a/apps/web/src/app/auth/organization-invite/organization-invite.ts +++ /dev/null @@ -1,40 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { Params } from "@angular/router"; -import { Jsonify } from "type-fest"; - -export class OrganizationInvite { - email: string; - initOrganization: boolean; - orgSsoIdentifier: string; - orgUserHasExistingUser: boolean; - organizationId: string; - organizationName: string; - organizationUserId: string; - token: string; - - static fromJSON(json: Jsonify): OrganizationInvite | null { - if (json == null) { - return null; - } - - return Object.assign(new OrganizationInvite(), json); - } - - static fromParams(params: Params): OrganizationInvite | null { - if (params == null) { - return null; - } - - return Object.assign(new OrganizationInvite(), { - email: params.email, - initOrganization: params.initOrganization?.toLocaleLowerCase() === "true", - orgSsoIdentifier: params.orgSsoIdentifier, - orgUserHasExistingUser: params.orgUserHasExistingUser?.toLocaleLowerCase() === "true", - organizationId: params.organizationId, - organizationName: params.organizationName, - organizationUserId: params.organizationUserId, - token: params.token, - }); - } -} diff --git a/apps/web/src/app/auth/set-password.component.ts b/apps/web/src/app/auth/set-password.component.ts index e297426f2c1..f61981a93d3 100644 --- a/apps/web/src/app/auth/set-password.component.ts +++ b/apps/web/src/app/auth/set-password.component.ts @@ -1,13 +1,12 @@ import { Component, inject } from "@angular/core"; import { SetPasswordComponent as BaseSetPasswordComponent } from "@bitwarden/angular/auth/components/set-password.component"; +import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { MasterKey, UserKey } from "@bitwarden/common/types/key"; import { RouterService } from "../core"; -import { AcceptOrganizationInviteService } from "./organization-invite/accept-organization.service"; - @Component({ selector: "app-set-password", templateUrl: "set-password.component.html", @@ -15,7 +14,7 @@ import { AcceptOrganizationInviteService } from "./organization-invite/accept-or }) export class SetPasswordComponent extends BaseSetPasswordComponent { routerService = inject(RouterService); - acceptOrganizationInviteService = inject(AcceptOrganizationInviteService); + organizationInviteService = inject(OrganizationInviteService); protected override async onSetPasswordSuccess( masterKey: MasterKey, @@ -26,6 +25,6 @@ export class SetPasswordComponent extends BaseSetPasswordComponent { // SSO JIT accepts org invites when setting their MP, meaning // we can clear the deep linked url for accepting it. await this.routerService.getAndClearLoginRedirectUrl(); - await this.acceptOrganizationInviteService.clearOrganizationInvitation(); + await this.organizationInviteService.clearOrganizationInvitation(); } } diff --git a/apps/web/src/app/auth/settings/change-password.component.ts b/apps/web/src/app/auth/settings/change-password.component.ts index 15d106057ba..ce10a0e5a34 100644 --- a/apps/web/src/app/auth/settings/change-password.component.ts +++ b/apps/web/src/app/auth/settings/change-password.component.ts @@ -43,34 +43,34 @@ export class ChangePasswordComponent characterMinimumMessage = ""; constructor( - i18nService: I18nService, - keyService: KeyService, - messagingService: MessagingService, - platformUtilsService: PlatformUtilsService, - policyService: PolicyService, private auditService: AuditService, private cipherService: CipherService, - private syncService: SyncService, + private keyRotationService: UserKeyRotationService, private masterPasswordApiService: MasterPasswordApiService, private router: Router, - dialogService: DialogService, + private syncService: SyncService, private userVerificationService: UserVerificationService, - private keyRotationService: UserKeyRotationService, - kdfConfigService: KdfConfigService, + protected accountService: AccountService, + protected dialogService: DialogService, + protected i18nService: I18nService, + protected kdfConfigService: KdfConfigService, + protected keyService: KeyService, protected masterPasswordService: InternalMasterPasswordServiceAbstraction, - accountService: AccountService, - toastService: ToastService, + protected messagingService: MessagingService, + protected platformUtilsService: PlatformUtilsService, + protected policyService: PolicyService, + protected toastService: ToastService, ) { super( + accountService, + dialogService, i18nService, + kdfConfigService, keyService, + masterPasswordService, messagingService, platformUtilsService, policyService, - dialogService, - kdfConfigService, - masterPasswordService, - accountService, toastService, ); } @@ -244,8 +244,7 @@ export class ChangePasswordComponent await this.masterPasswordApiService.postPassword(request); this.toastService.showToast({ variant: "success", - title: this.i18nService.t("masterPasswordChanged"), - message: this.i18nService.t("masterPasswordChangedDesc"), + message: this.i18nService.t("masterPasswordChanged"), }); this.messagingService.send("logout"); } catch { diff --git a/apps/web/src/app/auth/settings/emergency-access/takeover/emergency-access-takeover.component.ts b/apps/web/src/app/auth/settings/emergency-access/takeover/emergency-access-takeover.component.ts index d683545db59..ede60887725 100644 --- a/apps/web/src/app/auth/settings/emergency-access/takeover/emergency-access-takeover.component.ts +++ b/apps/web/src/app/auth/settings/emergency-access/takeover/emergency-access-takeover.component.ts @@ -71,15 +71,15 @@ export class EmergencyAccessTakeoverComponent protected toastService: ToastService, ) { super( + accountService, + dialogService, i18nService, + kdfConfigService, keyService, + masterPasswordService, messagingService, platformUtilsService, policyService, - dialogService, - kdfConfigService, - masterPasswordService, - accountService, toastService, ); } diff --git a/apps/web/src/app/auth/settings/security/password-settings/password-settings.component.html b/apps/web/src/app/auth/settings/security/password-settings/password-settings.component.html index fc6620762f9..b918e113e46 100644 --- a/apps/web/src/app/auth/settings/security/password-settings/password-settings.component.html +++ b/apps/web/src/app/auth/settings/security/password-settings/password-settings.component.html @@ -1,7 +1,6 @@

{{ "changeMasterPassword" | i18n }}

- {{ "loggedOutWarning" | i18n }}
diff --git a/apps/web/src/app/auth/settings/security/password-settings/password-settings.component.ts b/apps/web/src/app/auth/settings/security/password-settings/password-settings.component.ts index d94df18136e..0698ffe1f8d 100644 --- a/apps/web/src/app/auth/settings/security/password-settings/password-settings.component.ts +++ b/apps/web/src/app/auth/settings/security/password-settings/password-settings.component.ts @@ -2,7 +2,8 @@ import { Component, OnInit } from "@angular/core"; import { Router } from "@angular/router"; import { firstValueFrom } from "rxjs"; -import { ChangePasswordComponent, InputPasswordFlow } from "@bitwarden/auth/angular"; +import { ChangePasswordComponent } from "@bitwarden/angular/auth/password-management/change-password"; +import { InputPasswordFlow } from "@bitwarden/auth/angular"; import { UserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common"; import { CalloutModule } from "@bitwarden/components"; import { I18nPipe } from "@bitwarden/ui-common"; @@ -16,6 +17,7 @@ import { WebauthnLoginSettingsModule } from "../../webauthn-login-settings"; }) export class PasswordSettingsComponent implements OnInit { inputPasswordFlow = InputPasswordFlow.ChangePasswordWithOptionalUserKeyRotation; + changePasswordFeatureFlag = false; constructor( private router: Router, diff --git a/apps/web/src/app/auth/update-password.component.ts b/apps/web/src/app/auth/update-password.component.ts index c975f7c4168..bc53f824228 100644 --- a/apps/web/src/app/auth/update-password.component.ts +++ b/apps/web/src/app/auth/update-password.component.ts @@ -1,11 +1,10 @@ import { Component, inject } from "@angular/core"; import { UpdatePasswordComponent as BaseUpdatePasswordComponent } from "@bitwarden/angular/auth/components/update-password.component"; +import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service"; import { RouterService } from "../core"; -import { AcceptOrganizationInviteService } from "./organization-invite/accept-organization.service"; - @Component({ selector: "app-update-password", templateUrl: "update-password.component.html", @@ -13,13 +12,13 @@ import { AcceptOrganizationInviteService } from "./organization-invite/accept-or }) export class UpdatePasswordComponent extends BaseUpdatePasswordComponent { private routerService = inject(RouterService); - private acceptOrganizationInviteService = inject(AcceptOrganizationInviteService); + private organizationInviteService = inject(OrganizationInviteService); override async cancel() { // clearing the login redirect url so that the user // does not join the organization if they cancel await this.routerService.getAndClearLoginRedirectUrl(); - await this.acceptOrganizationInviteService.clearOrganizationInvitation(); + await this.organizationInviteService.clearOrganizationInvitation(); await super.cancel(); } } diff --git a/apps/web/src/app/billing/trial-initiation/complete-trial-initiation/complete-trial-initiation.component.ts b/apps/web/src/app/billing/trial-initiation/complete-trial-initiation/complete-trial-initiation.component.ts index 2b927f6db09..ce02ee8715a 100644 --- a/apps/web/src/app/billing/trial-initiation/complete-trial-initiation/complete-trial-initiation.component.ts +++ b/apps/web/src/app/billing/trial-initiation/complete-trial-initiation/complete-trial-initiation.component.ts @@ -18,6 +18,7 @@ import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/mod import { Policy } from "@bitwarden/common/admin-console/models/domain/policy"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; +import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service"; import { OrganizationBillingServiceAbstraction as OrganizationBillingService, OrganizationInformation, @@ -31,7 +32,6 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service" import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; import { ToastService } from "@bitwarden/components"; -import { AcceptOrganizationInviteService } from "../../../auth/organization-invite/accept-organization.service"; import { OrganizationCreatedEvent, SubscriptionProduct, @@ -115,7 +115,7 @@ export class CompleteTrialInitiationComponent implements OnInit, OnDestroy { private i18nService: I18nService, private routerService: RouterService, private organizationBillingService: OrganizationBillingService, - private acceptOrganizationInviteService: AcceptOrganizationInviteService, + private organizationInviteService: OrganizationInviteService, private toastService: ToastService, private registrationFinishService: RegistrationFinishService, private validationService: ValidationService, @@ -174,7 +174,7 @@ export class CompleteTrialInitiationComponent implements OnInit, OnDestroy { this.setupFamilySponsorship(qParams.sponsorshipToken); }); - const invite = await this.acceptOrganizationInviteService.getOrganizationInvite(); + const invite = await this.organizationInviteService.getOrganizationInvite(); let policies: Policy[] | null = null; if (invite != null) { diff --git a/apps/web/src/app/core/core.module.ts b/apps/web/src/app/core/core.module.ts index b8baa762e91..9cfe3117d40 100644 --- a/apps/web/src/app/core/core.module.ts +++ b/apps/web/src/app/core/core.module.ts @@ -10,6 +10,7 @@ import { OrganizationUserApiService, CollectionService, } from "@bitwarden/admin-console/common"; +import { ChangePasswordService } from "@bitwarden/angular/auth/password-management/change-password"; import { SetInitialPasswordService } from "@bitwarden/angular/auth/password-management/set-initial-password/set-initial-password.service.abstraction"; import { SafeProvider, safeProvider } from "@bitwarden/angular/platform/utils/safe-provider"; import { @@ -34,7 +35,6 @@ import { SsoComponentService, LoginDecryptionOptionsService, TwoFactorAuthDuoComponentService, - ChangePasswordService, } from "@bitwarden/auth/angular"; import { InternalUserDecryptionOptionsServiceAbstraction, @@ -52,6 +52,7 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; +import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service"; import { ClientType } from "@bitwarden/common/enums"; import { ProcessReloadServiceAbstraction } from "@bitwarden/common/key-management/abstractions/process-reload.service"; import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service"; @@ -108,6 +109,7 @@ import { } from "@bitwarden/key-management"; import { LockComponentService } from "@bitwarden/key-management-ui"; import { DefaultSshImportPromptService, SshImportPromptService } from "@bitwarden/vault"; +import { WebOrganizationInviteService } from "@bitwarden/web-vault/app/auth/core/services/organization-invite/web-organization-invite.service"; import { flagEnabled } from "../../utils/flags"; import { PolicyListService } from "../admin-console/core/policy-list.service"; @@ -122,7 +124,6 @@ import { WebSetInitialPasswordService, } from "../auth"; import { WebSsoComponentService } from "../auth/core/services/login/web-sso-component.service"; -import { AcceptOrganizationInviteService } from "../auth/organization-invite/accept-organization.service"; import { HtmlStorageService } from "../core/html-storage.service"; import { I18nService } from "../core/i18n.service"; import { WebFileDownloadService } from "../core/web-file-download.service"; @@ -246,17 +247,21 @@ const safeProviders: SafeProvider[] = [ provide: CLIENT_TYPE, useValue: ClientType.Web, }), + safeProvider({ + provide: OrganizationInviteService, + useClass: WebOrganizationInviteService, + deps: [GlobalStateProvider], + }), safeProvider({ provide: RegistrationFinishServiceAbstraction, useClass: WebRegistrationFinishService, deps: [ KeyServiceAbstraction, AccountApiServiceAbstraction, - AcceptOrganizationInviteService, + OrganizationInviteService, PolicyApiServiceAbstraction, LogService, PolicyService, - AccountService, ConfigService, ], }), @@ -275,12 +280,11 @@ const safeProviders: SafeProvider[] = [ provide: SetPasswordJitService, useClass: WebSetPasswordJitService, deps: [ - ApiService, - MasterPasswordApiService, - KeyServiceAbstraction, EncryptService, I18nServiceAbstraction, KdfConfigService, + KeyServiceAbstraction, + MasterPasswordApiService, InternalMasterPasswordServiceAbstraction, OrganizationApiServiceAbstraction, OrganizationUserApiService, @@ -301,7 +305,7 @@ const safeProviders: SafeProvider[] = [ OrganizationApiServiceAbstraction, OrganizationUserApiService, InternalUserDecryptionOptionsServiceAbstraction, - AcceptOrganizationInviteService, + OrganizationInviteService, RouterService, ], }), @@ -314,7 +318,7 @@ const safeProviders: SafeProvider[] = [ provide: LoginComponentService, useClass: WebLoginComponentService, deps: [ - AcceptOrganizationInviteService, + OrganizationInviteService, LogService, PolicyApiServiceAbstraction, InternalPolicyService, @@ -326,6 +330,7 @@ const safeProviders: SafeProvider[] = [ SsoLoginServiceAbstraction, Router, AccountService, + ConfigService, ], }), safeProvider({ @@ -378,7 +383,7 @@ const safeProviders: SafeProvider[] = [ safeProvider({ provide: LoginDecryptionOptionsService, useClass: WebLoginDecryptionOptionsService, - deps: [MessagingService, RouterService, AcceptOrganizationInviteService], + deps: [MessagingService, RouterService, OrganizationInviteService], }), safeProvider({ provide: IpcService, @@ -398,6 +403,7 @@ const safeProviders: SafeProvider[] = [ MasterPasswordApiService, InternalMasterPasswordServiceAbstraction, UserKeyRotationService, + RouterService, ], }), ]; diff --git a/apps/web/src/app/oss-routing.module.ts b/apps/web/src/app/oss-routing.module.ts index 31b9ca26e70..d3e7fc495ca 100644 --- a/apps/web/src/app/oss-routing.module.ts +++ b/apps/web/src/app/oss-routing.module.ts @@ -10,6 +10,7 @@ import { unauthGuardFn, activeAuthGuard, } from "@bitwarden/angular/auth/guards"; +import { ChangePasswordComponent } from "@bitwarden/angular/auth/password-management/change-password"; import { SetInitialPasswordComponent } from "@bitwarden/angular/auth/password-management/set-initial-password/set-initial-password.component"; import { canAccessFeature } from "@bitwarden/angular/platform/guard/feature-flag.guard"; import { @@ -144,13 +145,29 @@ const routes: Routes = [ { path: "update-temp-password", component: UpdateTempPasswordComponent, - canActivate: [authGuard], + canActivate: [ + canAccessFeature( + FeatureFlag.PM16117_ChangeExistingPasswordRefactor, + false, + "change-password", + false, + ), + authGuard, + ], data: { titleId: "updateTempPassword" } satisfies RouteDataProperties, }, { path: "update-password", component: UpdatePasswordComponent, - canActivate: [authGuard], + canActivate: [ + canAccessFeature( + FeatureFlag.PM16117_ChangeExistingPasswordRefactor, + false, + "change-password", + false, + ), + authGuard, + ], data: { titleId: "updatePassword" } satisfies RouteDataProperties, }, ], @@ -580,6 +597,14 @@ const routes: Routes = [ }, ], }, + { + path: "change-password", + component: ChangePasswordComponent, + canActivate: [ + canAccessFeature(FeatureFlag.PM16117_ChangeExistingPasswordRefactor), + authGuard, + ], + }, { path: "setup-extension", data: { diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index bc2e49e85cd..50a2cdbc4a9 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -1785,6 +1785,9 @@ "loggedOutWarning": { "message": "Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour." }, + "changePasswordWarning": { + "message": "After changing your password, you will need to log in with your new password. Active sessions on other devices will be logged out within one hour." + }, "emailChanged": { "message": "Email saved" }, @@ -6077,6 +6080,12 @@ "updateMasterPassword": { "message": "Update master password" }, + "accountRecoveryUpdateMasterPasswordSubtitle": { + "message": "Change your master password to complete account recovery." + }, + "updateMasterPasswordSubtitle": { + "message": "Your master password does not meet this organization’s requirements. Change your master password to continue." + }, "updateMasterPasswordWarning": { "message": "Your master password was recently changed by an administrator in your organization. In order to access the vault, you must update your master password now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour." }, diff --git a/libs/angular/src/auth/components/change-password.component.ts b/libs/angular/src/auth/components/change-password.component.ts index ca81f741b23..6adb684681c 100644 --- a/libs/angular/src/auth/components/change-password.component.ts +++ b/libs/angular/src/auth/components/change-password.component.ts @@ -37,15 +37,15 @@ export class ChangePasswordComponent implements OnInit, OnDestroy { protected destroy$ = new Subject(); constructor( + protected accountService: AccountService, + protected dialogService: DialogService, protected i18nService: I18nService, + protected kdfConfigService: KdfConfigService, protected keyService: KeyService, + protected masterPasswordService: InternalMasterPasswordServiceAbstraction, protected messagingService: MessagingService, protected platformUtilsService: PlatformUtilsService, protected policyService: PolicyService, - protected dialogService: DialogService, - protected kdfConfigService: KdfConfigService, - protected masterPasswordService: InternalMasterPasswordServiceAbstraction, - protected accountService: AccountService, protected toastService: ToastService, ) {} diff --git a/libs/angular/src/auth/components/set-password.component.ts b/libs/angular/src/auth/components/set-password.component.ts index 53f6abaa33c..1550b648734 100644 --- a/libs/angular/src/auth/components/set-password.component.ts +++ b/libs/angular/src/auth/components/set-password.component.ts @@ -14,7 +14,6 @@ import { // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // eslint-disable-next-line no-restricted-imports import { InternalUserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; @@ -58,38 +57,37 @@ export class SetPasswordComponent extends BaseChangePasswordComponent implements ForceSetPasswordReason = ForceSetPasswordReason; constructor( - accountService: AccountService, - masterPasswordService: InternalMasterPasswordServiceAbstraction, - i18nService: I18nService, - keyService: KeyService, - messagingService: MessagingService, - platformUtilsService: PlatformUtilsService, - private policyApiService: PolicyApiServiceAbstraction, - policyService: PolicyService, + protected accountService: AccountService, + protected dialogService: DialogService, + protected encryptService: EncryptService, + protected i18nService: I18nService, + protected kdfConfigService: KdfConfigService, + protected keyService: KeyService, + protected masterPasswordApiService: MasterPasswordApiService, + protected masterPasswordService: InternalMasterPasswordServiceAbstraction, + protected messagingService: MessagingService, + protected organizationApiService: OrganizationApiServiceAbstraction, + protected organizationUserApiService: OrganizationUserApiService, + protected platformUtilsService: PlatformUtilsService, + protected policyApiService: PolicyApiServiceAbstraction, + protected policyService: PolicyService, + protected route: ActivatedRoute, protected router: Router, - private masterPasswordApiService: MasterPasswordApiService, - private apiService: ApiService, - private syncService: SyncService, - private route: ActivatedRoute, - private organizationApiService: OrganizationApiServiceAbstraction, - private organizationUserApiService: OrganizationUserApiService, - private userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction, - private ssoLoginService: SsoLoginServiceAbstraction, - dialogService: DialogService, - kdfConfigService: KdfConfigService, - private encryptService: EncryptService, + protected ssoLoginService: SsoLoginServiceAbstraction, + protected syncService: SyncService, protected toastService: ToastService, + protected userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction, ) { super( + accountService, + dialogService, i18nService, + kdfConfigService, keyService, + masterPasswordService, messagingService, platformUtilsService, policyService, - dialogService, - kdfConfigService, - masterPasswordService, - accountService, toastService, ); } diff --git a/libs/angular/src/auth/components/update-password.component.ts b/libs/angular/src/auth/components/update-password.component.ts index 47affbecdf2..839c3b24ebf 100644 --- a/libs/angular/src/auth/components/update-password.component.ts +++ b/libs/angular/src/auth/components/update-password.component.ts @@ -52,15 +52,15 @@ export class UpdatePasswordComponent extends BaseChangePasswordComponent { toastService: ToastService, ) { super( + accountService, + dialogService, i18nService, + kdfConfigService, keyService, + masterPasswordService, messagingService, platformUtilsService, policyService, - dialogService, - kdfConfigService, - masterPasswordService, - accountService, toastService, ); } diff --git a/libs/angular/src/auth/components/update-temp-password.component.ts b/libs/angular/src/auth/components/update-temp-password.component.ts index db2f319998a..87db26a6b59 100644 --- a/libs/angular/src/auth/components/update-temp-password.component.ts +++ b/libs/angular/src/auth/components/update-temp-password.component.ts @@ -64,15 +64,15 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent imp toastService: ToastService, ) { super( + accountService, + dialogService, i18nService, + kdfConfigService, keyService, + masterPasswordService, messagingService, platformUtilsService, policyService, - dialogService, - kdfConfigService, - masterPasswordService, - accountService, toastService, ); } diff --git a/libs/angular/src/auth/guards/auth.guard.ts b/libs/angular/src/auth/guards/auth.guard.ts index 58ee3a59bbe..3722a7c802a 100644 --- a/libs/angular/src/auth/guards/auth.guard.ts +++ b/libs/angular/src/auth/guards/auth.guard.ts @@ -47,9 +47,6 @@ export const authGuard: CanActivateFn = async ( const isSetInitialPasswordFlagOn = await configService.getFeatureFlag( FeatureFlag.PM16117_SetInitialPasswordRefactor, ); - const isChangePasswordFlagOn = await configService.getFeatureFlag( - FeatureFlag.PM16117_ChangeExistingPasswordRefactor, - ); // User JIT provisioned into a master-password-encryption org if ( @@ -114,6 +111,10 @@ export const authGuard: CanActivateFn = async ( return router.createUrlTree([route]); } + const isChangePasswordFlagOn = await configService.getFeatureFlag( + FeatureFlag.PM16117_ChangeExistingPasswordRefactor, + ); + // Post- Account Recovery or Weak Password on login if ( (forceSetPasswordReason === ForceSetPasswordReason.AdminForcePasswordReset || diff --git a/libs/auth/src/angular/change-password/change-password.component.html b/libs/angular/src/auth/password-management/change-password/change-password.component.html similarity index 67% rename from libs/auth/src/angular/change-password/change-password.component.html rename to libs/angular/src/auth/password-management/change-password/change-password.component.html index fff873225be..7604ffacea7 100644 --- a/libs/auth/src/angular/change-password/change-password.component.html +++ b/libs/angular/src/auth/password-management/change-password/change-password.component.html @@ -6,6 +6,12 @@ >
{{ "loading" | i18n }} } @else { + {{ "changePasswordWarning" | i18n }} + } diff --git a/libs/angular/src/auth/password-management/change-password/change-password.component.ts b/libs/angular/src/auth/password-management/change-password/change-password.component.ts new file mode 100644 index 00000000000..78128962384 --- /dev/null +++ b/libs/angular/src/auth/password-management/change-password/change-password.component.ts @@ -0,0 +1,202 @@ +import { Component, Input, OnInit } from "@angular/core"; +import { firstValueFrom } from "rxjs"; + +// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. +// eslint-disable-next-line no-restricted-imports +import { + InputPasswordComponent, + InputPasswordFlow, + PasswordInputResult, +} from "@bitwarden/auth/angular"; +import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; +import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; +import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service"; +import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { SyncService } from "@bitwarden/common/platform/sync"; +import { UserId } from "@bitwarden/common/types/guid"; +import { + AnonLayoutWrapperDataService, + DialogService, + ToastService, + Icons, + CalloutComponent, +} from "@bitwarden/components"; +import { I18nPipe } from "@bitwarden/ui-common"; + +import { ChangePasswordService } from "./change-password.service.abstraction"; + +/** + * Change Password Component + * + * NOTE: The change password component uses the input-password component which will show the + * current password input form in some flows, although it could be left off. This is intentional + * and by design to maintain a strong security posture as some flows could have the user + * end up at a change password without having one before. + */ +@Component({ + selector: "auth-change-password", + templateUrl: "change-password.component.html", + imports: [InputPasswordComponent, I18nPipe, CalloutComponent], +}) +export class ChangePasswordComponent implements OnInit { + @Input() inputPasswordFlow: InputPasswordFlow = InputPasswordFlow.ChangePassword; + + activeAccount: Account | null = null; + email?: string; + userId?: UserId; + masterPasswordPolicyOptions?: MasterPasswordPolicyOptions; + initializing = true; + submitting = false; + formPromise?: Promise; + forceSetPasswordReason: ForceSetPasswordReason = ForceSetPasswordReason.None; + + protected readonly ForceSetPasswordReason = ForceSetPasswordReason; + + constructor( + private accountService: AccountService, + private changePasswordService: ChangePasswordService, + private i18nService: I18nService, + private masterPasswordService: InternalMasterPasswordServiceAbstraction, + private anonLayoutWrapperDataService: AnonLayoutWrapperDataService, + private organizationInviteService: OrganizationInviteService, + private messagingService: MessagingService, + private policyService: PolicyService, + private toastService: ToastService, + private syncService: SyncService, + private dialogService: DialogService, + private logService: LogService, + ) {} + + async ngOnInit() { + this.activeAccount = await firstValueFrom(this.accountService.activeAccount$); + + if (!this.activeAccount) { + throw new Error("No active active account found while trying to change passwords."); + } + + this.userId = this.activeAccount.id; + this.email = this.activeAccount.email; + + if (!this.userId) { + throw new Error("userId not found"); + } + + this.masterPasswordPolicyOptions = await firstValueFrom( + this.policyService.masterPasswordPolicyOptions$(this.userId), + ); + + this.forceSetPasswordReason = await firstValueFrom( + this.masterPasswordService.forceSetPasswordReason$(this.userId), + ); + + if (this.forceSetPasswordReason === ForceSetPasswordReason.AdminForcePasswordReset) { + this.anonLayoutWrapperDataService.setAnonLayoutWrapperData({ + pageIcon: Icons.LockIcon, + pageTitle: { key: "updateMasterPassword" }, + pageSubtitle: { key: "accountRecoveryUpdateMasterPasswordSubtitle" }, + }); + } else if (this.forceSetPasswordReason === ForceSetPasswordReason.WeakMasterPassword) { + this.anonLayoutWrapperDataService.setAnonLayoutWrapperData({ + pageIcon: Icons.LockIcon, + pageTitle: { key: "updateMasterPassword" }, + pageSubtitle: { key: "updateMasterPasswordSubtitle" }, + maxWidth: "lg", + }); + } + + this.initializing = false; + } + + async logOut() { + const confirmed = await this.dialogService.openSimpleDialog({ + title: { key: "logOut" }, + content: { key: "logOutConfirmation" }, + acceptButtonText: { key: "logOut" }, + type: "warning", + }); + + if (confirmed) { + await this.organizationInviteService.clearOrganizationInvitation(); + + if (this.changePasswordService.clearDeeplinkState) { + await this.changePasswordService.clearDeeplinkState(); + } + + // TODO: PM-23515 eventually use the logout service instead of messaging service once it is available without circular dependencies + this.messagingService.send("logout"); + } + } + + async handlePasswordFormSubmit(passwordInputResult: PasswordInputResult) { + this.submitting = true; + + try { + if (passwordInputResult.rotateUserKey) { + if (this.activeAccount == null) { + throw new Error("activeAccount not found"); + } + + if ( + passwordInputResult.currentPassword == null || + passwordInputResult.newPasswordHint == null + ) { + throw new Error("currentPassword or newPasswordHint not found"); + } + + await this.syncService.fullSync(true); + + await this.changePasswordService.rotateUserKeyMasterPasswordAndEncryptedData( + passwordInputResult.currentPassword, + passwordInputResult.newPassword, + this.activeAccount, + passwordInputResult.newPasswordHint, + ); + } else { + if (!this.userId) { + throw new Error("userId not found"); + } + + if (this.forceSetPasswordReason === ForceSetPasswordReason.AdminForcePasswordReset) { + await this.changePasswordService.changePasswordForAccountRecovery( + passwordInputResult, + this.userId, + ); + } else { + await this.changePasswordService.changePassword(passwordInputResult, this.userId); + } + + this.toastService.showToast({ + variant: "success", + message: this.i18nService.t("masterPasswordChanged"), + }); + + // TODO: PM-23515 eventually use the logout service instead of messaging service once it is available without circular dependencies + this.messagingService.send("logout"); + } + } catch (error) { + this.logService.error(error); + this.toastService.showToast({ + variant: "error", + title: "", + message: this.i18nService.t("errorOccurred"), + }); + } finally { + this.submitting = false; + } + } + + /** + * Shows the logout button in the case of admin force reset password or weak password upon login. + */ + protected secondaryButtonText(): { key: string } | undefined { + return this.forceSetPasswordReason === ForceSetPasswordReason.AdminForcePasswordReset || + this.forceSetPasswordReason === ForceSetPasswordReason.WeakMasterPassword + ? { key: "logOut" } + : undefined; + } +} diff --git a/libs/auth/src/angular/change-password/change-password.service.abstraction.ts b/libs/angular/src/auth/password-management/change-password/change-password.service.abstraction.ts similarity index 56% rename from libs/auth/src/angular/change-password/change-password.service.abstraction.ts rename to libs/angular/src/auth/password-management/change-password/change-password.service.abstraction.ts index b036db439f8..2fd3bbae67a 100644 --- a/libs/auth/src/angular/change-password/change-password.service.abstraction.ts +++ b/libs/angular/src/auth/password-management/change-password/change-password.service.abstraction.ts @@ -1,3 +1,5 @@ +// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. +// eslint-disable-next-line no-restricted-imports import { PasswordInputResult } from "@bitwarden/auth/angular"; import { Account } from "@bitwarden/common/auth/abstractions/account.service"; import { UserId } from "@bitwarden/common/types/guid"; @@ -32,5 +34,29 @@ export abstract class ChangePasswordService { * @param userId the `userId` * @throws if the `userId`, `currentMasterKey`, or `currentServerMasterKeyHash` is not found */ - abstract changePassword(passwordInputResult: PasswordInputResult, userId: UserId): Promise; + abstract changePassword( + passwordInputResult: PasswordInputResult, + userId: UserId | null, + ): Promise; + + /** + * Changes the user's password and re-encrypts the user key with the `newMasterKey`. + * - Specifically, this method uses credentials from the `passwordInputResult` to: + * 1. Decrypt the user key with the `currentMasterKey` + * 2. Re-encrypt that user key with the `newMasterKey`, resulting in a `newMasterKeyEncryptedUserKey` + * 3. Build a `PasswordRequest` object that gets PUTed to `"/accounts/update-temp-password"` so that the + * ForcePasswordReset gets set to false. + * @param passwordInputResult + * @param userId + */ + abstract changePasswordForAccountRecovery( + passwordInputResult: PasswordInputResult, + userId: UserId, + ): Promise; + + /** + * Optional method that will clear up any deep link state. + * - Currently only used on the web change password service. + */ + clearDeeplinkState?: () => Promise; } diff --git a/libs/auth/src/angular/change-password/default-change-password.service.spec.ts b/libs/angular/src/auth/password-management/change-password/default-change-password.service.spec.ts similarity index 77% rename from libs/auth/src/angular/change-password/default-change-password.service.spec.ts rename to libs/angular/src/auth/password-management/change-password/default-change-password.service.spec.ts index add2e62adbc..78969c61610 100644 --- a/libs/auth/src/angular/change-password/default-change-password.service.spec.ts +++ b/libs/angular/src/auth/password-management/change-password/default-change-password.service.spec.ts @@ -1,5 +1,8 @@ import { mock, MockProxy } from "jest-mock-extended"; +// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. +// eslint-disable-next-line no-restricted-imports +import { PasswordInputResult } from "@bitwarden/auth/angular"; import { Account } from "@bitwarden/common/auth/abstractions/account.service"; import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; @@ -9,8 +12,6 @@ import { UserId } from "@bitwarden/common/types/guid"; import { MasterKey, UserKey } from "@bitwarden/common/types/key"; import { KeyService, PBKDF2KdfConfig } from "@bitwarden/key-management"; -import { PasswordInputResult } from "../input-password/password-input-result"; - import { ChangePasswordService } from "./change-password.service.abstraction"; import { DefaultChangePasswordService } from "./default-change-password.service"; @@ -109,7 +110,7 @@ describe("DefaultChangePasswordService", () => { it("should throw if a currentMasterKey was not found", async () => { // Arrange const incorrectPasswordInputResult = { ...passwordInputResult }; - incorrectPasswordInputResult.currentMasterKey = null; + incorrectPasswordInputResult.currentMasterKey = undefined; // Act const testFn = sut.changePassword(incorrectPasswordInputResult, userId); @@ -123,7 +124,7 @@ describe("DefaultChangePasswordService", () => { it("should throw if a currentServerMasterKeyHash was not found", async () => { // Arrange const incorrectPasswordInputResult = { ...passwordInputResult }; - incorrectPasswordInputResult.currentServerMasterKeyHash = null; + incorrectPasswordInputResult.currentServerMasterKeyHash = undefined; // Act const testFn = sut.changePassword(incorrectPasswordInputResult, userId); @@ -174,4 +175,43 @@ describe("DefaultChangePasswordService", () => { ); }); }); + + describe("changePasswordForAccountRecovery()", () => { + it("should call the putUpdateTempPassword() API method with the correct UpdateTempPasswordRequest credentials", async () => { + // Act + await sut.changePasswordForAccountRecovery(passwordInputResult, userId); + + // Assert + expect(masterPasswordApiService.putUpdateTempPassword).toHaveBeenCalledWith( + expect.objectContaining({ + newMasterPasswordHash: passwordInputResult.newServerMasterKeyHash, + masterPasswordHint: passwordInputResult.newPasswordHint, + key: newMasterKeyEncryptedUserKey[1].encryptedString, + }), + ); + }); + + it("should throw an error if user key decryption fails", async () => { + // Arrange + masterPasswordService.decryptUserKeyWithMasterKey.mockResolvedValue(null); + + // Act + const testFn = sut.changePasswordForAccountRecovery(passwordInputResult, userId); + + // Assert + await expect(testFn).rejects.toThrow("Could not decrypt user key"); + }); + + it("should throw an error if putUpdateTempPassword() fails", async () => { + // Arrange + masterPasswordApiService.putUpdateTempPassword.mockRejectedValueOnce(new Error("error")); + + // Act + const testFn = sut.changePasswordForAccountRecovery(passwordInputResult, userId); + + // Assert + await expect(testFn).rejects.toThrow("Could not change password"); + expect(masterPasswordApiService.putUpdateTempPassword).toHaveBeenCalled(); + }); + }); }); diff --git a/libs/auth/src/angular/change-password/default-change-password.service.ts b/libs/angular/src/auth/password-management/change-password/default-change-password.service.ts similarity index 50% rename from libs/auth/src/angular/change-password/default-change-password.service.ts rename to libs/angular/src/auth/password-management/change-password/default-change-password.service.ts index 4c5f3d10d74..888799d863a 100644 --- a/libs/auth/src/angular/change-password/default-change-password.service.ts +++ b/libs/angular/src/auth/password-management/change-password/default-change-password.service.ts @@ -1,11 +1,18 @@ -import { PasswordInputResult, ChangePasswordService } from "@bitwarden/auth/angular"; +// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. +// eslint-disable-next-line no-restricted-imports +import { PasswordInputResult } from "@bitwarden/auth/angular"; import { Account } from "@bitwarden/common/auth/abstractions/account.service"; import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request"; +import { UpdateTempPasswordRequest } from "@bitwarden/common/auth/models/request/update-temp-password.request"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; +import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { UserId } from "@bitwarden/common/types/guid"; +import { UserKey } from "@bitwarden/common/types/key"; import { KeyService } from "@bitwarden/key-management"; +import { ChangePasswordService } from "./change-password.service.abstraction"; + export class DefaultChangePasswordService implements ChangePasswordService { constructor( protected keyService: KeyService, @@ -22,7 +29,11 @@ export class DefaultChangePasswordService implements ChangePasswordService { throw new Error("rotateUserKeyMasterPasswordAndEncryptedData() is only implemented in Web"); } - async changePassword(passwordInputResult: PasswordInputResult, userId: UserId) { + private async preparePasswordChange( + passwordInputResult: PasswordInputResult, + userId: UserId | null, + request: PasswordRequest | UpdateTempPasswordRequest, + ): Promise<[UserKey, EncString]> { if (!userId) { throw new Error("userId not found"); } @@ -45,15 +56,32 @@ export class DefaultChangePasswordService implements ChangePasswordService { throw new Error("Could not decrypt user key"); } - const newMasterKeyEncryptedUserKey = await this.keyService.encryptUserKeyWithMasterKey( + const newKeyValue = await this.keyService.encryptUserKeyWithMasterKey( passwordInputResult.newMasterKey, decryptedUserKey, ); + if (request instanceof PasswordRequest) { + request.masterPasswordHash = passwordInputResult.currentServerMasterKeyHash; + request.newMasterPasswordHash = passwordInputResult.newServerMasterKeyHash; + request.masterPasswordHint = passwordInputResult.newPasswordHint; + } else if (request instanceof UpdateTempPasswordRequest) { + request.newMasterPasswordHash = passwordInputResult.newServerMasterKeyHash; + request.masterPasswordHint = passwordInputResult.newPasswordHint; + } + + return newKeyValue; + } + + async changePassword(passwordInputResult: PasswordInputResult, userId: UserId | null) { const request = new PasswordRequest(); - request.masterPasswordHash = passwordInputResult.currentServerMasterKeyHash; - request.newMasterPasswordHash = passwordInputResult.newServerMasterKeyHash; - request.masterPasswordHint = passwordInputResult.newPasswordHint; + + const newMasterKeyEncryptedUserKey = await this.preparePasswordChange( + passwordInputResult, + userId, + request, + ); + request.key = newMasterKeyEncryptedUserKey[1].encryptedString as string; try { @@ -62,4 +90,23 @@ export class DefaultChangePasswordService implements ChangePasswordService { throw new Error("Could not change password"); } } + + async changePasswordForAccountRecovery(passwordInputResult: PasswordInputResult, userId: UserId) { + const request = new UpdateTempPasswordRequest(); + + const newMasterKeyEncryptedUserKey = await this.preparePasswordChange( + passwordInputResult, + userId, + request, + ); + + request.key = newMasterKeyEncryptedUserKey[1].encryptedString as string; + + try { + // TODO: PM-23047 will look to consolidate this into the change password endpoint. + await this.masterPasswordApiService.putUpdateTempPassword(request); + } catch { + throw new Error("Could not change password"); + } + } } diff --git a/libs/angular/src/auth/password-management/change-password/index.ts b/libs/angular/src/auth/password-management/change-password/index.ts new file mode 100644 index 00000000000..32734d39bc0 --- /dev/null +++ b/libs/angular/src/auth/password-management/change-password/index.ts @@ -0,0 +1,3 @@ +export * from "./change-password.component"; +export * from "./change-password.service.abstraction"; +export * from "./default-change-password.service"; diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index acb1553387b..d51d5e650c5 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -11,6 +11,10 @@ import { DefaultOrganizationUserApiService, OrganizationUserApiService, } from "@bitwarden/admin-console/common"; +import { + ChangePasswordService, + DefaultChangePasswordService, +} from "@bitwarden/angular/auth/password-management/change-password"; // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // eslint-disable-next-line no-restricted-imports import { @@ -29,8 +33,6 @@ import { TwoFactorAuthComponentService, TwoFactorAuthEmailComponentService, TwoFactorAuthWebAuthnComponentService, - ChangePasswordService, - DefaultChangePasswordService, } from "@bitwarden/auth/angular"; // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // eslint-disable-next-line no-restricted-imports @@ -115,6 +117,8 @@ import { AvatarService } from "@bitwarden/common/auth/services/avatar.service"; import { DevicesServiceImplementation } from "@bitwarden/common/auth/services/devices/devices.service.implementation"; import { DevicesApiServiceImplementation } from "@bitwarden/common/auth/services/devices-api.service.implementation"; import { MasterPasswordApiService } from "@bitwarden/common/auth/services/master-password/master-password-api.service.implementation"; +import { DefaultOrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/default-organization-invite.service"; +import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service"; import { PasswordResetEnrollmentServiceImplementation } from "@bitwarden/common/auth/services/password-reset-enrollment.service.implementation"; import { SsoLoginService } from "@bitwarden/common/auth/services/sso-login.service"; import { TokenService } from "@bitwarden/common/auth/services/token.service"; @@ -1406,16 +1410,20 @@ const safeProviders: SafeProvider[] = [ useClass: DefaultKdfConfigService, deps: [StateProvider], }), + safeProvider({ + provide: OrganizationInviteService, + useClass: DefaultOrganizationInviteService, + deps: [], + }), safeProvider({ provide: SetPasswordJitService, useClass: DefaultSetPasswordJitService, deps: [ - ApiServiceAbstraction, - MasterPasswordApiServiceAbstraction, - KeyService, EncryptService, I18nServiceAbstraction, KdfConfigService, + KeyService, + MasterPasswordApiServiceAbstraction, InternalMasterPasswordServiceAbstraction, OrganizationApiServiceAbstraction, OrganizationUserApiService, diff --git a/libs/auth/src/angular/change-password/change-password.component.ts b/libs/auth/src/angular/change-password/change-password.component.ts deleted file mode 100644 index 617b7ce9dd0..00000000000 --- a/libs/auth/src/angular/change-password/change-password.component.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { Component, Input, OnInit } from "@angular/core"; -import { firstValueFrom } from "rxjs"; - -import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; -import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; -import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; -import { SyncService } from "@bitwarden/common/platform/sync"; -import { UserId } from "@bitwarden/common/types/guid"; -// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. -// eslint-disable-next-line no-restricted-imports -import { ToastService } from "@bitwarden/components"; -import { I18nPipe } from "@bitwarden/ui-common"; - -import { - InputPasswordComponent, - InputPasswordFlow, -} from "../input-password/input-password.component"; -import { PasswordInputResult } from "../input-password/password-input-result"; - -import { ChangePasswordService } from "./change-password.service.abstraction"; - -@Component({ - selector: "auth-change-password", - templateUrl: "change-password.component.html", - imports: [InputPasswordComponent, I18nPipe], -}) -export class ChangePasswordComponent implements OnInit { - @Input() inputPasswordFlow: InputPasswordFlow = InputPasswordFlow.ChangePassword; - - activeAccount: Account | null = null; - email?: string; - userId?: UserId; - masterPasswordPolicyOptions?: MasterPasswordPolicyOptions; - initializing = true; - submitting = false; - - constructor( - private accountService: AccountService, - private changePasswordService: ChangePasswordService, - private i18nService: I18nService, - private messagingService: MessagingService, - private policyService: PolicyService, - private toastService: ToastService, - private syncService: SyncService, - ) {} - - async ngOnInit() { - this.activeAccount = await firstValueFrom(this.accountService.activeAccount$); - this.userId = this.activeAccount?.id; - this.email = this.activeAccount?.email; - - if (!this.userId) { - throw new Error("userId not found"); - } - - this.masterPasswordPolicyOptions = await firstValueFrom( - this.policyService.masterPasswordPolicyOptions$(this.userId), - ); - - this.initializing = false; - } - - async handlePasswordFormSubmit(passwordInputResult: PasswordInputResult) { - this.submitting = true; - - try { - if (passwordInputResult.rotateUserKey) { - if (this.activeAccount == null) { - throw new Error("activeAccount not found"); - } - - if ( - passwordInputResult.currentPassword == null || - passwordInputResult.newPasswordHint == null - ) { - throw new Error("currentPassword or newPasswordHint not found"); - } - - await this.syncService.fullSync(true); - - await this.changePasswordService.rotateUserKeyMasterPasswordAndEncryptedData( - passwordInputResult.currentPassword, - passwordInputResult.newPassword, - this.activeAccount, - passwordInputResult.newPasswordHint, - ); - } else { - if (!this.userId) { - throw new Error("userId not found"); - } - - await this.changePasswordService.changePassword(passwordInputResult, this.userId); - - this.toastService.showToast({ - variant: "success", - title: this.i18nService.t("masterPasswordChanged"), - message: this.i18nService.t("masterPasswordChangedDesc"), - }); - - this.messagingService.send("logout"); - } - } catch { - this.toastService.showToast({ - variant: "error", - title: "", - message: this.i18nService.t("errorOccurred"), - }); - } finally { - this.submitting = false; - } - } -} diff --git a/libs/auth/src/angular/index.ts b/libs/auth/src/angular/index.ts index fc5ffd71e9a..aa0041c7ec3 100644 --- a/libs/auth/src/angular/index.ts +++ b/libs/auth/src/angular/index.ts @@ -1,10 +1,6 @@ /** * This barrel file should only contain Angular exports */ -// change password -export * from "./change-password/change-password.component"; -export * from "./change-password/change-password.service.abstraction"; -export * from "./change-password/default-change-password.service"; // fingerprint dialog export * from "./fingerprint-dialog/fingerprint-dialog.component"; diff --git a/libs/auth/src/angular/input-password/input-password.component.html b/libs/auth/src/angular/input-password/input-password.component.html index b5a9f5a56e9..bf3a51b98bb 100644 --- a/libs/auth/src/angular/input-password/input-password.component.html +++ b/libs/auth/src/angular/input-password/input-password.component.html @@ -32,7 +32,7 @@
- + {{ "newMasterPass" | i18n }} val?.trim().toLowerCase() }) email?: string; @Input() userId?: UserId; @Input() loading = false; - @Input() masterPasswordPolicyOptions: MasterPasswordPolicyOptions | null = null; + @Input() masterPasswordPolicyOptions?: MasterPasswordPolicyOptions; @Input() inlineButtons = false; @Input() primaryButtonText?: Translation; @@ -169,7 +169,7 @@ export class InputPasswordComponent implements OnInit { protected get minPasswordLengthMsg() { if ( - this.masterPasswordPolicyOptions != null && + this.masterPasswordPolicyOptions != undefined && this.masterPasswordPolicyOptions.minLength > 0 ) { return this.i18nService.t("characterMinimum", this.masterPasswordPolicyOptions.minLength); @@ -463,7 +463,7 @@ export class InputPasswordComponent implements OnInit { /** * Returns `true` if the current password is correct (it can be used to successfully decrypt - * the masterKeyEncrypedUserKey), `false` otherwise + * the masterKeyEncryptedUserKey), `false` otherwise */ private async verifyCurrentPassword( currentPassword: string, diff --git a/libs/auth/src/angular/login/login.component.ts b/libs/auth/src/angular/login/login.component.ts index 5e5d5bde4e3..b3509850ac0 100644 --- a/libs/auth/src/angular/login/login.component.ts +++ b/libs/auth/src/angular/login/login.component.ts @@ -18,9 +18,12 @@ import { Policy } from "@bitwarden/common/admin-console/models/domain/policy"; import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; import { ClientType, HttpStatusCode } from "@bitwarden/common/enums"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { MasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; @@ -122,6 +125,8 @@ export class LoginComponent implements OnInit, OnDestroy { private logService: LogService, private validationService: ValidationService, private loginSuccessHandlerService: LoginSuccessHandlerService, + private masterPasswordService: MasterPasswordServiceAbstraction, + private configService: ConfigService, ) { this.clientType = this.platformUtilsService.getClientType(); } @@ -225,7 +230,29 @@ export class LoginComponent implements OnInit, OnDestroy { return; } - const credentials = new PasswordLoginCredentials(email, masterPassword); + let credentials: PasswordLoginCredentials; + + if ( + await this.configService.getFeatureFlag(FeatureFlag.PM16117_ChangeExistingPasswordRefactor) + ) { + // Try to retrieve any org policies from an org invite now so we can send it to the + // login strategies. Since it is optional and we only want to be doing this on the + // web we will only send in content in the right context. + const orgPoliciesFromInvite = this.loginComponentService.getOrgPoliciesFromOrgInvite + ? await this.loginComponentService.getOrgPoliciesFromOrgInvite() + : null; + + const orgMasterPasswordPolicyOptions = orgPoliciesFromInvite?.enforcedPasswordPolicyOptions; + + credentials = new PasswordLoginCredentials( + email, + masterPassword, + undefined, + orgMasterPasswordPolicyOptions, + ); + } else { + credentials = new PasswordLoginCredentials(email, masterPassword); + } try { const authResult = await this.loginStrategyService.logIn(credentials); @@ -284,7 +311,7 @@ export class LoginComponent implements OnInit, OnDestroy { This is now unsupported and requires a downgraded client */ this.toastService.showToast({ variant: "error", - title: this.i18nService.t("errorOccured"), + title: this.i18nService.t("errorOccurred"), message: this.i18nService.t("legacyEncryptionUnsupported"), }); return; @@ -325,7 +352,13 @@ export class LoginComponent implements OnInit, OnDestroy { orgPolicies.enforcedPasswordPolicyOptions, ); if (isPasswordChangeRequired) { - await this.router.navigate(["update-password"]); + const changePasswordFeatureFlagOn = await this.configService.getFeatureFlag( + FeatureFlag.PM16117_ChangeExistingPasswordRefactor, + ); + + await this.router.navigate( + changePasswordFeatureFlagOn ? ["change-password"] : ["update-password"], + ); return; } } @@ -337,9 +370,15 @@ export class LoginComponent implements OnInit, OnDestroy { await this.router.navigate(["vault"]); } } + /** * Checks if the master password meets the enforced policy requirements * and if the user is required to change their password. + * + * TODO: This is duplicate checking that we want to only do in the password login strategy. + * Once we no longer need the policies state being set to reference later in change password + * via using the Admin Console's new policy endpoint changes we can remove this. Consult + * PM-23001 for details. */ private async isPasswordChangeRequiredByOrgPolicy( enforcedPasswordPolicyOptions: MasterPasswordPolicyOptions, diff --git a/libs/auth/src/angular/new-device-verification/new-device-verification.component.ts b/libs/auth/src/angular/new-device-verification/new-device-verification.component.ts index a8aa3bd5525..4325b4bcbc1 100644 --- a/libs/auth/src/angular/new-device-verification/new-device-verification.component.ts +++ b/libs/auth/src/angular/new-device-verification/new-device-verification.component.ts @@ -2,11 +2,17 @@ import { CommonModule } from "@angular/common"; import { Component, OnDestroy, OnInit } from "@angular/core"; import { FormBuilder, ReactiveFormsModule, Validators } from "@angular/forms"; import { Router } from "@angular/router"; -import { Subject, takeUntil } from "rxjs"; +import { firstValueFrom, Subject, takeUntil } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { LoginSuccessHandlerService } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; +import { getUserId } from "@bitwarden/common/auth/services/account.service"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { MasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. @@ -61,6 +67,9 @@ export class NewDeviceVerificationComponent implements OnInit, OnDestroy { private logService: LogService, private i18nService: I18nService, private loginSuccessHandlerService: LoginSuccessHandlerService, + private configService: ConfigService, + private accountService: AccountService, + private masterPasswordService: MasterPasswordServiceAbstraction, ) {} async ngOnInit() { @@ -141,8 +150,29 @@ export class NewDeviceVerificationComponent implements OnInit, OnDestroy { // eslint-disable-next-line @typescript-eslint/no-floating-promises this.loginSuccessHandlerService.run(authResult.userId); - // If verification succeeds, navigate to vault - await this.router.navigate(["/vault"]); + // TODO: PM-22663 use the new service to handle routing. + if ( + await this.configService.getFeatureFlag(FeatureFlag.PM16117_ChangeExistingPasswordRefactor) + ) { + const activeUserId = await firstValueFrom( + this.accountService.activeAccount$.pipe(getUserId), + ); + + const forceSetPasswordReason = await firstValueFrom( + this.masterPasswordService.forceSetPasswordReason$(activeUserId), + ); + + if ( + forceSetPasswordReason === ForceSetPasswordReason.WeakMasterPassword || + forceSetPasswordReason === ForceSetPasswordReason.AdminForcePasswordReset + ) { + await this.router.navigate(["/change-password"]); + } else { + await this.router.navigate(["/vault"]); + } + } else { + await this.router.navigate(["/vault"]); + } } catch (e) { this.logService.error(e); let errorMessage = diff --git a/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.spec.ts b/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.spec.ts index 37afa77f0d4..2fd01f79ca9 100644 --- a/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.spec.ts +++ b/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.spec.ts @@ -8,7 +8,6 @@ import { FakeUserDecryptionOptions as UserDecryptionOptions, InternalUserDecryptionOptionsServiceAbstraction, } from "@bitwarden/auth/common"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { OrganizationKeysResponse } from "@bitwarden/common/admin-console/models/response/organization-keys.response"; import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; @@ -33,7 +32,6 @@ import { SetPasswordCredentials } from "./set-password-jit.service.abstraction"; describe("DefaultSetPasswordJitService", () => { let sut: DefaultSetPasswordJitService; - let apiService: MockProxy; let masterPasswordApiService: MockProxy; let keyService: MockProxy; let encryptService: MockProxy; @@ -45,7 +43,6 @@ describe("DefaultSetPasswordJitService", () => { let userDecryptionOptionsService: MockProxy; beforeEach(() => { - apiService = mock(); masterPasswordApiService = mock(); keyService = mock(); encryptService = mock(); @@ -57,12 +54,11 @@ describe("DefaultSetPasswordJitService", () => { userDecryptionOptionsService = mock(); sut = new DefaultSetPasswordJitService( - apiService, - masterPasswordApiService, - keyService, encryptService, i18nService, kdfConfigService, + keyService, + masterPasswordApiService, masterPasswordService, organizationApiService, organizationUserApiService, diff --git a/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.ts b/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.ts index ec274b9c4af..7d228fccb9b 100644 --- a/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.ts +++ b/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.ts @@ -9,7 +9,6 @@ import { OrganizationUserResetPasswordEnrollmentRequest, } from "@bitwarden/admin-console/common"; import { InternalUserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; @@ -31,12 +30,11 @@ import { export class DefaultSetPasswordJitService implements SetPasswordJitService { constructor( - protected apiService: ApiService, - protected masterPasswordApiService: MasterPasswordApiService, - protected keyService: KeyService, protected encryptService: EncryptService, protected i18nService: I18nService, protected kdfConfigService: KdfConfigService, + protected keyService: KeyService, + protected masterPasswordApiService: MasterPasswordApiService, protected masterPasswordService: InternalMasterPasswordServiceAbstraction, protected organizationApiService: OrganizationApiServiceAbstraction, protected organizationUserApiService: OrganizationUserApiService, diff --git a/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.ts b/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.ts index 43a63498634..a281411f971 100644 --- a/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.ts +++ b/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.ts @@ -394,7 +394,7 @@ export class TwoFactorAuthComponent implements OnInit, OnDestroy { this.toastService.showToast({ variant: "error", - title: this.i18nService.t("errorOccured"), + title: this.i18nService.t("errorOccurred"), message: this.i18nService.t("legacyEncryptionUnsupported"), }); return true; @@ -494,7 +494,7 @@ export class TwoFactorAuthComponent implements OnInit, OnDestroy { return; } - const defaultSuccessRoute = await this.determineDefaultSuccessRoute(); + const defaultSuccessRoute = await this.determineDefaultSuccessRoute(authResult.userId); await this.router.navigate([defaultSuccessRoute], { queryParams: { @@ -503,12 +503,28 @@ export class TwoFactorAuthComponent implements OnInit, OnDestroy { }); } - private async determineDefaultSuccessRoute(): Promise { + private async determineDefaultSuccessRoute(userId: UserId): Promise { const activeAccountStatus = await firstValueFrom(this.authService.activeAccountStatus$); if (activeAccountStatus === AuthenticationStatus.Locked) { return "lock"; } + // TODO: PM-22663 use the new service to handle routing. + if ( + await this.configService.getFeatureFlag(FeatureFlag.PM16117_ChangeExistingPasswordRefactor) + ) { + const forceSetPasswordReason = await firstValueFrom( + this.masterPasswordService.forceSetPasswordReason$(userId), + ); + + if ( + forceSetPasswordReason === ForceSetPasswordReason.WeakMasterPassword || + forceSetPasswordReason === ForceSetPasswordReason.AdminForcePasswordReset + ) { + return "change-password"; + } + } + return "vault"; } diff --git a/libs/auth/src/common/login-strategies/auth-request-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/auth-request-login.strategy.spec.ts index 487afcb3001..0b19fecdc4e 100644 --- a/libs/auth/src/common/login-strategies/auth-request-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/auth-request-login.strategy.spec.ts @@ -14,6 +14,7 @@ import { VaultTimeoutSettingsService, } from "@bitwarden/common/key-management/vault-timeout"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; @@ -55,6 +56,7 @@ describe("AuthRequestLoginStrategy", () => { let vaultTimeoutSettingsService: MockProxy; let kdfConfigService: MockProxy; let environmentService: MockProxy; + let configService: MockProxy; const mockUserId = Utils.newGuid() as UserId; let accountService: FakeAccountService; @@ -91,6 +93,7 @@ describe("AuthRequestLoginStrategy", () => { vaultTimeoutSettingsService = mock(); kdfConfigService = mock(); environmentService = mock(); + configService = mock(); accountService = mockAccountServiceWith(mockUserId); masterPasswordService = new FakeMasterPasswordService(); @@ -121,6 +124,7 @@ describe("AuthRequestLoginStrategy", () => { vaultTimeoutSettingsService, kdfConfigService, environmentService, + configService, ); tokenResponse = identityTokenResponseFactory(); diff --git a/libs/auth/src/common/login-strategies/login.strategy.spec.ts b/libs/auth/src/common/login-strategies/login.strategy.spec.ts index a0ccba649b6..cc9cae20b5c 100644 --- a/libs/auth/src/common/login-strategies/login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/login.strategy.spec.ts @@ -24,6 +24,7 @@ import { VaultTimeoutSettingsService, } from "@bitwarden/common/key-management/vault-timeout"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; @@ -123,6 +124,7 @@ describe("LoginStrategy", () => { let vaultTimeoutSettingsService: MockProxy; let kdfConfigService: MockProxy; let environmentService: MockProxy; + let configService: MockProxy; let passwordLoginStrategy: PasswordLoginStrategy; let credentials: PasswordLoginCredentials; @@ -148,6 +150,7 @@ describe("LoginStrategy", () => { passwordStrengthService = mock(); billingAccountProfileStateService = mock(); environmentService = mock(); + configService = mock(); vaultTimeoutSettingsService = mock(); @@ -177,6 +180,7 @@ describe("LoginStrategy", () => { vaultTimeoutSettingsService, kdfConfigService, environmentService, + configService, ); credentials = new PasswordLoginCredentials(email, masterPassword); }); @@ -491,6 +495,7 @@ describe("LoginStrategy", () => { vaultTimeoutSettingsService, kdfConfigService, environmentService, + configService, ); apiService.postIdentityToken.mockResolvedValue(identityTokenResponseFactory()); @@ -551,6 +556,7 @@ describe("LoginStrategy", () => { vaultTimeoutSettingsService, kdfConfigService, environmentService, + configService, ); const result = await passwordLoginStrategy.logIn(credentials); diff --git a/libs/auth/src/common/login-strategies/login.strategy.ts b/libs/auth/src/common/login-strategies/login.strategy.ts index dc51ce1fa04..463ea676163 100644 --- a/libs/auth/src/common/login-strategies/login.strategy.ts +++ b/libs/auth/src/common/login-strategies/login.strategy.ts @@ -25,6 +25,7 @@ import { } from "@bitwarden/common/key-management/vault-timeout"; import { KeysRequest } from "@bitwarden/common/models/request/keys.request"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; @@ -91,6 +92,7 @@ export abstract class LoginStrategy { protected vaultTimeoutSettingsService: VaultTimeoutSettingsService, protected KdfConfigService: KdfConfigService, protected environmentService: EnvironmentService, + protected configService: ConfigService, ) {} abstract exportCache(): CacheData; diff --git a/libs/auth/src/common/login-strategies/password-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/password-login.strategy.spec.ts index f996aa7a1f6..61a06f94b02 100644 --- a/libs/auth/src/common/login-strategies/password-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/password-login.strategy.spec.ts @@ -3,6 +3,7 @@ import { BehaviorSubject } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; @@ -11,6 +12,7 @@ import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/id import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response"; import { MasterPasswordPolicyResponse } from "@bitwarden/common/auth/models/response/master-password-policy.response"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { FakeMasterPasswordService } from "@bitwarden/common/key-management/master-password/services/fake-master-password.service"; import { @@ -18,6 +20,7 @@ import { VaultTimeoutSettingsService, } from "@bitwarden/common/key-management/vault-timeout"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; @@ -54,7 +57,7 @@ const masterKey = new SymmetricCryptoKey( ) as MasterKey; const userId = Utils.newGuid() as UserId; const deviceId = Utils.newGuid(); -const masterPasswordPolicy = new MasterPasswordPolicyResponse({ +const masterPasswordPolicyResponse = new MasterPasswordPolicyResponse({ EnforceOnLogin: true, MinLength: 8, }); @@ -82,6 +85,7 @@ describe("PasswordLoginStrategy", () => { let vaultTimeoutSettingsService: MockProxy; let kdfConfigService: MockProxy; let environmentService: MockProxy; + let configService: MockProxy; let passwordLoginStrategy: PasswordLoginStrategy; let credentials: PasswordLoginCredentials; @@ -109,6 +113,7 @@ describe("PasswordLoginStrategy", () => { vaultTimeoutSettingsService = mock(); kdfConfigService = mock(); environmentService = mock(); + configService = mock(); appIdService.getAppId.mockResolvedValue(deviceId); tokenService.decodeAccessToken.mockResolvedValue({ @@ -148,9 +153,10 @@ describe("PasswordLoginStrategy", () => { vaultTimeoutSettingsService, kdfConfigService, environmentService, + configService, ); credentials = new PasswordLoginCredentials(email, masterPassword); - tokenResponse = identityTokenResponseFactory(masterPasswordPolicy); + tokenResponse = identityTokenResponseFactory(masterPasswordPolicyResponse); apiService.postIdentityToken.mockResolvedValue(tokenResponse); @@ -227,6 +233,67 @@ describe("PasswordLoginStrategy", () => { expect(policyService.evaluateMasterPassword).toHaveBeenCalled(); }); + it("when given master password policies as part of the login credentials from an org invite, it combines them with the token response policies to evaluate the user's password as weak", async () => { + const passwordStrengthScore = 0; + + passwordStrengthService.getPasswordStrength.mockReturnValue({ + score: passwordStrengthScore, + } as any); + policyService.evaluateMasterPassword.mockReturnValue(false); + tokenService.decodeAccessToken.mockResolvedValue({ sub: userId }); + + jest + .spyOn(configService, "getFeatureFlag") + .mockImplementation((flag: FeatureFlag) => + Promise.resolve(flag === FeatureFlag.PM16117_ChangeExistingPasswordRefactor), + ); + + credentials.masterPasswordPoliciesFromOrgInvite = Object.assign( + new MasterPasswordPolicyOptions(), + { + minLength: 10, + minComplexity: 2, + requireUpper: true, + requireLower: true, + requireNumbers: true, + requireSpecial: true, + enforceOnLogin: true, + }, + ); + + const combinedMasterPasswordPolicyOptions = Object.assign(new MasterPasswordPolicyOptions(), { + minLength: 10, + minComplexity: 2, + requireUpper: true, + requireLower: true, + requireNumbers: true, + requireSpecial: true, + enforceOnLogin: false, + }); + + policyService.combineMasterPasswordPolicyOptions.mockReturnValue( + combinedMasterPasswordPolicyOptions, + ); + + await passwordLoginStrategy.logIn(credentials); + + expect(policyService.combineMasterPasswordPolicyOptions).toHaveBeenCalledWith( + credentials.masterPasswordPoliciesFromOrgInvite, + MasterPasswordPolicyOptions.fromResponse(masterPasswordPolicyResponse), + ); + + expect(policyService.evaluateMasterPassword).toHaveBeenCalledWith( + passwordStrengthScore, + credentials.masterPassword, + combinedMasterPasswordPolicyOptions, + ); + + expect(masterPasswordService.mock.setForceSetPasswordReason).toHaveBeenCalledWith( + ForceSetPasswordReason.WeakMasterPassword, + userId, + ); + }); + it("forces the user to update their master password on successful login when it does not meet master password policy requirements", async () => { passwordStrengthService.getPasswordStrength.mockReturnValue({ score: 0 } as any); policyService.evaluateMasterPassword.mockReturnValue(false); @@ -251,7 +318,7 @@ describe("PasswordLoginStrategy", () => { TwoFactorProviders2: { 0: null }, error: "invalid_grant", error_description: "Two factor required.", - MasterPasswordPolicy: masterPasswordPolicy, + MasterPasswordPolicy: masterPasswordPolicyResponse, }); // First login request fails requiring 2FA @@ -271,7 +338,7 @@ describe("PasswordLoginStrategy", () => { TwoFactorProviders2: { 0: null }, error: "invalid_grant", error_description: "Two factor required.", - MasterPasswordPolicy: masterPasswordPolicy, + MasterPasswordPolicy: masterPasswordPolicyResponse, }); // First login request fails requiring 2FA @@ -280,7 +347,7 @@ describe("PasswordLoginStrategy", () => { // Second login request succeeds apiService.postIdentityToken.mockResolvedValueOnce( - identityTokenResponseFactory(masterPasswordPolicy), + identityTokenResponseFactory(masterPasswordPolicyResponse), ); await passwordLoginStrategy.logInTwoFactor({ provider: TwoFactorProviderType.Authenticator, diff --git a/libs/auth/src/common/login-strategies/password-login.strategy.ts b/libs/auth/src/common/login-strategies/password-login.strategy.ts index 8b92e65f1f8..cd3d5df1d5e 100644 --- a/libs/auth/src/common/login-strategies/password-login.strategy.ts +++ b/libs/auth/src/common/login-strategies/password-login.strategy.ts @@ -12,6 +12,7 @@ import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/ide import { IdentityDeviceVerificationResponse } from "@bitwarden/common/auth/models/response/identity-device-verification.response"; import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { HashPurpose } from "@bitwarden/common/platform/enums"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; @@ -75,7 +76,7 @@ export class PasswordLoginStrategy extends LoginStrategy { this.localMasterKeyHash$ = this.cache.pipe(map((state) => state.localMasterKeyHash)); } - override async logIn(credentials: PasswordLoginCredentials) { + override async logIn(credentials: PasswordLoginCredentials): Promise { const { email, masterPassword, twoFactor } = credentials; const data = new PasswordLoginStrategyData(); @@ -163,18 +164,42 @@ export class PasswordLoginStrategy extends LoginStrategy { credentials: PasswordLoginCredentials, authResult: AuthResult, ): Promise { - // TODO: PM-21084 - investigate if we should be sending down masterPasswordPolicy on the IdentityDeviceVerificationResponse like we do for the IdentityTwoFactorResponse + // TODO: PM-21084 - investigate if we should be sending down masterPasswordPolicy on the + // IdentityDeviceVerificationResponse like we do for the IdentityTwoFactorResponse // If the response is a device verification response, we don't need to evaluate the password if (identityResponse instanceof IdentityDeviceVerificationResponse) { return; } // The identity result can contain master password policies for the user's organizations - const masterPasswordPolicyOptions = - this.getMasterPasswordPolicyOptionsFromResponse(identityResponse); + let masterPasswordPolicyOptions: MasterPasswordPolicyOptions | undefined; - if (!masterPasswordPolicyOptions?.enforceOnLogin) { - return; + if ( + await this.configService.getFeatureFlag(FeatureFlag.PM16117_ChangeExistingPasswordRefactor) + ) { + // Get the master password policy options from both the org invite and the identity response. + masterPasswordPolicyOptions = this.policyService.combineMasterPasswordPolicyOptions( + credentials.masterPasswordPoliciesFromOrgInvite, + this.getMasterPasswordPolicyOptionsFromResponse(identityResponse), + ); + + // We deliberately do not check enforceOnLogin as existing users who are logging + // in after getting an org invite should always be forced to set a password that + // meets the org's policy. Org Invite -> Registration also works this way for + // new BW users as well. + if ( + !credentials.masterPasswordPoliciesFromOrgInvite && + !masterPasswordPolicyOptions?.enforceOnLogin + ) { + return; + } + } else { + masterPasswordPolicyOptions = + this.getMasterPasswordPolicyOptionsFromResponse(identityResponse); + + if (!masterPasswordPolicyOptions?.enforceOnLogin) { + return; + } } // If there is a policy active, evaluate the supplied password before its no longer in memory diff --git a/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts index 98142003c6e..ea041081985 100644 --- a/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts @@ -139,7 +139,6 @@ describe("SsoLoginStrategy", () => { deviceTrustService, authRequestService, i18nService, - configService, accountService, masterPasswordService, keyService, @@ -157,6 +156,7 @@ describe("SsoLoginStrategy", () => { vaultTimeoutSettingsService, kdfConfigService, environmentService, + configService, ); credentials = new SsoLoginCredentials(ssoCode, ssoCodeVerifier, ssoRedirectUrl, ssoOrgId); }); diff --git a/libs/auth/src/common/login-strategies/sso-login.strategy.ts b/libs/auth/src/common/login-strategies/sso-login.strategy.ts index 8b60e42f03e..8ab84f0968a 100644 --- a/libs/auth/src/common/login-strategies/sso-login.strategy.ts +++ b/libs/auth/src/common/login-strategies/sso-login.strategy.ts @@ -13,7 +13,6 @@ import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/key-management/device-trust/abstractions/device-trust.service.abstraction"; import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { UserId } from "@bitwarden/common/types/guid"; @@ -74,7 +73,6 @@ export class SsoLoginStrategy extends LoginStrategy { private deviceTrustService: DeviceTrustServiceAbstraction, private authRequestService: AuthRequestServiceAbstraction, private i18nService: I18nService, - private configService: ConfigService, ...sharedDeps: ConstructorParameters ) { super(...sharedDeps); diff --git a/libs/auth/src/common/login-strategies/user-api-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/user-api-login.strategy.spec.ts index 957a6a8e777..7114afbf94f 100644 --- a/libs/auth/src/common/login-strategies/user-api-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/user-api-login.strategy.spec.ts @@ -13,6 +13,7 @@ import { VaultTimeoutSettingsService, } from "@bitwarden/common/key-management/vault-timeout"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { Environment, EnvironmentService, @@ -56,6 +57,7 @@ describe("UserApiLoginStrategy", () => { let billingAccountProfileStateService: MockProxy; let vaultTimeoutSettingsService: MockProxy; let kdfConfigService: MockProxy; + let configService: MockProxy; let apiLogInStrategy: UserApiLoginStrategy; let credentials: UserApiLoginCredentials; @@ -88,6 +90,7 @@ describe("UserApiLoginStrategy", () => { billingAccountProfileStateService = mock(); vaultTimeoutSettingsService = mock(); kdfConfigService = mock(); + configService = mock(); appIdService.getAppId.mockResolvedValue(deviceId); tokenService.getTwoFactorToken.mockResolvedValue(null); @@ -115,6 +118,7 @@ describe("UserApiLoginStrategy", () => { vaultTimeoutSettingsService, kdfConfigService, environmentService, + configService, ); credentials = new UserApiLoginCredentials(apiClientId, apiClientSecret); diff --git a/libs/auth/src/common/login-strategies/webauthn-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/webauthn-login.strategy.spec.ts index 432e4142d0c..f5ba2d0be23 100644 --- a/libs/auth/src/common/login-strategies/webauthn-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/webauthn-login.strategy.spec.ts @@ -16,6 +16,7 @@ import { VaultTimeoutSettingsService, } from "@bitwarden/common/key-management/vault-timeout"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; @@ -54,6 +55,7 @@ describe("WebAuthnLoginStrategy", () => { let vaultTimeoutSettingsService: MockProxy; let kdfConfigService: MockProxy; let environmentService: MockProxy; + let configService: MockProxy; let webAuthnLoginStrategy!: WebAuthnLoginStrategy; @@ -98,6 +100,7 @@ describe("WebAuthnLoginStrategy", () => { vaultTimeoutSettingsService = mock(); kdfConfigService = mock(); environmentService = mock(); + configService = mock(); tokenService.getTwoFactorToken.mockResolvedValue(null); appIdService.getAppId.mockResolvedValue(deviceId); @@ -124,6 +127,7 @@ describe("WebAuthnLoginStrategy", () => { vaultTimeoutSettingsService, kdfConfigService, environmentService, + configService, ); // Create credentials diff --git a/libs/auth/src/common/models/domain/login-credentials.ts b/libs/auth/src/common/models/domain/login-credentials.ts index bce8ce54de5..96ee88945eb 100644 --- a/libs/auth/src/common/models/domain/login-credentials.ts +++ b/libs/auth/src/common/models/domain/login-credentials.ts @@ -2,6 +2,7 @@ // @ts-strict-ignore import { Jsonify } from "type-fest"; +import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; import { AuthenticationType } from "@bitwarden/common/auth/enums/authentication-type"; import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request"; import { WebAuthnLoginAssertionResponseRequest } from "@bitwarden/common/auth/services/webauthn-login/request/webauthn-login-assertion-response.request"; @@ -15,6 +16,7 @@ export class PasswordLoginCredentials { public email: string, public masterPassword: string, public twoFactor?: TokenTwoFactorRequest, + public masterPasswordPoliciesFromOrgInvite?: MasterPasswordPolicyOptions, ) {} } diff --git a/libs/auth/src/common/services/login-strategies/login-strategy.service.ts b/libs/auth/src/common/services/login-strategies/login-strategy.service.ts index 767d52de370..6900e5e5872 100644 --- a/libs/auth/src/common/services/login-strategies/login-strategy.service.ts +++ b/libs/auth/src/common/services/login-strategies/login-strategy.service.ts @@ -402,6 +402,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction { this.vaultTimeoutSettingsService, this.kdfConfigService, this.environmentService, + this.configService, ]; return source.pipe( @@ -425,7 +426,6 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction { this.deviceTrustService, this.authRequestService, this.i18nService, - this.configService, ...sharedDeps, ); case AuthenticationType.UserApiKey: diff --git a/libs/common/src/admin-console/abstractions/policy/policy.service.abstraction.ts b/libs/common/src/admin-console/abstractions/policy/policy.service.abstraction.ts index bf02872ed7c..8df7e44986b 100644 --- a/libs/common/src/admin-console/abstractions/policy/policy.service.abstraction.ts +++ b/libs/common/src/admin-console/abstractions/policy/policy.service.abstraction.ts @@ -50,6 +50,25 @@ export abstract class PolicyService { policies?: Policy[], ) => Observable; + /** + * Combines all Master Password policies that are passed in and returns + * back the strongest combination of all the policies in the form of a + * MasterPasswordPolicyOptions. + * @param policies + */ + abstract combinePoliciesIntoMasterPasswordPolicyOptions( + policies: Policy[], + ): MasterPasswordPolicyOptions | undefined; + + /** + * Takes an arbitrary amount of Master Password Policy options in any form and merges them + * together using the strictest combination of all of them. + * @param masterPasswordPolicyOptions + */ + abstract combineMasterPasswordPolicyOptions( + ...masterPasswordPolicyOptions: MasterPasswordPolicyOptions[] + ): MasterPasswordPolicyOptions | undefined; + /** * Evaluates whether a proposed Master Password complies with all Master Password policies that apply to the user. */ diff --git a/libs/common/src/admin-console/services/policy/default-policy.service.spec.ts b/libs/common/src/admin-console/services/policy/default-policy.service.spec.ts index 7787bdbc943..9db61ec5c95 100644 --- a/libs/common/src/admin-console/services/policy/default-policy.service.spec.ts +++ b/libs/common/src/admin-console/services/policy/default-policy.service.spec.ts @@ -536,6 +536,152 @@ describe("PolicyService", () => { }); }); + describe("combinePoliciesIntoMasterPasswordPolicyOptions", () => { + let policyService: DefaultPolicyService; + let stateProvider: FakeStateProvider; + let organizationService: MockProxy; + + beforeEach(() => { + stateProvider = new FakeStateProvider(mockAccountServiceWith(userId)); + organizationService = mock(); + policyService = new DefaultPolicyService(stateProvider, organizationService); + }); + + it("returns undefined when there are no policies", () => { + const result = policyService.combinePoliciesIntoMasterPasswordPolicyOptions([]); + expect(result).toBeUndefined(); + }); + + it("returns options for a single policy", () => { + const masterPasswordPolicyRequirements = { + minComplexity: 3, + minLength: 10, + requireUpper: true, + }; + const policies = [ + new Policy( + policyData( + "1", + "org1", + PolicyType.MasterPassword, + true, + masterPasswordPolicyRequirements, + ), + ), + ]; + + const result = policyService.combinePoliciesIntoMasterPasswordPolicyOptions(policies); + + expect(result).toEqual({ + minComplexity: 3, + minLength: 10, + requireUpper: true, + requireLower: false, + requireNumbers: false, + requireSpecial: false, + enforceOnLogin: false, + }); + }); + + it("merges options from multiple policies", () => { + const masterPasswordPolicyRequirements1 = { + minComplexity: 3, + minLength: 10, + requireUpper: true, + }; + const masterPasswordPolicyRequirements2 = { minComplexity: 5, requireNumbers: true }; + const policies = [ + new Policy( + policyData( + "1", + "org1", + PolicyType.MasterPassword, + true, + masterPasswordPolicyRequirements1, + ), + ), + new Policy( + policyData( + "2", + "org2", + PolicyType.MasterPassword, + true, + masterPasswordPolicyRequirements2, + ), + ), + ]; + + const result = policyService.combinePoliciesIntoMasterPasswordPolicyOptions(policies); + + expect(result).toEqual({ + minComplexity: 5, + minLength: 10, + requireUpper: true, + requireLower: false, + requireNumbers: true, + requireSpecial: false, + enforceOnLogin: false, + }); + }); + + it("ignores disabled policies", () => { + const masterPasswordPolicyRequirements = { + minComplexity: 3, + minLength: 10, + requireUpper: true, + }; + const policies = [ + new Policy( + policyData( + "1", + "org1", + PolicyType.MasterPassword, + false, + masterPasswordPolicyRequirements, + ), + ), + ]; + + const result = policyService.combinePoliciesIntoMasterPasswordPolicyOptions(policies); + + expect(result).toBeUndefined(); + }); + + it("ignores policies with no data", () => { + const policies = [new Policy(policyData("1", "org1", PolicyType.MasterPassword, true))]; + + const result = policyService.combinePoliciesIntoMasterPasswordPolicyOptions(policies); + + expect(result).toBeUndefined(); + }); + + it("returns undefined when policies are not MasterPassword related", () => { + const unrelatedPolicyRequirements = { + minComplexity: 3, + minLength: 10, + requireUpper: true, + }; + const policies = [ + new Policy( + policyData( + "1", + "org1", + PolicyType.MaximumVaultTimeout, + true, + unrelatedPolicyRequirements, + ), + ), + new Policy( + policyData("2", "org2", PolicyType.DisableSend, true, unrelatedPolicyRequirements), + ), + ]; + + const result = policyService.combinePoliciesIntoMasterPasswordPolicyOptions(policies); + + expect(result).toBeUndefined(); + }); + }); + function policyData( id: string, organizationId: string, diff --git a/libs/common/src/admin-console/services/policy/default-policy.service.ts b/libs/common/src/admin-console/services/policy/default-policy.service.ts index b6e03ddf257..667dd9082a4 100644 --- a/libs/common/src/admin-console/services/policy/default-policy.service.ts +++ b/libs/common/src/admin-console/services/policy/default-policy.service.ts @@ -89,6 +89,8 @@ export class DefaultPolicyService implements PolicyService { const policies$ = policies ? of(policies) : this.policies$(userId); return policies$.pipe( map((obsPolicies) => { + // TODO: replace with this.combinePoliciesIntoMasterPasswordPolicyOptions(obsPolicies)) once + // FeatureFlag.PM16117_ChangeExistingPasswordRefactor is removed. let enforcedOptions: MasterPasswordPolicyOptions | undefined = undefined; const filteredPolicies = obsPolicies.filter((p) => p.type === PolicyType.MasterPassword) ?? []; @@ -146,6 +148,47 @@ export class DefaultPolicyService implements PolicyService { ); } + combinePoliciesIntoMasterPasswordPolicyOptions( + policies: Policy[], + ): MasterPasswordPolicyOptions | undefined { + let enforcedOptions: MasterPasswordPolicyOptions | undefined = undefined; + const filteredPolicies = policies.filter((p) => p.type === PolicyType.MasterPassword) ?? []; + + if (filteredPolicies.length === 0) { + return; + } + + filteredPolicies.forEach((currentPolicy) => { + if (!currentPolicy.enabled || !currentPolicy.data) { + return undefined; + } + + if (!enforcedOptions) { + enforcedOptions = new MasterPasswordPolicyOptions(); + } + + this.mergeMasterPasswordPolicyOptions(enforcedOptions, currentPolicy.data); + }); + + return enforcedOptions; + } + + combineMasterPasswordPolicyOptions( + ...policies: MasterPasswordPolicyOptions[] + ): MasterPasswordPolicyOptions | undefined { + let combinedOptions: MasterPasswordPolicyOptions | undefined = undefined; + + policies.forEach((currentOptions) => { + if (!combinedOptions) { + combinedOptions = new MasterPasswordPolicyOptions(); + } + + this.mergeMasterPasswordPolicyOptions(combinedOptions, currentOptions); + }); + + return combinedOptions; + } + evaluateMasterPassword( passwordStrength: number, newPassword: string, @@ -245,4 +288,28 @@ export class DefaultPolicyService implements PolicyService { return organization.canManagePolicies; } } + + private mergeMasterPasswordPolicyOptions( + target: MasterPasswordPolicyOptions | undefined, + source: MasterPasswordPolicyOptions | undefined, + ) { + if (!target) { + target = new MasterPasswordPolicyOptions(); + } + + // For complexity and minLength, take the highest value. + // For boolean settings, enable it if either policy has it enabled (OR). + if (source) { + target.minComplexity = Math.max( + target.minComplexity, + source.minComplexity ?? target.minComplexity, + ); + target.minLength = Math.max(target.minLength, source.minLength ?? target.minLength); + target.requireUpper = Boolean(target.requireUpper || source.requireUpper); + target.requireLower = Boolean(target.requireLower || source.requireLower); + target.requireNumbers = Boolean(target.requireNumbers || source.requireNumbers); + target.requireSpecial = Boolean(target.requireSpecial || source.requireSpecial); + target.enforceOnLogin = Boolean(target.enforceOnLogin || source.enforceOnLogin); + } + } } diff --git a/libs/common/src/auth/services/organization-invite/default-organization-invite.service.ts b/libs/common/src/auth/services/organization-invite/default-organization-invite.service.ts new file mode 100644 index 00000000000..0ebbbaa8c0c --- /dev/null +++ b/libs/common/src/auth/services/organization-invite/default-organization-invite.service.ts @@ -0,0 +1,26 @@ +import { OrganizationInvite } from "@bitwarden/common/auth/services/organization-invite/organization-invite"; +import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service"; + +export class DefaultOrganizationInviteService implements OrganizationInviteService { + /** + * No-op implementation. + */ + async getOrganizationInvite(): Promise { + return null; + } + + /** + * No-op implementation. + * @param invite an organization invite + */ + async setOrganizationInvitation(invite: OrganizationInvite): Promise { + return; + } + + /** + * No-op implementation. + * */ + async clearOrganizationInvitation(): Promise { + return; + } +} diff --git a/libs/common/src/auth/services/organization-invite/organization-invite-state.ts b/libs/common/src/auth/services/organization-invite/organization-invite-state.ts new file mode 100644 index 00000000000..c544fa3269f --- /dev/null +++ b/libs/common/src/auth/services/organization-invite/organization-invite-state.ts @@ -0,0 +1,13 @@ +import { OrganizationInvite } from "@bitwarden/common/auth/services/organization-invite/organization-invite"; +import { KeyDefinition, ORGANIZATION_INVITE_DISK } from "@bitwarden/common/platform/state"; + +// We're storing the organization invite for 2 reasons: +// 1. If the org requires a MP policy check, we need to keep track that the user has already been redirected when they return. +// 2. The MP policy check happens on login/register flows, we need to store the token to retrieve the policies then. +export const ORGANIZATION_INVITE = new KeyDefinition( + ORGANIZATION_INVITE_DISK, + "organizationInvite", + { + deserializer: (invite) => (invite ? OrganizationInvite.fromJSON(invite) : null), + }, +); diff --git a/libs/common/src/auth/services/organization-invite/organization-invite.service.ts b/libs/common/src/auth/services/organization-invite/organization-invite.service.ts new file mode 100644 index 00000000000..15d9b1533f5 --- /dev/null +++ b/libs/common/src/auth/services/organization-invite/organization-invite.service.ts @@ -0,0 +1,20 @@ +import { OrganizationInvite } from "@bitwarden/common/auth/services/organization-invite/organization-invite"; + +export abstract class OrganizationInviteService { + /** + * Returns the currently stored organization invite + */ + abstract getOrganizationInvite: () => Promise; + + /** + * Stores a new organization invite + * @param invite an organization invite + * @throws if the invite is nullish + */ + abstract setOrganizationInvitation: (invite: OrganizationInvite) => Promise; + + /** + * Clears the currently stored organization invite + */ + abstract clearOrganizationInvitation: () => Promise; +} diff --git a/libs/common/src/auth/services/organization-invite/organization-invite.ts b/libs/common/src/auth/services/organization-invite/organization-invite.ts new file mode 100644 index 00000000000..d18fdcedb41 --- /dev/null +++ b/libs/common/src/auth/services/organization-invite/organization-invite.ts @@ -0,0 +1,20 @@ +import { Jsonify } from "type-fest"; + +export class OrganizationInvite { + email?: string; + initOrganization?: boolean; + orgSsoIdentifier?: string; + orgUserHasExistingUser?: boolean; + organizationId?: string; + organizationName?: string; + organizationUserId?: string; + token?: string; + + static fromJSON(json: Jsonify): OrganizationInvite | null { + if (json == null) { + return null; + } + + return Object.assign(new OrganizationInvite(), json); + } +} From 8c3c5ab861e286da36fd2b93e805f2e27220bbcb Mon Sep 17 00:00:00 2001 From: Vicki League Date: Thu, 10 Jul 2025 09:14:46 -0400 Subject: [PATCH 094/239] [CL-759] Remove browser style overrides for checkbox (#15552) --- apps/browser/src/popup/scss/base.scss | 4 ++-- libs/components/src/checkbox/checkbox.component.ts | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/browser/src/popup/scss/base.scss b/apps/browser/src/popup/scss/base.scss index 2b625678b89..0565de1712c 100644 --- a/apps/browser/src/popup/scss/base.scss +++ b/apps/browser/src/popup/scss/base.scss @@ -100,7 +100,7 @@ a:not(popup-page a, popup-tab-navigation a) { } } -input:not(bit-form-field input, bit-search input), +input:not(bit-form-field input, bit-search input, input[bitcheckbox]), select:not(bit-form-field select), textarea:not(bit-form-field textarea) { @include themify($themes) { @@ -109,7 +109,7 @@ textarea:not(bit-form-field textarea) { } } -input, +input:not(input[bitcheckbox]), select, textarea, button:not(bit-chip-select button) { diff --git a/libs/components/src/checkbox/checkbox.component.ts b/libs/components/src/checkbox/checkbox.component.ts index c420b3f3473..6159b01d2b5 100644 --- a/libs/components/src/checkbox/checkbox.component.ts +++ b/libs/components/src/checkbox/checkbox.component.ts @@ -15,6 +15,7 @@ export class CheckboxComponent implements BitFormControlAbstraction { protected inputClasses = [ "tw-appearance-none", "tw-outline-none", + "tw-box-border", "tw-relative", "tw-transition", "tw-cursor-pointer", @@ -37,6 +38,7 @@ export class CheckboxComponent implements BitFormControlAbstraction { "before:tw-border", "before:tw-border-solid", "before:tw-border-secondary-500", + "before:tw-box-border", "after:tw-content-['']", "after:tw-block", @@ -44,6 +46,7 @@ export class CheckboxComponent implements BitFormControlAbstraction { "after:tw-inset-0", "after:tw-h-[1.12rem]", "after:tw-w-[1.12rem]", + "after:tw-box-border", "hover:before:tw-border-2", "[&>label]:before:tw-border-2", From a53b1e9ffb38cedd71ae90a0fe61eb814e84b152 Mon Sep 17 00:00:00 2001 From: Alex Morask <144709477+amorask-bitwarden@users.noreply.github.com> Date: Thu, 10 Jul 2025 08:32:40 -0500 Subject: [PATCH 095/239] [PM-21881] Manage payment details outside of checkout (#15458) * Add billable-entity * Add payment types * Add billing.client * Update stripe.service * Add payment method components * Add address.pipe * Add billing address components * Add account credit components * Add component index * Add feature flag * Re-work organization warnings code * Add organization-payment-details.component * Backfill translations * Set up organization FF routing * Add account-payment-details.component * Set up account FF routing * Add provider-payment-details.component * Set up provider FF routing * Use inline component templates for re-usable payment components * Remove errant rebase file * Removed public accessibility modifier * Fix failing test --- .../collections/vault.component.html | 8 +- .../collections/vault.component.ts | 21 +- .../organization-layout.component.html | 6 +- .../layouts/organization-layout.component.ts | 15 + .../individual-billing-routing.module.ts | 7 + .../account-payment-details.component.html | 26 + .../account-payment-details.component.ts | 116 ++ .../individual/subscription.component.html | 5 +- .../individual/subscription.component.ts | 20 +- .../organization-billing-routing.module.ts | 12 + ...rganization-payment-details.component.html | 41 + .../organization-payment-details.component.ts | 187 +++ .../organization-payment-method.component.ts | 20 +- .../add-account-credit-dialog.component.ts | 241 ++++ .../change-payment-method-dialog.component.ts | 113 ++ .../display-account-credit.component.ts | 63 + .../display-billing-address.component.ts | 56 + .../display-payment-method.component.ts | 107 ++ .../edit-billing-address-dialog.component.ts | 147 +++ .../enter-billing-address.component.ts | 194 +++ .../enter-payment-method.component.ts | 408 ++++++ .../app/billing/payment/components/index.ts | 9 + .../verify-bank-account.component.ts | 86 ++ .../payment/pipes/address.pipe.spec.ts | 65 + .../app/billing/payment/pipes/address.pipe.ts | 32 + .../src/app/billing/payment/pipes/index.ts | 1 + .../billing/payment/types/billing-address.ts | 37 + .../src/app/billing/payment/types/index.ts | 6 + .../payment/types/masked-payment-method.ts | 114 ++ .../payment/types/selectable-country.ts | 259 ++++ .../app/billing/payment/types/tax-id-type.ts | 1123 +++++++++++++++++ .../src/app/billing/payment/types/tax-id.ts | 18 + .../payment/types/tokenized-payment-method.ts | 22 + .../app/billing/services/billing.client.ts | 153 +++ apps/web/src/app/billing/services/index.ts | 1 + .../app/billing/services/stripe.service.ts | 124 +- .../billing/services/trial-flow.service.ts | 9 +- .../shared/payment-method.component.ts | 11 + .../src/app/billing/types/billable-entity.ts | 42 + apps/web/src/app/billing/types/index.ts | 2 + .../app/billing/warnings/components/index.ts | 2 + ...anization-free-trial-warning.component.ts} | 22 +- ...ion-reseller-renewal-warning.component.ts} | 18 +- .../app/billing/warnings/services/index.ts | 1 + .../organization-warnings.service.spec.ts | 0 .../services/organization-warnings.service.ts | 73 +- .../src/app/billing/warnings/types/index.ts | 1 + .../warnings/types/organization-warnings.ts | 11 + .../vault-banners.component.spec.ts | 5 + .../vault-banners/vault-banners.component.ts | 11 +- apps/web/src/locales/en/messages.json | 48 + .../providers/providers-layout.component.html | 6 + .../providers/providers-layout.component.ts | 8 + .../providers/providers-routing.module.ts | 9 + .../provider-payment-details.component.html | 33 + .../provider-payment-details.component.ts | 133 ++ .../provider-subscription.component.html | 88 +- .../provider-subscription.component.ts | 7 + .../overview/overview.component.ts | 14 +- libs/common/src/enums/feature-flag.enum.ts | 2 + 60 files changed, 4268 insertions(+), 151 deletions(-) create mode 100644 apps/web/src/app/billing/individual/payment-details/account-payment-details.component.html create mode 100644 apps/web/src/app/billing/individual/payment-details/account-payment-details.component.ts create mode 100644 apps/web/src/app/billing/organizations/payment-details/organization-payment-details.component.html create mode 100644 apps/web/src/app/billing/organizations/payment-details/organization-payment-details.component.ts create mode 100644 apps/web/src/app/billing/payment/components/add-account-credit-dialog.component.ts create mode 100644 apps/web/src/app/billing/payment/components/change-payment-method-dialog.component.ts create mode 100644 apps/web/src/app/billing/payment/components/display-account-credit.component.ts create mode 100644 apps/web/src/app/billing/payment/components/display-billing-address.component.ts create mode 100644 apps/web/src/app/billing/payment/components/display-payment-method.component.ts create mode 100644 apps/web/src/app/billing/payment/components/edit-billing-address-dialog.component.ts create mode 100644 apps/web/src/app/billing/payment/components/enter-billing-address.component.ts create mode 100644 apps/web/src/app/billing/payment/components/enter-payment-method.component.ts create mode 100644 apps/web/src/app/billing/payment/components/index.ts create mode 100644 apps/web/src/app/billing/payment/components/verify-bank-account.component.ts create mode 100644 apps/web/src/app/billing/payment/pipes/address.pipe.spec.ts create mode 100644 apps/web/src/app/billing/payment/pipes/address.pipe.ts create mode 100644 apps/web/src/app/billing/payment/pipes/index.ts create mode 100644 apps/web/src/app/billing/payment/types/billing-address.ts create mode 100644 apps/web/src/app/billing/payment/types/index.ts create mode 100644 apps/web/src/app/billing/payment/types/masked-payment-method.ts create mode 100644 apps/web/src/app/billing/payment/types/selectable-country.ts create mode 100644 apps/web/src/app/billing/payment/types/tax-id-type.ts create mode 100644 apps/web/src/app/billing/payment/types/tax-id.ts create mode 100644 apps/web/src/app/billing/payment/types/tokenized-payment-method.ts create mode 100644 apps/web/src/app/billing/services/billing.client.ts create mode 100644 apps/web/src/app/billing/types/billable-entity.ts create mode 100644 apps/web/src/app/billing/types/index.ts create mode 100644 apps/web/src/app/billing/warnings/components/index.ts rename apps/web/src/app/billing/warnings/{free-trial-warning.component.ts => components/organization-free-trial-warning.component.ts} (68%) rename apps/web/src/app/billing/warnings/{reseller-renewal-warning.component.ts => components/organization-reseller-renewal-warning.component.ts} (63%) create mode 100644 apps/web/src/app/billing/warnings/services/index.ts rename apps/web/src/app/billing/{ => warnings}/services/organization-warnings.service.spec.ts (100%) rename apps/web/src/app/billing/{ => warnings}/services/organization-warnings.service.ts (78%) create mode 100644 apps/web/src/app/billing/warnings/types/index.ts create mode 100644 apps/web/src/app/billing/warnings/types/organization-warnings.ts create mode 100644 bitwarden_license/bit-web/src/app/billing/providers/payment-details/provider-payment-details.component.html create mode 100644 bitwarden_license/bit-web/src/app/billing/providers/payment-details/provider-payment-details.component.ts diff --git a/apps/web/src/app/admin-console/organizations/collections/vault.component.html b/apps/web/src/app/admin-console/organizations/collections/vault.component.html index e8782ca0f2d..ddfcda04c76 100644 --- a/apps/web/src/app/admin-console/organizations/collections/vault.component.html +++ b/apps/web/src/app/admin-console/organizations/collections/vault.component.html @@ -1,14 +1,14 @@ - - - + - + - + @let paymentDetailsPageData = paymentDetailsPageData$ | async; + diff --git a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts index dc1913a5336..89f62ed8975 100644 --- a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts +++ b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts @@ -64,6 +64,11 @@ export class OrganizationLayoutComponent implements OnInit { protected showSponsoredFamiliesDropdown$: Observable; protected canShowPoliciesTab$: Observable; + protected paymentDetailsPageData$: Observable<{ + route: string; + textKey: string; + }>; + constructor( private route: ActivatedRoute, private organizationService: OrganizationService, @@ -135,6 +140,16 @@ export class OrganizationLayoutComponent implements OnInit { ), ), ); + + this.paymentDetailsPageData$ = this.configService + .getFeatureFlag$(FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout) + .pipe( + map((managePaymentDetailsOutsideCheckout) => + managePaymentDetailsOutsideCheckout + ? { route: "billing/payment-details", textKey: "paymentDetails" } + : { route: "billing/payment-method", textKey: "paymentMethod" }, + ), + ); } canShowVaultTab(organization: Organization): boolean { diff --git a/apps/web/src/app/billing/individual/individual-billing-routing.module.ts b/apps/web/src/app/billing/individual/individual-billing-routing.module.ts index bb1ada0b719..87b342ed997 100644 --- a/apps/web/src/app/billing/individual/individual-billing-routing.module.ts +++ b/apps/web/src/app/billing/individual/individual-billing-routing.module.ts @@ -1,6 +1,8 @@ import { NgModule } from "@angular/core"; import { RouterModule, Routes } from "@angular/router"; +import { AccountPaymentDetailsComponent } from "@bitwarden/web-vault/app/billing/individual/payment-details/account-payment-details.component"; + import { PaymentMethodComponent } from "../shared"; import { BillingHistoryViewComponent } from "./billing-history-view.component"; @@ -30,6 +32,11 @@ const routes: Routes = [ component: PaymentMethodComponent, data: { titleId: "paymentMethod" }, }, + { + path: "payment-details", + component: AccountPaymentDetailsComponent, + data: { titleId: "paymentDetails" }, + }, { path: "billing-history", component: BillingHistoryViewComponent, diff --git a/apps/web/src/app/billing/individual/payment-details/account-payment-details.component.html b/apps/web/src/app/billing/individual/payment-details/account-payment-details.component.html new file mode 100644 index 00000000000..c10590d8b1b --- /dev/null +++ b/apps/web/src/app/billing/individual/payment-details/account-payment-details.component.html @@ -0,0 +1,26 @@ + + @let view = view$ | async; + @if (!view) { + + + {{ "loading" | i18n }} + + } @else { + + + + + + } + diff --git a/apps/web/src/app/billing/individual/payment-details/account-payment-details.component.ts b/apps/web/src/app/billing/individual/payment-details/account-payment-details.component.ts new file mode 100644 index 00000000000..4a4d0f60c0b --- /dev/null +++ b/apps/web/src/app/billing/individual/payment-details/account-payment-details.component.ts @@ -0,0 +1,116 @@ +import { Component } from "@angular/core"; +import { ActivatedRoute, Router } from "@angular/router"; +import { + BehaviorSubject, + EMPTY, + filter, + from, + map, + merge, + Observable, + shareReplay, + switchMap, + tap, +} from "rxjs"; +import { catchError } from "rxjs/operators"; + +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; + +import { HeaderModule } from "../../../layouts/header/header.module"; +import { SharedModule } from "../../../shared"; +import { + DisplayAccountCreditComponent, + DisplayPaymentMethodComponent, +} from "../../payment/components"; +import { MaskedPaymentMethod } from "../../payment/types"; +import { BillingClient } from "../../services"; +import { accountToBillableEntity, BillableEntity } from "../../types"; + +class RedirectError { + constructor( + public path: string[], + public relativeTo: ActivatedRoute, + ) {} +} + +type View = { + account: BillableEntity; + paymentMethod: MaskedPaymentMethod | null; + credit: number | null; +}; + +@Component({ + templateUrl: "./account-payment-details.component.html", + standalone: true, + imports: [ + DisplayAccountCreditComponent, + DisplayPaymentMethodComponent, + HeaderModule, + SharedModule, + ], + providers: [BillingClient], +}) +export class AccountPaymentDetailsComponent { + private viewState$ = new BehaviorSubject(null); + + private load$: Observable = this.accountService.activeAccount$.pipe( + switchMap((account) => + this.configService + .getFeatureFlag$(FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout) + .pipe( + map((managePaymentDetailsOutsideCheckout) => { + if (!managePaymentDetailsOutsideCheckout) { + throw new RedirectError(["../payment-method"], this.activatedRoute); + } + return account; + }), + ), + ), + accountToBillableEntity, + switchMap(async (account) => { + const [paymentMethod, credit] = await Promise.all([ + this.billingClient.getPaymentMethod(account), + this.billingClient.getCredit(account), + ]); + + return { + account, + paymentMethod, + credit, + }; + }), + shareReplay({ bufferSize: 1, refCount: false }), + catchError((error: unknown) => { + if (error instanceof RedirectError) { + return from(this.router.navigate(error.path, { relativeTo: error.relativeTo })).pipe( + switchMap(() => EMPTY), + ); + } + throw error; + }), + ); + + view$: Observable = merge( + this.load$.pipe(tap((view) => this.viewState$.next(view))), + this.viewState$.pipe(filter((view): view is View => view !== null)), + ).pipe(shareReplay({ bufferSize: 1, refCount: true })); + + constructor( + private accountService: AccountService, + private activatedRoute: ActivatedRoute, + private billingClient: BillingClient, + private configService: ConfigService, + private router: Router, + ) {} + + setPaymentMethod = (paymentMethod: MaskedPaymentMethod) => { + if (this.viewState$.value) { + this.viewState$.next({ + ...this.viewState$.value, + paymentMethod, + }); + } + }; +} diff --git a/apps/web/src/app/billing/individual/subscription.component.html b/apps/web/src/app/billing/individual/subscription.component.html index 934a24570f4..fa2eb0412a9 100644 --- a/apps/web/src/app/billing/individual/subscription.component.html +++ b/apps/web/src/app/billing/individual/subscription.component.html @@ -3,7 +3,10 @@ {{ "subscription" | i18n }} - {{ "paymentMethod" | i18n }} + @let paymentMethodPageData = paymentDetailsPageData$ | async; + {{ + paymentMethodPageData.textKey | i18n + }} {{ "billingHistory" | i18n }} diff --git a/apps/web/src/app/billing/individual/subscription.component.ts b/apps/web/src/app/billing/individual/subscription.component.ts index 2a08ec85127..c6a20a9f6a3 100644 --- a/apps/web/src/app/billing/individual/subscription.component.ts +++ b/apps/web/src/app/billing/individual/subscription.component.ts @@ -1,10 +1,12 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore import { Component, OnInit } from "@angular/core"; -import { Observable, switchMap } from "rxjs"; +import { map, Observable, switchMap } from "rxjs"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; @Component({ @@ -13,16 +15,32 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl }) export class SubscriptionComponent implements OnInit { hasPremium$: Observable; + paymentDetailsPageData$: Observable<{ + route: string; + textKey: string; + }>; + selfHosted: boolean; constructor( private platformUtilsService: PlatformUtilsService, billingAccountProfileStateService: BillingAccountProfileStateService, accountService: AccountService, + private configService: ConfigService, ) { this.hasPremium$ = accountService.activeAccount$.pipe( switchMap((account) => billingAccountProfileStateService.hasPremiumPersonally$(account.id)), ); + + this.paymentDetailsPageData$ = this.configService + .getFeatureFlag$(FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout) + .pipe( + map((managePaymentDetailsOutsideCheckout) => + managePaymentDetailsOutsideCheckout + ? { route: "payment-details", textKey: "paymentDetails" } + : { route: "payment-method", textKey: "paymentMethod" }, + ), + ); } ngOnInit() { diff --git a/apps/web/src/app/billing/organizations/organization-billing-routing.module.ts b/apps/web/src/app/billing/organizations/organization-billing-routing.module.ts index 1bfb9fc4912..692791db855 100644 --- a/apps/web/src/app/billing/organizations/organization-billing-routing.module.ts +++ b/apps/web/src/app/billing/organizations/organization-billing-routing.module.ts @@ -2,6 +2,7 @@ import { NgModule } from "@angular/core"; import { RouterModule, Routes } from "@angular/router"; import { canAccessBillingTab } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { OrganizationPaymentDetailsComponent } from "@bitwarden/web-vault/app/billing/organizations/payment-details/organization-payment-details.component"; import { organizationPermissionsGuard } from "../../admin-console/organizations/guards/org-permissions.guard"; import { organizationIsUnmanaged } from "../../billing/guards/organization-is-unmanaged.guard"; @@ -36,6 +37,17 @@ const routes: Routes = [ titleId: "paymentMethod", }, }, + { + path: "payment-details", + component: OrganizationPaymentDetailsComponent, + canActivate: [ + organizationPermissionsGuard((org) => org.canEditPaymentMethods), + organizationIsUnmanaged, + ], + data: { + titleId: "paymentDetails", + }, + }, { path: "history", component: OrgBillingHistoryViewComponent, diff --git a/apps/web/src/app/billing/organizations/payment-details/organization-payment-details.component.html b/apps/web/src/app/billing/organizations/payment-details/organization-payment-details.component.html new file mode 100644 index 00000000000..17f4349fdd5 --- /dev/null +++ b/apps/web/src/app/billing/organizations/payment-details/organization-payment-details.component.html @@ -0,0 +1,41 @@ +@let organization = organization$ | async; +@if (organization) { + + +} + + + @let view = view$ | async; + @if (!view) { + + + {{ "loading" | i18n }} + + } @else { + + + + + + + + } + diff --git a/apps/web/src/app/billing/organizations/payment-details/organization-payment-details.component.ts b/apps/web/src/app/billing/organizations/payment-details/organization-payment-details.component.ts new file mode 100644 index 00000000000..3618696f697 --- /dev/null +++ b/apps/web/src/app/billing/organizations/payment-details/organization-payment-details.component.ts @@ -0,0 +1,187 @@ +import { Component, OnInit, ViewChild } from "@angular/core"; +import { ActivatedRoute, Router } from "@angular/router"; +import { + BehaviorSubject, + catchError, + EMPTY, + filter, + firstValueFrom, + from, + lastValueFrom, + map, + merge, + Observable, + shareReplay, + switchMap, + tap, +} from "rxjs"; + +import { + getOrganizationById, + OrganizationService, +} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { getUserId } from "@bitwarden/common/auth/services/account.service"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; +import { DialogService } from "@bitwarden/components"; + +import { HeaderModule } from "../../../layouts/header/header.module"; +import { SharedModule } from "../../../shared"; +import { + ChangePaymentMethodDialogComponent, + DisplayAccountCreditComponent, + DisplayBillingAddressComponent, + DisplayPaymentMethodComponent, +} from "../../payment/components"; +import { BillingAddress, MaskedPaymentMethod } from "../../payment/types"; +import { BillingClient } from "../../services"; +import { BillableEntity, organizationToBillableEntity } from "../../types"; +import { OrganizationFreeTrialWarningComponent } from "../../warnings/components"; + +class RedirectError { + constructor( + public path: string[], + public relativeTo: ActivatedRoute, + ) {} +} + +type View = { + organization: BillableEntity; + paymentMethod: MaskedPaymentMethod | null; + billingAddress: BillingAddress | null; + credit: number | null; +}; + +@Component({ + templateUrl: "./organization-payment-details.component.html", + standalone: true, + imports: [ + DisplayBillingAddressComponent, + DisplayAccountCreditComponent, + DisplayPaymentMethodComponent, + HeaderModule, + OrganizationFreeTrialWarningComponent, + SharedModule, + ], + providers: [BillingClient], +}) +export class OrganizationPaymentDetailsComponent implements OnInit { + @ViewChild(OrganizationFreeTrialWarningComponent) + organizationFreeTrialWarningComponent!: OrganizationFreeTrialWarningComponent; + + private viewState$ = new BehaviorSubject(null); + + private load$: Observable = this.accountService.activeAccount$ + .pipe( + getUserId, + switchMap((userId) => + this.organizationService + .organizations$(userId) + .pipe(getOrganizationById(this.activatedRoute.snapshot.params.organizationId)), + ), + ) + .pipe( + switchMap((organization) => + this.configService + .getFeatureFlag$(FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout) + .pipe( + map((managePaymentDetailsOutsideCheckout) => { + if (!managePaymentDetailsOutsideCheckout) { + throw new RedirectError(["../payment-method"], this.activatedRoute); + } + return organization; + }), + ), + ), + organizationToBillableEntity, + switchMap(async (organization) => { + const [paymentMethod, billingAddress, credit] = await Promise.all([ + this.billingClient.getPaymentMethod(organization), + this.billingClient.getBillingAddress(organization), + this.billingClient.getCredit(organization), + ]); + + return { + organization, + paymentMethod, + billingAddress, + credit, + }; + }), + catchError((error: unknown) => { + if (error instanceof RedirectError) { + return from(this.router.navigate(error.path, { relativeTo: error.relativeTo })).pipe( + switchMap(() => EMPTY), + ); + } + throw error; + }), + ); + + view$: Observable = merge( + this.load$.pipe(tap((view) => this.viewState$.next(view))), + this.viewState$.pipe(filter((view): view is View => view !== null)), + ).pipe(shareReplay({ bufferSize: 1, refCount: true })); + + organization$ = this.view$.pipe(map((view) => view.organization.data as Organization)); + + constructor( + private accountService: AccountService, + private activatedRoute: ActivatedRoute, + private billingClient: BillingClient, + private configService: ConfigService, + private dialogService: DialogService, + private organizationService: OrganizationService, + private router: Router, + ) {} + + async ngOnInit() { + const openChangePaymentMethodDialogOnStart = + (history.state?.launchPaymentModalAutomatically as boolean) ?? false; + + if (openChangePaymentMethodDialogOnStart) { + history.replaceState({ ...history.state, launchPaymentModalAutomatically: false }, ""); + await this.changePaymentMethod(); + } + } + + changePaymentMethod = async () => { + const view = await firstValueFrom(this.view$); + const dialogRef = ChangePaymentMethodDialogComponent.open(this.dialogService, { + data: { + owner: view.organization, + }, + }); + const result = await lastValueFrom(dialogRef.closed); + if (result?.type === "success") { + this.setPaymentMethod(result.paymentMethod); + if (!view.billingAddress && result.paymentMethod.type !== "payPal") { + const billingAddress = await this.billingClient.getBillingAddress(view.organization); + if (billingAddress) { + this.setBillingAddress(billingAddress); + } + } + this.organizationFreeTrialWarningComponent.refresh(); + } + }; + + setBillingAddress = (billingAddress: BillingAddress) => { + if (this.viewState$.value) { + this.viewState$.next({ + ...this.viewState$.value, + billingAddress, + }); + } + }; + + setPaymentMethod = (paymentMethod: MaskedPaymentMethod) => { + if (this.viewState$.value) { + this.viewState$.next({ + ...this.viewState$.value, + paymentMethod, + }); + } + }; +} diff --git a/apps/web/src/app/billing/organizations/payment-method/organization-payment-method.component.ts b/apps/web/src/app/billing/organizations/payment-method/organization-payment-method.component.ts index 36ac7debae2..9b144fe59a7 100644 --- a/apps/web/src/app/billing/organizations/payment-method/organization-payment-method.component.ts +++ b/apps/web/src/app/billing/organizations/payment-method/organization-payment-method.component.ts @@ -4,7 +4,7 @@ import { Location } from "@angular/common"; import { Component, OnDestroy } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { ActivatedRoute, Router } from "@angular/router"; -import { firstValueFrom, from, lastValueFrom, map, switchMap } from "rxjs"; +import { combineLatest, firstValueFrom, from, lastValueFrom, map, switchMap } from "rxjs"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { @@ -19,6 +19,8 @@ import { TaxInformation } from "@bitwarden/common/billing/models/domain"; import { VerifyBankAccountRequest } from "@bitwarden/common/billing/models/request/verify-bank-account.request"; import { OrganizationSubscriptionResponse } from "@bitwarden/common/billing/models/response/organization-subscription.response"; import { PaymentSourceResponse } from "@bitwarden/common/billing/models/response/payment-source.response"; +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 { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { SyncService } from "@bitwarden/common/platform/sync"; @@ -72,18 +74,28 @@ export class OrganizationPaymentMethodComponent implements OnDestroy { private accountService: AccountService, protected syncService: SyncService, private billingNotificationService: BillingNotificationService, + private configService: ConfigService, ) { - this.activatedRoute.params + combineLatest([ + this.activatedRoute.params, + this.configService.getFeatureFlag$(FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout), + ]) .pipe( - takeUntilDestroyed(), - switchMap(({ organizationId }) => { + switchMap(([{ organizationId }, managePaymentDetailsOutsideCheckout]) => { if (this.platformUtilsService.isSelfHost()) { return from(this.router.navigate(["/settings/subscription"])); } + if (managePaymentDetailsOutsideCheckout) { + return from( + this.router.navigate(["../payment-details"], { relativeTo: this.activatedRoute }), + ); + } + this.organizationId = organizationId; return from(this.load()); }), + takeUntilDestroyed(), ) .subscribe(); diff --git a/apps/web/src/app/billing/payment/components/add-account-credit-dialog.component.ts b/apps/web/src/app/billing/payment/components/add-account-credit-dialog.component.ts new file mode 100644 index 00000000000..2030d0e73ec --- /dev/null +++ b/apps/web/src/app/billing/payment/components/add-account-credit-dialog.component.ts @@ -0,0 +1,241 @@ +import { DIALOG_DATA } from "@angular/cdk/dialog"; +import { Component, ElementRef, Inject, ViewChild } from "@angular/core"; +import { + AbstractControl, + FormControl, + FormGroup, + ValidationErrors, + ValidatorFn, + Validators, +} from "@angular/forms"; +import { map } from "rxjs"; + +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { DialogConfig, DialogRef, DialogService, ToastService } from "@bitwarden/components"; + +import { SharedModule } from "../../../shared"; +import { BillingClient } from "../../services"; +import { BillableEntity } from "../../types"; + +type DialogParams = { + owner: BillableEntity; +}; + +type DialogResult = "cancelled" | "error" | "launched"; + +type PayPalConfig = { + businessId: string; + buttonAction: string; +}; + +declare const process: { + env: { + PAYPAL_CONFIG: PayPalConfig; + }; +}; + +const positiveNumberValidator = + (message: string): ValidatorFn => + (control: AbstractControl): ValidationErrors | null => { + if (!control.value) { + return null; + } + + const value = parseFloat(control.value); + + if (isNaN(value) || value <= 0) { + return { notPositiveNumber: { message } }; + } + + return null; + }; + +@Component({ + template: ` +
+ + + {{ "addCredit" | i18n }} + +
+

{{ "creditDelayed" | i18n }}

+
+ + + PayPal + + + Bitcoin + + +
+
+ + {{ "amount" | i18n }} + + $USD + +
+
+ + + + +
+
+
+ + + + + + + + + + + + + + + +
+ `, + standalone: true, + imports: [SharedModule], + providers: [BillingClient], +}) +export class AddAccountCreditDialogComponent { + @ViewChild("payPalForm", { read: ElementRef, static: true }) payPalForm!: ElementRef; + + protected payPalConfig = process.env.PAYPAL_CONFIG as PayPalConfig; + protected redirectUrl = window.location.href; + + protected formGroup = new FormGroup({ + paymentMethod: new FormControl<"payPal" | "bitPay">("payPal"), + amount: new FormControl("0.00", [ + Validators.required, + positiveNumberValidator(this.i18nService.t("mustBePositiveNumber")), + ]), + }); + + protected payPalCustom$ = this.configService.cloudRegion$.pipe( + map((cloudRegion) => { + switch (this.dialogParams.owner.type) { + case "account": { + return `user_id=${this.dialogParams.owner.data.id},account_credit=1,region=${cloudRegion}`; + } + case "organization": { + return `organization_id=${this.dialogParams.owner.data.id},account_credit=1,region=${cloudRegion}`; + } + case "provider": { + return `provider_id=${this.dialogParams.owner.data.id},account_credit=1,region=${cloudRegion}`; + } + } + }), + ); + + constructor( + private billingClient: BillingClient, + private configService: ConfigService, + @Inject(DIALOG_DATA) private dialogParams: DialogParams, + private dialogRef: DialogRef, + private i18nService: I18nService, + private platformUtilsService: PlatformUtilsService, + private toastService: ToastService, + ) {} + + submit = async (): Promise => { + this.formGroup.markAllAsTouched(); + + if (!this.formGroup.valid) { + return; + } + + if (this.formGroup.value.paymentMethod === "bitPay") { + const result = await this.billingClient.addCreditWithBitPay(this.dialogParams.owner, { + amount: this.amount!, + redirectUrl: this.redirectUrl, + }); + + switch (result.type) { + case "success": { + this.platformUtilsService.launchUri(result.value); + this.dialogRef.close("launched"); + break; + } + case "error": { + this.toastService.showToast({ + variant: "error", + title: "", + message: result.message, + }); + this.dialogRef.close("error"); + break; + } + } + } + + this.payPalForm.nativeElement.submit(); + this.dialogRef.close("launched"); + }; + + formatAmount = (): void => { + if (this.formGroup.value.amount) { + const amount = parseFloat(this.formGroup.value.amount); + if (isNaN(amount)) { + this.formGroup.controls.amount.setValue(null); + } else { + this.formGroup.controls.amount.setValue(amount.toFixed(2).toString()); + } + } + }; + + get amount(): number | null { + if (this.formGroup.value.amount) { + const amount = parseFloat(this.formGroup.value.amount); + if (isNaN(amount)) { + return null; + } + return amount; + } + return null; + } + + get payPalSubject(): string { + switch (this.dialogParams.owner.type) { + case "account": { + return this.dialogParams.owner.data.email; + } + case "organization": + case "provider": { + return this.dialogParams.owner.data.name; + } + } + } + + static open = (dialogService: DialogService, dialogConfig: DialogConfig) => + dialogService.open(AddAccountCreditDialogComponent, dialogConfig); +} diff --git a/apps/web/src/app/billing/payment/components/change-payment-method-dialog.component.ts b/apps/web/src/app/billing/payment/components/change-payment-method-dialog.component.ts new file mode 100644 index 00000000000..efd0055fb95 --- /dev/null +++ b/apps/web/src/app/billing/payment/components/change-payment-method-dialog.component.ts @@ -0,0 +1,113 @@ +import { DIALOG_DATA } from "@angular/cdk/dialog"; +import { Component, Inject, ViewChild } from "@angular/core"; + +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { DialogConfig, DialogRef, DialogService, ToastService } from "@bitwarden/components"; + +import { SharedModule } from "../../../shared"; +import { BillingClient } from "../../services"; +import { BillableEntity } from "../../types"; +import { MaskedPaymentMethod } from "../types"; + +import { EnterPaymentMethodComponent } from "./enter-payment-method.component"; + +type DialogParams = { + owner: BillableEntity; +}; + +type DialogResult = + | { type: "cancelled" } + | { type: "error" } + | { type: "success"; paymentMethod: MaskedPaymentMethod }; + +@Component({ + template: ` +
+ + + {{ "changePaymentMethod" | i18n }} + +
+ + +
+ + + + +
+
+ `, + standalone: true, + imports: [EnterPaymentMethodComponent, SharedModule], + providers: [BillingClient], +}) +export class ChangePaymentMethodDialogComponent { + @ViewChild(EnterPaymentMethodComponent) + private enterPaymentMethodComponent!: EnterPaymentMethodComponent; + protected formGroup = EnterPaymentMethodComponent.getFormGroup(); + + constructor( + private billingClient: BillingClient, + @Inject(DIALOG_DATA) protected dialogParams: DialogParams, + private dialogRef: DialogRef, + private i18nService: I18nService, + private toastService: ToastService, + ) {} + + submit = async () => { + this.formGroup.markAllAsTouched(); + + if (!this.formGroup.valid) { + return; + } + + const paymentMethod = await this.enterPaymentMethodComponent.tokenize(); + const billingAddress = + this.formGroup.value.type !== "payPal" + ? this.formGroup.controls.billingAddress.getRawValue() + : null; + + const result = await this.billingClient.updatePaymentMethod( + this.dialogParams.owner, + paymentMethod, + billingAddress, + ); + + switch (result.type) { + case "success": { + this.toastService.showToast({ + variant: "success", + title: "", + message: this.i18nService.t("paymentMethodUpdated"), + }); + this.dialogRef.close({ + type: "success", + paymentMethod: result.value, + }); + break; + } + case "error": { + this.toastService.showToast({ + variant: "error", + title: "", + message: result.message, + }); + this.dialogRef.close({ type: "error" }); + break; + } + } + }; + + static open = (dialogService: DialogService, dialogConfig: DialogConfig) => + dialogService.open(ChangePaymentMethodDialogComponent, dialogConfig); +} diff --git a/apps/web/src/app/billing/payment/components/display-account-credit.component.ts b/apps/web/src/app/billing/payment/components/display-account-credit.component.ts new file mode 100644 index 00000000000..7cbe3a27f30 --- /dev/null +++ b/apps/web/src/app/billing/payment/components/display-account-credit.component.ts @@ -0,0 +1,63 @@ +import { CurrencyPipe } from "@angular/common"; +import { Component, Input } from "@angular/core"; + +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { DialogService, ToastService } from "@bitwarden/components"; + +import { SharedModule } from "../../../shared"; +import { BillingClient } from "../../services"; +import { BillableEntity } from "../../types"; + +import { AddAccountCreditDialogComponent } from "./add-account-credit-dialog.component"; + +@Component({ + selector: "app-display-account-credit", + template: ` + +

{{ "accountCredit" | i18n }}: {{ formattedCredit }}

+

{{ "availableCreditAppliedToInvoice" | i18n }}

+ +
+ `, + standalone: true, + imports: [SharedModule], + providers: [BillingClient, CurrencyPipe], +}) +export class DisplayAccountCreditComponent { + @Input({ required: true }) owner!: BillableEntity; + @Input({ required: true }) credit!: number | null; + + constructor( + private billingClient: BillingClient, + private currencyPipe: CurrencyPipe, + private dialogService: DialogService, + private i18nService: I18nService, + private toastService: ToastService, + ) {} + + addAccountCredit = async () => { + if (this.owner.type !== "account") { + const billingAddress = await this.billingClient.getBillingAddress(this.owner); + if (!billingAddress) { + this.toastService.showToast({ + variant: "error", + title: "", + message: this.i18nService.t("billingAddressRequiredToAddCredit"), + }); + } + } + + AddAccountCreditDialogComponent.open(this.dialogService, { + data: { + owner: this.owner, + }, + }); + }; + + get formattedCredit(): string | null { + const credit = this.credit ?? 0; + return this.currencyPipe.transform(credit, "$"); + } +} diff --git a/apps/web/src/app/billing/payment/components/display-billing-address.component.ts b/apps/web/src/app/billing/payment/components/display-billing-address.component.ts new file mode 100644 index 00000000000..f0a11321e5d --- /dev/null +++ b/apps/web/src/app/billing/payment/components/display-billing-address.component.ts @@ -0,0 +1,56 @@ +import { Component, EventEmitter, Input, Output } from "@angular/core"; +import { lastValueFrom } from "rxjs"; + +import { DialogService } from "@bitwarden/components"; + +import { SharedModule } from "../../../shared"; +import { BillableEntity } from "../../types"; +import { AddressPipe } from "../pipes"; +import { BillingAddress } from "../types"; + +import { EditBillingAddressDialogComponent } from "./edit-billing-address-dialog.component"; + +@Component({ + selector: "app-display-billing-address", + template: ` + +

{{ "billingAddress" | i18n }}

+ @if (billingAddress) { +

{{ billingAddress | address }}

+ @if (billingAddress.taxId) { +

{{ "taxId" | i18n: billingAddress.taxId.value }}

+ } + } @else { +

{{ "noBillingAddress" | i18n }}

+ } + @let key = billingAddress ? "editBillingAddress" : "addBillingAddress"; + +
+ `, + standalone: true, + imports: [AddressPipe, SharedModule], +}) +export class DisplayBillingAddressComponent { + @Input({ required: true }) owner!: BillableEntity; + @Input({ required: true }) billingAddress!: BillingAddress | null; + @Output() updated = new EventEmitter(); + + constructor(private dialogService: DialogService) {} + + editBillingAddress = async (): Promise => { + const dialogRef = EditBillingAddressDialogComponent.open(this.dialogService, { + data: { + owner: this.owner, + billingAddress: this.billingAddress, + }, + }); + + const result = await lastValueFrom(dialogRef.closed); + + if (result?.type === "success") { + this.updated.emit(result.billingAddress); + } + }; +} diff --git a/apps/web/src/app/billing/payment/components/display-payment-method.component.ts b/apps/web/src/app/billing/payment/components/display-payment-method.component.ts new file mode 100644 index 00000000000..769472bcfcf --- /dev/null +++ b/apps/web/src/app/billing/payment/components/display-payment-method.component.ts @@ -0,0 +1,107 @@ +import { Component, EventEmitter, Input, Output } from "@angular/core"; +import { lastValueFrom } from "rxjs"; + +import { DialogService } from "@bitwarden/components"; + +import { SharedModule } from "../../../shared"; +import { BillableEntity } from "../../types"; +import { MaskedPaymentMethod } from "../types"; + +import { ChangePaymentMethodDialogComponent } from "./change-payment-method-dialog.component"; +import { VerifyBankAccountComponent } from "./verify-bank-account.component"; + +@Component({ + selector: "app-display-payment-method", + template: ` + +

{{ "paymentMethod" | i18n }}

+ @if (paymentMethod) { + @switch (paymentMethod.type) { + @case ("bankAccount") { + @if (!paymentMethod.verified) { + + + } + +

+ + {{ paymentMethod.bankName }}, *{{ paymentMethod.last4 }} + @if (!paymentMethod.verified) { + - {{ "unverified" | i18n }} + } +

+ } + @case ("card") { +

+ @let brandIcon = getBrandIconForCard(); + @if (brandIcon !== null) { + + } @else { + + } + {{ paymentMethod.brand | titlecase }}, *{{ paymentMethod.last4 }}, + {{ paymentMethod.expiration }} +

+ } + @case ("payPal") { +

+ + {{ paymentMethod.email }} +

+ } + } + } @else { +

{{ "noPaymentMethod" | i18n }}

+ } + @let key = paymentMethod ? "changePaymentMethod" : "addPaymentMethod"; + +
+ `, + standalone: true, + imports: [SharedModule, VerifyBankAccountComponent], +}) +export class DisplayPaymentMethodComponent { + @Input({ required: true }) owner!: BillableEntity; + @Input({ required: true }) paymentMethod!: MaskedPaymentMethod | null; + @Output() updated = new EventEmitter(); + + protected availableCardIcons: Record = { + amex: "card-amex", + diners: "card-diners-club", + discover: "card-discover", + jcb: "card-jcb", + mastercard: "card-mastercard", + unionpay: "card-unionpay", + visa: "card-visa", + }; + + constructor(private dialogService: DialogService) {} + + changePaymentMethod = async (): Promise => { + const dialogRef = ChangePaymentMethodDialogComponent.open(this.dialogService, { + data: { + owner: this.owner, + }, + }); + + const result = await lastValueFrom(dialogRef.closed); + + if (result?.type === "success") { + this.updated.emit(result.paymentMethod); + } + }; + + onBankAccountVerified = (paymentMethod: MaskedPaymentMethod) => this.updated.emit(paymentMethod); + + protected getBrandIconForCard = (): string | null => { + if (this.paymentMethod?.type !== "card") { + return null; + } + + return this.paymentMethod.brand in this.availableCardIcons + ? this.availableCardIcons[this.paymentMethod.brand] + : null; + }; +} diff --git a/apps/web/src/app/billing/payment/components/edit-billing-address-dialog.component.ts b/apps/web/src/app/billing/payment/components/edit-billing-address-dialog.component.ts new file mode 100644 index 00000000000..c844d08df58 --- /dev/null +++ b/apps/web/src/app/billing/payment/components/edit-billing-address-dialog.component.ts @@ -0,0 +1,147 @@ +import { DIALOG_DATA } from "@angular/cdk/dialog"; +import { Component, Inject } from "@angular/core"; + +import { ProductTierType } from "@bitwarden/common/billing/enums"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { DialogConfig, DialogRef, DialogService, ToastService } from "@bitwarden/components"; + +import { SharedModule } from "../../../shared"; +import { BillingClient } from "../../services"; +import { BillableEntity } from "../../types"; +import { BillingAddress, getTaxIdTypeForCountry } from "../types"; + +import { EnterBillingAddressComponent } from "./enter-billing-address.component"; + +type DialogParams = { + owner: BillableEntity; + billingAddress: BillingAddress | null; +}; + +type DialogResult = + | { type: "cancelled" } + | { type: "error" } + | { type: "success"; billingAddress: BillingAddress }; + +@Component({ + template: ` +
+ + + {{ "editBillingAddress" | i18n }} + +
+ +
+ + + + +
+
+ `, + standalone: true, + imports: [EnterBillingAddressComponent, SharedModule], + providers: [BillingClient], +}) +export class EditBillingAddressDialogComponent { + protected formGroup = EnterBillingAddressComponent.getFormGroup(); + + constructor( + private billingClient: BillingClient, + @Inject(DIALOG_DATA) protected dialogParams: DialogParams, + private dialogRef: DialogRef, + private i18nService: I18nService, + private toastService: ToastService, + ) { + if (dialogParams.billingAddress) { + this.formGroup.patchValue({ + ...dialogParams.billingAddress, + taxId: dialogParams.billingAddress.taxId?.value, + }); + } + } + + submit = async (): Promise => { + this.formGroup.markAllAsTouched(); + + if (this.formGroup.invalid) { + return; + } + + const { taxId, ...addressFields } = this.formGroup.getRawValue(); + + const taxIdType = taxId ? getTaxIdTypeForCountry(addressFields.country) : null; + + const billingAddress = taxIdType + ? { ...addressFields, taxId: { code: taxIdType.code, value: taxId! } } + : { ...addressFields, taxId: null }; + + const result = await this.billingClient.updateBillingAddress( + this.dialogParams.owner, + billingAddress, + ); + + switch (result.type) { + case "success": { + this.toastService.showToast({ + variant: "success", + title: "", + message: this.i18nService.t("billingAddressUpdated"), + }); + this.dialogRef.close({ + type: "success", + billingAddress: result.value, + }); + break; + } + case "error": { + this.toastService.showToast({ + variant: "error", + title: "", + message: result.message, + }); + this.dialogRef.close({ + type: "error", + }); + break; + } + } + }; + + get supportsTaxId(): boolean { + switch (this.dialogParams.owner.type) { + case "account": { + return false; + } + case "organization": { + return [ + ProductTierType.TeamsStarter, + ProductTierType.Teams, + ProductTierType.Enterprise, + ].includes(this.dialogParams.owner.data.productTierType); + } + case "provider": { + return true; + } + } + } + + static open = (dialogService: DialogService, dialogConfig: DialogConfig) => + dialogService.open(EditBillingAddressDialogComponent, dialogConfig); +} diff --git a/apps/web/src/app/billing/payment/components/enter-billing-address.component.ts b/apps/web/src/app/billing/payment/components/enter-billing-address.component.ts new file mode 100644 index 00000000000..0419828d8ba --- /dev/null +++ b/apps/web/src/app/billing/payment/components/enter-billing-address.component.ts @@ -0,0 +1,194 @@ +import { Component, Input, OnDestroy, OnInit } from "@angular/core"; +import { FormControl, FormGroup, Validators } from "@angular/forms"; +import { map, Observable, startWith, Subject, takeUntil } from "rxjs"; + +import { ControlsOf } from "@bitwarden/angular/types/controls-of"; + +import { SharedModule } from "../../../shared"; +import { BillingAddress, selectableCountries, taxIdTypes } from "../types"; + +export interface BillingAddressControls { + country: string; + postalCode: string; + line1: string | null; + line2: string | null; + city: string | null; + state: string | null; + taxId: string | null; +} + +export type BillingAddressFormGroup = FormGroup>; + +type Scenario = + | { + type: "checkout"; + supportsTaxId: boolean; + } + | { + type: "update"; + existing?: BillingAddress; + supportsTaxId: boolean; + }; + +@Component({ + selector: "app-enter-billing-address", + template: ` +
+
+
+ + {{ "country" | i18n }} + + @for (selectableCountry of selectableCountries; track selectableCountry.value) { + + } + + +
+
+ + {{ "zipPostalCode" | i18n }} + + +
+
+ + {{ "address1" | i18n }} + + +
+
+ + {{ "address2" | i18n }} + + +
+
+ + {{ "cityTown" | i18n }} + + +
+
+ + {{ "stateProvince" | i18n }} + + +
+ @if (supportsTaxId$ | async) { +
+ + {{ "taxIdNumber" | i18n }} + + +
+ } +
+
+ `, + standalone: true, + imports: [SharedModule], +}) +export class EnterBillingAddressComponent implements OnInit, OnDestroy { + @Input({ required: true }) scenario!: Scenario; + @Input({ required: true }) group!: BillingAddressFormGroup; + + protected selectableCountries = selectableCountries; + protected supportsTaxId$!: Observable; + + private destroy$ = new Subject(); + + ngOnInit() { + switch (this.scenario.type) { + case "checkout": { + this.disableAddressControls(); + break; + } + case "update": { + if (this.scenario.existing) { + this.group.patchValue({ + ...this.scenario.existing, + taxId: this.scenario.existing.taxId?.value, + }); + } + } + } + + this.supportsTaxId$ = this.group.controls.country.valueChanges.pipe( + startWith(this.group.value.country ?? this.selectableCountries[0].value), + map((country) => { + if (!this.scenario.supportsTaxId) { + return false; + } + + return taxIdTypes.filter((taxIdType) => taxIdType.iso === country).length > 0; + }), + ); + + this.supportsTaxId$.pipe(takeUntil(this.destroy$)).subscribe((supportsTaxId) => { + if (supportsTaxId) { + this.group.controls.taxId.enable(); + } else { + this.group.controls.taxId.disable(); + } + }); + } + + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); + } + + disableAddressControls = () => { + this.group.controls.line1.disable(); + this.group.controls.line2.disable(); + this.group.controls.city.disable(); + this.group.controls.state.disable(); + }; + + static getFormGroup = (): BillingAddressFormGroup => + new FormGroup({ + country: new FormControl("", { + nonNullable: true, + validators: [Validators.required], + }), + postalCode: new FormControl("", { + nonNullable: true, + validators: [Validators.required], + }), + line1: new FormControl(null), + line2: new FormControl(null), + city: new FormControl(null), + state: new FormControl(null), + taxId: new FormControl(null), + }); +} diff --git a/apps/web/src/app/billing/payment/components/enter-payment-method.component.ts b/apps/web/src/app/billing/payment/components/enter-payment-method.component.ts new file mode 100644 index 00000000000..4f5b2e3b15c --- /dev/null +++ b/apps/web/src/app/billing/payment/components/enter-payment-method.component.ts @@ -0,0 +1,408 @@ +import { Component, Input, OnInit } from "@angular/core"; +import { FormControl, FormGroup, Validators } from "@angular/forms"; +import { BehaviorSubject, startWith, Subject, takeUntil } from "rxjs"; + +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { PopoverModule, ToastService } from "@bitwarden/components"; + +import { SharedModule } from "../../../shared"; +import { BillingServicesModule, BraintreeService, StripeService } from "../../services"; +import { PaymentLabelComponent } from "../../shared/payment/payment-label.component"; +import { + isTokenizablePaymentMethod, + selectableCountries, + TokenizablePaymentMethod, + TokenizedPaymentMethod, +} from "../types"; + +type PaymentMethodOption = TokenizablePaymentMethod | "accountCredit"; + +type PaymentMethodFormGroup = FormGroup<{ + type: FormControl; + bankAccount: FormGroup<{ + routingNumber: FormControl; + accountNumber: FormControl; + accountHolderName: FormControl; + accountHolderType: FormControl<"" | "company" | "individual">; + }>; + billingAddress: FormGroup<{ + country: FormControl; + postalCode: FormControl; + }>; +}>; + +@Component({ + selector: "app-enter-payment-method", + template: ` + @let showBillingDetails = includeBillingAddress && selected !== "payPal"; +
+ @if (showBillingDetails) { +
{{ "paymentMethod" | i18n }}
+ } +
+ + + + + {{ "creditCard" | i18n }} + + + @if (showBankAccount) { + + + + {{ "bankAccount" | i18n }} + + + } + @if (showPayPal) { + + + + {{ "payPal" | i18n }} + + + } + @if (showAccountCredit) { + + + + {{ "accountCredit" | i18n }} + + + } + +
+ @switch (selected) { + @case ("card") { +
+
+ + {{ "number" | i18n }} + +
+
+
+ Visa, MasterCard, Discover, AmEx, JCB, Diners Club, UnionPay +
+
+ + {{ "expiration" | i18n }} + +
+
+
+ + {{ "securityCodeSlashCVV" | i18n }} + + +

{{ "cardSecurityCodeDescription" | i18n }}

+
+
+
+
+
+ } + @case ("bankAccount") { + + + {{ "verifyBankAccountWarning" | i18n }} + +
+ + {{ "routingNumber" | i18n }} + + + + {{ "accountNumber" | i18n }} + + + + {{ "accountHolderName" | i18n }} + + + + {{ "bankAccountType" | i18n }} + + + + + + +
+
+ } + @case ("payPal") { + +
+
+ {{ "paypalClickSubmit" | i18n }} +
+
+ } + @case ("accountCredit") { + + + {{ "makeSureEnoughCredit" | i18n }} + + + } + } + @if (showBillingDetails) { +
{{ "billingAddress" | i18n }}
+
+
+ + {{ "country" | i18n }} + + @for (selectableCountry of selectableCountries; track selectableCountry.value) { + + } + + +
+
+ + {{ "zipPostalCode" | i18n }} + + +
+
+ } +
+ `, + standalone: true, + imports: [BillingServicesModule, PaymentLabelComponent, PopoverModule, SharedModule], +}) +export class EnterPaymentMethodComponent implements OnInit { + @Input({ required: true }) group!: PaymentMethodFormGroup; + + private showBankAccountSubject = new BehaviorSubject(true); + showBankAccount$ = this.showBankAccountSubject.asObservable(); + @Input() + set showBankAccount(value: boolean) { + this.showBankAccountSubject.next(value); + } + get showBankAccount(): boolean { + return this.showBankAccountSubject.value; + } + + @Input() showPayPal: boolean = true; + @Input() showAccountCredit: boolean = false; + @Input() includeBillingAddress: boolean = false; + + protected selectableCountries = selectableCountries; + + private destroy$ = new Subject(); + + constructor( + private braintreeService: BraintreeService, + private i18nService: I18nService, + private logService: LogService, + private stripeService: StripeService, + private toastService: ToastService, + ) {} + + ngOnInit() { + this.stripeService.loadStripe( + { + cardNumber: "#stripe-card-number", + cardExpiry: "#stripe-card-expiry", + cardCvc: "#stripe-card-cvc", + }, + true, + ); + + if (this.showPayPal) { + this.braintreeService.loadBraintree("#braintree-container", false); + } + + if (!this.includeBillingAddress) { + this.group.controls.billingAddress.disable(); + } + + this.group.controls.type.valueChanges + .pipe(startWith(this.group.controls.type.value), takeUntil(this.destroy$)) + .subscribe((selected) => { + if (selected === "bankAccount") { + this.group.controls.bankAccount.enable(); + if (this.includeBillingAddress) { + this.group.controls.billingAddress.enable(); + } + } else { + switch (selected) { + case "card": { + this.stripeService.mountElements(); + if (this.includeBillingAddress) { + this.group.controls.billingAddress.enable(); + } + break; + } + case "payPal": { + this.braintreeService.createDropin(); + if (this.includeBillingAddress) { + this.group.controls.billingAddress.disable(); + } + break; + } + } + this.group.controls.bankAccount.disable(); + } + }); + + this.showBankAccount$.pipe(takeUntil(this.destroy$)).subscribe((showBankAccount) => { + if (!showBankAccount && this.selected === "bankAccount") { + this.select("card"); + } + }); + } + + select = (paymentMethod: PaymentMethodOption) => + this.group.controls.type.patchValue(paymentMethod); + + tokenize = async (): Promise => { + const exchange = async (paymentMethod: TokenizablePaymentMethod) => { + switch (paymentMethod) { + case "bankAccount": { + this.group.controls.bankAccount.markAllAsTouched(); + if (!this.group.controls.bankAccount.valid) { + throw new Error("Attempted to tokenize invalid bank account information."); + } + + const bankAccount = this.group.controls.bankAccount.getRawValue(); + const clientSecret = await this.stripeService.createSetupIntent("bankAccount"); + const billingDetails = this.group.controls.billingAddress.enabled + ? this.group.controls.billingAddress.getRawValue() + : undefined; + return await this.stripeService.setupBankAccountPaymentMethod( + clientSecret, + bankAccount, + billingDetails, + ); + } + case "card": { + const clientSecret = await this.stripeService.createSetupIntent("card"); + const billingDetails = this.group.controls.billingAddress.enabled + ? this.group.controls.billingAddress.getRawValue() + : undefined; + return this.stripeService.setupCardPaymentMethod(clientSecret, billingDetails); + } + case "payPal": { + return this.braintreeService.requestPaymentMethod(); + } + } + }; + + if (!isTokenizablePaymentMethod(this.selected)) { + throw new Error(`Attempted to tokenize a non-tokenizable payment method: ${this.selected}`); + } + + try { + const token = await exchange(this.selected); + return { type: this.selected, token }; + } catch (error: unknown) { + this.logService.error(error); + this.toastService.showToast({ + variant: "error", + title: "", + message: this.i18nService.t("problemSubmittingPaymentMethod"), + }); + throw error; + } + }; + + validate = (): boolean => { + if (this.selected === "bankAccount") { + this.group.controls.bankAccount.markAllAsTouched(); + return this.group.controls.bankAccount.valid; + } + + return true; + }; + + get selected(): PaymentMethodOption { + return this.group.value.type!; + } + + static getFormGroup = (): PaymentMethodFormGroup => + new FormGroup({ + type: new FormControl("card", { nonNullable: true }), + bankAccount: new FormGroup({ + routingNumber: new FormControl("", { + nonNullable: true, + validators: [Validators.required], + }), + accountNumber: new FormControl("", { + nonNullable: true, + validators: [Validators.required], + }), + accountHolderName: new FormControl("", { + nonNullable: true, + validators: [Validators.required], + }), + accountHolderType: new FormControl<"" | "company" | "individual">("", { + nonNullable: true, + validators: [Validators.required], + }), + }), + billingAddress: new FormGroup({ + country: new FormControl("", { + nonNullable: true, + validators: [Validators.required], + }), + postalCode: new FormControl("", { + nonNullable: true, + validators: [Validators.required], + }), + }), + }); +} diff --git a/apps/web/src/app/billing/payment/components/index.ts b/apps/web/src/app/billing/payment/components/index.ts new file mode 100644 index 00000000000..3bf7f5ecd36 --- /dev/null +++ b/apps/web/src/app/billing/payment/components/index.ts @@ -0,0 +1,9 @@ +export * from "./add-account-credit-dialog.component"; +export * from "./change-payment-method-dialog.component"; +export * from "./display-account-credit.component"; +export * from "./display-billing-address.component"; +export * from "./display-payment-method.component"; +export * from "./edit-billing-address-dialog.component"; +export * from "./enter-billing-address.component"; +export * from "./enter-payment-method.component"; +export * from "./verify-bank-account.component"; diff --git a/apps/web/src/app/billing/payment/components/verify-bank-account.component.ts b/apps/web/src/app/billing/payment/components/verify-bank-account.component.ts new file mode 100644 index 00000000000..f79e9a1b5fc --- /dev/null +++ b/apps/web/src/app/billing/payment/components/verify-bank-account.component.ts @@ -0,0 +1,86 @@ +import { Component, EventEmitter, Input, Output } from "@angular/core"; +import { FormControl, FormGroup, Validators } from "@angular/forms"; + +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { ToastService } from "@bitwarden/components"; + +import { SharedModule } from "../../../shared"; +import { BillingClient } from "../../services"; +import { BillableEntity } from "../../types"; +import { MaskedPaymentMethod } from "../types"; + +@Component({ + selector: "app-verify-bank-account", + template: ` + +

{{ "verifyBankAccountWithStatementDescriptorInstructions" | i18n }}

+
+ + {{ "descriptorCode" | i18n }} + + + +
+
+ `, + standalone: true, + imports: [SharedModule], + providers: [BillingClient], +}) +export class VerifyBankAccountComponent { + @Input({ required: true }) owner!: BillableEntity; + @Output() verified = new EventEmitter(); + + protected formGroup = new FormGroup({ + descriptorCode: new FormControl("", [ + Validators.required, + Validators.minLength(6), + Validators.maxLength(6), + ]), + }); + + constructor( + private billingClient: BillingClient, + private i18nService: I18nService, + private toastService: ToastService, + ) {} + + submit = async (): Promise => { + this.formGroup.markAllAsTouched(); + + if (!this.formGroup.valid) { + return; + } + + const result = await this.billingClient.verifyBankAccount( + this.owner, + this.formGroup.value.descriptorCode!, + ); + + switch (result.type) { + case "success": { + this.toastService.showToast({ + variant: "success", + title: "", + message: this.i18nService.t("bankAccountVerified"), + }); + this.verified.emit(result.value); + break; + } + case "error": { + this.toastService.showToast({ + variant: "error", + title: "", + message: result.message, + }); + } + } + }; +} diff --git a/apps/web/src/app/billing/payment/pipes/address.pipe.spec.ts b/apps/web/src/app/billing/payment/pipes/address.pipe.spec.ts new file mode 100644 index 00000000000..c497bbf2f0f --- /dev/null +++ b/apps/web/src/app/billing/payment/pipes/address.pipe.spec.ts @@ -0,0 +1,65 @@ +import { AddressPipe } from "./address.pipe"; + +describe("AddressPipe", () => { + let pipe: AddressPipe; + + beforeEach(() => { + pipe = new AddressPipe(); + }); + + it("should format a complete address with all fields", () => { + const address = { + country: "United States", + postalCode: "10001", + line1: "123 Main St", + line2: "Apt 4B", + city: "New York", + state: "NY", + }; + + const result = pipe.transform(address); + expect(result).toBe("123 Main St, Apt 4B, New York, NY, 10001, United States"); + }); + + it("should format address without line2", () => { + const address = { + country: "United States", + postalCode: "10001", + line1: "123 Main St", + line2: null, + city: "New York", + state: "NY", + }; + + const result = pipe.transform(address); + expect(result).toBe("123 Main St, New York, NY, 10001, United States"); + }); + + it("should format address without state", () => { + const address = { + country: "United Kingdom", + postalCode: "SW1A 1AA", + line1: "123 Main St", + line2: "Apt 4B", + city: "London", + state: null, + }; + + const result = pipe.transform(address); + expect(result).toBe("123 Main St, Apt 4B, London, SW1A 1AA, United Kingdom"); + }); + + it("should format minimal address with only required fields", () => { + const address = { + country: "United States", + postalCode: "10001", + line1: null, + line2: null, + city: null, + state: null, + }; + + const result = pipe.transform(address); + expect(result).toBe("10001, United States"); + }); +}); diff --git a/apps/web/src/app/billing/payment/pipes/address.pipe.ts b/apps/web/src/app/billing/payment/pipes/address.pipe.ts new file mode 100644 index 00000000000..da612950a27 --- /dev/null +++ b/apps/web/src/app/billing/payment/pipes/address.pipe.ts @@ -0,0 +1,32 @@ +import { Pipe, PipeTransform } from "@angular/core"; + +import { BillingAddress } from "../types"; + +@Pipe({ + name: "address", +}) +export class AddressPipe implements PipeTransform { + transform(address: Omit): string { + const parts: string[] = []; + + if (address.line1) { + parts.push(address.line1); + } + + if (address.line2) { + parts.push(address.line2); + } + + if (address.city) { + parts.push(address.city); + } + + if (address.state) { + parts.push(address.state); + } + + parts.push(address.postalCode, address.country); + + return parts.join(", "); + } +} diff --git a/apps/web/src/app/billing/payment/pipes/index.ts b/apps/web/src/app/billing/payment/pipes/index.ts new file mode 100644 index 00000000000..d95cff6b6f8 --- /dev/null +++ b/apps/web/src/app/billing/payment/pipes/index.ts @@ -0,0 +1 @@ +export * from "./address.pipe"; diff --git a/apps/web/src/app/billing/payment/types/billing-address.ts b/apps/web/src/app/billing/payment/types/billing-address.ts new file mode 100644 index 00000000000..eddb24673f5 --- /dev/null +++ b/apps/web/src/app/billing/payment/types/billing-address.ts @@ -0,0 +1,37 @@ +import { BaseResponse } from "@bitwarden/common/models/response/base.response"; + +import { TaxId, TaxIdResponse } from "./tax-id"; + +export type BillingAddress = { + country: string; + postalCode: string; + line1: string | null; + line2: string | null; + city: string | null; + state: string | null; + taxId: TaxId | null; +}; + +export class BillingAddressResponse extends BaseResponse implements BillingAddress { + country: string; + postalCode: string; + line1: string | null; + line2: string | null; + city: string | null; + state: string | null; + taxId: TaxId | null; + + constructor(response: any) { + super(response); + + this.country = this.getResponseProperty("Country"); + this.postalCode = this.getResponseProperty("PostalCode"); + this.line1 = this.getResponseProperty("Line1"); + this.line2 = this.getResponseProperty("Line2"); + this.city = this.getResponseProperty("City"); + this.state = this.getResponseProperty("State"); + + const taxId = this.getResponseProperty("TaxId"); + this.taxId = taxId ? new TaxIdResponse(taxId) : null; + } +} diff --git a/apps/web/src/app/billing/payment/types/index.ts b/apps/web/src/app/billing/payment/types/index.ts new file mode 100644 index 00000000000..a8534c5aba4 --- /dev/null +++ b/apps/web/src/app/billing/payment/types/index.ts @@ -0,0 +1,6 @@ +export * from "./billing-address"; +export * from "./masked-payment-method"; +export * from "./selectable-country"; +export * from "./tax-id"; +export * from "./tax-id-type"; +export * from "./tokenized-payment-method"; diff --git a/apps/web/src/app/billing/payment/types/masked-payment-method.ts b/apps/web/src/app/billing/payment/types/masked-payment-method.ts new file mode 100644 index 00000000000..8d07706b14c --- /dev/null +++ b/apps/web/src/app/billing/payment/types/masked-payment-method.ts @@ -0,0 +1,114 @@ +import { BaseResponse } from "@bitwarden/common/models/response/base.response"; + +import { + BankAccountPaymentMethod, + CardPaymentMethod, + PayPalPaymentMethod, +} from "./tokenized-payment-method"; + +export const StripeCardBrands = { + amex: "amex", + diners: "diners", + discover: "discover", + eftpos_au: "eftpos_au", + jcb: "jcb", + link: "link", + mastercard: "mastercard", + unionpay: "unionpay", + visa: "visa", + unknown: "unknown", +} as const; + +export type StripeCardBrand = (typeof StripeCardBrands)[keyof typeof StripeCardBrands]; + +type MaskedBankAccount = { + type: BankAccountPaymentMethod; + bankName: string; + last4: string; + verified: boolean; +}; + +type MaskedCard = { + type: CardPaymentMethod; + brand: StripeCardBrand; + last4: string; + expiration: string; +}; + +type MaskedPayPalAccount = { + type: PayPalPaymentMethod; + email: string; +}; + +export type MaskedPaymentMethod = MaskedBankAccount | MaskedCard | MaskedPayPalAccount; + +export class MaskedPaymentMethodResponse extends BaseResponse { + value: MaskedPaymentMethod; + + constructor(response: any) { + super(response); + + const type = this.getResponseProperty("Type"); + switch (type) { + case "card": { + this.value = new MaskedCardResponse(response); + break; + } + case "bankAccount": { + this.value = new MaskedBankAccountResponse(response); + break; + } + case "payPal": { + this.value = new MaskedPayPalAccountResponse(response); + break; + } + default: { + throw new Error(`Cannot deserialize unsupported payment method type: ${type}`); + } + } + } +} + +class MaskedBankAccountResponse extends BaseResponse implements MaskedBankAccount { + type: BankAccountPaymentMethod; + bankName: string; + last4: string; + verified: boolean; + + constructor(response: any) { + super(response); + + this.type = "bankAccount"; + this.bankName = this.getResponseProperty("BankName"); + this.last4 = this.getResponseProperty("Last4"); + this.verified = this.getResponseProperty("Verified"); + } +} + +class MaskedCardResponse extends BaseResponse implements MaskedCard { + type: CardPaymentMethod; + brand: StripeCardBrand; + last4: string; + expiration: string; + + constructor(response: any) { + super(response); + + this.type = "card"; + this.brand = this.getResponseProperty("Brand"); + this.last4 = this.getResponseProperty("Last4"); + this.expiration = this.getResponseProperty("Expiration"); + } +} + +class MaskedPayPalAccountResponse extends BaseResponse implements MaskedPayPalAccount { + type: PayPalPaymentMethod; + email: string; + + constructor(response: any) { + super(response); + + this.type = "payPal"; + this.email = this.getResponseProperty("Email"); + } +} diff --git a/apps/web/src/app/billing/payment/types/selectable-country.ts b/apps/web/src/app/billing/payment/types/selectable-country.ts new file mode 100644 index 00000000000..71d6af95cc7 --- /dev/null +++ b/apps/web/src/app/billing/payment/types/selectable-country.ts @@ -0,0 +1,259 @@ +type SelectableCountry = Readonly<{ + name: string; + value: string; + disabled: boolean; +}>; + +export const selectableCountries: ReadonlyArray = [ + { name: "-- Select --", value: "", disabled: false }, + { name: "United States", value: "US", disabled: false }, + { name: "China", value: "CN", disabled: false }, + { name: "France", value: "FR", disabled: false }, + { name: "Germany", value: "DE", disabled: false }, + { name: "Canada", value: "CA", disabled: false }, + { name: "United Kingdom", value: "GB", disabled: false }, + { name: "Australia", value: "AU", disabled: false }, + { name: "India", value: "IN", disabled: false }, + { name: "", value: "-", disabled: true }, + { name: "Afghanistan", value: "AF", disabled: false }, + { name: "Åland Islands", value: "AX", disabled: false }, + { name: "Albania", value: "AL", disabled: false }, + { name: "Algeria", value: "DZ", disabled: false }, + { name: "American Samoa", value: "AS", disabled: false }, + { name: "Andorra", value: "AD", disabled: false }, + { name: "Angola", value: "AO", disabled: false }, + { name: "Anguilla", value: "AI", disabled: false }, + { name: "Antarctica", value: "AQ", disabled: false }, + { name: "Antigua and Barbuda", value: "AG", disabled: false }, + { name: "Argentina", value: "AR", disabled: false }, + { name: "Armenia", value: "AM", disabled: false }, + { name: "Aruba", value: "AW", disabled: false }, + { name: "Austria", value: "AT", disabled: false }, + { name: "Azerbaijan", value: "AZ", disabled: false }, + { name: "Bahamas", value: "BS", disabled: false }, + { name: "Bahrain", value: "BH", disabled: false }, + { name: "Bangladesh", value: "BD", disabled: false }, + { name: "Barbados", value: "BB", disabled: false }, + { name: "Belarus", value: "BY", disabled: false }, + { name: "Belgium", value: "BE", disabled: false }, + { name: "Belize", value: "BZ", disabled: false }, + { name: "Benin", value: "BJ", disabled: false }, + { name: "Bermuda", value: "BM", disabled: false }, + { name: "Bhutan", value: "BT", disabled: false }, + { name: "Bolivia, Plurinational State of", value: "BO", disabled: false }, + { name: "Bonaire, Sint Eustatius and Saba", value: "BQ", disabled: false }, + { name: "Bosnia and Herzegovina", value: "BA", disabled: false }, + { name: "Botswana", value: "BW", disabled: false }, + { name: "Bouvet Island", value: "BV", disabled: false }, + { name: "Brazil", value: "BR", disabled: false }, + { name: "British Indian Ocean Territory", value: "IO", disabled: false }, + { name: "Brunei Darussalam", value: "BN", disabled: false }, + { name: "Bulgaria", value: "BG", disabled: false }, + { name: "Burkina Faso", value: "BF", disabled: false }, + { name: "Burundi", value: "BI", disabled: false }, + { name: "Cambodia", value: "KH", disabled: false }, + { name: "Cameroon", value: "CM", disabled: false }, + { name: "Cape Verde", value: "CV", disabled: false }, + { name: "Cayman Islands", value: "KY", disabled: false }, + { name: "Central African Republic", value: "CF", disabled: false }, + { name: "Chad", value: "TD", disabled: false }, + { name: "Chile", value: "CL", disabled: false }, + { name: "Christmas Island", value: "CX", disabled: false }, + { name: "Cocos (Keeling) Islands", value: "CC", disabled: false }, + { name: "Colombia", value: "CO", disabled: false }, + { name: "Comoros", value: "KM", disabled: false }, + { name: "Congo", value: "CG", disabled: false }, + { name: "Congo, the Democratic Republic of the", value: "CD", disabled: false }, + { name: "Cook Islands", value: "CK", disabled: false }, + { name: "Costa Rica", value: "CR", disabled: false }, + { name: "Côte d'Ivoire", value: "CI", disabled: false }, + { name: "Croatia", value: "HR", disabled: false }, + { name: "Cuba", value: "CU", disabled: false }, + { name: "Curaçao", value: "CW", disabled: false }, + { name: "Cyprus", value: "CY", disabled: false }, + { name: "Czech Republic", value: "CZ", disabled: false }, + { name: "Denmark", value: "DK", disabled: false }, + { name: "Djibouti", value: "DJ", disabled: false }, + { name: "Dominica", value: "DM", disabled: false }, + { name: "Dominican Republic", value: "DO", disabled: false }, + { name: "Ecuador", value: "EC", disabled: false }, + { name: "Egypt", value: "EG", disabled: false }, + { name: "El Salvador", value: "SV", disabled: false }, + { name: "Equatorial Guinea", value: "GQ", disabled: false }, + { name: "Eritrea", value: "ER", disabled: false }, + { name: "Estonia", value: "EE", disabled: false }, + { name: "Ethiopia", value: "ET", disabled: false }, + { name: "Falkland Islands (Malvinas)", value: "FK", disabled: false }, + { name: "Faroe Islands", value: "FO", disabled: false }, + { name: "Fiji", value: "FJ", disabled: false }, + { name: "Finland", value: "FI", disabled: false }, + { name: "French Guiana", value: "GF", disabled: false }, + { name: "French Polynesia", value: "PF", disabled: false }, + { name: "French Southern Territories", value: "TF", disabled: false }, + { name: "Gabon", value: "GA", disabled: false }, + { name: "Gambia", value: "GM", disabled: false }, + { name: "Georgia", value: "GE", disabled: false }, + { name: "Ghana", value: "GH", disabled: false }, + { name: "Gibraltar", value: "GI", disabled: false }, + { name: "Greece", value: "GR", disabled: false }, + { name: "Greenland", value: "GL", disabled: false }, + { name: "Grenada", value: "GD", disabled: false }, + { name: "Guadeloupe", value: "GP", disabled: false }, + { name: "Guam", value: "GU", disabled: false }, + { name: "Guatemala", value: "GT", disabled: false }, + { name: "Guernsey", value: "GG", disabled: false }, + { name: "Guinea", value: "GN", disabled: false }, + { name: "Guinea-Bissau", value: "GW", disabled: false }, + { name: "Guyana", value: "GY", disabled: false }, + { name: "Haiti", value: "HT", disabled: false }, + { name: "Heard Island and McDonald Islands", value: "HM", disabled: false }, + { name: "Holy See (Vatican City State)", value: "VA", disabled: false }, + { name: "Honduras", value: "HN", disabled: false }, + { name: "Hong Kong", value: "HK", disabled: false }, + { name: "Hungary", value: "HU", disabled: false }, + { name: "Iceland", value: "IS", disabled: false }, + { name: "Indonesia", value: "ID", disabled: false }, + { name: "Iran, Islamic Republic of", value: "IR", disabled: false }, + { name: "Iraq", value: "IQ", disabled: false }, + { name: "Ireland", value: "IE", disabled: false }, + { name: "Isle of Man", value: "IM", disabled: false }, + { name: "Israel", value: "IL", disabled: false }, + { name: "Italy", value: "IT", disabled: false }, + { name: "Jamaica", value: "JM", disabled: false }, + { name: "Japan", value: "JP", disabled: false }, + { name: "Jersey", value: "JE", disabled: false }, + { name: "Jordan", value: "JO", disabled: false }, + { name: "Kazakhstan", value: "KZ", disabled: false }, + { name: "Kenya", value: "KE", disabled: false }, + { name: "Kiribati", value: "KI", disabled: false }, + { name: "Korea, Democratic People's Republic of", value: "KP", disabled: false }, + { name: "Korea, Republic of", value: "KR", disabled: false }, + { name: "Kuwait", value: "KW", disabled: false }, + { name: "Kyrgyzstan", value: "KG", disabled: false }, + { name: "Lao People's Democratic Republic", value: "LA", disabled: false }, + { name: "Latvia", value: "LV", disabled: false }, + { name: "Lebanon", value: "LB", disabled: false }, + { name: "Lesotho", value: "LS", disabled: false }, + { name: "Liberia", value: "LR", disabled: false }, + { name: "Libya", value: "LY", disabled: false }, + { name: "Liechtenstein", value: "LI", disabled: false }, + { name: "Lithuania", value: "LT", disabled: false }, + { name: "Luxembourg", value: "LU", disabled: false }, + { name: "Macao", value: "MO", disabled: false }, + { name: "Macedonia, the former Yugoslav Republic of", value: "MK", disabled: false }, + { name: "Madagascar", value: "MG", disabled: false }, + { name: "Malawi", value: "MW", disabled: false }, + { name: "Malaysia", value: "MY", disabled: false }, + { name: "Maldives", value: "MV", disabled: false }, + { name: "Mali", value: "ML", disabled: false }, + { name: "Malta", value: "MT", disabled: false }, + { name: "Marshall Islands", value: "MH", disabled: false }, + { name: "Martinique", value: "MQ", disabled: false }, + { name: "Mauritania", value: "MR", disabled: false }, + { name: "Mauritius", value: "MU", disabled: false }, + { name: "Mayotte", value: "YT", disabled: false }, + { name: "Mexico", value: "MX", disabled: false }, + { name: "Micronesia, Federated States of", value: "FM", disabled: false }, + { name: "Moldova, Republic of", value: "MD", disabled: false }, + { name: "Monaco", value: "MC", disabled: false }, + { name: "Mongolia", value: "MN", disabled: false }, + { name: "Montenegro", value: "ME", disabled: false }, + { name: "Montserrat", value: "MS", disabled: false }, + { name: "Morocco", value: "MA", disabled: false }, + { name: "Mozambique", value: "MZ", disabled: false }, + { name: "Myanmar", value: "MM", disabled: false }, + { name: "Namibia", value: "NA", disabled: false }, + { name: "Nauru", value: "NR", disabled: false }, + { name: "Nepal", value: "NP", disabled: false }, + { name: "Netherlands", value: "NL", disabled: false }, + { name: "New Caledonia", value: "NC", disabled: false }, + { name: "New Zealand", value: "NZ", disabled: false }, + { name: "Nicaragua", value: "NI", disabled: false }, + { name: "Niger", value: "NE", disabled: false }, + { name: "Nigeria", value: "NG", disabled: false }, + { name: "Niue", value: "NU", disabled: false }, + { name: "Norfolk Island", value: "NF", disabled: false }, + { name: "Northern Mariana Islands", value: "MP", disabled: false }, + { name: "Norway", value: "NO", disabled: false }, + { name: "Oman", value: "OM", disabled: false }, + { name: "Pakistan", value: "PK", disabled: false }, + { name: "Palau", value: "PW", disabled: false }, + { name: "Palestinian Territory, Occupied", value: "PS", disabled: false }, + { name: "Panama", value: "PA", disabled: false }, + { name: "Papua New Guinea", value: "PG", disabled: false }, + { name: "Paraguay", value: "PY", disabled: false }, + { name: "Peru", value: "PE", disabled: false }, + { name: "Philippines", value: "PH", disabled: false }, + { name: "Pitcairn", value: "PN", disabled: false }, + { name: "Poland", value: "PL", disabled: false }, + { name: "Portugal", value: "PT", disabled: false }, + { name: "Puerto Rico", value: "PR", disabled: false }, + { name: "Qatar", value: "QA", disabled: false }, + { name: "Réunion", value: "RE", disabled: false }, + { name: "Romania", value: "RO", disabled: false }, + { name: "Russian Federation", value: "RU", disabled: false }, + { name: "Rwanda", value: "RW", disabled: false }, + { name: "Saint Barthélemy", value: "BL", disabled: false }, + { name: "Saint Helena, Ascension and Tristan da Cunha", value: "SH", disabled: false }, + { name: "Saint Kitts and Nevis", value: "KN", disabled: false }, + { name: "Saint Lucia", value: "LC", disabled: false }, + { name: "Saint Martin (French part)", value: "MF", disabled: false }, + { name: "Saint Pierre and Miquelon", value: "PM", disabled: false }, + { name: "Saint Vincent and the Grenadines", value: "VC", disabled: false }, + { name: "Samoa", value: "WS", disabled: false }, + { name: "San Marino", value: "SM", disabled: false }, + { name: "Sao Tome and Principe", value: "ST", disabled: false }, + { name: "Saudi Arabia", value: "SA", disabled: false }, + { name: "Senegal", value: "SN", disabled: false }, + { name: "Serbia", value: "RS", disabled: false }, + { name: "Seychelles", value: "SC", disabled: false }, + { name: "Sierra Leone", value: "SL", disabled: false }, + { name: "Singapore", value: "SG", disabled: false }, + { name: "Sint Maarten (Dutch part)", value: "SX", disabled: false }, + { name: "Slovakia", value: "SK", disabled: false }, + { name: "Slovenia", value: "SI", disabled: false }, + { name: "Solomon Islands", value: "SB", disabled: false }, + { name: "Somalia", value: "SO", disabled: false }, + { name: "South Africa", value: "ZA", disabled: false }, + { name: "South Georgia and the South Sandwich Islands", value: "GS", disabled: false }, + { name: "South Sudan", value: "SS", disabled: false }, + { name: "Spain", value: "ES", disabled: false }, + { name: "Sri Lanka", value: "LK", disabled: false }, + { name: "Sudan", value: "SD", disabled: false }, + { name: "Suriname", value: "SR", disabled: false }, + { name: "Svalbard and Jan Mayen", value: "SJ", disabled: false }, + { name: "Swaziland", value: "SZ", disabled: false }, + { name: "Sweden", value: "SE", disabled: false }, + { name: "Switzerland", value: "CH", disabled: false }, + { name: "Syrian Arab Republic", value: "SY", disabled: false }, + { name: "Taiwan", value: "TW", disabled: false }, + { name: "Tajikistan", value: "TJ", disabled: false }, + { name: "Tanzania, United Republic of", value: "TZ", disabled: false }, + { name: "Thailand", value: "TH", disabled: false }, + { name: "Timor-Leste", value: "TL", disabled: false }, + { name: "Togo", value: "TG", disabled: false }, + { name: "Tokelau", value: "TK", disabled: false }, + { name: "Tonga", value: "TO", disabled: false }, + { name: "Trinidad and Tobago", value: "TT", disabled: false }, + { name: "Tunisia", value: "TN", disabled: false }, + { name: "Turkey", value: "TR", disabled: false }, + { name: "Turkmenistan", value: "TM", disabled: false }, + { name: "Turks and Caicos Islands", value: "TC", disabled: false }, + { name: "Tuvalu", value: "TV", disabled: false }, + { name: "Uganda", value: "UG", disabled: false }, + { name: "Ukraine", value: "UA", disabled: false }, + { name: "United Arab Emirates", value: "AE", disabled: false }, + { name: "United States Minor Outlying Islands", value: "UM", disabled: false }, + { name: "Uruguay", value: "UY", disabled: false }, + { name: "Uzbekistan", value: "UZ", disabled: false }, + { name: "Vanuatu", value: "VU", disabled: false }, + { name: "Venezuela, Bolivarian Republic of", value: "VE", disabled: false }, + { name: "Viet Nam", value: "VN", disabled: false }, + { name: "Virgin Islands, British", value: "VG", disabled: false }, + { name: "Virgin Islands, U.S.", value: "VI", disabled: false }, + { name: "Wallis and Futuna", value: "WF", disabled: false }, + { name: "Western Sahara", value: "EH", disabled: false }, + { name: "Yemen", value: "YE", disabled: false }, + { name: "Zambia", value: "ZM", disabled: false }, + { name: "Zimbabwe", value: "ZW", disabled: false }, +]; diff --git a/apps/web/src/app/billing/payment/types/tax-id-type.ts b/apps/web/src/app/billing/payment/types/tax-id-type.ts new file mode 100644 index 00000000000..8f6264e088c --- /dev/null +++ b/apps/web/src/app/billing/payment/types/tax-id-type.ts @@ -0,0 +1,1123 @@ +export type TaxIdType = Readonly<{ + country: string; + iso: string; + code: string; + description: string; + example: string; + impactsTaxCalculation: boolean; +}>; + +export const getTaxIdTypeForCountry = (country: string): TaxIdType | null => { + const types = taxIdTypes.filter((type) => type.iso === country); + if (types.length === 0) { + return null; + } else if (types.length === 1) { + return types[0]; + } else { + const impactful = types.find((taxIdType) => taxIdType.impactsTaxCalculation); + if (!impactful) { + return types[0]; + } + return impactful; + } +}; + +export const taxIdTypes: ReadonlyArray = [ + { + country: "Albania", + iso: "AL", + code: "al_tin", + description: "Albania Tax Identification Number", + example: "J12345678N", + impactsTaxCalculation: true, + }, + { + country: "Andorra", + iso: "AD", + code: "ad_nrt", + description: "Andorran NRT number", + example: "A-123456-Z", + impactsTaxCalculation: false, + }, + { + country: "Angola", + iso: "AO", + code: "ao_tin", + description: "Angola Tax Identification Number", + example: "5123456789", + impactsTaxCalculation: false, + }, + { + country: "Argentina", + iso: "AR", + code: "ar_cuit", + description: "Argentinian tax ID number", + example: "12-3456789-01", + impactsTaxCalculation: false, + }, + { + country: "Armenia", + iso: "AM", + code: "am_tin", + description: "Armenia Tax Identification Number", + example: "2538904", + impactsTaxCalculation: true, + }, + { + country: "Aruba", + iso: "AW", + code: "aw_tin", + description: "Aruba Tax Identification Number", + example: "12345678", + impactsTaxCalculation: true, + }, + { + country: "Australia", + iso: "AU", + code: "au_abn", + description: "Australian Business Number (AU ABN)", + example: "12345678912", + impactsTaxCalculation: true, + }, + { + country: "Australia", + iso: "AU", + code: "au_arn", + description: "Australian Taxation Office Reference Number", + example: "123456789123", + impactsTaxCalculation: false, + }, + { + country: "Austria", + iso: "AT", + code: "eu_vat", + description: "European VAT number", + example: "ATU12345678", + impactsTaxCalculation: true, + }, + { + country: "Azerbaijan", + iso: "AZ", + code: "az_tin", + description: "Azerbaijan Tax Identification Number", + example: "123456789", + impactsTaxCalculation: true, + }, + { + country: "Bahamas", + iso: "BS", + code: "bs_tin", + description: "Bahamas Tax Identification Number", + example: "123.456.789", + impactsTaxCalculation: false, + }, + { + country: "Bahrain", + iso: "BH", + code: "bh_vat", + description: "Bahraini VAT Number", + example: "123456789012345", + impactsTaxCalculation: true, + }, + { + country: "Bangladesh", + iso: "BD", + code: "bd_bin", + description: "Bangladesh Business Identification Number", + example: "123456789-0123", + impactsTaxCalculation: true, + }, + { + country: "Barbados", + iso: "BB", + code: "bb_tin", + description: "Barbados Tax Identification Number", + example: "1123456789012", + impactsTaxCalculation: false, + }, + { + country: "Belarus", + iso: "BY", + code: "by_tin", + description: "Belarus TIN Number", + example: "123456789", + impactsTaxCalculation: true, + }, + { + country: "Belgium", + iso: "BE", + code: "eu_vat", + description: "European VAT number", + example: "BE0123456789", + impactsTaxCalculation: true, + }, + { + country: "Benin", + iso: "BJ", + code: "bj_ifu", + description: "Benin Tax Identification Number (Identifiant Fiscal Unique)", + example: "1234567890123", + impactsTaxCalculation: true, + }, + { + country: "Bolivia", + iso: "BO", + code: "bo_tin", + description: "Bolivian tax ID", + example: "123456789", + impactsTaxCalculation: false, + }, + { + country: "Bosnia & Herzegovina", + iso: "BA", + code: "ba_tin", + description: "Bosnia and Herzegovina Tax Identification Number", + example: "123456789012", + impactsTaxCalculation: true, + }, + { + country: "Brazil", + iso: "BR", + code: "br_cnpj", + description: "Brazilian CNPJ number", + example: "01.234.456/5432-10", + impactsTaxCalculation: false, + }, + { + country: "Brazil", + iso: "BR", + code: "br_cpf", + description: "Brazilian CPF number", + example: "123.456.789-87", + impactsTaxCalculation: false, + }, + { + country: "Bulgaria", + iso: "BG", + code: "bg_uic", + description: "Bulgaria Unified Identification Code", + example: "123456789", + impactsTaxCalculation: false, + }, + { + country: "Bulgaria", + iso: "BG", + code: "eu_vat", + description: "European VAT number", + example: "BG0123456789", + impactsTaxCalculation: true, + }, + { + country: "Burkina Faso", + iso: "BF", + code: "bf_ifu", + description: "Burkina Faso Tax Identification Number (Numéro d'Identifiant Fiscal Unique)", + example: "12345678A", + impactsTaxCalculation: true, + }, + { + country: "Cambodia", + iso: "KH", + code: "kh_tin", + description: "Cambodia Tax Identification Number", + example: "1001-123456789", + impactsTaxCalculation: true, + }, + { + country: "Cameroon", + iso: "CM", + code: "cm_niu", + description: "Cameroon Tax Identification Number (Numéro d'Identifiant fiscal Unique)", + example: "M123456789000L", + impactsTaxCalculation: false, + }, + { + country: "Canada", + iso: "CA", + code: "ca_bn", + description: "Canadian BN", + example: "123456789", + impactsTaxCalculation: false, + }, + { + country: "Canada", + iso: "CA", + code: "ca_gst_hst", + description: "Canadian GST/HST number", + example: "123456789RT0002", + impactsTaxCalculation: true, + }, + { + country: "Canada", + iso: "CA", + code: "ca_pst_bc", + description: "Canadian PST number (British Columbia)", + example: "PST-1234-5678", + impactsTaxCalculation: false, + }, + { + country: "Canada", + iso: "CA", + code: "ca_pst_mb", + description: "Canadian PST number (Manitoba)", + example: "123456-7", + impactsTaxCalculation: false, + }, + { + country: "Canada", + iso: "CA", + code: "ca_pst_sk", + description: "Canadian PST number (Saskatchewan)", + example: "1234567", + impactsTaxCalculation: false, + }, + { + country: "Canada", + iso: "CA", + code: "ca_qst", + description: "Canadian QST number (Québec)", + example: "1234567890TQ1234", + impactsTaxCalculation: true, + }, + { + country: "Cape Verde", + iso: "CV", + code: "cv_nif", + description: "Cape Verde Tax Identification Number (Número de Identificação Fiscal)", + example: "213456789", + impactsTaxCalculation: false, + }, + { + country: "Chile", + iso: "CL", + code: "cl_tin", + description: "Chilean TIN", + example: "12.345.678-K", + impactsTaxCalculation: true, + }, + { + country: "China", + iso: "CN", + code: "cn_tin", + description: "Chinese tax ID", + example: "123456789012345678", + impactsTaxCalculation: false, + }, + { + country: "Colombia", + iso: "CO", + code: "co_nit", + description: "Colombian NIT number", + example: "123.456.789-0", + impactsTaxCalculation: false, + }, + { + country: "Congo - Kinshasa", + iso: "CD", + code: "cd_nif", + description: "Congo (DR) Tax Identification Number (Número de Identificação Fiscal)", + example: "A0123456M", + impactsTaxCalculation: false, + }, + { + country: "Costa Rica", + iso: "CR", + code: "cr_tin", + description: "Costa Rican tax ID", + example: "1-234-567890", + impactsTaxCalculation: false, + }, + { + country: "Croatia", + iso: "HR", + code: "eu_vat", + description: "European VAT number", + example: "HR12345678912", + impactsTaxCalculation: true, + }, + { + country: "Croatia", + iso: "HR", + code: "hr_oib", + description: "Croatian Personal Identification Number", + example: "12345678901", + impactsTaxCalculation: false, + }, + { + country: "Cyprus", + iso: "CY", + code: "eu_vat", + description: "European VAT number", + example: "CY12345678Z", + impactsTaxCalculation: true, + }, + { + country: "Czech Republic", + iso: "CZ", + code: "eu_vat", + description: "European VAT number", + example: "CZ1234567890", + impactsTaxCalculation: true, + }, + { + country: "Denmark", + iso: "DK", + code: "eu_vat", + description: "European VAT number", + example: "DK12345678", + impactsTaxCalculation: true, + }, + { + country: "Dominican Republic", + iso: "DO", + code: "do_rcn", + description: "Dominican RCN number", + example: "123-4567890-1", + impactsTaxCalculation: false, + }, + { + country: "Ecuador", + iso: "EC", + code: "ec_ruc", + description: "Ecuadorian RUC number", + example: "1234567890001", + impactsTaxCalculation: false, + }, + { + country: "Egypt", + iso: "EG", + code: "eg_tin", + description: "Egyptian Tax Identification Number", + example: "123456789", + impactsTaxCalculation: true, + }, + { + country: "El Salvador", + iso: "SV", + code: "sv_nit", + description: "El Salvadorian NIT number", + example: "1234-567890-123-4", + impactsTaxCalculation: false, + }, + { + country: "Estonia", + iso: "EE", + code: "eu_vat", + description: "European VAT number", + example: "EE123456789", + impactsTaxCalculation: true, + }, + { + country: "Ethiopia", + iso: "ET", + code: "et_tin", + description: "Ethiopia Tax Identification Number", + example: "1234567890", + impactsTaxCalculation: true, + }, + { + country: "EU", + iso: "EU", + code: "eu_oss_vat", + description: "European One Stop Shop VAT number for non-Union scheme", + example: "EU123456789", + impactsTaxCalculation: false, + }, + { + country: "Finland", + iso: "FI", + code: "eu_vat", + description: "European VAT number", + example: "FI12345678", + impactsTaxCalculation: true, + }, + { + country: "France", + iso: "FR", + code: "eu_vat", + description: "European VAT number", + example: "FRAB123456789", + impactsTaxCalculation: true, + }, + { + country: "Georgia", + iso: "GE", + code: "ge_vat", + description: "Georgian VAT", + example: "123456789", + impactsTaxCalculation: true, + }, + { + country: "Germany", + iso: "DE", + code: "de_stn", + description: "German Tax Number (Steuernummer)", + example: "1234567890", + impactsTaxCalculation: false, + }, + { + country: "Germany", + iso: "DE", + code: "eu_vat", + description: "European VAT number", + example: "DE123456789", + impactsTaxCalculation: true, + }, + { + country: "Greece", + iso: "GR", + code: "eu_vat", + description: "European VAT number", + example: "EL123456789", + impactsTaxCalculation: true, + }, + { + country: "Guinea", + iso: "GN", + code: "gn_nif", + description: "Guinea Tax Identification Number (Número de Identificação Fiscal)", + example: "123456789", + impactsTaxCalculation: true, + }, + { + country: "Hong Kong", + iso: "HK", + code: "hk_br", + description: "Hong Kong BR number", + example: "12345678", + impactsTaxCalculation: false, + }, + { + country: "Hungary", + iso: "HU", + code: "eu_vat", + description: "European VAT number", + example: "HU12345678", + impactsTaxCalculation: true, + }, + { + country: "Hungary", + iso: "HU", + code: "hu_tin", + description: "Hungary tax number (adószám)", + example: "12345678-1-23", + impactsTaxCalculation: false, + }, + { + country: "Iceland", + iso: "IS", + code: "is_vat", + description: "Icelandic VAT", + example: "123456", + impactsTaxCalculation: true, + }, + { + country: "India", + iso: "IN", + code: "in_gst", + description: "Indian GST number", + example: "12ABCDE3456FGZH", + impactsTaxCalculation: true, + }, + { + country: "Indonesia", + iso: "ID", + code: "id_npwp", + description: "Indonesian NPWP number", + example: "012.345.678.9-012.345", + impactsTaxCalculation: false, + }, + { + country: "Ireland", + iso: "IE", + code: "eu_vat", + description: "European VAT number", + example: "IE1234567AB", + impactsTaxCalculation: true, + }, + { + country: "Israel", + iso: "IL", + code: "il_vat", + description: "Israel VAT", + example: "12345", + impactsTaxCalculation: false, + }, + { + country: "Italy", + iso: "IT", + code: "eu_vat", + description: "European VAT number", + example: "IT12345678912", + impactsTaxCalculation: true, + }, + { + country: "Japan", + iso: "JP", + code: "jp_cn", + description: "Japanese Corporate Number (*Hōjin Bangō*)", + example: "1234567891234", + impactsTaxCalculation: false, + }, + { + country: "Japan", + iso: "JP", + code: "jp_rn", + description: + "Japanese Registered Foreign Businesses' Registration Number (*Tōroku Kokugai Jigyōsha no Tōroku Bangō*)", + example: "12345", + impactsTaxCalculation: false, + }, + { + country: "Japan", + iso: "JP", + code: "jp_trn", + description: "Japanese Tax Registration Number (*Tōroku Bangō*)", + example: "T1234567891234", + impactsTaxCalculation: true, + }, + { + country: "Kazakhstan", + iso: "KZ", + code: "kz_bin", + description: "Kazakhstani Business Identification Number", + example: "123456789012", + impactsTaxCalculation: true, + }, + { + country: "Kenya", + iso: "KE", + code: "ke_pin", + description: "Kenya Revenue Authority Personal Identification Number", + example: "P000111111A", + impactsTaxCalculation: false, + }, + { + country: "Kyrgyzstan", + iso: "KG", + code: "kg_tin", + description: "Kyrgyzstan Tax Identification Number", + example: "12345678901234", + impactsTaxCalculation: false, + }, + { + country: "Laos", + iso: "LA", + code: "la_tin", + description: "Laos Tax Identification Number", + example: "123456789-000", + impactsTaxCalculation: false, + }, + { + country: "Latvia", + iso: "LV", + code: "eu_vat", + description: "European VAT number", + example: "LV12345678912", + impactsTaxCalculation: true, + }, + { + country: "Liechtenstein", + iso: "LI", + code: "li_uid", + description: "Liechtensteinian UID number", + example: "CHE123456789", + impactsTaxCalculation: false, + }, + { + country: "Liechtenstein", + iso: "LI", + code: "li_vat", + description: "Liechtensteinian VAT number", + example: "12345", + impactsTaxCalculation: true, + }, + { + country: "Lithuania", + iso: "LT", + code: "eu_vat", + description: "European VAT number", + example: "LT123456789123", + impactsTaxCalculation: true, + }, + { + country: "Luxembourg", + iso: "LU", + code: "eu_vat", + description: "European VAT number", + example: "LU12345678", + impactsTaxCalculation: true, + }, + { + country: "Malaysia", + iso: "MY", + code: "my_frp", + description: "Malaysian FRP number", + example: "12345678", + impactsTaxCalculation: false, + }, + { + country: "Malaysia", + iso: "MY", + code: "my_itn", + description: "Malaysian ITN", + example: "C 1234567890", + impactsTaxCalculation: false, + }, + { + country: "Malaysia", + iso: "MY", + code: "my_sst", + description: "Malaysian SST number", + example: "A12-3456-78912345", + impactsTaxCalculation: false, + }, + { + country: "Malta", + iso: "MT", + code: "eu_vat", + description: "European VAT number", + example: "MT12345678", + impactsTaxCalculation: true, + }, + { + country: "Mauritania", + iso: "MR", + code: "mr_nif", + description: "Mauritania Tax Identification Number (Número de Identificação Fiscal)", + example: "12345678", + impactsTaxCalculation: false, + }, + { + country: "Mexico", + iso: "MX", + code: "mx_rfc", + description: "Mexican RFC number", + example: "ABC010203AB9", + impactsTaxCalculation: false, + }, + { + country: "Moldova", + iso: "MD", + code: "md_vat", + description: "Moldova VAT Number", + example: "1234567", + impactsTaxCalculation: true, + }, + { + country: "Montenegro", + iso: "ME", + code: "me_pib", + description: "Montenegro PIB Number", + example: "12345678", + impactsTaxCalculation: false, + }, + { + country: "Morocco", + iso: "MA", + code: "ma_vat", + description: "Morocco VAT Number", + example: "12345678", + impactsTaxCalculation: true, + }, + { + country: "Nepal", + iso: "NP", + code: "np_pan", + description: "Nepal PAN Number", + example: "123456789", + impactsTaxCalculation: true, + }, + { + country: "Netherlands", + iso: "NL", + code: "eu_vat", + description: "European VAT number", + example: "NL123456789B12", + impactsTaxCalculation: true, + }, + { + country: "New Zealand", + iso: "NZ", + code: "nz_gst", + description: "New Zealand GST number", + example: "123456789", + impactsTaxCalculation: true, + }, + { + country: "Nigeria", + iso: "NG", + code: "ng_tin", + description: "Nigerian Tax Identification Number", + example: "12345678-0001", + impactsTaxCalculation: false, + }, + { + country: "North Macedonia", + iso: "MK", + code: "mk_vat", + description: "North Macedonia VAT Number", + example: "MK1234567890123", + impactsTaxCalculation: true, + }, + { + country: "Norway", + iso: "NO", + code: "no_vat", + description: "Norwegian VAT number", + example: "123456789MVA", + impactsTaxCalculation: true, + }, + { + country: "Norway", + iso: "NO", + code: "no_voec", + description: "Norwegian VAT on e-commerce number", + example: "1234567", + impactsTaxCalculation: false, + }, + { + country: "Oman", + iso: "OM", + code: "om_vat", + description: "Omani VAT Number", + example: "OM1234567890", + impactsTaxCalculation: true, + }, + { + country: "Peru", + iso: "PE", + code: "pe_ruc", + description: "Peruvian RUC number", + example: "12345678901", + impactsTaxCalculation: true, + }, + { + country: "Philippines", + iso: "PH", + code: "ph_tin", + description: "Philippines Tax Identification Number", + example: "123456789012", + impactsTaxCalculation: true, + }, + { + country: "Poland", + iso: "PL", + code: "eu_vat", + description: "European VAT number", + example: "PL1234567890", + impactsTaxCalculation: true, + }, + { + country: "Portugal", + iso: "PT", + code: "eu_vat", + description: "European VAT number", + example: "PT123456789", + impactsTaxCalculation: true, + }, + { + country: "Romania", + iso: "RO", + code: "eu_vat", + description: "European VAT number", + example: "RO1234567891", + impactsTaxCalculation: true, + }, + { + country: "Romania", + iso: "RO", + code: "ro_tin", + description: "Romanian tax ID number", + example: "1234567890123", + impactsTaxCalculation: false, + }, + { + country: "Russia", + iso: "RU", + code: "ru_inn", + description: "Russian INN", + example: "1234567891", + impactsTaxCalculation: true, + }, + { + country: "Russia", + iso: "RU", + code: "ru_kpp", + description: "Russian KPP", + example: "123456789", + impactsTaxCalculation: true, + }, + { + country: "Saudi Arabia", + iso: "SA", + code: "sa_vat", + description: "Saudi Arabia VAT", + example: "123456789012345", + impactsTaxCalculation: true, + }, + { + country: "Senegal", + iso: "SN", + code: "sn_ninea", + description: "Senegal NINEA Number", + example: "12345672A2", + impactsTaxCalculation: false, + }, + { + country: "Serbia", + iso: "RS", + code: "rs_pib", + description: "Serbian PIB number", + example: "123456789", + impactsTaxCalculation: false, + }, + { + country: "Singapore", + iso: "SG", + code: "sg_gst", + description: "Singaporean GST", + example: "M12345678X", + impactsTaxCalculation: true, + }, + { + country: "Singapore", + iso: "SG", + code: "sg_uen", + description: "Singaporean UEN", + example: "123456789F", + impactsTaxCalculation: false, + }, + { + country: "Slovakia", + iso: "SK", + code: "eu_vat", + description: "European VAT number", + example: "SK1234567891", + impactsTaxCalculation: true, + }, + { + country: "Slovenia", + iso: "SI", + code: "eu_vat", + description: "European VAT number", + example: "SI12345678", + impactsTaxCalculation: true, + }, + { + country: "Slovenia", + iso: "SI", + code: "si_tin", + description: "Slovenia tax number (davčna številka)", + example: "12345678", + impactsTaxCalculation: false, + }, + { + country: "South Africa", + iso: "ZA", + code: "za_vat", + description: "South African VAT number", + example: "4123456789", + impactsTaxCalculation: true, + }, + { + country: "South Korea", + iso: "KR", + code: "kr_brn", + description: "Korean BRN", + example: "123-45-67890", + impactsTaxCalculation: true, + }, + { + country: "Spain", + iso: "ES", + code: "es_cif", + description: "Spanish NIF number (previously Spanish CIF number)", + example: "A12345678", + impactsTaxCalculation: false, + }, + { + country: "Spain", + iso: "ES", + code: "eu_vat", + description: "European VAT number", + example: "ESA1234567Z", + impactsTaxCalculation: true, + }, + { + country: "Suriname", + iso: "SR", + code: "sr_fin", + description: "Suriname FIN Number", + example: "1234567890", + impactsTaxCalculation: true, + }, + { + country: "Sweden", + iso: "SE", + code: "eu_vat", + description: "European VAT number", + example: "SE123456789123", + impactsTaxCalculation: true, + }, + { + country: "Switzerland", + iso: "CH", + code: "ch_uid", + description: "Switzerland UID number", + example: "CHE-123.456.789 HR", + impactsTaxCalculation: false, + }, + { + country: "Switzerland", + iso: "CH", + code: "ch_vat", + description: "Switzerland VAT number", + example: "CHE-123.456.789 MWST", + impactsTaxCalculation: true, + }, + { + country: "Taiwan", + iso: "TW", + code: "tw_vat", + description: "Taiwanese VAT", + example: "12345678", + impactsTaxCalculation: true, + }, + { + country: "Tajikistan", + iso: "TJ", + code: "tj_tin", + description: "Tajikistan Tax Identification Number", + example: "123456789", + impactsTaxCalculation: true, + }, + { + country: "Tanzania", + iso: "TZ", + code: "tz_vat", + description: "Tanzania VAT Number", + example: "12345678A", + impactsTaxCalculation: true, + }, + { + country: "Thailand", + iso: "TH", + code: "th_vat", + description: "Thai VAT", + example: "1234567891234", + impactsTaxCalculation: true, + }, + { + country: "Turkey", + iso: "TR", + code: "tr_tin", + description: "Turkish Tax Identification Number", + example: "123456789", + impactsTaxCalculation: true, + }, + { + country: "Uganda", + iso: "UG", + code: "ug_tin", + description: "Uganda Tax Identification Number", + example: "1014751879", + impactsTaxCalculation: true, + }, + { + country: "Ukraine", + iso: "UA", + code: "ua_vat", + description: "Ukrainian VAT", + example: "123456789", + impactsTaxCalculation: true, + }, + { + country: "United Arab Emirates", + iso: "AE", + code: "ae_trn", + description: "United Arab Emirates TRN", + example: "123456789012345", + impactsTaxCalculation: true, + }, + { + country: "United Kingdom", + iso: "GB", + code: "eu_vat", + description: "Northern Ireland VAT number", + example: "XI123456789", + impactsTaxCalculation: true, + }, + { + country: "United Kingdom", + iso: "GB", + code: "gb_vat", + description: "United Kingdom VAT number", + example: "GB123456789", + impactsTaxCalculation: true, + }, + { + country: "United States", + iso: "US", + code: "us_ein", + description: "United States EIN", + example: "12-3456789", + impactsTaxCalculation: false, + }, + { + country: "Uruguay", + iso: "UY", + code: "uy_ruc", + description: "Uruguayan RUC number", + example: "123456789012", + impactsTaxCalculation: true, + }, + { + country: "Uzbekistan", + iso: "UZ", + code: "uz_tin", + description: "Uzbekistan TIN Number", + example: "123456789", + impactsTaxCalculation: false, + }, + { + country: "Uzbekistan", + iso: "UZ", + code: "uz_vat", + description: "Uzbekistan VAT Number", + example: "123456789012", + impactsTaxCalculation: true, + }, + { + country: "Venezuela", + iso: "VE", + code: "ve_rif", + description: "Venezuelan RIF number", + example: "A-12345678-9", + impactsTaxCalculation: false, + }, + { + country: "Vietnam", + iso: "VN", + code: "vn_tin", + description: "Vietnamese tax ID number", + example: "1234567890", + impactsTaxCalculation: false, + }, + { + country: "Zambia", + iso: "ZM", + code: "zm_tin", + description: "Zambia Tax Identification Number", + example: "1004751879", + impactsTaxCalculation: false, + }, + { + country: "Zimbabwe", + iso: "ZW", + code: "zw_tin", + description: "Zimbabwe Tax Identification Number", + example: "1234567890", + impactsTaxCalculation: false, + }, +]; diff --git a/apps/web/src/app/billing/payment/types/tax-id.ts b/apps/web/src/app/billing/payment/types/tax-id.ts new file mode 100644 index 00000000000..80df42a3436 --- /dev/null +++ b/apps/web/src/app/billing/payment/types/tax-id.ts @@ -0,0 +1,18 @@ +import { BaseResponse } from "@bitwarden/common/models/response/base.response"; + +export interface TaxId { + code: string; + value: string; +} + +export class TaxIdResponse extends BaseResponse implements TaxId { + code: string; + value: string; + + constructor(response: any) { + super(response); + + this.code = this.getResponseProperty("Code"); + this.value = this.getResponseProperty("Value"); + } +} diff --git a/apps/web/src/app/billing/payment/types/tokenized-payment-method.ts b/apps/web/src/app/billing/payment/types/tokenized-payment-method.ts new file mode 100644 index 00000000000..def240f534b --- /dev/null +++ b/apps/web/src/app/billing/payment/types/tokenized-payment-method.ts @@ -0,0 +1,22 @@ +export const TokenizablePaymentMethods = { + bankAccount: "bankAccount", + card: "card", + payPal: "payPal", +} as const; + +export type BankAccountPaymentMethod = typeof TokenizablePaymentMethods.bankAccount; +export type CardPaymentMethod = typeof TokenizablePaymentMethods.card; +export type PayPalPaymentMethod = typeof TokenizablePaymentMethods.payPal; + +export type TokenizablePaymentMethod = + (typeof TokenizablePaymentMethods)[keyof typeof TokenizablePaymentMethods]; + +export const isTokenizablePaymentMethod = (value: string): value is TokenizablePaymentMethod => { + const valid = Object.values(TokenizablePaymentMethods) as readonly string[]; + return valid.includes(value); +}; + +export type TokenizedPaymentMethod = { + type: TokenizablePaymentMethod; + token: string; +}; diff --git a/apps/web/src/app/billing/services/billing.client.ts b/apps/web/src/app/billing/services/billing.client.ts new file mode 100644 index 00000000000..69f82eab19a --- /dev/null +++ b/apps/web/src/app/billing/services/billing.client.ts @@ -0,0 +1,153 @@ +import { Injectable } from "@angular/core"; + +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; + +import { + BillingAddress, + BillingAddressResponse, + MaskedPaymentMethod, + MaskedPaymentMethodResponse, + TokenizedPaymentMethod, +} from "../payment/types"; +import { BillableEntity } from "../types"; + +type Result = + | { + type: "success"; + value: T; + } + | { + type: "error"; + message: string; + }; + +@Injectable() +export class BillingClient { + constructor(private apiService: ApiService) {} + + private getEndpoint = (entity: BillableEntity): string => { + switch (entity.type) { + case "account": { + return "/account/billing/vnext"; + } + case "organization": { + return `/organizations/${entity.data.id}/billing/vnext`; + } + case "provider": { + return `/providers/${entity.data.id}/billing/vnext`; + } + } + }; + + addCreditWithBitPay = async ( + owner: BillableEntity, + credit: { amount: number; redirectUrl: string }, + ): Promise> => { + const path = `${this.getEndpoint(owner)}/credit/bitpay`; + try { + const data = await this.apiService.send("POST", path, credit, true, true); + return { + type: "success", + value: data as string, + }; + } catch (error: any) { + if (error instanceof ErrorResponse) { + return { + type: "error", + message: error.message, + }; + } + throw error; + } + }; + + getBillingAddress = async (owner: BillableEntity): Promise => { + const path = `${this.getEndpoint(owner)}/address`; + const data = await this.apiService.send("GET", path, null, true, true); + return data ? new BillingAddressResponse(data) : null; + }; + + getCredit = async (owner: BillableEntity): Promise => { + const path = `${this.getEndpoint(owner)}/credit`; + const data = await this.apiService.send("GET", path, null, true, true); + return data ? (data as number) : null; + }; + + getPaymentMethod = async (owner: BillableEntity): Promise => { + const path = `${this.getEndpoint(owner)}/payment-method`; + const data = await this.apiService.send("GET", path, null, true, true); + return data ? new MaskedPaymentMethodResponse(data).value : null; + }; + + updateBillingAddress = async ( + owner: BillableEntity, + billingAddress: BillingAddress, + ): Promise> => { + const path = `${this.getEndpoint(owner)}/address`; + try { + const data = await this.apiService.send("PUT", path, billingAddress, true, true); + return { + type: "success", + value: new BillingAddressResponse(data), + }; + } catch (error: any) { + if (error instanceof ErrorResponse) { + return { + type: "error", + message: error.message, + }; + } + throw error; + } + }; + + updatePaymentMethod = async ( + owner: BillableEntity, + paymentMethod: TokenizedPaymentMethod, + billingAddress: Pick | null, + ): Promise> => { + const path = `${this.getEndpoint(owner)}/payment-method`; + try { + const request = { + ...paymentMethod, + billingAddress, + }; + const data = await this.apiService.send("PUT", path, request, true, true); + return { + type: "success", + value: new MaskedPaymentMethodResponse(data).value, + }; + } catch (error: any) { + if (error instanceof ErrorResponse) { + return { + type: "error", + message: error.message, + }; + } + throw error; + } + }; + + verifyBankAccount = async ( + owner: BillableEntity, + descriptorCode: string, + ): Promise> => { + const path = `${this.getEndpoint(owner)}/payment-method/verify-bank-account`; + try { + const data = await this.apiService.send("POST", path, { descriptorCode }, true, true); + return { + type: "success", + value: new MaskedPaymentMethodResponse(data).value, + }; + } catch (error: any) { + if (error instanceof ErrorResponse) { + return { + type: "error", + message: error.message, + }; + } + throw error; + } + }; +} diff --git a/apps/web/src/app/billing/services/index.ts b/apps/web/src/app/billing/services/index.ts index e291ca6a454..dcd2c05034a 100644 --- a/apps/web/src/app/billing/services/index.ts +++ b/apps/web/src/app/billing/services/index.ts @@ -1,3 +1,4 @@ +export * from "./billing.client"; export * from "./billing-services.module"; export * from "./braintree.service"; export * from "./stripe.service"; diff --git a/apps/web/src/app/billing/services/stripe.service.ts b/apps/web/src/app/billing/services/stripe.service.ts index 360187ecd1e..7ea0d7d52c8 100644 --- a/apps/web/src/app/billing/services/stripe.service.ts +++ b/apps/web/src/app/billing/services/stripe.service.ts @@ -2,11 +2,43 @@ // @ts-strict-ignore import { Injectable } from "@angular/core"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { BankAccount } from "@bitwarden/common/billing/models/domain"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { BankAccountPaymentMethod, CardPaymentMethod } from "../payment/types"; + import { BillingServicesModule } from "./billing-services.module"; +type SetupBankAccountRequest = { + payment_method: { + us_bank_account: { + routing_number: string; + account_number: string; + account_holder_type: string; + }; + billing_details: { + name: string; + address?: { + country: string; + postal_code: string; + }; + }; + }; +}; + +type SetupCardRequest = { + payment_method: { + card: string; + billing_details?: { + address: { + country: string; + postal_code: string; + }; + }; + }; +}; + @Injectable({ providedIn: BillingServicesModule }) export class StripeService { private stripe: any; @@ -17,7 +49,28 @@ export class StripeService { cardCvc: string; }; - constructor(private logService: LogService) {} + constructor( + private apiService: ApiService, + private logService: LogService, + ) {} + + createSetupIntent = async ( + paymentMethod: BankAccountPaymentMethod | CardPaymentMethod, + ): Promise => { + const getPath = () => { + switch (paymentMethod) { + case "bankAccount": { + return "/setup-intent/bank-account"; + } + case "card": { + return "/setup-intent/card"; + } + } + }; + + const response = await this.apiService.send("POST", getPath(), null, true, true); + return response as string; + }; /** * Loads [Stripe JS]{@link https://docs.stripe.com/js} in the element of the current page and mounts @@ -51,25 +104,28 @@ export class StripeService { window.document.head.appendChild(script); } - /** - * Re-mounts previously created Stripe credit card [elements]{@link https://docs.stripe.com/js/elements_object/create} into the HTML elements - * specified during the {@link loadStripe} call. This is useful for when those HTML elements are removed from the DOM by Angular. - */ - mountElements(i: number = 0) { + mountElements(attempt: number = 1) { setTimeout(() => { - if (!document.querySelector(this.elementIds.cardNumber) && i < 10) { - this.logService.warning("Stripe container missing, retrying..."); - this.mountElements(i + 1); - return; - } + if (!this.elements) { + this.logService.warning(`Stripe elements are missing, retrying for attempt ${attempt}...`); + this.mountElements(attempt + 1); + } else { + const cardNumber = this.elements.getElement("cardNumber"); + const cardExpiry = this.elements.getElement("cardExpiry"); + const cardCVC = this.elements.getElement("cardCvc"); - const cardNumber = this.elements.getElement("cardNumber"); - const cardExpiry = this.elements.getElement("cardExpiry"); - const cardCvc = this.elements.getElement("cardCvc"); - cardNumber.mount(this.elementIds.cardNumber); - cardExpiry.mount(this.elementIds.cardExpiry); - cardCvc.mount(this.elementIds.cardCvc); - }, 50); + if ([cardNumber, cardExpiry, cardCVC].some((element) => !element)) { + this.logService.warning( + `Some Stripe card elements are missing, retrying for attempt ${attempt}...`, + ); + this.mountElements(attempt + 1); + } else { + cardNumber.mount(this.elementIds.cardNumber); + cardExpiry.mount(this.elementIds.cardExpiry); + cardCVC.mount(this.elementIds.cardCvc); + } + } + }, 100); } /** @@ -81,8 +137,9 @@ export class StripeService { async setupBankAccountPaymentMethod( clientSecret: string, { accountHolderName, routingNumber, accountNumber, accountHolderType }: BankAccount, + billingDetails?: { country: string; postalCode: string }, ): Promise { - const result = await this.stripe.confirmUsBankAccountSetup(clientSecret, { + const request: SetupBankAccountRequest = { payment_method: { us_bank_account: { routing_number: routingNumber, @@ -93,7 +150,16 @@ export class StripeService { name: accountHolderName, }, }, - }); + }; + + if (billingDetails) { + request.payment_method.billing_details.address = { + country: billingDetails.country, + postal_code: billingDetails.postalCode, + }; + } + + const result = await this.stripe.confirmUsBankAccountSetup(clientSecret, request); if (result.error || (result.setupIntent && result.setupIntent.status !== "requires_action")) { this.logService.error(result.error); throw result.error; @@ -107,13 +173,25 @@ export class StripeService { * thereby creating and storing a Stripe [PaymentMethod]{@link https://docs.stripe.com/api/payment_methods}. * @returns The ID of the newly created PaymentMethod. */ - async setupCardPaymentMethod(clientSecret: string): Promise { + async setupCardPaymentMethod( + clientSecret: string, + billingDetails?: { country: string; postalCode: string }, + ): Promise { const cardNumber = this.elements.getElement("cardNumber"); - const result = await this.stripe.confirmCardSetup(clientSecret, { + const request: SetupCardRequest = { payment_method: { card: cardNumber, }, - }); + }; + if (billingDetails) { + request.payment_method.billing_details = { + address: { + country: billingDetails.country, + postal_code: billingDetails.postalCode, + }, + }; + } + const result = await this.stripe.confirmCardSetup(clientSecret, request); if (result.error || (result.setupIntent && result.setupIntent.status !== "succeeded")) { this.logService.error(result.error); throw result.error; diff --git a/apps/web/src/app/billing/services/trial-flow.service.ts b/apps/web/src/app/billing/services/trial-flow.service.ts index 81bcf8dcabd..831cc129e60 100644 --- a/apps/web/src/app/billing/services/trial-flow.service.ts +++ b/apps/web/src/app/billing/services/trial-flow.service.ts @@ -11,6 +11,8 @@ import { BillingSourceResponse } from "@bitwarden/common/billing/models/response import { OrganizationBillingMetadataResponse } from "@bitwarden/common/billing/models/response/organization-billing-metadata.response"; import { OrganizationSubscriptionResponse } from "@bitwarden/common/billing/models/response/organization-subscription.response"; import { PaymentSourceResponse } from "@bitwarden/common/billing/models/response/payment-source.response"; +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 { DialogService } from "@bitwarden/components"; @@ -28,6 +30,7 @@ export class TrialFlowService { private router: Router, protected billingApiService: BillingApiServiceAbstraction, private organizationApiService: OrganizationApiServiceAbstraction, + private configService: ConfigService, ) {} checkForOrgsWithUpcomingPaymentIssues( organization: Organization, @@ -131,7 +134,11 @@ export class TrialFlowService { } private async navigateToPaymentMethod(orgId: string) { - await this.router.navigate(["organizations", `${orgId}`, "billing", "payment-method"], { + const managePaymentDetailsOutsideCheckout = await this.configService.getFeatureFlag( + FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout, + ); + const route = managePaymentDetailsOutsideCheckout ? "payment-details" : "payment-method"; + await this.router.navigate(["organizations", `${orgId}`, "billing", route], { state: { launchPaymentModalAutomatically: true }, queryParams: { launchPaymentModalAutomatically: true }, }); diff --git a/apps/web/src/app/billing/shared/payment-method.component.ts b/apps/web/src/app/billing/shared/payment-method.component.ts index 74793bccc01..0e116b4f39a 100644 --- a/apps/web/src/app/billing/shared/payment-method.component.ts +++ b/apps/web/src/app/billing/shared/payment-method.component.ts @@ -18,7 +18,9 @@ import { PaymentMethodType } from "@bitwarden/common/billing/enums"; import { BillingPaymentResponse } from "@bitwarden/common/billing/models/response/billing-payment.response"; import { OrganizationSubscriptionResponse } from "@bitwarden/common/billing/models/response/organization-subscription.response"; import { SubscriptionResponse } from "@bitwarden/common/billing/models/response/subscription.response"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { VerifyBankRequest } from "@bitwarden/common/models/request/verify-bank.request"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { SyncService } from "@bitwarden/common/platform/sync"; @@ -79,6 +81,7 @@ export class PaymentMethodComponent implements OnInit, OnDestroy { private organizationService: OrganizationService, private accountService: AccountService, protected syncService: SyncService, + private configService: ConfigService, ) { const state = this.router.getCurrentNavigation()?.extras?.state; // incase the above state is undefined or null we use redundantState @@ -107,6 +110,14 @@ export class PaymentMethodComponent implements OnInit, OnDestroy { return; } + const managePaymentDetailsOutsideCheckout = await this.configService.getFeatureFlag( + FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout, + ); + + if (managePaymentDetailsOutsideCheckout) { + await this.router.navigate(["../payment-details"], { relativeTo: this.route }); + } + await this.load(); this.firstLoaded = true; }); diff --git a/apps/web/src/app/billing/types/billable-entity.ts b/apps/web/src/app/billing/types/billable-entity.ts new file mode 100644 index 00000000000..79ed12a4161 --- /dev/null +++ b/apps/web/src/app/billing/types/billable-entity.ts @@ -0,0 +1,42 @@ +import { map } from "rxjs"; + +import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; +import { Provider } from "@bitwarden/common/admin-console/models/domain/provider"; +import { Account } from "@bitwarden/common/auth/abstractions/account.service"; + +export type BillableEntity = + | { type: "account"; data: Account } + | { type: "organization"; data: Organization } + | { type: "provider"; data: Provider }; + +export const accountToBillableEntity = map((account) => { + if (!account) { + throw new Error("Account not found"); + } + return { + type: "account", + data: account, + }; +}); + +export const organizationToBillableEntity = map( + (organization) => { + if (!organization) { + throw new Error("Organization not found"); + } + return { + type: "organization", + data: organization, + }; + }, +); + +export const providerToBillableEntity = map((provider) => { + if (!provider) { + throw new Error("Organization not found"); + } + return { + type: "provider", + data: provider, + }; +}); diff --git a/apps/web/src/app/billing/types/index.ts b/apps/web/src/app/billing/types/index.ts new file mode 100644 index 00000000000..1278e0f2e14 --- /dev/null +++ b/apps/web/src/app/billing/types/index.ts @@ -0,0 +1,2 @@ +export * from "./billable-entity"; +export * from "./free-trial"; diff --git a/apps/web/src/app/billing/warnings/components/index.ts b/apps/web/src/app/billing/warnings/components/index.ts new file mode 100644 index 00000000000..1e1e0682e62 --- /dev/null +++ b/apps/web/src/app/billing/warnings/components/index.ts @@ -0,0 +1,2 @@ +export * from "./organization-free-trial-warning.component"; +export * from "./organization-reseller-renewal-warning.component"; diff --git a/apps/web/src/app/billing/warnings/free-trial-warning.component.ts b/apps/web/src/app/billing/warnings/components/organization-free-trial-warning.component.ts similarity index 68% rename from apps/web/src/app/billing/warnings/free-trial-warning.component.ts rename to apps/web/src/app/billing/warnings/components/organization-free-trial-warning.component.ts index b000878bf66..074358537b6 100644 --- a/apps/web/src/app/billing/warnings/free-trial-warning.component.ts +++ b/apps/web/src/app/billing/warnings/components/organization-free-trial-warning.component.ts @@ -6,15 +6,13 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga import { AnchorLinkDirective, BannerComponent } from "@bitwarden/components"; import { I18nPipe } from "@bitwarden/ui-common"; -import { - FreeTrialWarning, - OrganizationWarningsService, -} from "../services/organization-warnings.service"; +import { OrganizationWarningsService } from "../services"; +import { OrganizationFreeTrialWarning } from "../types"; @Component({ - selector: "app-free-trial-warning", + selector: "app-organization-free-trial-warning", template: ` - @let warning = freeTrialWarning$ | async; + @let warning = warning$ | async; @if (warning) { (); - freeTrialWarning$!: Observable; + warning$!: Observable; constructor(private organizationWarningsService: OrganizationWarningsService) {} ngOnInit() { - this.freeTrialWarning$ = this.organizationWarningsService.getFreeTrialWarning$( - this.organization, - ); + this.warning$ = this.organizationWarningsService.getFreeTrialWarning$(this.organization); } + + refresh = () => { + this.warning$ = this.organizationWarningsService.getFreeTrialWarning$(this.organization, true); + }; } diff --git a/apps/web/src/app/billing/warnings/reseller-renewal-warning.component.ts b/apps/web/src/app/billing/warnings/components/organization-reseller-renewal-warning.component.ts similarity index 63% rename from apps/web/src/app/billing/warnings/reseller-renewal-warning.component.ts rename to apps/web/src/app/billing/warnings/components/organization-reseller-renewal-warning.component.ts index 6bcfba5ce6c..f45dd443dda 100644 --- a/apps/web/src/app/billing/warnings/reseller-renewal-warning.component.ts +++ b/apps/web/src/app/billing/warnings/components/organization-reseller-renewal-warning.component.ts @@ -5,15 +5,13 @@ import { Observable } from "rxjs"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { BannerComponent } from "@bitwarden/components"; -import { - OrganizationWarningsService, - ResellerRenewalWarning, -} from "../services/organization-warnings.service"; +import { OrganizationWarningsService } from "../services"; +import { OrganizationResellerRenewalWarning } from "../types"; @Component({ - selector: "app-reseller-renewal-warning", + selector: "app-organization-reseller-renewal-warning", template: ` - @let warning = resellerRenewalWarning$ | async; + @let warning = warning$ | async; @if (warning) { ; + warning$!: Observable; constructor(private organizationWarningsService: OrganizationWarningsService) {} ngOnInit() { - this.resellerRenewalWarning$ = this.organizationWarningsService.getResellerRenewalWarning$( - this.organization, - ); + this.warning$ = this.organizationWarningsService.getResellerRenewalWarning$(this.organization); } } diff --git a/apps/web/src/app/billing/warnings/services/index.ts b/apps/web/src/app/billing/warnings/services/index.ts new file mode 100644 index 00000000000..fbd1c56f350 --- /dev/null +++ b/apps/web/src/app/billing/warnings/services/index.ts @@ -0,0 +1 @@ +export * from "./organization-warnings.service"; diff --git a/apps/web/src/app/billing/services/organization-warnings.service.spec.ts b/apps/web/src/app/billing/warnings/services/organization-warnings.service.spec.ts similarity index 100% rename from apps/web/src/app/billing/services/organization-warnings.service.spec.ts rename to apps/web/src/app/billing/warnings/services/organization-warnings.service.spec.ts diff --git a/apps/web/src/app/billing/services/organization-warnings.service.ts b/apps/web/src/app/billing/warnings/services/organization-warnings.service.ts similarity index 78% rename from apps/web/src/app/billing/services/organization-warnings.service.ts rename to apps/web/src/app/billing/warnings/services/organization-warnings.service.ts index f75220a7744..fa53992afe0 100644 --- a/apps/web/src/app/billing/services/organization-warnings.service.ts +++ b/apps/web/src/app/billing/warnings/services/organization-warnings.service.ts @@ -1,25 +1,20 @@ import { Injectable } from "@angular/core"; import { Router } from "@angular/router"; -import { - filter, - from, - lastValueFrom, - map, - Observable, - shareReplay, - switchMap, - takeWhile, -} from "rxjs"; +import { filter, from, lastValueFrom, map, Observable, switchMap, takeWhile } from "rxjs"; import { take } from "rxjs/operators"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { OrganizationBillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/organizations/organization-billing-api.service.abstraction"; import { OrganizationWarningsResponse } from "@bitwarden/common/billing/models/response/organization-warnings.response"; +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 { OrganizationId } from "@bitwarden/common/types/guid"; import { DialogService } from "@bitwarden/components"; -import { openChangePlanDialog } from "@bitwarden/web-vault/app/billing/organizations/change-plan-dialog.component"; + +import { openChangePlanDialog } from "../../organizations/change-plan-dialog.component"; +import { OrganizationFreeTrialWarning, OrganizationResellerRenewalWarning } from "../types"; const format = (date: Date) => date.toLocaleDateString("en-US", { @@ -28,21 +23,12 @@ const format = (date: Date) => year: "numeric", }); -export type FreeTrialWarning = { - organization: Pick; - message: string; -}; - -export type ResellerRenewalWarning = { - type: "info" | "warning"; - message: string; -}; - @Injectable({ providedIn: "root" }) export class OrganizationWarningsService { private cache$ = new Map>(); constructor( + private configService: ConfigService, private dialogService: DialogService, private i18nService: I18nService, private organizationApiService: OrganizationApiServiceAbstraction, @@ -50,8 +36,11 @@ export class OrganizationWarningsService { private router: Router, ) {} - getFreeTrialWarning$ = (organization: Organization): Observable => - this.getWarning$(organization, (response) => response.freeTrial).pipe( + getFreeTrialWarning$ = ( + organization: Organization, + bypassCache: boolean = false, + ): Observable => + this.getWarning$(organization, (response) => response.freeTrial, bypassCache).pipe( map((warning) => { const { remainingTrialDays } = warning; @@ -76,9 +65,12 @@ export class OrganizationWarningsService { }), ); - getResellerRenewalWarning$ = (organization: Organization): Observable => - this.getWarning$(organization, (response) => response.resellerRenewal).pipe( - map((warning): ResellerRenewalWarning | null => { + getResellerRenewalWarning$ = ( + organization: Organization, + bypassCache: boolean = false, + ): Observable => + this.getWarning$(organization, (response) => response.resellerRenewal, bypassCache).pipe( + map((warning): OrganizationResellerRenewalWarning | null => { switch (warning.type) { case "upcoming": { return { @@ -116,8 +108,11 @@ export class OrganizationWarningsService { filter((result): result is NonNullable => result !== null), ); - showInactiveSubscriptionDialog$ = (organization: Organization): Observable => - this.getWarning$(organization, (response) => response.inactiveSubscription).pipe( + showInactiveSubscriptionDialog$ = ( + organization: Organization, + bypassCache: boolean = false, + ): Observable => + this.getWarning$(organization, (response) => response.inactiveSubscription, bypassCache).pipe( switchMap(async (warning) => { switch (warning.resolution) { case "contact_provider": { @@ -142,8 +137,14 @@ export class OrganizationWarningsService { cancelButtonText: this.i18nService.t("close"), }); if (confirmed) { + const managePaymentDetailsOutsideCheckout = await this.configService.getFeatureFlag( + FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout, + ); + const route = managePaymentDetailsOutsideCheckout + ? "payment-details" + : "payment-method"; await this.router.navigate( - ["organizations", `${organization.id}`, "billing", "payment-method"], + ["organizations", `${organization.id}`, "billing", route], { state: { launchPaymentModalAutomatically: true }, }, @@ -177,14 +178,15 @@ export class OrganizationWarningsService { }), ); - private getResponse$ = (organization: Organization): Observable => { + private getResponse$ = ( + organization: Organization, + bypassCache: boolean = false, + ): Observable => { const existing = this.cache$.get(organization.id as OrganizationId); - if (existing) { + if (existing && !bypassCache) { return existing; } - const response$ = from(this.organizationBillingApiService.getWarnings(organization.id)).pipe( - shareReplay({ bufferSize: 1, refCount: false }), - ); + const response$ = from(this.organizationBillingApiService.getWarnings(organization.id)); this.cache$.set(organization.id as OrganizationId, response$); return response$; }; @@ -192,8 +194,9 @@ export class OrganizationWarningsService { private getWarning$ = ( organization: Organization, extract: (response: OrganizationWarningsResponse) => T | null | undefined, + bypassCache: boolean = false, ): Observable => - this.getResponse$(organization).pipe( + this.getResponse$(organization, bypassCache).pipe( map(extract), takeWhile((warning): warning is T => !!warning), take(1), diff --git a/apps/web/src/app/billing/warnings/types/index.ts b/apps/web/src/app/billing/warnings/types/index.ts new file mode 100644 index 00000000000..fc0c7d278ed --- /dev/null +++ b/apps/web/src/app/billing/warnings/types/index.ts @@ -0,0 +1 @@ +export * from "./organization-warnings"; diff --git a/apps/web/src/app/billing/warnings/types/organization-warnings.ts b/apps/web/src/app/billing/warnings/types/organization-warnings.ts new file mode 100644 index 00000000000..96bf5aff6f1 --- /dev/null +++ b/apps/web/src/app/billing/warnings/types/organization-warnings.ts @@ -0,0 +1,11 @@ +import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; + +export type OrganizationFreeTrialWarning = { + organization: Pick; + message: string; +}; + +export type OrganizationResellerRenewalWarning = { + type: "info" | "warning"; + message: string; +}; diff --git a/apps/web/src/app/vault/individual-vault/vault-banners/vault-banners.component.spec.ts b/apps/web/src/app/vault/individual-vault/vault-banners/vault-banners.component.spec.ts index 997d9bc3fe3..197b6426468 100644 --- a/apps/web/src/app/vault/individual-vault/vault-banners/vault-banners.component.spec.ts +++ b/apps/web/src/app/vault/individual-vault/vault-banners/vault-banners.component.spec.ts @@ -8,6 +8,7 @@ import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { MessageListener } from "@bitwarden/common/platform/messaging"; @@ -87,6 +88,10 @@ describe("VaultBannersComponent", () => { allMessages$: messageSubject.asObservable(), }), }, + { + provide: ConfigService, + useValue: mock(), + }, ], }) .overrideProvider(VaultBannersService, { useValue: bannerService }) diff --git a/apps/web/src/app/vault/individual-vault/vault-banners/vault-banners.component.ts b/apps/web/src/app/vault/individual-vault/vault-banners/vault-banners.component.ts index 7eafaa50c18..4dd5bb7ff2d 100644 --- a/apps/web/src/app/vault/individual-vault/vault-banners/vault-banners.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault-banners/vault-banners.component.ts @@ -1,9 +1,11 @@ import { Component, Input, OnInit } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { Router } from "@angular/router"; -import { firstValueFrom, map, Observable, switchMap, filter } from "rxjs"; +import { filter, firstValueFrom, map, Observable, switchMap } from "rxjs"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { MessageListener } from "@bitwarden/common/platform/messaging"; import { UserId } from "@bitwarden/common/types/guid"; @@ -35,6 +37,7 @@ export class VaultBannersComponent implements OnInit { private i18nService: I18nService, private accountService: AccountService, private messageListener: MessageListener, + private configService: ConfigService, ) { this.premiumBannerVisible$ = this.activeUserId$.pipe( filter((userId): userId is UserId => userId != null), @@ -68,12 +71,16 @@ export class VaultBannersComponent implements OnInit { } async navigateToPaymentMethod(organizationId: string): Promise { + const managePaymentDetailsOutsideCheckout = await this.configService.getFeatureFlag( + FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout, + ); + const route = managePaymentDetailsOutsideCheckout ? "payment-details" : "payment-method"; const navigationExtras = { state: { launchPaymentModalAutomatically: true }, }; await this.router.navigate( - ["organizations", organizationId, "billing", "payment-method"], + ["organizations", organizationId, "billing", route], navigationExtras, ); } diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 50a2cdbc4a9..9150028f4d6 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -10802,5 +10802,53 @@ "billingAddressRequiredToAddCredit": { "message": "Billing address required to add credit.", "description": "Error message shown when trying to add credit to a trialing organization without a billing address." + }, + "billingAddress": { + "message": "Billing address" + }, + "addBillingAddress": { + "message": "Add billing address" + }, + "editBillingAddress": { + "message": "Edit billing address" + }, + "noBillingAddress": { + "message": "No address on file." + }, + "billingAddressUpdated": { + "message": "Your billing address has been updated." + }, + "paymentDetails": { + "message": "Payment details" + }, + "paymentMethodUpdated": { + "message": "Your payment method has been updated." + }, + "bankAccountVerified": { + "message": "Your bank account has been verified." + }, + "availableCreditAppliedToInvoice": { + "message": "Any available credit will be automatically applied towards invoices generated for this account." + }, + "mustBePositiveNumber": { + "message": "Must be a positive number" + }, + "cardSecurityCode": { + "message": "Card security code" + }, + "cardSecurityCodeDescription": { + "message": "Card security code, also known as CVV or CVC, is typically a 3 digit number printed on the back of your credit card or 4 digit number printed on the front above your card number." + }, + "verifyBankAccountWarning": { + "message": "Payment with a bank account is only available to customers in the United States. You will be required to verify your bank account. We will make a micro-deposit within the next 1-2 business days. Enter the statement descriptor code from this deposit on the Payment Details page to verify the bank account. Failure to verify the bank account will result in a missed payment and your subscription being suspended." + }, + "taxId": { + "message": "Tax ID: $TAX_ID$", + "placeholders": { + "tax_id": { + "content": "$1", + "example": "12-3456789" + } + } } } diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/providers-layout.component.html b/bitwarden_license/bit-web/src/app/admin-console/providers/providers-layout.component.html index 8266b20b306..0a084848dbe 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/providers-layout.component.html +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/providers-layout.component.html @@ -31,6 +31,12 @@ *ngIf="canAccessBilling$ | async" > + @if (managePaymentDetailsOutsideCheckout$ | async) { + + } ; protected clientsTranslationKey$: Observable; + protected managePaymentDetailsOutsideCheckout$: Observable; constructor( private route: ActivatedRoute, private providerService: ProviderService, + private configService: ConfigService, ) {} ngOnInit() { @@ -69,6 +73,10 @@ export class ProvidersLayoutComponent implements OnInit, OnDestroy { provider.providerType === ProviderType.BusinessUnit ? "businessUnits" : "clients", ), ); + + this.managePaymentDetailsOutsideCheckout$ = this.configService.getFeatureFlag$( + FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout, + ); } ngOnDestroy() { diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/providers-routing.module.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/providers-routing.module.ts index 482d2c881c1..7a554275f08 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/providers-routing.module.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/providers-routing.module.ts @@ -13,6 +13,7 @@ import { hasConsolidatedBilling, ProviderBillingHistoryComponent, } from "../../billing/providers"; +import { ProviderPaymentDetailsComponent } from "../../billing/providers/payment-details/provider-payment-details.component"; import { SetupBusinessUnitComponent } from "../../billing/providers/setup/setup-business-unit.component"; import { ClientsComponent } from "./clients/clients.component"; @@ -142,6 +143,14 @@ const routes: Routes = [ titleId: "subscription", }, }, + { + path: "payment-details", + component: ProviderPaymentDetailsComponent, + canActivate: [providerPermissionsGuard()], + data: { + titleId: "paymentDetails", + }, + }, { path: "history", component: ProviderBillingHistoryComponent, diff --git a/bitwarden_license/bit-web/src/app/billing/providers/payment-details/provider-payment-details.component.html b/bitwarden_license/bit-web/src/app/billing/providers/payment-details/provider-payment-details.component.html new file mode 100644 index 00000000000..375faab8d34 --- /dev/null +++ b/bitwarden_license/bit-web/src/app/billing/providers/payment-details/provider-payment-details.component.html @@ -0,0 +1,33 @@ + + + @let view = view$ | async; + @if (!view) { + + + {{ "loading" | i18n }} + + } @else { + + + + + + + + } + diff --git a/bitwarden_license/bit-web/src/app/billing/providers/payment-details/provider-payment-details.component.ts b/bitwarden_license/bit-web/src/app/billing/providers/payment-details/provider-payment-details.component.ts new file mode 100644 index 00000000000..dbf948518a2 --- /dev/null +++ b/bitwarden_license/bit-web/src/app/billing/providers/payment-details/provider-payment-details.component.ts @@ -0,0 +1,133 @@ +import { Component } from "@angular/core"; +import { ActivatedRoute, Router } from "@angular/router"; +import { + BehaviorSubject, + EMPTY, + filter, + from, + map, + merge, + Observable, + shareReplay, + switchMap, + tap, +} from "rxjs"; +import { catchError } from "rxjs/operators"; + +import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; +import { + DisplayAccountCreditComponent, + DisplayBillingAddressComponent, + DisplayPaymentMethodComponent, +} from "@bitwarden/web-vault/app/billing/payment/components"; +import { + BillingAddress, + MaskedPaymentMethod, +} from "@bitwarden/web-vault/app/billing/payment/types"; +import { BillingClient } from "@bitwarden/web-vault/app/billing/services"; +import { BillableEntity, providerToBillableEntity } from "@bitwarden/web-vault/app/billing/types"; +import { HeaderModule } from "@bitwarden/web-vault/app/layouts/header/header.module"; +import { SharedModule } from "@bitwarden/web-vault/app/shared"; + +class RedirectError { + constructor( + public path: string[], + public relativeTo: ActivatedRoute, + ) {} +} + +type View = { + provider: BillableEntity; + paymentMethod: MaskedPaymentMethod | null; + billingAddress: BillingAddress | null; + credit: number | null; +}; + +@Component({ + templateUrl: "./provider-payment-details.component.html", + standalone: true, + imports: [ + DisplayBillingAddressComponent, + DisplayAccountCreditComponent, + DisplayPaymentMethodComponent, + HeaderModule, + SharedModule, + ], + providers: [BillingClient], +}) +export class ProviderPaymentDetailsComponent { + private viewState$ = new BehaviorSubject(null); + + private load$: Observable = this.activatedRoute.params.pipe( + switchMap(({ providerId }) => this.providerService.get$(providerId)), + switchMap((provider) => + this.configService + .getFeatureFlag$(FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout) + .pipe( + map((managePaymentDetailsOutsideCheckout) => { + if (!managePaymentDetailsOutsideCheckout) { + throw new RedirectError(["../subscription"], this.activatedRoute); + } + return provider; + }), + ), + ), + providerToBillableEntity, + switchMap(async (provider) => { + const [paymentMethod, billingAddress, credit] = await Promise.all([ + this.billingClient.getPaymentMethod(provider), + this.billingClient.getBillingAddress(provider), + this.billingClient.getCredit(provider), + ]); + + return { + provider, + paymentMethod, + billingAddress, + credit, + }; + }), + shareReplay({ bufferSize: 1, refCount: false }), + catchError((error: unknown) => { + if (error instanceof RedirectError) { + return from(this.router.navigate(error.path, { relativeTo: error.relativeTo })).pipe( + switchMap(() => EMPTY), + ); + } + throw error; + }), + ); + + view$: Observable = merge( + this.load$.pipe(tap((view) => this.viewState$.next(view))), + this.viewState$.pipe(filter((view): view is View => view !== null)), + ).pipe(shareReplay({ bufferSize: 1, refCount: true })); + + constructor( + private activatedRoute: ActivatedRoute, + private billingClient: BillingClient, + private configService: ConfigService, + private providerService: ProviderService, + private router: Router, + ) {} + + setBillingAddress = (billingAddress: BillingAddress) => { + if (this.viewState$.value) { + this.viewState$.next({ + ...this.viewState$.value, + billingAddress, + }); + } + }; + + setPaymentMethod = (paymentMethod: MaskedPaymentMethod) => { + if (this.viewState$.value) { + this.viewState$.next({ + ...this.viewState$.value, + paymentMethod, + }); + } + }; +} diff --git a/bitwarden_license/bit-web/src/app/billing/providers/subscription/provider-subscription.component.html b/bitwarden_license/bit-web/src/app/billing/providers/subscription/provider-subscription.component.html index 7f2b205fc22..0205d2838d1 100644 --- a/bitwarden_license/bit-web/src/app/billing/providers/subscription/provider-subscription.component.html +++ b/bitwarden_license/bit-web/src/app/billing/providers/subscription/provider-subscription.component.html @@ -62,49 +62,51 @@
- - -

- {{ "accountCredit" | i18n }} -

-

{{ subscription.accountCredit | currency: "$" }}

-

{{ "creditAppliedDesc" | i18n }}

-
- - -

{{ "paymentMethod" | i18n }}

-

- {{ "noPaymentMethod" | i18n }} -

- - - -

- - {{ subscription.paymentSource.description }} - - {{ "unverified" | i18n }} + @if (!managePaymentDetailsOutsideCheckout) { + + +

+ {{ "accountCredit" | i18n }} +

+

{{ subscription.accountCredit | currency: "$" }}

+

{{ "creditAppliedDesc" | i18n }}

+
+ + +

{{ "paymentMethod" | i18n }}

+

+ {{ "noPaymentMethod" | i18n }}

- - -
- - -

{{ "taxInformation" | i18n }}

-

{{ "taxInformationDesc" | i18n }}

- -
+ + + +

+ + {{ subscription.paymentSource.description }} + - {{ "unverified" | i18n }} +

+
+ + + + +

{{ "taxInformation" | i18n }}

+

{{ "taxInformationDesc" | i18n }}

+ +
+ } diff --git a/bitwarden_license/bit-web/src/app/billing/providers/subscription/provider-subscription.component.ts b/bitwarden_license/bit-web/src/app/billing/providers/subscription/provider-subscription.component.ts index cff2d8e63fe..83a23760d80 100644 --- a/bitwarden_license/bit-web/src/app/billing/providers/subscription/provider-subscription.component.ts +++ b/bitwarden_license/bit-web/src/app/billing/providers/subscription/provider-subscription.component.ts @@ -13,6 +13,8 @@ import { ProviderPlanResponse, ProviderSubscriptionResponse, } from "@bitwarden/common/billing/models/response/provider-subscription-response"; +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 { DialogService, ToastService } from "@bitwarden/components"; import { BillingNotificationService } from "@bitwarden/web-vault/app/billing/services/billing-notification.service"; @@ -34,6 +36,7 @@ export class ProviderSubscriptionComponent implements OnInit, OnDestroy { protected loading: boolean; private destroy$ = new Subject(); protected totalCost: number; + protected managePaymentDetailsOutsideCheckout: boolean; protected readonly TaxInformation = TaxInformation; @@ -44,6 +47,7 @@ export class ProviderSubscriptionComponent implements OnInit, OnDestroy { private billingNotificationService: BillingNotificationService, private dialogService: DialogService, private toastService: ToastService, + private configService: ConfigService, ) {} async ngOnInit() { @@ -51,6 +55,9 @@ export class ProviderSubscriptionComponent implements OnInit, OnDestroy { .pipe( concatMap(async (params) => { this.providerId = params.providerId; + this.managePaymentDetailsOutsideCheckout = await this.configService.getFeatureFlag( + FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout, + ); await this.load(); this.firstLoaded = true; }), diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/overview/overview.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/overview/overview.component.ts index 1fd0afd3458..ca17ea3bc94 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/overview/overview.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/overview/overview.component.ts @@ -29,6 +29,8 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { OrganizationBillingServiceAbstraction } from "@bitwarden/common/billing/abstractions"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; @@ -129,6 +131,7 @@ export class OverviewComponent implements OnInit, OnDestroy { private trialFlowService: TrialFlowService, private organizationBillingService: OrganizationBillingServiceAbstraction, private billingNotificationService: BillingNotificationService, + private configService: ConfigService, ) {} ngOnInit() { @@ -250,12 +253,13 @@ export class OverviewComponent implements OnInit, OnDestroy { } async navigateToPaymentMethod() { - await this.router.navigate( - ["organizations", `${this.organizationId}`, "billing", "payment-method"], - { - state: { launchPaymentModalAutomatically: true }, - }, + const managePaymentDetailsOutsideCheckout = await this.configService.getFeatureFlag( + FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout, ); + const route = managePaymentDetailsOutsideCheckout ? "payment-details" : "payment-method"; + await this.router.navigate(["organizations", `${this.organizationId}`, "billing", route], { + state: { launchPaymentModalAutomatically: true }, + }); } ngOnDestroy(): void { diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index 68228b63bea..8d9eebe6f9f 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -34,6 +34,7 @@ export enum FeatureFlag { PM19956_RequireProviderPaymentMethodDuringSetup = "pm-19956-require-provider-payment-method-during-setup", UseOrganizationWarningsService = "use-organization-warnings-service", AllowTrialLengthZero = "pm-20322-allow-trial-length-0", + PM21881_ManagePaymentDetailsOutsideCheckout = "pm-21881-manage-payment-details-outside-checkout", /* Data Insights and Reporting */ EnableRiskInsightsNotifications = "enable-risk-insights-notifications", @@ -116,6 +117,7 @@ export const DefaultFeatureFlagValue = { [FeatureFlag.PM19956_RequireProviderPaymentMethodDuringSetup]: FALSE, [FeatureFlag.UseOrganizationWarningsService]: FALSE, [FeatureFlag.AllowTrialLengthZero]: FALSE, + [FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout]: FALSE, /* Key Management */ [FeatureFlag.PrivateKeyRegeneration]: FALSE, From 952b84a011c0013b5a064fb055cab99feb0c34a7 Mon Sep 17 00:00:00 2001 From: Nick Krantz <125900171+nick-livefront@users.noreply.github.com> Date: Thu, 10 Jul 2025 09:46:18 -0500 Subject: [PATCH 096/239] add missing label/title for importing SSH Key (#15516) --- .../components/sshkey-section/sshkey-section.component.html | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/vault/src/cipher-form/components/sshkey-section/sshkey-section.component.html b/libs/vault/src/cipher-form/components/sshkey-section/sshkey-section.component.html index b919ed69f0d..de528267db0 100644 --- a/libs/vault/src/cipher-form/components/sshkey-section/sshkey-section.component.html +++ b/libs/vault/src/cipher-form/components/sshkey-section/sshkey-section.component.html @@ -21,6 +21,7 @@ bitSuffix data-testid="import-privateKey" *ngIf="showImport" + appA11yTitle="{{ 'importSshKeyFromClipboard' | i18n }}" (click)="importSshKeyFromClipboard()" > From b1b513b527eddae1d96abf2060aebd3a7e3651eb Mon Sep 17 00:00:00 2001 From: Nick Krantz <125900171+nick-livefront@users.noreply.github.com> Date: Thu, 10 Jul 2025 10:09:42 -0500 Subject: [PATCH 097/239] when a colleciton is deleted, always refresh ciphers (#15549) --- .../organizations/collections/vault.component.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/web/src/app/admin-console/organizations/collections/vault.component.ts b/apps/web/src/app/admin-console/organizations/collections/vault.component.ts index 9c2293889e3..1956498322b 100644 --- a/apps/web/src/app/admin-console/organizations/collections/vault.component.ts +++ b/apps/web/src/app/admin-console/organizations/collections/vault.component.ts @@ -1138,10 +1138,11 @@ export class VaultComponent implements OnInit, OnDestroy { message: this.i18nService.t("deletedCollectionId", collection.name), }); + // Clear the cipher cache to clear the deleted collection from the cipher state + await this.cipherService.clear(); + // Navigate away if we deleted the collection we were viewing if (this.selectedCollection?.node.id === collection.id) { - // Clear the cipher cache to clear the deleted collection from the cipher state - await this.cipherService.clear(); void this.router.navigate([], { queryParams: { collectionId: this.selectedCollection.parent?.node.id ?? null }, queryParamsHandling: "merge", From 8135e840abe292106657d6164505f7c26c213d24 Mon Sep 17 00:00:00 2001 From: Leslie Tilton <23057410+Banrion@users.noreply.github.com> Date: Thu, 10 Jul 2025 10:33:23 -0500 Subject: [PATCH 098/239] Remove nested bit-layout after bit-layout changes fixed bug that required it (#15559) --- .../risk-insights.component.html | 260 +++++++++--------- .../risk-insights.component.ts | 2 - 2 files changed, 129 insertions(+), 133 deletions(-) diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/risk-insights.component.html b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/risk-insights.component.html index 627db269097..89ea600f6e0 100644 --- a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/risk-insights.component.html +++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/risk-insights.component.html @@ -1,140 +1,138 @@ - -

{{ "riskInsights" | i18n }}

-
- {{ "reviewAtRiskPasswords" | i18n }} -
-
- - {{ - "dataLastUpdated" | i18n: (dataLastUpdated$ | async | date: "MMMM d, y 'at' h:mm a") - }} - - - {{ "refresh" | i18n }} - - - - +

{{ "riskInsights" | i18n }}

+
+ {{ "reviewAtRiskPasswords" | i18n }} +
+
+ + {{ + "dataLastUpdated" | i18n: (dataLastUpdated$ | async | date: "MMMM d, y 'at' h:mm a") + }} + + + {{ "refresh" | i18n }} + + + -
- - - - - - - - {{ "criticalApplicationsWithCount" | i18n: (criticalApps$ | async)?.length ?? 0 }} - - - - + +
+ + + + + + + + {{ "criticalApplicationsWithCount" | i18n: (criticalApps$ | async)?.length ?? 0 }} + + + + - - - - - - {{ - (dataService.atRiskMemberDetails.length > 0 - ? "atRiskMembersDescription" - : "atRiskMembersDescriptionNone" - ) | i18n - }} - -
-
{{ "email" | i18n }}
-
- {{ "atRiskPasswords" | i18n }} -
+ + + + + + {{ + (dataService.atRiskMemberDetails.length > 0 + ? "atRiskMembersDescription" + : "atRiskMembersDescriptionNone" + ) | i18n + }} + +
+
{{ "email" | i18n }}
+
+ {{ "atRiskPasswords" | i18n }}
- -
-
{{ member.email }}
-
{{ member.atRiskPasswordCount }}
-
-
- - - - - - - - -
- {{ "atRiskMembersWithCount" | i18n: dataService.appAtRiskMembers.members.length }}
-
- {{ - (dataService.appAtRiskMembers.members.length > 0 - ? "atRiskMembersDescriptionWithApp" - : "atRiskMembersDescriptionWithAppNone" - ) | i18n: dataService.appAtRiskMembers.applicationName - }} -
-
- + +
{{ member.email }}
- -
- -
- - - - - - - {{ - (dataService.atRiskAppDetails.length > 0 - ? "atRiskApplicationsDescription" - : "atRiskApplicationsDescriptionNone" - ) | i18n - }} - -
-
- {{ "application" | i18n }} -
-
- {{ "atRiskPasswords" | i18n }} -
+
{{ member.atRiskPasswordCount }}
- -
-
{{ app.applicationName }}
-
{{ app.atRiskPasswordCount }}
-
-
-
-
- - +
+ + + + + + + +
+ {{ "atRiskMembersWithCount" | i18n: dataService.appAtRiskMembers.members.length }} +
+
+ {{ + (dataService.appAtRiskMembers.members.length > 0 + ? "atRiskMembersDescriptionWithApp" + : "atRiskMembersDescriptionWithAppNone" + ) | i18n: dataService.appAtRiskMembers.applicationName + }} +
+
+ +
{{ member.email }}
+
+
+
+
+ + + + + + + {{ + (dataService.atRiskAppDetails.length > 0 + ? "atRiskApplicationsDescription" + : "atRiskApplicationsDescriptionNone" + ) | i18n + }} + +
+
+ {{ "application" | i18n }} +
+
+ {{ "atRiskPasswords" | i18n }} +
+
+ +
+
{{ app.applicationName }}
+
{{ app.atRiskPasswordCount }}
+
+
+
+
+
+ diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/risk-insights.component.ts b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/risk-insights.component.ts index b6da0f79255..5f94db0ee3c 100644 --- a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/risk-insights.component.ts +++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/risk-insights.component.ts @@ -23,7 +23,6 @@ import { DrawerBodyComponent, DrawerComponent, DrawerHeaderComponent, - LayoutComponent, TabsModule, } from "@bitwarden/components"; import { HeaderModule } from "@bitwarden/web-vault/app/layouts/header/header.module"; @@ -53,7 +52,6 @@ export enum RiskInsightsTabType { DrawerComponent, DrawerBodyComponent, DrawerHeaderComponent, - LayoutComponent, ], }) export class RiskInsightsComponent implements OnInit { From 318040233c8c17f0e909bca5d777c00c628b10c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Thu, 10 Jul 2025 19:17:13 +0200 Subject: [PATCH 099/239] [PM-23159] Update arboard and enable exclude from history on Linux (#15393) --- apps/desktop/desktop_native/Cargo.lock | 4 ++-- apps/desktop/desktop_native/Cargo.toml | 14 +++++++------- apps/desktop/desktop_native/core/src/clipboard.rs | 8 ++++++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/apps/desktop/desktop_native/Cargo.lock b/apps/desktop/desktop_native/Cargo.lock index d02ffb9b026..9d0fe633013 100644 --- a/apps/desktop/desktop_native/Cargo.lock +++ b/apps/desktop/desktop_native/Cargo.lock @@ -120,9 +120,9 @@ checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "arboard" -version = "3.5.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1df21f715862ede32a0c525ce2ca4d52626bb0007f8c18b87a384503ac33e70" +checksum = "55f533f8e0af236ffe5eb979b99381df3258853f00ba2e44b6e1955292c75227" dependencies = [ "clipboard-win", "log", diff --git a/apps/desktop/desktop_native/Cargo.toml b/apps/desktop/desktop_native/Cargo.toml index 1aa6f784ec7..a778c9ed359 100644 --- a/apps/desktop/desktop_native/Cargo.toml +++ b/apps/desktop/desktop_native/Cargo.toml @@ -11,23 +11,23 @@ publish = false [workspace.dependencies] aes = "=0.8.4" anyhow = "=1.0.94" -arboard = { version = "=3.5.0", default-features = false } -argon2 = "=0.5.3" +arboard = { version = "=3.6.0", default-features = false } +argon2 = "=0.5.3" ashpd = "=0.11.0" base64 = "=0.22.1" bindgen = "=0.72.0" bitwarden-russh = { git = "https://github.com/bitwarden/bitwarden-russh.git", rev = "a641316227227f8777fdf56ac9fa2d6b5f7fe662" } byteorder = "=1.5.0" bytes = "=1.10.1" -cbc = "=0.1.2" +cbc = "=0.1.2" core-foundation = "=0.10.0" dirs = "=6.0.0" -ed25519 = "=2.2.3" +ed25519 = "=2.2.3" embed_plist = "=1.2.2" futures = "=0.3.31" hex = "=0.4.3" homedir = "=0.3.4" -interprocess = "=2.2.1" +interprocess = "=2.2.1" keytar = "=0.1.6" libc = "=0.2.172" log = "=0.4.25" @@ -37,7 +37,7 @@ napi-derive = "=2.16.13" oo7 = "=0.4.3" oslog = "=0.2.0" pin-project = "=1.1.10" -pkcs8 = "=0.10.2" +pkcs8 = "=0.10.2" rand = "=0.9.1" rsa = "=0.9.6" russh-cryptovec = "=0.7.3" @@ -50,7 +50,7 @@ sha2 = "=0.10.8" simplelog = "=0.12.2" ssh-encoding = "=0.2.0" ssh-key = {version = "=0.6.7", default-features = false } -sysinfo = "=0.35.0" +sysinfo = "=0.35.0" thiserror = "=2.0.12" tokio = "=1.45.0" tokio-stream = "=0.1.15" diff --git a/apps/desktop/desktop_native/core/src/clipboard.rs b/apps/desktop/desktop_native/core/src/clipboard.rs index bb3e3a43149..32163ca3d1a 100644 --- a/apps/desktop/desktop_native/core/src/clipboard.rs +++ b/apps/desktop/desktop_native/core/src/clipboard.rs @@ -30,10 +30,14 @@ fn clipboard_set(set: Set, password: bool) -> Set { // Wait for clipboard to be available on linux #[cfg(target_os = "linux")] -fn clipboard_set(set: Set, _password: bool) -> Set { +fn clipboard_set(set: Set, password: bool) -> Set { use arboard::SetExtLinux; - set.wait() + if password { + set.exclude_from_history().wait() + } else { + set.wait() + } } #[cfg(target_os = "macos")] From c5be837b51c556c2e9614d188a27c76682edb172 Mon Sep 17 00:00:00 2001 From: Todd Martin <106564991+trmartin4@users.noreply.github.com> Date: Thu, 10 Jul 2025 15:00:49 -0400 Subject: [PATCH 100/239] chore(feature-flag) [PM-22604] Remove 2FA persistence feature flag * Removed flag. * Fixed tests to no longer reference flag. * Fixed test. * Removed duplicate test class. * Moved files into folders for yubikey and authenticator * Removed TwoFactorAuthEmailComponentService since it is no longer needed * Removed export * Fixed export --- ...actor-auth-email-component.service.spec.ts | 112 ------------ ...two-factor-auth-email-component.service.ts | 49 ------ .../src/popup/services/services.module.ts | 7 - .../src/services/jslib-services.module.ts | 7 - .../two-factor-auth/child-components/index.ts | 1 - ...o-factor-auth-authenticator.component.html | 0 ...two-factor-auth-authenticator.component.ts | 0 ...two-factor-auth-email-component.service.ts | 6 - .../two-factor-auth-email/index.ts | 2 - ...auth-component-email-cache.service.spec.ts | 165 ------------------ ...auth-email-component-cache.service.spec.ts | 78 +-------- ...ctor-auth-email-component-cache.service.ts | 27 --- ...two-factor-auth-email-component.service.ts | 10 -- .../two-factor-auth-email.component.ts | 5 - .../two-factor-auth-yubikey.component.html | 0 .../two-factor-auth-yubikey.component.ts | 0 ...actor-auth-component-cache.service.spec.ts | 84 +-------- ...two-factor-auth-component-cache.service.ts | 27 --- .../two-factor-auth.component.spec.ts | 1 - .../two-factor-auth.component.ts | 7 +- libs/common/src/enums/feature-flag.enum.ts | 2 - 21 files changed, 9 insertions(+), 581 deletions(-) delete mode 100644 apps/browser/src/auth/services/extension-two-factor-auth-email-component.service.spec.ts delete mode 100644 apps/browser/src/auth/services/extension-two-factor-auth-email-component.service.ts rename libs/auth/src/angular/two-factor-auth/child-components/{ => two-factor-auth-authenticator}/two-factor-auth-authenticator.component.html (100%) rename libs/auth/src/angular/two-factor-auth/child-components/{ => two-factor-auth-authenticator}/two-factor-auth-authenticator.component.ts (100%) delete mode 100644 libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/default-two-factor-auth-email-component.service.ts delete mode 100644 libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/index.ts delete mode 100644 libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-component-email-cache.service.spec.ts delete mode 100644 libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email-component.service.ts rename libs/auth/src/angular/two-factor-auth/child-components/{ => two-factor-auth-yubikey}/two-factor-auth-yubikey.component.html (100%) rename libs/auth/src/angular/two-factor-auth/child-components/{ => two-factor-auth-yubikey}/two-factor-auth-yubikey.component.ts (100%) diff --git a/apps/browser/src/auth/services/extension-two-factor-auth-email-component.service.spec.ts b/apps/browser/src/auth/services/extension-two-factor-auth-email-component.service.spec.ts deleted file mode 100644 index 432d00047a2..00000000000 --- a/apps/browser/src/auth/services/extension-two-factor-auth-email-component.service.spec.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { MockProxy, mock } from "jest-mock-extended"; - -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; -import { DialogService } from "@bitwarden/components"; - -// Must mock modules before importing -jest.mock("../popup/utils/auth-popout-window", () => { - const originalModule = jest.requireActual("../popup/utils/auth-popout-window"); - - return { - ...originalModule, // avoid losing the original module's exports - openTwoFactorAuthEmailPopout: jest.fn(), - }; -}); - -jest.mock("../../platform/browser/browser-popup-utils", () => ({ - inPopup: jest.fn(), -})); - -// FIXME (PM-22628): Popup imports are forbidden in background -// eslint-disable-next-line no-restricted-imports -import { openTwoFactorAuthEmailPopout } from "../../auth/popup/utils/auth-popout-window"; -import BrowserPopupUtils from "../../platform/browser/browser-popup-utils"; - -import { ExtensionTwoFactorAuthEmailComponentService } from "./extension-two-factor-auth-email-component.service"; - -describe("ExtensionTwoFactorAuthEmailComponentService", () => { - let extensionTwoFactorAuthEmailComponentService: ExtensionTwoFactorAuthEmailComponentService; - - let dialogService: MockProxy; - let window: MockProxy; - let configService: MockProxy; - - beforeEach(() => { - jest.clearAllMocks(); - - dialogService = mock(); - window = mock(); - configService = mock(); - - extensionTwoFactorAuthEmailComponentService = new ExtensionTwoFactorAuthEmailComponentService( - dialogService, - window, - configService, - ); - }); - - describe("openPopoutIfApprovedForEmail2fa", () => { - it("should open a popout if the user confirms the warning to popout the extension when in the popup", async () => { - // Arrange - configService.getFeatureFlag.mockResolvedValue(false); - dialogService.openSimpleDialog.mockResolvedValue(true); - - jest.spyOn(BrowserPopupUtils, "inPopup").mockReturnValue(true); - - // Act - await extensionTwoFactorAuthEmailComponentService.openPopoutIfApprovedForEmail2fa(); - - // Assert - expect(dialogService.openSimpleDialog).toHaveBeenCalledWith({ - title: { key: "warning" }, - content: { key: "popup2faCloseMessage" }, - type: "warning", - }); - - expect(openTwoFactorAuthEmailPopout).toHaveBeenCalled(); - }); - - it("should not open a popout if the user cancels the warning to popout the extension when in the popup", async () => { - // Arrange - configService.getFeatureFlag.mockResolvedValue(false); - dialogService.openSimpleDialog.mockResolvedValue(false); - - jest.spyOn(BrowserPopupUtils, "inPopup").mockReturnValue(true); - - // Act - await extensionTwoFactorAuthEmailComponentService.openPopoutIfApprovedForEmail2fa(); - - // Assert - expect(dialogService.openSimpleDialog).toHaveBeenCalledWith({ - title: { key: "warning" }, - content: { key: "popup2faCloseMessage" }, - type: "warning", - }); - - expect(openTwoFactorAuthEmailPopout).not.toHaveBeenCalled(); - }); - - it("should not open a popout if not in the popup", async () => { - // Arrange - configService.getFeatureFlag.mockResolvedValue(false); - jest.spyOn(BrowserPopupUtils, "inPopup").mockReturnValue(false); - - // Act - await extensionTwoFactorAuthEmailComponentService.openPopoutIfApprovedForEmail2fa(); - - // Assert - expect(dialogService.openSimpleDialog).not.toHaveBeenCalled(); - expect(openTwoFactorAuthEmailPopout).not.toHaveBeenCalled(); - }); - - it("does not prompt or open a popout if the feature flag is enabled", async () => { - configService.getFeatureFlag.mockResolvedValue(true); - jest.spyOn(BrowserPopupUtils, "inPopup").mockReturnValue(true); - - await extensionTwoFactorAuthEmailComponentService.openPopoutIfApprovedForEmail2fa(); - - expect(dialogService.openSimpleDialog).not.toHaveBeenCalled(); - expect(openTwoFactorAuthEmailPopout).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/apps/browser/src/auth/services/extension-two-factor-auth-email-component.service.ts b/apps/browser/src/auth/services/extension-two-factor-auth-email-component.service.ts deleted file mode 100644 index e9cb53f935e..00000000000 --- a/apps/browser/src/auth/services/extension-two-factor-auth-email-component.service.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { - DefaultTwoFactorAuthEmailComponentService, - TwoFactorAuthEmailComponentService, -} from "@bitwarden/auth/angular"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; -import { DialogService } from "@bitwarden/components"; - -// FIXME (PM-22628): Popup imports are forbidden in background -// eslint-disable-next-line no-restricted-imports -import { openTwoFactorAuthEmailPopout } from "../../auth/popup/utils/auth-popout-window"; -import BrowserPopupUtils from "../../platform/browser/browser-popup-utils"; - -// TODO: popup state persistence should eventually remove the need for this service -export class ExtensionTwoFactorAuthEmailComponentService - extends DefaultTwoFactorAuthEmailComponentService - implements TwoFactorAuthEmailComponentService -{ - constructor( - private dialogService: DialogService, - private window: Window, - private configService: ConfigService, - ) { - super(); - } - - async openPopoutIfApprovedForEmail2fa(): Promise { - const isTwoFactorFormPersistenceEnabled = await this.configService.getFeatureFlag( - FeatureFlag.PM9115_TwoFactorExtensionDataPersistence, - ); - - if (isTwoFactorFormPersistenceEnabled) { - // If the feature flag is enabled, we don't need to prompt the user to open the popout - return; - } - - if (BrowserPopupUtils.inPopup(this.window)) { - const confirmed = await this.dialogService.openSimpleDialog({ - title: { key: "warning" }, - content: { key: "popup2faCloseMessage" }, - type: "warning", - }); - if (confirmed) { - await openTwoFactorAuthEmailPopout(); - this.window.close(); - } - } - } -} diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index d70418137f8..ca8a76f7bcb 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -24,7 +24,6 @@ import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services. import { LoginComponentService, TwoFactorAuthComponentService, - TwoFactorAuthEmailComponentService, TwoFactorAuthDuoComponentService, TwoFactorAuthWebAuthnComponentService, SsoComponentService, @@ -147,7 +146,6 @@ import { ExtensionSsoComponentService } from "../../auth/popup/login/extension-s import { ExtensionLogoutService } from "../../auth/popup/logout/extension-logout.service"; import { ExtensionTwoFactorAuthComponentService } from "../../auth/services/extension-two-factor-auth-component.service"; import { ExtensionTwoFactorAuthDuoComponentService } from "../../auth/services/extension-two-factor-auth-duo-component.service"; -import { ExtensionTwoFactorAuthEmailComponentService } from "../../auth/services/extension-two-factor-auth-email-component.service"; import { ExtensionTwoFactorAuthWebAuthnComponentService } from "../../auth/services/extension-two-factor-auth-webauthn-component.service"; import { AutofillService as AutofillServiceAbstraction } from "../../autofill/services/abstractions/autofill.service"; import AutofillService from "../../autofill/services/autofill.service"; @@ -560,11 +558,6 @@ const safeProviders: SafeProvider[] = [ useClass: ExtensionTwoFactorAuthComponentService, deps: [WINDOW], }), - safeProvider({ - provide: TwoFactorAuthEmailComponentService, - useClass: ExtensionTwoFactorAuthEmailComponentService, - deps: [DialogService, WINDOW, ConfigService], - }), safeProvider({ provide: TwoFactorAuthWebAuthnComponentService, useClass: ExtensionTwoFactorAuthWebAuthnComponentService, diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index d51d5e650c5..c3f33f2a796 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -24,14 +24,12 @@ import { DefaultRegistrationFinishService, DefaultSetPasswordJitService, DefaultTwoFactorAuthComponentService, - DefaultTwoFactorAuthEmailComponentService, DefaultTwoFactorAuthWebAuthnComponentService, LoginComponentService, LoginDecryptionOptionsService, RegistrationFinishService as RegistrationFinishServiceAbstraction, SetPasswordJitService, TwoFactorAuthComponentService, - TwoFactorAuthEmailComponentService, TwoFactorAuthWebAuthnComponentService, } from "@bitwarden/auth/angular"; // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. @@ -1471,11 +1469,6 @@ const safeProviders: SafeProvider[] = [ useClass: DefaultTwoFactorAuthWebAuthnComponentService, deps: [], }), - safeProvider({ - provide: TwoFactorAuthEmailComponentService, - useClass: DefaultTwoFactorAuthEmailComponentService, - deps: [], - }), safeProvider({ provide: ViewCacheService, useExisting: NoopViewCacheService, diff --git a/libs/auth/src/angular/two-factor-auth/child-components/index.ts b/libs/auth/src/angular/two-factor-auth/child-components/index.ts index 429da3f14b3..d48cb8a6921 100644 --- a/libs/auth/src/angular/two-factor-auth/child-components/index.ts +++ b/libs/auth/src/angular/two-factor-auth/child-components/index.ts @@ -1,3 +1,2 @@ -export * from "./two-factor-auth-email"; export * from "./two-factor-auth-duo"; export * from "./two-factor-auth-webauthn"; diff --git a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-authenticator.component.html b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-authenticator/two-factor-auth-authenticator.component.html similarity index 100% rename from libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-authenticator.component.html rename to libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-authenticator/two-factor-auth-authenticator.component.html diff --git a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-authenticator.component.ts b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-authenticator/two-factor-auth-authenticator.component.ts similarity index 100% rename from libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-authenticator.component.ts rename to libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-authenticator/two-factor-auth-authenticator.component.ts diff --git a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/default-two-factor-auth-email-component.service.ts b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/default-two-factor-auth-email-component.service.ts deleted file mode 100644 index caae13acc38..00000000000 --- a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/default-two-factor-auth-email-component.service.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { TwoFactorAuthEmailComponentService } from "./two-factor-auth-email-component.service"; - -export class DefaultTwoFactorAuthEmailComponentService - implements TwoFactorAuthEmailComponentService { - // no default implementation -} diff --git a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/index.ts b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/index.ts deleted file mode 100644 index 91f11b0b7dd..00000000000 --- a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./default-two-factor-auth-email-component.service"; -export * from "./two-factor-auth-email-component.service"; diff --git a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-component-email-cache.service.spec.ts b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-component-email-cache.service.spec.ts deleted file mode 100644 index d2d86710b72..00000000000 --- a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-component-email-cache.service.spec.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { TestBed } from "@angular/core/testing"; -import { mock, MockProxy } from "jest-mock-extended"; -import { BehaviorSubject } from "rxjs"; - -import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; - -import { - TwoFactorAuthEmailComponentCache, - TwoFactorAuthEmailComponentCacheService, -} from "./two-factor-auth-email-component-cache.service"; - -describe("TwoFactorAuthEmailCache", () => { - describe("fromJSON", () => { - it("returns null when input is null", () => { - const result = TwoFactorAuthEmailComponentCache.fromJSON(null as any); - expect(result).toBeNull(); - }); - - it("creates a TwoFactorAuthEmailCache instance from valid JSON", () => { - const jsonData = { emailSent: true }; - const result = TwoFactorAuthEmailComponentCache.fromJSON(jsonData); - - expect(result).not.toBeNull(); - expect(result).toBeInstanceOf(TwoFactorAuthEmailComponentCache); - expect(result?.emailSent).toBe(true); - }); - }); -}); - -describe("TwoFactorAuthEmailComponentCacheService", () => { - let service: TwoFactorAuthEmailComponentCacheService; - let mockViewCacheService: MockProxy; - let mockConfigService: MockProxy; - let cacheData: BehaviorSubject; - let mockSignal: any; - - beforeEach(() => { - mockViewCacheService = mock(); - mockConfigService = mock(); - cacheData = new BehaviorSubject(null); - mockSignal = jest.fn(() => cacheData.getValue()); - mockSignal.set = jest.fn((value: TwoFactorAuthEmailComponentCache | null) => - cacheData.next(value), - ); - mockViewCacheService.signal.mockReturnValue(mockSignal); - - TestBed.configureTestingModule({ - providers: [ - TwoFactorAuthEmailComponentCacheService, - { provide: ViewCacheService, useValue: mockViewCacheService }, - { provide: ConfigService, useValue: mockConfigService }, - ], - }); - - service = TestBed.inject(TwoFactorAuthEmailComponentCacheService); - }); - - it("creates the service", () => { - expect(service).toBeTruthy(); - }); - - describe("init", () => { - it("sets featureEnabled to true when flag is enabled", async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(true); - - await service.init(); - - expect(mockConfigService.getFeatureFlag).toHaveBeenCalledWith( - FeatureFlag.PM9115_TwoFactorExtensionDataPersistence, - ); - - service.cacheData({ emailSent: true }); - expect(mockSignal.set).toHaveBeenCalled(); - }); - - it("sets featureEnabled to false when flag is disabled", async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(false); - - await service.init(); - - expect(mockConfigService.getFeatureFlag).toHaveBeenCalledWith( - FeatureFlag.PM9115_TwoFactorExtensionDataPersistence, - ); - - service.cacheData({ emailSent: true }); - expect(mockSignal.set).not.toHaveBeenCalled(); - }); - }); - - describe("cacheData", () => { - beforeEach(async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(true); - await service.init(); - }); - - it("caches email sent state when feature is enabled", () => { - service.cacheData({ emailSent: true }); - - expect(mockSignal.set).toHaveBeenCalledWith({ - emailSent: true, - }); - }); - - it("does not cache data when feature is disabled", async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(false); - await service.init(); - - service.cacheData({ emailSent: true }); - - expect(mockSignal.set).not.toHaveBeenCalled(); - }); - }); - - describe("clearCachedData", () => { - beforeEach(async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(true); - await service.init(); - }); - - it("clears cached data when feature is enabled", () => { - service.clearCachedData(); - - expect(mockSignal.set).toHaveBeenCalledWith(null); - }); - - it("does not clear cached data when feature is disabled", async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(false); - await service.init(); - - service.clearCachedData(); - - expect(mockSignal.set).not.toHaveBeenCalled(); - }); - }); - - describe("getCachedData", () => { - beforeEach(async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(true); - await service.init(); - }); - - it("returns cached data when feature is enabled", () => { - const testData = new TwoFactorAuthEmailComponentCache(); - testData.emailSent = true; - cacheData.next(testData); - - const result = service.getCachedData(); - - expect(result).toEqual(testData); - expect(mockSignal).toHaveBeenCalled(); - }); - - it("returns null when feature is disabled", async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(false); - await service.init(); - - const result = service.getCachedData(); - - expect(result).toBeNull(); - expect(mockSignal).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email-component-cache.service.spec.ts b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email-component-cache.service.spec.ts index 36d99ee56ac..e5ab04b51ad 100644 --- a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email-component-cache.service.spec.ts +++ b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email-component-cache.service.spec.ts @@ -3,7 +3,6 @@ import { mock, MockProxy } from "jest-mock-extended"; import { BehaviorSubject } from "rxjs"; import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { @@ -61,87 +60,26 @@ describe("TwoFactorAuthEmailComponentCacheService", () => { expect(service).toBeTruthy(); }); - describe("init", () => { - it("sets featureEnabled to true when flag is enabled", async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(true); - - await service.init(); - - expect(mockConfigService.getFeatureFlag).toHaveBeenCalledWith( - FeatureFlag.PM9115_TwoFactorExtensionDataPersistence, - ); - - service.cacheData({ emailSent: true }); - expect(mockSignal.set).toHaveBeenCalled(); - }); - - it("sets featureEnabled to false when flag is disabled", async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(false); - - await service.init(); - - expect(mockConfigService.getFeatureFlag).toHaveBeenCalledWith( - FeatureFlag.PM9115_TwoFactorExtensionDataPersistence, - ); - - service.cacheData({ emailSent: true }); - expect(mockSignal.set).not.toHaveBeenCalled(); - }); - }); - describe("cacheData", () => { - beforeEach(async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(true); - await service.init(); - }); - - it("caches email sent state when feature is enabled", () => { + it("caches email sent state", () => { service.cacheData({ emailSent: true }); expect(mockSignal.set).toHaveBeenCalledWith({ emailSent: true, }); }); - - it("does not cache data when feature is disabled", async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(false); - await service.init(); - - service.cacheData({ emailSent: true }); - - expect(mockSignal.set).not.toHaveBeenCalled(); - }); }); describe("clearCachedData", () => { - beforeEach(async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(true); - await service.init(); - }); - - it("clears cached data when feature is enabled", () => { + it("clears cached data", () => { service.clearCachedData(); expect(mockSignal.set).toHaveBeenCalledWith(null); }); - - it("does not clear cached data when feature is disabled", async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(false); - await service.init(); - - service.clearCachedData(); - - expect(mockSignal.set).not.toHaveBeenCalled(); - }); }); describe("getCachedData", () => { - beforeEach(async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(true); - await service.init(); - }); - - it("returns cached data when feature is enabled", () => { + it("returns cached data", () => { const testData = new TwoFactorAuthEmailComponentCache(); testData.emailSent = true; cacheData.next(testData); @@ -151,15 +89,5 @@ describe("TwoFactorAuthEmailComponentCacheService", () => { expect(result).toEqual(testData); expect(mockSignal).toHaveBeenCalled(); }); - - it("returns null when feature is disabled", async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(false); - await service.init(); - - const result = service.getCachedData(); - - expect(result).toBeNull(); - expect(mockSignal).not.toHaveBeenCalled(); - }); }); }); diff --git a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email-component-cache.service.ts b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email-component-cache.service.ts index d274b8003d7..d98387e1cf5 100644 --- a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email-component-cache.service.ts +++ b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email-component-cache.service.ts @@ -2,8 +2,6 @@ import { inject, Injectable, WritableSignal } from "@angular/core"; import { Jsonify } from "type-fest"; import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; /** * The key for the email two factor auth component cache. @@ -34,10 +32,6 @@ export class TwoFactorAuthEmailComponentCache { @Injectable() export class TwoFactorAuthEmailComponentCacheService { private viewCacheService: ViewCacheService = inject(ViewCacheService); - private configService: ConfigService = inject(ConfigService); - - /** True when the feature flag is enabled */ - private featureEnabled: boolean = false; /** * Signal for the cached email state. @@ -49,23 +43,10 @@ export class TwoFactorAuthEmailComponentCacheService { deserializer: TwoFactorAuthEmailComponentCache.fromJSON, }); - /** - * Must be called once before interacting with the cached data. - */ - async init() { - this.featureEnabled = await this.configService.getFeatureFlag( - FeatureFlag.PM9115_TwoFactorExtensionDataPersistence, - ); - } - /** * Cache the email sent state. */ cacheData(data: { emailSent: boolean }): void { - if (!this.featureEnabled) { - return; - } - this.emailCache.set({ emailSent: data.emailSent, } as TwoFactorAuthEmailComponentCache); @@ -75,10 +56,6 @@ export class TwoFactorAuthEmailComponentCacheService { * Clear the cached email data. */ clearCachedData(): void { - if (!this.featureEnabled) { - return; - } - this.emailCache.set(null); } @@ -86,10 +63,6 @@ export class TwoFactorAuthEmailComponentCacheService { * Get whether the email has been sent. */ getCachedData(): TwoFactorAuthEmailComponentCache | null { - if (!this.featureEnabled) { - return null; - } - return this.emailCache(); } } diff --git a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email-component.service.ts b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email-component.service.ts deleted file mode 100644 index fa96b6b96c2..00000000000 --- a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email-component.service.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * A service that manages all cross client functionality for the email 2FA component. - */ -export abstract class TwoFactorAuthEmailComponentService { - /** - * Optionally shows a warning to the user that they might need to popout the - * window to complete email 2FA. - */ - abstract openPopoutIfApprovedForEmail2fa?(): Promise; -} diff --git a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email.component.ts b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email.component.ts index 65641284cf1..9b402f3a956 100644 --- a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email.component.ts +++ b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email.component.ts @@ -25,7 +25,6 @@ import { } from "@bitwarden/components"; import { TwoFactorAuthEmailComponentCacheService } from "./two-factor-auth-email-component-cache.service"; -import { TwoFactorAuthEmailComponentService } from "./two-factor-auth-email-component.service"; @Component({ selector: "app-two-factor-auth-email", @@ -66,14 +65,10 @@ export class TwoFactorAuthEmailComponent implements OnInit { protected apiService: ApiService, protected appIdService: AppIdService, private toastService: ToastService, - private twoFactorAuthEmailComponentService: TwoFactorAuthEmailComponentService, private cacheService: TwoFactorAuthEmailComponentCacheService, ) {} async ngOnInit(): Promise { - await this.twoFactorAuthEmailComponentService.openPopoutIfApprovedForEmail2fa?.(); - await this.cacheService.init(); - // Check if email was already sent const cachedData = this.cacheService.getCachedData(); if (cachedData?.emailSent) { diff --git a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-yubikey.component.html b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-yubikey/two-factor-auth-yubikey.component.html similarity index 100% rename from libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-yubikey.component.html rename to libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-yubikey/two-factor-auth-yubikey.component.html diff --git a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-yubikey.component.ts b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-yubikey/two-factor-auth-yubikey.component.ts similarity index 100% rename from libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-yubikey.component.ts rename to libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-yubikey/two-factor-auth-yubikey.component.ts diff --git a/libs/auth/src/angular/two-factor-auth/two-factor-auth-component-cache.service.spec.ts b/libs/auth/src/angular/two-factor-auth/two-factor-auth-component-cache.service.spec.ts index 5b5d486556b..24cd18d43e5 100644 --- a/libs/auth/src/angular/two-factor-auth/two-factor-auth-component-cache.service.spec.ts +++ b/libs/auth/src/angular/two-factor-auth/two-factor-auth-component-cache.service.spec.ts @@ -4,8 +4,6 @@ import { BehaviorSubject } from "rxjs"; import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { TwoFactorAuthComponentCache, @@ -40,13 +38,11 @@ describe("TwoFactorAuthCache", () => { describe("TwoFactorAuthComponentCacheService", () => { let service: TwoFactorAuthComponentCacheService; let mockViewCacheService: MockProxy; - let mockConfigService: MockProxy; let cacheData: BehaviorSubject; let mockSignal: any; beforeEach(() => { mockViewCacheService = mock(); - mockConfigService = mock(); cacheData = new BehaviorSubject(null); mockSignal = jest.fn(() => cacheData.getValue()); mockSignal.set = jest.fn((value: TwoFactorAuthComponentCache | null) => cacheData.next(value)); @@ -56,7 +52,6 @@ describe("TwoFactorAuthComponentCacheService", () => { providers: [ TwoFactorAuthComponentCacheService, { provide: ViewCacheService, useValue: mockViewCacheService }, - { provide: ConfigService, useValue: mockConfigService }, ], }); @@ -67,41 +62,8 @@ describe("TwoFactorAuthComponentCacheService", () => { expect(service).toBeTruthy(); }); - describe("init", () => { - it("sets featureEnabled to true when flag is enabled", async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(true); - - await service.init(); - - expect(mockConfigService.getFeatureFlag).toHaveBeenCalledWith( - FeatureFlag.PM9115_TwoFactorExtensionDataPersistence, - ); - - service.cacheData({ token: "123456" }); - expect(mockSignal.set).toHaveBeenCalled(); - }); - - it("sets featureEnabled to false when flag is disabled", async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(false); - - await service.init(); - - expect(mockConfigService.getFeatureFlag).toHaveBeenCalledWith( - FeatureFlag.PM9115_TwoFactorExtensionDataPersistence, - ); - - service.cacheData({ token: "123456" }); - expect(mockSignal.set).not.toHaveBeenCalled(); - }); - }); - describe("cacheData", () => { - beforeEach(async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(true); - await service.init(); - }); - - it("caches complete data when feature is enabled", () => { + it("caches complete data", () => { const testData: TwoFactorAuthComponentData = { token: "123456", remember: true, @@ -117,7 +79,7 @@ describe("TwoFactorAuthComponentCacheService", () => { }); }); - it("caches partial data when feature is enabled", () => { + it("caches partial data", () => { service.cacheData({ token: "123456" }); expect(mockSignal.set).toHaveBeenCalledWith({ @@ -126,46 +88,18 @@ describe("TwoFactorAuthComponentCacheService", () => { selectedProviderType: undefined, }); }); - - it("does not cache data when feature is disabled", async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(false); - await service.init(); - - service.cacheData({ token: "123456" }); - - expect(mockSignal.set).not.toHaveBeenCalled(); - }); }); describe("clearCachedData", () => { - beforeEach(async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(true); - await service.init(); - }); - - it("clears cached data when feature is enabled", () => { + it("clears cached data", () => { service.clearCachedData(); expect(mockSignal.set).toHaveBeenCalledWith(null); }); - - it("does not clear cached data when feature is disabled", async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(false); - await service.init(); - - service.clearCachedData(); - - expect(mockSignal.set).not.toHaveBeenCalled(); - }); }); describe("getCachedData", () => { - beforeEach(async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(true); - await service.init(); - }); - - it("returns cached data when feature is enabled", () => { + it("returns cached data", () => { const testData = new TwoFactorAuthComponentCache(); testData.token = "123456"; testData.remember = true; @@ -177,15 +111,5 @@ describe("TwoFactorAuthComponentCacheService", () => { expect(result).toEqual(testData); expect(mockSignal).toHaveBeenCalled(); }); - - it("returns null when feature is disabled", async () => { - mockConfigService.getFeatureFlag.mockResolvedValue(false); - await service.init(); - - const result = service.getCachedData(); - - expect(result).toBeNull(); - expect(mockSignal).not.toHaveBeenCalled(); - }); }); }); diff --git a/libs/auth/src/angular/two-factor-auth/two-factor-auth-component-cache.service.ts b/libs/auth/src/angular/two-factor-auth/two-factor-auth-component-cache.service.ts index 2d9fcaa5633..33aa76680e4 100644 --- a/libs/auth/src/angular/two-factor-auth/two-factor-auth-component-cache.service.ts +++ b/libs/auth/src/angular/two-factor-auth/two-factor-auth-component-cache.service.ts @@ -3,8 +3,6 @@ import { Jsonify } from "type-fest"; import { ViewCacheService } from "@bitwarden/angular/platform/view-cache"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; const TWO_FACTOR_AUTH_COMPONENT_CACHE_KEY = "two-factor-auth-component-cache"; @@ -40,10 +38,6 @@ export interface TwoFactorAuthComponentData { @Injectable() export class TwoFactorAuthComponentCacheService { private viewCacheService: ViewCacheService = inject(ViewCacheService); - private configService: ConfigService = inject(ConfigService); - - /** True when the `PM9115_TwoFactorExtensionDataPersistence` flag is enabled */ - private featureEnabled: boolean = false; /** * Signal for the cached TwoFactorAuthData. @@ -57,23 +51,10 @@ export class TwoFactorAuthComponentCacheService { constructor() {} - /** - * Must be called once before interacting with the cached data. - */ - async init() { - this.featureEnabled = await this.configService.getFeatureFlag( - FeatureFlag.PM9115_TwoFactorExtensionDataPersistence, - ); - } - /** * Update the cache with the new TwoFactorAuthData. */ cacheData(data: TwoFactorAuthComponentData): void { - if (!this.featureEnabled) { - return; - } - this.twoFactorAuthComponentCache.set({ token: data.token, remember: data.remember, @@ -85,10 +66,6 @@ export class TwoFactorAuthComponentCacheService { * Clears the cached TwoFactorAuthData. */ clearCachedData(): void { - if (!this.featureEnabled) { - return; - } - this.twoFactorAuthComponentCache.set(null); } @@ -96,10 +73,6 @@ export class TwoFactorAuthComponentCacheService { * Returns the cached TwoFactorAuthData (when available). */ getCachedData(): TwoFactorAuthComponentCache | null { - if (!this.featureEnabled) { - return null; - } - return this.twoFactorAuthComponentCache(); } } diff --git a/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.spec.ts b/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.spec.ts index 4ab3841e48e..e7678102360 100644 --- a/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.spec.ts +++ b/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.spec.ts @@ -121,7 +121,6 @@ describe("TwoFactorAuthComponent", () => { mockTwoFactorAuthCompCacheService = mock(); mockTwoFactorAuthCompCacheService.getCachedData.mockReturnValue(null); - mockTwoFactorAuthCompCacheService.init.mockResolvedValue(); mockUserDecryptionOpts = { noMasterPassword: new UserDecryptionOptions({ diff --git a/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.ts b/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.ts index a281411f971..50cc2d88d6a 100644 --- a/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.ts +++ b/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.ts @@ -60,11 +60,11 @@ import { TwoFactorAuthDuoIcon, } from "../icons/two-factor-auth"; -import { TwoFactorAuthAuthenticatorComponent } from "./child-components/two-factor-auth-authenticator.component"; +import { TwoFactorAuthAuthenticatorComponent } from "./child-components/two-factor-auth-authenticator/two-factor-auth-authenticator.component"; import { TwoFactorAuthDuoComponent } from "./child-components/two-factor-auth-duo/two-factor-auth-duo.component"; import { TwoFactorAuthEmailComponent } from "./child-components/two-factor-auth-email/two-factor-auth-email.component"; import { TwoFactorAuthWebAuthnComponent } from "./child-components/two-factor-auth-webauthn/two-factor-auth-webauthn.component"; -import { TwoFactorAuthYubikeyComponent } from "./child-components/two-factor-auth-yubikey.component"; +import { TwoFactorAuthYubikeyComponent } from "./child-components/two-factor-auth-yubikey/two-factor-auth-yubikey.component"; import { TwoFactorAuthComponentCacheService, TwoFactorAuthComponentData, @@ -180,9 +180,6 @@ export class TwoFactorAuthComponent implements OnInit, OnDestroy { this.listenForAuthnSessionTimeout(); - // Initialize the cache - await this.twoFactorAuthComponentCacheService.init(); - // Load cached form data if available let loadedCachedProviderType = false; const cachedData = this.twoFactorAuthComponentCacheService.getCachedData(); diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index 8d9eebe6f9f..71de8fb5433 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -17,7 +17,6 @@ export enum FeatureFlag { /* Auth */ PM16117_SetInitialPasswordRefactor = "pm-16117-set-initial-password-refactor", PM16117_ChangeExistingPasswordRefactor = "pm-16117-change-existing-password-refactor", - PM9115_TwoFactorExtensionDataPersistence = "pm-9115-two-factor-extension-data-persistence", PM14938_BrowserExtensionLoginApproval = "pm-14938-browser-extension-login-approvals", /* Autofill */ @@ -107,7 +106,6 @@ export const DefaultFeatureFlagValue = { /* Auth */ [FeatureFlag.PM16117_SetInitialPasswordRefactor]: FALSE, [FeatureFlag.PM16117_ChangeExistingPasswordRefactor]: FALSE, - [FeatureFlag.PM9115_TwoFactorExtensionDataPersistence]: FALSE, [FeatureFlag.PM14938_BrowserExtensionLoginApproval]: FALSE, /* Billing */ From 3bdc223376f03536ab5110f8f5b790f117a20742 Mon Sep 17 00:00:00 2001 From: Daniel Riera Date: Thu, 10 Jul 2025 15:16:58 -0400 Subject: [PATCH 101/239] PM-23298 White/black background appears in iframe containing notifications on Chromium browsers (#15436) * PM-23298 * Revert "Failsafe for Chromium browsers' forced rendering of opaque bkgd (#15098)" This reverts commit 64e577e2e6480ea1d35962b410aaf5fa71ff4e06. * set style explicitly on iframe --- apps/browser/src/autofill/notification/bar.ts | 11 +---------- ...notifications-content.service.spec.ts.snap | 4 ++-- .../overlay-notifications-content.service.ts | 10 +++------- apps/browser/src/autofill/utils/index.ts | 19 ------------------- 4 files changed, 6 insertions(+), 38 deletions(-) diff --git a/apps/browser/src/autofill/notification/bar.ts b/apps/browser/src/autofill/notification/bar.ts index a83e9fce531..285ae4aa257 100644 --- a/apps/browser/src/autofill/notification/bar.ts +++ b/apps/browser/src/autofill/notification/bar.ts @@ -12,7 +12,7 @@ import { NotificationConfirmationContainer } from "../content/components/notific import { NotificationContainer } from "../content/components/notification/container"; import { selectedFolder as selectedFolderSignal } from "../content/components/signals/selected-folder"; import { selectedVault as selectedVaultSignal } from "../content/components/signals/selected-vault"; -import { buildSvgDomElement, matchAllowedColorSchemes } from "../utils"; +import { buildSvgDomElement } from "../utils"; import { circleCheckIcon } from "../utils/svg-icons"; import { @@ -238,15 +238,6 @@ async function initNotificationBar(message: NotificationBarWindowMessage) { const i18n = getI18n(); const resolvedTheme = getResolvedTheme(theme ?? ThemeTypes.Light); - // https://drafts.csswg.org/css-color-adjust-1/#preferred - // Prevents preferred color scheme from forcing an opaque background in the iframe - const colorScheme = new URLSearchParams(window.location.search).get("colorScheme") || ""; - const allowedColorScheme = matchAllowedColorSchemes(colorScheme); - const meta = document.createElement("meta"); - meta.setAttribute("name", "color-scheme"); - meta.setAttribute("content", allowedColorScheme); - document.getElementsByTagName("head")[0].appendChild(meta); - if (useComponentBar) { const resolvedType = resolveNotificationType(notificationBarIframeInitData); const headerMessage = getNotificationHeaderMessage(i18n, resolvedType); diff --git a/apps/browser/src/autofill/overlay/notifications/content/__snapshots__/overlay-notifications-content.service.spec.ts.snap b/apps/browser/src/autofill/overlay/notifications/content/__snapshots__/overlay-notifications-content.service.spec.ts.snap index 1b5d9a73888..18c3baa876c 100644 --- a/apps/browser/src/autofill/overlay/notifications/content/__snapshots__/overlay-notifications-content.service.spec.ts.snap +++ b/apps/browser/src/autofill/overlay/notifications/content/__snapshots__/overlay-notifications-content.service.spec.ts.snap @@ -7,8 +7,8 @@ exports[`OverlayNotificationsContentService opening the notification bar creates >