From 78dafe2265e3d92937f9e7db168d62576526a13b Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Thu, 8 May 2025 18:16:11 +0200 Subject: [PATCH 01/11] Cleanup migrated components (#14625) Cleans up migrated components by removing unnecessary old behaviour. - Removes ng-template and ViewChild used by the old Modal Service. - Remove aria-dismiss used by old Modals. - Remove aria-haspopup and aria-expanded on bitMenuTriggerFor since it's handled by the directive. --- .../vault-header/vault-header.component.html | 1 - .../organizations/collections/vault.component.html | 3 --- .../organizations/members/members.component.html | 1 - .../organizations/members/members.component.ts | 5 +---- .../organizations/policies/policies.component.html | 1 - .../organizations/policies/policies.component.ts | 5 +---- .../organizations/settings/account.component.html | 3 --- .../organizations/settings/account.component.ts | 7 +------ .../app/auth/settings/account/account.component.html | 3 --- .../emergency-access/emergency-access.component.html | 4 ---- .../emergency-access/emergency-access.component.ts | 8 +------- .../view/emergency-access-view.component.html | 2 -- .../view/emergency-access-view.component.ts | 3 +-- .../two-factor/two-factor-setup.component.html | 5 ----- .../settings/two-factor/two-factor-setup.component.ts | 10 +--------- .../app/dirt/reports/pages/cipher-report.component.ts | 4 +--- .../pages/exposed-passwords-report.component.html | 1 - .../pages/inactive-two-factor-report.component.html | 1 - .../pages/reused-passwords-report.component.html | 1 - .../pages/unsecured-websites-report.component.html | 1 - .../reports/pages/weak-passwords-report.component.html | 1 - apps/web/src/app/tools/send/send.component.html | 1 - .../individual-vault/folder-add-edit.component.html | 2 +- .../app/vault/individual-vault/vault.component.html | 7 ------- .../providers/clients/clients.component.html | 3 --- .../src/breadcrumbs/breadcrumbs.component.html | 1 - 26 files changed, 8 insertions(+), 76 deletions(-) diff --git a/apps/web/src/app/admin-console/organizations/collections/vault-header/vault-header.component.html b/apps/web/src/app/admin-console/organizations/collections/vault-header/vault-header.component.html index 3ef48ff9015..60214a9fd61 100644 --- a/apps/web/src/app/admin-console/organizations/collections/vault-header/vault-header.component.html +++ b/apps/web/src/app/admin-console/organizations/collections/vault-header/vault-header.component.html @@ -35,7 +35,6 @@ [bitMenuTriggerFor]="editCollectionMenu" size="small" type="button" - aria-haspopup="true" > 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 22da9a566f4..e8782ca0f2d 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 @@ -153,6 +153,3 @@ - - - diff --git a/apps/web/src/app/admin-console/organizations/members/members.component.html b/apps/web/src/app/admin-console/organizations/members/members.component.html index d35bb1a8dad..2162e33081f 100644 --- a/apps/web/src/app/admin-console/organizations/members/members.component.html +++ b/apps/web/src/app/admin-console/organizations/members/members.component.html @@ -374,4 +374,3 @@ - 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 5f9df110d3c..6a3ca58b73d 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 @@ -1,6 +1,6 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { Component, ViewChild, ViewContainerRef } from "@angular/core"; +import { Component } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { ActivatedRoute, Router } from "@angular/router"; import { @@ -90,9 +90,6 @@ class MembersTableDataSource extends PeopleTableDataSource templateUrl: "members.component.html", }) export class MembersComponent extends BaseMembersComponent { - @ViewChild("resetPasswordTemplate", { read: ViewContainerRef, static: true }) - resetPasswordModalRef: ViewContainerRef; - userType = OrganizationUserType; userStatusType = OrganizationUserStatusType; memberTab = MemberDialogTab; diff --git a/apps/web/src/app/admin-console/organizations/policies/policies.component.html b/apps/web/src/app/admin-console/organizations/policies/policies.component.html index e40b9d80e9e..016d631019e 100644 --- a/apps/web/src/app/admin-console/organizations/policies/policies.component.html +++ b/apps/web/src/app/admin-console/organizations/policies/policies.component.html @@ -35,5 +35,4 @@ - diff --git a/apps/web/src/app/admin-console/organizations/policies/policies.component.ts b/apps/web/src/app/admin-console/organizations/policies/policies.component.ts index 2b86d76d9b1..6e3b34eaa30 100644 --- a/apps/web/src/app/admin-console/organizations/policies/policies.component.ts +++ b/apps/web/src/app/admin-console/organizations/policies/policies.component.ts @@ -1,6 +1,6 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core"; +import { Component, OnInit } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { firstValueFrom, lastValueFrom, map, Observable, switchMap } from "rxjs"; import { first } from "rxjs/operators"; @@ -33,9 +33,6 @@ import { PolicyEditComponent, PolicyEditDialogResult } from "./policy-edit.compo templateUrl: "policies.component.html", }) export class PoliciesComponent implements OnInit { - @ViewChild("editTemplate", { read: ViewContainerRef, static: true }) - editModalRef: ViewContainerRef; - loading = true; organizationId: string; policies: BasePolicy[]; diff --git a/apps/web/src/app/admin-console/organizations/settings/account.component.html b/apps/web/src/app/admin-console/organizations/settings/account.component.html index 8ae94b08f57..e6064779ece 100644 --- a/apps/web/src/app/admin-console/organizations/settings/account.component.html +++ b/apps/web/src/app/admin-console/organizations/settings/account.component.html @@ -93,7 +93,4 @@ {{ "purgeVault" | i18n }} - - - diff --git a/apps/web/src/app/admin-console/organizations/settings/account.component.ts b/apps/web/src/app/admin-console/organizations/settings/account.component.ts index 57892442c16..f3997fe669e 100644 --- a/apps/web/src/app/admin-console/organizations/settings/account.component.ts +++ b/apps/web/src/app/admin-console/organizations/settings/account.component.ts @@ -1,6 +1,6 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { Component, OnDestroy, OnInit, ViewChild, ViewContainerRef } from "@angular/core"; +import { Component, OnDestroy, OnInit } from "@angular/core"; import { FormBuilder, Validators } from "@angular/forms"; import { ActivatedRoute, Router } from "@angular/router"; import { @@ -43,11 +43,6 @@ import { DeleteOrganizationDialogResult, openDeleteOrganizationDialog } from "./ templateUrl: "account.component.html", }) export class AccountComponent implements OnInit, OnDestroy { - @ViewChild("apiKeyTemplate", { read: ViewContainerRef, static: true }) - apiKeyModalRef: ViewContainerRef; - @ViewChild("rotateApiKeyTemplate", { read: ViewContainerRef, static: true }) - rotateApiKeyModalRef: ViewContainerRef; - selfHosted = false; canEditSubscription = true; loading = true; diff --git a/apps/web/src/app/auth/settings/account/account.component.html b/apps/web/src/app/auth/settings/account/account.component.html index c5edc021614..74fa02f5f93 100644 --- a/apps/web/src/app/auth/settings/account/account.component.html +++ b/apps/web/src/app/auth/settings/account/account.component.html @@ -51,7 +51,4 @@ {{ "deleteAccount" | i18n }} - - - diff --git a/apps/web/src/app/auth/settings/emergency-access/emergency-access.component.html b/apps/web/src/app/auth/settings/emergency-access/emergency-access.component.html index ab93f0be3bc..8a802e4f6af 100644 --- a/apps/web/src/app/auth/settings/emergency-access/emergency-access.component.html +++ b/apps/web/src/app/auth/settings/emergency-access/emergency-access.component.html @@ -272,7 +272,3 @@ - - - - diff --git a/apps/web/src/app/auth/settings/emergency-access/emergency-access.component.ts b/apps/web/src/app/auth/settings/emergency-access/emergency-access.component.ts index dc464c18059..f55d731d7f2 100644 --- a/apps/web/src/app/auth/settings/emergency-access/emergency-access.component.ts +++ b/apps/web/src/app/auth/settings/emergency-access/emergency-access.component.ts @@ -1,6 +1,6 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core"; +import { Component, OnInit } from "@angular/core"; import { lastValueFrom, Observable, firstValueFrom, switchMap } from "rxjs"; import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe"; @@ -44,12 +44,6 @@ import { templateUrl: "emergency-access.component.html", }) export class EmergencyAccessComponent implements OnInit { - @ViewChild("addEdit", { read: ViewContainerRef, static: true }) addEditModalRef: ViewContainerRef; - @ViewChild("takeoverTemplate", { read: ViewContainerRef, static: true }) - takeoverModalRef: ViewContainerRef; - @ViewChild("confirmTemplate", { read: ViewContainerRef, static: true }) - confirmModalRef: ViewContainerRef; - loaded = false; canAccessPremium$: Observable; trustedContacts: GranteeEmergencyAccess[]; diff --git a/apps/web/src/app/auth/settings/emergency-access/view/emergency-access-view.component.html b/apps/web/src/app/auth/settings/emergency-access/view/emergency-access-view.component.html index cb170a1275a..20cc50c4d59 100644 --- a/apps/web/src/app/auth/settings/emergency-access/view/emergency-access-view.component.html +++ b/apps/web/src/app/auth/settings/emergency-access/view/emergency-access-view.component.html @@ -51,5 +51,3 @@ {{ "loading" | i18n }} - - diff --git a/apps/web/src/app/auth/settings/emergency-access/view/emergency-access-view.component.ts b/apps/web/src/app/auth/settings/emergency-access/view/emergency-access-view.component.ts index bf7ca29da9b..55ebf860cff 100644 --- a/apps/web/src/app/auth/settings/emergency-access/view/emergency-access-view.component.ts +++ b/apps/web/src/app/auth/settings/emergency-access/view/emergency-access-view.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core"; +import { Component, OnInit } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; import { firstValueFrom } from "rxjs"; @@ -17,7 +17,6 @@ import { EmergencyViewDialogComponent } from "./emergency-view-dialog.component" providers: [{ provide: CipherFormConfigService, useClass: DefaultCipherFormConfigService }], }) export class EmergencyAccessViewComponent implements OnInit { - @ViewChild("attachments", { read: ViewContainerRef, static: true }) id: EmergencyAccessId | null = null; ciphers: CipherView[] = []; loaded = false; diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-setup.component.html b/apps/web/src/app/auth/settings/two-factor/two-factor-setup.component.html index 4206927772b..16c3dcb3cda 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-setup.component.html +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-setup.component.html @@ -84,8 +84,3 @@ - - - - - diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-setup.component.ts b/apps/web/src/app/auth/settings/two-factor/two-factor-setup.component.ts index fcf07dce9b7..d240dc467ae 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-setup.component.ts +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-setup.component.ts @@ -1,6 +1,6 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { Component, OnDestroy, OnInit, ViewChild, ViewContainerRef } from "@angular/core"; +import { Component, OnDestroy, OnInit } from "@angular/core"; import { first, firstValueFrom, @@ -12,7 +12,6 @@ import { switchMap, } from "rxjs"; -import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; @@ -52,9 +51,6 @@ import { TwoFactorVerifyComponent } from "./two-factor-verify.component"; imports: [ItemModule, LooseComponentsModule, SharedModule], }) export class TwoFactorSetupComponent implements OnInit, OnDestroy { - @ViewChild("yubikeyTemplate", { read: ViewContainerRef, static: true }) - yubikeyModalRef: ViewContainerRef; - organizationId: string; organization: Organization; providers: any[] = []; @@ -62,7 +58,6 @@ export class TwoFactorSetupComponent implements OnInit, OnDestroy { recoveryCodeWarningMessage: string; showPolicyWarning = false; loading = true; - modal: ModalRef; formPromise: Promise; tabbedHeader = true; @@ -283,9 +278,6 @@ export class TwoFactorSetupComponent implements OnInit, OnDestroy { } protected updateStatus(enabled: boolean, type: TwoFactorProviderType) { - if (!enabled && this.modal != null) { - this.modal.close(); - } this.providers.forEach((p) => { if (p.type === type && enabled !== undefined) { p.enabled = enabled; diff --git a/apps/web/src/app/dirt/reports/pages/cipher-report.component.ts b/apps/web/src/app/dirt/reports/pages/cipher-report.component.ts index ceda7b1c480..d6c96ff232e 100644 --- a/apps/web/src/app/dirt/reports/pages/cipher-report.component.ts +++ b/apps/web/src/app/dirt/reports/pages/cipher-report.component.ts @@ -1,6 +1,6 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { Directive, ViewChild, ViewContainerRef, OnDestroy } from "@angular/core"; +import { Directive, OnDestroy } from "@angular/core"; import { BehaviorSubject, lastValueFrom, @@ -37,8 +37,6 @@ import { AdminConsoleCipherFormConfigService } from "../../../vault/org-vault/se @Directive() export class CipherReportComponent implements OnDestroy { - @ViewChild("cipherAddEdit", { read: ViewContainerRef, static: true }) - cipherAddEditModalRef: ViewContainerRef; isAdminConsoleActive = false; loading = false; diff --git a/apps/web/src/app/dirt/reports/pages/exposed-passwords-report.component.html b/apps/web/src/app/dirt/reports/pages/exposed-passwords-report.component.html index 05da9865c62..8e665936496 100644 --- a/apps/web/src/app/dirt/reports/pages/exposed-passwords-report.component.html +++ b/apps/web/src/app/dirt/reports/pages/exposed-passwords-report.component.html @@ -96,5 +96,4 @@ - diff --git a/apps/web/src/app/dirt/reports/pages/inactive-two-factor-report.component.html b/apps/web/src/app/dirt/reports/pages/inactive-two-factor-report.component.html index cec9d45ff56..fb19bb382b8 100644 --- a/apps/web/src/app/dirt/reports/pages/inactive-two-factor-report.component.html +++ b/apps/web/src/app/dirt/reports/pages/inactive-two-factor-report.component.html @@ -108,5 +108,4 @@ > - diff --git a/apps/web/src/app/dirt/reports/pages/reused-passwords-report.component.html b/apps/web/src/app/dirt/reports/pages/reused-passwords-report.component.html index 78d13ba5c65..37c2c2f8a8c 100644 --- a/apps/web/src/app/dirt/reports/pages/reused-passwords-report.component.html +++ b/apps/web/src/app/dirt/reports/pages/reused-passwords-report.component.html @@ -98,5 +98,4 @@ - diff --git a/apps/web/src/app/dirt/reports/pages/unsecured-websites-report.component.html b/apps/web/src/app/dirt/reports/pages/unsecured-websites-report.component.html index 4e1c7feb22c..e28760f7746 100644 --- a/apps/web/src/app/dirt/reports/pages/unsecured-websites-report.component.html +++ b/apps/web/src/app/dirt/reports/pages/unsecured-websites-report.component.html @@ -96,5 +96,4 @@ - diff --git a/apps/web/src/app/dirt/reports/pages/weak-passwords-report.component.html b/apps/web/src/app/dirt/reports/pages/weak-passwords-report.component.html index 21053d70916..807bc751b23 100644 --- a/apps/web/src/app/dirt/reports/pages/weak-passwords-report.component.html +++ b/apps/web/src/app/dirt/reports/pages/weak-passwords-report.component.html @@ -100,5 +100,4 @@ - diff --git a/apps/web/src/app/tools/send/send.component.html b/apps/web/src/app/tools/send/send.component.html index 72e3031398b..e55d5e56f78 100644 --- a/apps/web/src/app/tools/send/send.component.html +++ b/apps/web/src/app/tools/send/send.component.html @@ -206,4 +206,3 @@ - diff --git a/apps/web/src/app/vault/individual-vault/folder-add-edit.component.html b/apps/web/src/app/vault/individual-vault/folder-add-edit.component.html index b6c9679887e..556672534ea 100644 --- a/apps/web/src/app/vault/individual-vault/folder-add-edit.component.html +++ b/apps/web/src/app/vault/individual-vault/folder-add-edit.component.html @@ -13,7 +13,7 @@ -
diff --git a/apps/web/src/app/vault/individual-vault/vault.component.html b/apps/web/src/app/vault/individual-vault/vault.component.html index aa27fa4ad85..c20209a0192 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.html +++ b/apps/web/src/app/vault/individual-vault/vault.component.html @@ -84,10 +84,3 @@
- - - - - - - diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/clients/clients.component.html b/bitwarden_license/bit-web/src/app/admin-console/providers/clients/clients.component.html index 668d59b8830..de1db6f0c7a 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/clients/clients.component.html +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/clients/clients.component.html @@ -57,9 +57,6 @@ bitMenuItem buttonType="secondary" type="button" - data-toggle="dropdown" - aria-haspopup="true" - aria-expanded="false" appA11yTitle="{{ 'options' | i18n }}" > diff --git a/libs/components/src/breadcrumbs/breadcrumbs.component.html b/libs/components/src/breadcrumbs/breadcrumbs.component.html index 5205e19cee5..887c7982f3b 100644 --- a/libs/components/src/breadcrumbs/breadcrumbs.component.html +++ b/libs/components/src/breadcrumbs/breadcrumbs.component.html @@ -36,7 +36,6 @@ bitIconButton="bwi-ellipsis-h" [bitMenuTriggerFor]="overflowMenu" size="small" - aria-haspopup > @for (breadcrumb of overflow; track breadcrumb) { From 3030eb7552caca57ed84b749d77646e298595ed5 Mon Sep 17 00:00:00 2001 From: Alec Rippberger <127791530+alec-livefront@users.noreply.github.com> Date: Thu, 8 May 2025 11:24:52 -0500 Subject: [PATCH 02/11] [PM-19212] Consolidate password set routing to AuthGuard using ForceSetPasswordReason (#14356) * Consolidates component routing, removing routing to update-temp-password from components. All routing to update-temp-password should happen in the AuthGuard now. --------- Co-authored-by: Jared Snider Co-authored-by: Todd Martin --- .../browser/src/background/main.background.ts | 6 - apps/browser/src/popup/app.component.ts | 4 - apps/cli/src/auth/commands/login.command.ts | 16 ++- apps/cli/src/program.ts | 1 + apps/desktop/src/app/app.component.ts | 9 -- .../base-login-via-webauthn.component.ts | 7 - .../login-via-auth-request.component.ts | 3 - .../auth/src/angular/login/login.component.ts | 6 +- .../new-device-verification.component.ts | 5 - libs/auth/src/angular/sso/sso.component.ts | 8 -- .../two-factor-auth.component.ts | 19 --- .../login-strategies/login.strategy.spec.ts | 12 +- .../common/login-strategies/login.strategy.ts | 36 +++-- .../password-login.strategy.spec.ts | 20 +-- .../password-login.strategy.ts | 127 +++++++++++------- .../sso-login.strategy.spec.ts | 10 +- .../login-strategies/sso-login.strategy.ts | 72 ++++++++++ .../webauthn-login.strategy.spec.ts | 1 - .../src/auth/models/domain/auth-result.ts | 3 - .../domain/force-set-password-reason.ts | 5 + .../services/master-password.service.spec.ts | 104 ++++++++++++++ .../services/master-password.service.ts | 11 ++ .../src/lock/components/lock.component.ts | 4 - 23 files changed, 324 insertions(+), 165 deletions(-) create mode 100644 libs/common/src/key-management/master-password/services/master-password.service.spec.ts diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index da47542ee6b..d295fddda52 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -39,7 +39,6 @@ import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/auth/ import { UserVerificationApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/user-verification/user-verification-api.service.abstraction"; import { UserVerificationService as UserVerificationServiceAbstraction } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; -import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; import { AccountServiceImplementation } from "@bitwarden/common/auth/services/account.service"; import { AuthService } from "@bitwarden/common/auth/services/auth.service"; import { AvatarService } from "@bitwarden/common/auth/services/avatar.service"; @@ -1511,9 +1510,6 @@ export default class MainBackground { } nextAccountStatus = await this.authService.getAuthStatus(userId); - const forcePasswordReset = - (await firstValueFrom(this.masterPasswordService.forceSetPasswordReason$(userId))) != - ForceSetPasswordReason.None; await this.systemService.clearPendingClipboard(); @@ -1521,8 +1517,6 @@ export default class MainBackground { this.messagingService.send("goHome"); } else if (nextAccountStatus === AuthenticationStatus.Locked) { this.messagingService.send("locked", { userId: userId }); - } else if (forcePasswordReset) { - this.messagingService.send("update-temp-password", { userId: userId }); } else { this.messagingService.send("unlocked", { userId: userId }); await this.refreshBadge(); diff --git a/apps/browser/src/popup/app.component.ts b/apps/browser/src/popup/app.component.ts index 6a08bf007bb..49579f889b3 100644 --- a/apps/browser/src/popup/app.component.ts +++ b/apps/browser/src/popup/app.component.ts @@ -160,10 +160,6 @@ export class AppComponent implements OnInit, OnDestroy { // 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.router.navigate(["/remove-password"]); - } else if (msg.command == "update-temp-password") { - // 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.router.navigate(["/update-temp-password"]); } }), takeUntil(this.destroy$), diff --git a/apps/cli/src/auth/commands/login.command.ts b/apps/cli/src/auth/commands/login.command.ts index 8a94cc4175a..b26ce94207d 100644 --- a/apps/cli/src/auth/commands/login.command.ts +++ b/apps/cli/src/auth/commands/login.command.ts @@ -32,6 +32,7 @@ import { UpdateTempPasswordRequest } from "@bitwarden/common/auth/models/request import { ClientType } from "@bitwarden/common/enums"; import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service"; import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service"; +import { MasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; @@ -77,6 +78,7 @@ export class LoginCommand { protected logoutCallback: () => Promise, protected kdfConfigService: KdfConfigService, protected ssoUrlService: SsoUrlService, + protected masterPasswordService: MasterPasswordServiceAbstraction, ) {} async run(email: string, password: string, options: OptionValues) { @@ -361,14 +363,14 @@ export class LoginCommand { await this.syncService.fullSync(true); // Handle updating passwords if NOT using an API Key for authentication - if ( - response.forcePasswordReset != ForceSetPasswordReason.None && - clientId == null && - clientSecret == null - ) { - if (response.forcePasswordReset === ForceSetPasswordReason.AdminForcePasswordReset) { + if (clientId == null && clientSecret == null) { + const forceSetPasswordReason = await firstValueFrom( + this.masterPasswordService.forceSetPasswordReason$(response.userId), + ); + + if (forceSetPasswordReason === ForceSetPasswordReason.AdminForcePasswordReset) { return await this.updateTempPassword(response.userId); - } else if (response.forcePasswordReset === ForceSetPasswordReason.WeakMasterPassword) { + } else if (forceSetPasswordReason === ForceSetPasswordReason.WeakMasterPassword) { return await this.updateWeakPassword(response.userId, password); } } diff --git a/apps/cli/src/program.ts b/apps/cli/src/program.ts index c6b79c7dff2..dca4effcdc9 100644 --- a/apps/cli/src/program.ts +++ b/apps/cli/src/program.ts @@ -172,6 +172,7 @@ export class Program extends BaseProgram { async () => await this.serviceContainer.logout(), this.serviceContainer.kdfConfigService, this.serviceContainer.ssoUrlService, + this.serviceContainer.masterPasswordService, ); const response = await command.run(email, password, options); this.processResponse(response, true); diff --git a/apps/desktop/src/app/app.component.ts b/apps/desktop/src/app/app.component.ts index 3ce4d57e25b..c3cfdf49c2c 100644 --- a/apps/desktop/src/app/app.component.ts +++ b/apps/desktop/src/app/app.component.ts @@ -27,7 +27,6 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; -import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { ProcessReloadServiceAbstraction } from "@bitwarden/common/key-management/abstractions/process-reload.service"; import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service"; @@ -409,17 +408,9 @@ export class AppComponent implements OnInit, OnDestroy { const locked = (await this.authService.getAuthStatus(message.userId)) === AuthenticationStatus.Locked; - const forcedPasswordReset = - (await firstValueFrom( - this.masterPasswordService.forceSetPasswordReason$(message.userId), - )) != ForceSetPasswordReason.None; if (locked) { this.modalService.closeAll(); await this.router.navigate(["lock"]); - } else if (forcedPasswordReset) { - // 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.router.navigate(["update-temp-password"]); } else { this.messagingService.send("unlocked"); this.loading = true; diff --git a/libs/angular/src/auth/components/base-login-via-webauthn.component.ts b/libs/angular/src/auth/components/base-login-via-webauthn.component.ts index 1ad4829767a..5d30fc997dc 100644 --- a/libs/angular/src/auth/components/base-login-via-webauthn.component.ts +++ b/libs/angular/src/auth/components/base-login-via-webauthn.component.ts @@ -6,7 +6,6 @@ import { firstValueFrom } from "rxjs"; import { LoginSuccessHandlerService } from "@bitwarden/auth/common"; import { WebAuthnLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/webauthn/webauthn-login.service.abstraction"; -import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; import { WebAuthnLoginCredentialAssertionView } from "@bitwarden/common/auth/models/view/webauthn-login/webauthn-login-credential-assertion.view"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -21,7 +20,6 @@ export class BaseLoginViaWebAuthnComponent implements OnInit { protected currentState: State = "assert"; protected successRoute = "/vault"; - protected forcePasswordResetRoute = "/update-temp-password"; constructor( private webAuthnLoginService: WebAuthnLoginServiceAbstraction, @@ -73,11 +71,6 @@ export class BaseLoginViaWebAuthnComponent implements OnInit { await this.loginSuccessHandlerService.run(authResult.userId); } - if (authResult.forcePasswordReset == ForceSetPasswordReason.AdminForcePasswordReset) { - await this.router.navigate([this.forcePasswordResetRoute]); - return; - } - await this.router.navigate([this.successRoute]); } catch (error) { if (error instanceof ErrorResponse) { diff --git a/libs/auth/src/angular/login-via-auth-request/login-via-auth-request.component.ts b/libs/auth/src/angular/login-via-auth-request/login-via-auth-request.component.ts index 5de2339bda1..ab5b0c09b32 100644 --- a/libs/auth/src/angular/login-via-auth-request/login-via-auth-request.component.ts +++ b/libs/auth/src/angular/login-via-auth-request/login-via-auth-request.component.ts @@ -19,7 +19,6 @@ import { AuthRequestType } from "@bitwarden/common/auth/enums/auth-request-type" import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { AdminAuthRequestStorable } from "@bitwarden/common/auth/models/domain/admin-auth-req-storable"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; -import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; import { AuthRequest } from "@bitwarden/common/auth/models/request/auth.request"; import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response"; import { LoginViaAuthRequestView } from "@bitwarden/common/auth/models/view/login-via-auth-request.view"; @@ -820,8 +819,6 @@ export class LoginViaAuthRequestComponent implements OnInit, OnDestroy { private async handlePostLoginNavigation(loginResponse: AuthResult) { if (loginResponse.requiresTwoFactor) { await this.router.navigate(["2fa"]); - } else if (loginResponse.forcePasswordReset != ForceSetPasswordReason.None) { - await this.router.navigate(["update-temp-password"]); } else { await this.handleSuccessfulLoginNavigation(loginResponse.userId); } diff --git a/libs/auth/src/angular/login/login.component.ts b/libs/auth/src/angular/login/login.component.ts index eb2bdcee291..cd226cddcec 100644 --- a/libs/auth/src/angular/login/login.component.ts +++ b/libs/auth/src/angular/login/login.component.ts @@ -17,7 +17,6 @@ import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/mod 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 { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; import { ClientType, HttpStatusCode } from "@bitwarden/common/enums"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; @@ -307,10 +306,7 @@ export class LoginComponent implements OnInit, OnDestroy { await this.loginSuccessHandlerService.run(authResult.userId); // Determine where to send the user next - if (authResult.forcePasswordReset != ForceSetPasswordReason.None) { - await this.router.navigate(["update-temp-password"]); - return; - } + // The AuthGuard will handle routing to update-temp-password based on state // TODO: PM-18269 - evaluate if we can combine this with the // password evaluation done in the password login strategy. 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 c083643c9b4..a2b0b23d05c 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 @@ -136,11 +136,6 @@ export class NewDeviceVerificationComponent implements OnInit, OnDestroy { return; } - if (authResult.forcePasswordReset) { - await this.router.navigate(["/update-temp-password"]); - return; - } - this.loginSuccessHandlerService.run(authResult.userId); // If verification succeeds, navigate to vault diff --git a/libs/auth/src/angular/sso/sso.component.ts b/libs/auth/src/angular/sso/sso.component.ts index 311ebf174ef..a91a8ed20e9 100644 --- a/libs/auth/src/angular/sso/sso.component.ts +++ b/libs/auth/src/angular/sso/sso.component.ts @@ -541,14 +541,6 @@ export class SsoComponent implements OnInit { }); } - private async handleForcePasswordReset(orgIdentifier: string) { - await this.router.navigate(["update-temp-password"], { - queryParams: { - identifier: orgIdentifier, - }, - }); - } - private async handleSuccessfulLogin() { await this.router.navigate(["lock"]); } 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 f09d7163667..e7e62260b49 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 @@ -575,25 +575,6 @@ export class TwoFactorAuthComponent implements OnInit, OnDestroy { }); } - /** - * Determines if a user needs to reset their password based on certain conditions. - * Users can be forced to reset their password via an admin or org policy disallowing weak passwords. - * Note: this is different from the SSO component login flow as a user can - * login with MP and then have to pass 2FA to finish login and we can actually - * evaluate if they have a weak password at that time. - * - * @param {AuthResult} authResult - The authentication result. - * @returns {boolean} Returns true if a password reset is required, false otherwise. - */ - private isForcePasswordResetRequired(authResult: AuthResult): boolean { - const forceResetReasons = [ - ForceSetPasswordReason.AdminForcePasswordReset, - ForceSetPasswordReason.WeakMasterPassword, - ]; - - return forceResetReasons.includes(authResult.forcePasswordReset); - } - showContinueButton() { return ( this.selectedProviderType != null && 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 fc3be61fe11..5a5a9dc2575 100644 --- a/libs/auth/src/common/login-strategies/login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/login.strategy.spec.ts @@ -296,13 +296,9 @@ describe("LoginStrategy", () => { const expected = new AuthResult(); expected.userId = userId; - expected.forcePasswordReset = ForceSetPasswordReason.AdminForcePasswordReset; expected.resetMasterPassword = true; - expected.twoFactorProviders = {} as Partial< - Record> - >; - expected.captchaSiteKey = ""; expected.twoFactorProviders = null; + expected.captchaSiteKey = ""; expect(result).toEqual(expected); }); @@ -316,13 +312,9 @@ describe("LoginStrategy", () => { const expected = new AuthResult(); expected.userId = userId; - expected.forcePasswordReset = ForceSetPasswordReason.AdminForcePasswordReset; expected.resetMasterPassword = false; - expected.twoFactorProviders = {} as Partial< - Record> - >; - expected.captchaSiteKey = ""; expected.twoFactorProviders = null; + expected.captchaSiteKey = ""; expect(result).toEqual(expected); expect(masterPasswordService.mock.setForceSetPasswordReason).toHaveBeenCalledWith( diff --git a/libs/auth/src/common/login-strategies/login.strategy.ts b/libs/auth/src/common/login-strategies/login.strategy.ts index 96d7b6b0f74..e252d50a5ab 100644 --- a/libs/auth/src/common/login-strategies/login.strategy.ts +++ b/libs/auth/src/common/login-strategies/login.strategy.ts @@ -277,17 +277,7 @@ export abstract class LoginStrategy { result.resetMasterPassword = response.resetMasterPassword; - // Convert boolean to enum and set the state for the master password service to - // so we know when we reach the auth guard that we need to guide them properly to admin - // password reset. - if (response.forcePasswordReset) { - result.forcePasswordReset = ForceSetPasswordReason.AdminForcePasswordReset; - - await this.masterPasswordService.setForceSetPasswordReason( - ForceSetPasswordReason.AdminForcePasswordReset, - userId, - ); - } + 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 @@ -318,6 +308,30 @@ export abstract class LoginStrategy { return false; } + /** + * Checks if adminForcePasswordReset is true and sets the ForceSetPasswordReason.AdminForcePasswordReset flag in the master password service. + * @param adminForcePasswordReset - The admin force password reset flag + * @param userId - The user ID + * @returns a promise that resolves to a boolean indicating whether the admin force password reset flag was set + */ + async processForceSetPasswordReason( + adminForcePasswordReset: boolean, + userId: UserId, + ): Promise { + if (!adminForcePasswordReset) { + return false; + } + + // set the flag in the master password service so we know when we reach the auth guard + // that we need to guide them properly to admin password reset. + await this.masterPasswordService.setForceSetPasswordReason( + ForceSetPasswordReason.AdminForcePasswordReset, + userId, + ); + + return true; + } + protected async createKeyPairForOldAccount(userId: UserId) { try { const userKey = await this.keyService.getUserKeyWithLegacySupport(userId); 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 3752960fc47..2923908fb7b 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 @@ -211,20 +211,18 @@ describe("PasswordLoginStrategy", () => { it("does not force the user to update their master password when there are no requirements", async () => { apiService.postIdentityToken.mockResolvedValueOnce(identityTokenResponseFactory()); - const result = await passwordLoginStrategy.logIn(credentials); + await passwordLoginStrategy.logIn(credentials); expect(policyService.evaluateMasterPassword).not.toHaveBeenCalled(); - expect(result.forcePasswordReset).toEqual(ForceSetPasswordReason.None); }); it("does not force the user to update their master password when it meets requirements", async () => { passwordStrengthService.getPasswordStrength.mockReturnValue({ score: 5 } as any); policyService.evaluateMasterPassword.mockReturnValue(true); - const result = await passwordLoginStrategy.logIn(credentials); + await passwordLoginStrategy.logIn(credentials); expect(policyService.evaluateMasterPassword).toHaveBeenCalled(); - expect(result.forcePasswordReset).toEqual(ForceSetPasswordReason.None); }); it("forces the user to update their master password on successful login when it does not meet master password policy requirements", async () => { @@ -232,14 +230,13 @@ describe("PasswordLoginStrategy", () => { policyService.evaluateMasterPassword.mockReturnValue(false); tokenService.decodeAccessToken.mockResolvedValue({ sub: userId }); - const result = await passwordLoginStrategy.logIn(credentials); + await passwordLoginStrategy.logIn(credentials); expect(policyService.evaluateMasterPassword).toHaveBeenCalled(); expect(masterPasswordService.mock.setForceSetPasswordReason).toHaveBeenCalledWith( ForceSetPasswordReason.WeakMasterPassword, userId, ); - expect(result.forcePasswordReset).toEqual(ForceSetPasswordReason.WeakMasterPassword); }); it("forces the user to update their master password on successful 2FA login when it does not meet master password policy requirements", async () => { @@ -257,13 +254,13 @@ describe("PasswordLoginStrategy", () => { // First login request fails requiring 2FA apiService.postIdentityToken.mockResolvedValueOnce(token2FAResponse); - const firstResult = await passwordLoginStrategy.logIn(credentials); + await passwordLoginStrategy.logIn(credentials); // Second login request succeeds apiService.postIdentityToken.mockResolvedValueOnce( identityTokenResponseFactory(masterPasswordPolicy), ); - const secondResult = await passwordLoginStrategy.logInTwoFactor( + await passwordLoginStrategy.logInTwoFactor( { provider: TwoFactorProviderType.Authenticator, token: "123456", @@ -272,15 +269,11 @@ describe("PasswordLoginStrategy", () => { "", ); - // First login attempt should not save the force password reset options - expect(firstResult.forcePasswordReset).toEqual(ForceSetPasswordReason.None); - - // Second login attempt should save the force password reset options and return in result + // Second login attempt should save the force password reset options expect(masterPasswordService.mock.setForceSetPasswordReason).toHaveBeenCalledWith( ForceSetPasswordReason.WeakMasterPassword, userId, ); - expect(secondResult.forcePasswordReset).toEqual(ForceSetPasswordReason.WeakMasterPassword); }); it("handles new device verification login with OTP", async () => { @@ -298,7 +291,6 @@ describe("PasswordLoginStrategy", () => { newDeviceOtp: deviceVerificationOtp, }), ); - expect(result.forcePasswordReset).toBe(ForceSetPasswordReason.None); expect(result.resetMasterPassword).toBe(false); expect(result.userId).toBe(userId); }); 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 f0a8d40f914..6af9d8dbb6b 100644 --- a/libs/auth/src/common/login-strategies/password-login.strategy.ts +++ b/libs/auth/src/common/login-strategies/password-login.strategy.ts @@ -109,35 +109,8 @@ export class PasswordLoginStrategy extends LoginStrategy { return authResult; } - const masterPasswordPolicyOptions = - this.getMasterPasswordPolicyOptionsFromResponse(identityResponse); + await this.evaluateMasterPasswordIfRequired(identityResponse, credentials, authResult); - // The identity result can contain master password policies for the user's organizations - if (masterPasswordPolicyOptions?.enforceOnLogin) { - // If there is a policy active, evaluate the supplied password before its no longer in memory - const meetsRequirements = this.evaluateMasterPassword( - credentials, - masterPasswordPolicyOptions, - ); - if (meetsRequirements) { - return authResult; - } - - if (identityResponse instanceof IdentityTwoFactorResponse) { - // Save the flag to this strategy for use in 2fa login as the master password is about to pass out of scope - this.cache.next({ - ...this.cache.value, - forcePasswordResetReason: ForceSetPasswordReason.WeakMasterPassword, - }); - } else { - // Authentication was successful, save the force update password options with the state service - await this.masterPasswordService.setForceSetPasswordReason( - ForceSetPasswordReason.WeakMasterPassword, - authResult.userId, // userId is only available on successful login - ); - authResult.forcePasswordReset = ForceSetPasswordReason.WeakMasterPassword; - } - } return authResult; } @@ -151,20 +124,6 @@ export class PasswordLoginStrategy extends LoginStrategy { const result = await super.logInTwoFactor(twoFactor); - // 2FA was successful, save the force update password options with the state service if defined - const forcePasswordResetReason = this.cache.value.forcePasswordResetReason; - if ( - !result.requiresTwoFactor && - !result.requiresCaptcha && - forcePasswordResetReason != ForceSetPasswordReason.None - ) { - await this.masterPasswordService.setForceSetPasswordReason( - forcePasswordResetReason, - result.userId, - ); - result.forcePasswordReset = forcePasswordResetReason; - } - return result; } @@ -208,13 +167,58 @@ export class PasswordLoginStrategy extends LoginStrategy { return !response.key; } - private getMasterPasswordPolicyOptionsFromResponse( - response: + private async evaluateMasterPasswordIfRequired( + identityResponse: | IdentityTokenResponse | IdentityTwoFactorResponse | IdentityDeviceVerificationResponse, - ): MasterPasswordPolicyOptions { - if (response == null || response instanceof IdentityDeviceVerificationResponse) { + 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 + // 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); + + if (!masterPasswordPolicyOptions?.enforceOnLogin) { + return; + } + + // If there is a policy active, evaluate the supplied password before its no longer in memory + const meetsRequirements = this.evaluateMasterPassword(credentials, masterPasswordPolicyOptions); + if (meetsRequirements) { + return; + } + + if (identityResponse instanceof IdentityTwoFactorResponse) { + // Save the flag to this strategy for use in 2fa as the master password is about to pass out of scope + this.cache.next({ + ...this.cache.value, + forcePasswordResetReason: ForceSetPasswordReason.WeakMasterPassword, + }); + } + + // Authentication was successful, save the force update password options with the state service + // if there isn't already a reason set (this would only be AdminForcePasswordReset as that can be set server side + // and would have already been processed in the base login strategy processForceSetPasswordReason method) + // Note: masterPasswordService.setForceSetPasswordReason will not allow overwriting + // AdminForcePasswordReset with any other reason except for None. This is because + // an AdminForcePasswordReset will always force a user to update their password to a password that meets the policy. + await this.masterPasswordService.setForceSetPasswordReason( + ForceSetPasswordReason.WeakMasterPassword, + authResult.userId, // userId is only available on successful login + ); + } + + private getMasterPasswordPolicyOptionsFromResponse( + response: IdentityTokenResponse | IdentityTwoFactorResponse, + ): MasterPasswordPolicyOptions | null { + if (response == null) { return null; } return MasterPasswordPolicyOptions.fromResponse(response.masterPasswordPolicy); @@ -246,4 +250,35 @@ export class PasswordLoginStrategy extends LoginStrategy { const [authResult] = await this.startLogIn(); return authResult; } + + /** + * Override to handle the WeakMasterPassword reason if no other reason is set. + * @param authResult - The authentication result + * @param userId - The user ID + */ + override async processForceSetPasswordReason( + adminForcePasswordReset: boolean, + userId: UserId, + ): Promise { + // handle any existing reasons + const adminForcePasswordResetFlagSet = await super.processForceSetPasswordReason( + adminForcePasswordReset, + userId, + ); + + // If we are already processing an admin force password reset, don't process other reasons + if (adminForcePasswordResetFlagSet) { + return false; + } + + // If we have a cached weak password reason from login/logInTwoFactor apply it + const cachedReason = this.cache.value.forcePasswordResetReason; + if (cachedReason !== ForceSetPasswordReason.None) { + await this.masterPasswordService.setForceSetPasswordReason(cachedReason, userId); + return true; + } + + // If none of the conditions are met, return false + return false; + } } 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 546fa0c5fa7..d743a71f160 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 @@ -1,5 +1,5 @@ import { mock, MockProxy } from "jest-mock-extended"; -import { BehaviorSubject } from "rxjs"; +import { BehaviorSubject, of } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; @@ -37,10 +37,11 @@ import { AuthRequestServiceAbstraction, InternalUserDecryptionOptionsServiceAbstraction, } from "../abstractions"; +import { UserDecryptionOptions } from "../models"; import { SsoLoginCredentials } from "../models/domain/login-credentials"; import { identityTokenResponseFactory } from "./login.strategy.spec"; -import { SsoLoginStrategy } from "./sso-login.strategy"; +import { SsoLoginStrategy, SsoLoginStrategyData } from "./sso-login.strategy"; describe("SsoLoginStrategy", () => { let accountService: FakeAccountService; @@ -123,8 +124,11 @@ describe("SsoLoginStrategy", () => { mockVaultTimeoutBSub.asObservable(), ); + const userDecryptionOptions = new UserDecryptionOptions(); + userDecryptionOptionsService.userDecryptionOptions$ = of(userDecryptionOptions); + ssoLoginStrategy = new SsoLoginStrategy( - null, + {} as SsoLoginStrategyData, keyConnectorService, deviceTrustService, authRequestService, 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 1dd01d6fc75..d81284a960e 100644 --- a/libs/auth/src/common/login-strategies/sso-login.strategy.ts +++ b/libs/auth/src/common/login-strategies/sso-login.strategy.ts @@ -4,6 +4,7 @@ import { firstValueFrom, Observable, map, BehaviorSubject } from "rxjs"; import { Jsonify } from "type-fest"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; +import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; import { SsoTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/sso-token.request"; import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response"; import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; @@ -355,4 +356,75 @@ export class SsoLoginStrategy extends LoginStrategy { sso: this.cache.value, }; } + + /** + * Override to handle SSO-specific ForceSetPasswordReason flags,including TdeOffboarding, + * TdeUserWithoutPasswordHasPasswordResetPermission, and SsoNewJitProvisionedUser cases. + * @param authResult - The authentication result + * @param userId - The user ID + */ + override async processForceSetPasswordReason( + adminForcePasswordReset: boolean, + userId: UserId, + ): Promise { + // handle any existing reasons + const adminForcePasswordResetFlagSet = await super.processForceSetPasswordReason( + adminForcePasswordReset, + userId, + ); + + // If we are already processing an admin force password reset, don't process other reasons + if (adminForcePasswordResetFlagSet) { + return false; + } + + // Check for TDE-related conditions + const userDecryptionOptions = await firstValueFrom( + this.userDecryptionOptionsService.userDecryptionOptions$, + ); + + if (!userDecryptionOptions) { + return false; + } + + // Check for TDE offboarding - user is being offboarded from TDE and needs to set a password + if (userDecryptionOptions.trustedDeviceOption?.isTdeOffboarding) { + await this.masterPasswordService.setForceSetPasswordReason( + ForceSetPasswordReason.TdeOffboarding, + userId, + ); + return true; + } + + // Check if user has permission to set password but hasn't yet + if ( + !userDecryptionOptions.hasMasterPassword && + userDecryptionOptions.trustedDeviceOption?.hasManageResetPasswordPermission + ) { + await this.masterPasswordService.setForceSetPasswordReason( + ForceSetPasswordReason.TdeUserWithoutPasswordHasPasswordResetPermission, + userId, + ); + + return true; + } + + // Check for new SSO JIT provisioned user + // If a user logs in via SSO but has no master password and no alternative encryption methods + // Then they must be a newly provisioned user who needs to set up their encryption + if ( + !userDecryptionOptions.hasMasterPassword && + !userDecryptionOptions.keyConnectorOption?.keyConnectorUrl && + !userDecryptionOptions.trustedDeviceOption + ) { + await this.masterPasswordService.setForceSetPasswordReason( + ForceSetPasswordReason.SsoNewJitProvisionedUser, + userId, + ); + return true; + } + + // If none of the conditions are met, return false + return false; + } } 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 ebbe2f3b6cb..fb4cbd55ad9 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 @@ -209,7 +209,6 @@ describe("WebAuthnLoginStrategy", () => { expect(authResult).toBeInstanceOf(AuthResult); expect(authResult).toMatchObject({ captchaSiteKey: "", - forcePasswordReset: 0, resetMasterPassword: false, twoFactorProviders: null, requiresTwoFactor: false, diff --git a/libs/common/src/auth/models/domain/auth-result.ts b/libs/common/src/auth/models/domain/auth-result.ts index fdc8c963a1b..5177363ac89 100644 --- a/libs/common/src/auth/models/domain/auth-result.ts +++ b/libs/common/src/auth/models/domain/auth-result.ts @@ -4,8 +4,6 @@ import { Utils } from "../../../platform/misc/utils"; import { UserId } from "../../../types/guid"; import { TwoFactorProviderType } from "../../enums/two-factor-provider-type"; -import { ForceSetPasswordReason } from "./force-set-password-reason"; - export class AuthResult { userId: UserId; captchaSiteKey = ""; @@ -17,7 +15,6 @@ export class AuthResult { * */ resetMasterPassword = false; - forcePasswordReset: ForceSetPasswordReason = ForceSetPasswordReason.None; twoFactorProviders: Partial>> = null; ssoEmail2FaSessionToken?: string; email: string; 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 011ef7fff8d..56d52860443 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 @@ -31,4 +31,9 @@ export enum ForceSetPasswordReason { * Occurs when TDE is disabled and master password has to be set. */ TdeOffboarding, + + /** + * Occurs when a new SSO user is JIT provisioned and needs to set their master password. + */ + SsoNewJitProvisionedUser, } diff --git a/libs/common/src/key-management/master-password/services/master-password.service.spec.ts b/libs/common/src/key-management/master-password/services/master-password.service.spec.ts new file mode 100644 index 00000000000..93439ac8caa --- /dev/null +++ b/libs/common/src/key-management/master-password/services/master-password.service.spec.ts @@ -0,0 +1,104 @@ +import { mock, MockProxy } from "jest-mock-extended"; +import { of } from "rxjs"; +import * as rxjs from "rxjs"; + +import { ForceSetPasswordReason } from "../../../auth/models/domain/force-set-password-reason"; +import { KeyGenerationService } from "../../../platform/abstractions/key-generation.service"; +import { LogService } from "../../../platform/abstractions/log.service"; +import { StateService } from "../../../platform/abstractions/state.service"; +import { StateProvider } from "../../../platform/state"; +import { UserId } from "../../../types/guid"; +import { EncryptService } from "../../crypto/abstractions/encrypt.service"; + +import { MasterPasswordService } from "./master-password.service"; + +describe("MasterPasswordService", () => { + let sut: MasterPasswordService; + + let stateProvider: MockProxy; + let stateService: MockProxy; + let keyGenerationService: MockProxy; + let encryptService: MockProxy; + let logService: MockProxy; + + const userId = "user-id" as UserId; + const mockUserState = { + state$: of(null), + update: jest.fn().mockResolvedValue(null), + }; + + beforeEach(() => { + stateProvider = mock(); + stateService = mock(); + keyGenerationService = mock(); + encryptService = mock(); + logService = mock(); + + stateProvider.getUser.mockReturnValue(mockUserState as any); + + mockUserState.update.mockReset(); + + sut = new MasterPasswordService( + stateProvider, + stateService, + keyGenerationService, + encryptService, + logService, + ); + }); + + describe("setForceSetPasswordReason", () => { + it("calls stateProvider with the provided reason and user ID", async () => { + const reason = ForceSetPasswordReason.WeakMasterPassword; + + await sut.setForceSetPasswordReason(reason, userId); + + expect(stateProvider.getUser).toHaveBeenCalled(); + expect(mockUserState.update).toHaveBeenCalled(); + + // Call the update function to verify it returns the correct reason + const updateFn = mockUserState.update.mock.calls[0][0]; + expect(updateFn(null)).toBe(reason); + }); + + it("throws an error if reason is null", async () => { + await expect( + sut.setForceSetPasswordReason(null as unknown as ForceSetPasswordReason, userId), + ).rejects.toThrow("Reason is required."); + }); + + it("throws an error if user ID is null", async () => { + await expect( + sut.setForceSetPasswordReason(ForceSetPasswordReason.None, null as unknown as UserId), + ).rejects.toThrow("User ID is required."); + }); + + it("does not overwrite AdminForcePasswordReset with other reasons except None", async () => { + jest + .spyOn(sut, "forceSetPasswordReason$") + .mockReturnValue(of(ForceSetPasswordReason.AdminForcePasswordReset)); + + jest + .spyOn(rxjs, "firstValueFrom") + .mockResolvedValue(ForceSetPasswordReason.AdminForcePasswordReset); + + await sut.setForceSetPasswordReason(ForceSetPasswordReason.WeakMasterPassword, userId); + + expect(mockUserState.update).not.toHaveBeenCalled(); + }); + + it("allows overwriting AdminForcePasswordReset with None", async () => { + jest + .spyOn(sut, "forceSetPasswordReason$") + .mockReturnValue(of(ForceSetPasswordReason.AdminForcePasswordReset)); + + jest + .spyOn(rxjs, "firstValueFrom") + .mockResolvedValue(ForceSetPasswordReason.AdminForcePasswordReset); + + await sut.setForceSetPasswordReason(ForceSetPasswordReason.None, userId); + + expect(mockUserState.update).toHaveBeenCalled(); + }); + }); +}); diff --git a/libs/common/src/key-management/master-password/services/master-password.service.ts b/libs/common/src/key-management/master-password/services/master-password.service.ts index 9ed01cf0c83..72b18d8bfba 100644 --- a/libs/common/src/key-management/master-password/services/master-password.service.ts +++ b/libs/common/src/key-management/master-password/services/master-password.service.ts @@ -148,6 +148,17 @@ export class MasterPasswordService implements InternalMasterPasswordServiceAbstr if (userId == null) { throw new Error("User ID is required."); } + + // Don't overwrite AdminForcePasswordReset with any other reasons other than None + // as we must allow a reset when the user has completed admin account recovery + const currentReason = await firstValueFrom(this.forceSetPasswordReason$(userId)); + if ( + currentReason === ForceSetPasswordReason.AdminForcePasswordReset && + reason !== ForceSetPasswordReason.None + ) { + return; + } + await this.stateProvider.getUser(userId, FORCE_SET_PASSWORD_REASON).update((_) => reason); } 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 125bf6ab6af..80d64e17b84 100644 --- a/libs/key-management-ui/src/lock/components/lock.component.ts +++ b/libs/key-management-ui/src/lock/components/lock.component.ts @@ -121,8 +121,6 @@ export class LockComponent implements OnInit, OnDestroy { showPassword = false; private enforcedMasterPasswordOptions?: MasterPasswordPolicyOptions = undefined; - forcePasswordResetRoute = "update-temp-password"; - formGroup: FormGroup | null = null; // Browser extension properties: @@ -605,8 +603,6 @@ export class LockComponent implements OnInit, OnDestroy { ForceSetPasswordReason.WeakMasterPassword, userId, ); - await this.router.navigate([this.forcePasswordResetRoute]); - return; } } catch (e) { // Do not prevent unlock if there is an error evaluating policies From 667efc6fae391090bf1b790041ff633e883831d0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 8 May 2025 16:50:02 +0000 Subject: [PATCH 03/11] [deps] UI Foundation: Update @storybook/addon-designs to v8.2.1 (#14491) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 12 ++++++------ package.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index d94f8d56dc0..887a6861d53 100644 --- a/package-lock.json +++ b/package-lock.json @@ -87,7 +87,7 @@ "@ngtools/webpack": "18.2.12", "@storybook/addon-a11y": "8.5.2", "@storybook/addon-actions": "8.5.2", - "@storybook/addon-designs": "8.0.4", + "@storybook/addon-designs": "8.2.1", "@storybook/addon-essentials": "8.5.2", "@storybook/addon-interactions": "8.5.2", "@storybook/addon-links": "8.5.2", @@ -10163,9 +10163,9 @@ } }, "node_modules/@storybook/addon-designs": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/@storybook/addon-designs/-/addon-designs-8.0.4.tgz", - "integrity": "sha512-BrEWks1BRnZis2e8OoE1LhFS+x2d094Tzpbb3jQBve2IfDv/X006RSuy1WyplNxskdYdBESCH45MlRn4lhP5ew==", + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/@storybook/addon-designs/-/addon-designs-8.2.1.tgz", + "integrity": "sha512-orwihs1D5alhh4Qu3BSJKbSgQOdSagvRX/25m5fYZQAaqVErBY0lRR4vCAU/G/STkcdv+MHwIQ5U+0kX5Tm2+w==", "dev": true, "license": "MIT", "dependencies": { @@ -10175,8 +10175,8 @@ "@storybook/blocks": "^8.0.0 || ^8.1.0-0 || ^8.2.0-0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0", "@storybook/components": "^8.0.0 || ^8.1.0-0 || ^8.2.0-0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0", "@storybook/theming": "^8.0.0 || ^8.1.0-0 || ^8.2.0-0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta" }, "peerDependenciesMeta": { "@storybook/blocks": { diff --git a/package.json b/package.json index 5035e1b1da8..a5880e53927 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "@ngtools/webpack": "18.2.12", "@storybook/addon-a11y": "8.5.2", "@storybook/addon-actions": "8.5.2", - "@storybook/addon-designs": "8.0.4", + "@storybook/addon-designs": "8.2.1", "@storybook/addon-essentials": "8.5.2", "@storybook/addon-interactions": "8.5.2", "@storybook/addon-links": "8.5.2", From e6bc43bc8f459db15e3fbb5ab85523515db77c83 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 8 May 2025 12:58:49 -0400 Subject: [PATCH 04/11] [deps] Platform: Update Rust crate oo7 to v0.4.3 (#14485) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- apps/desktop/desktop_native/Cargo.lock | 519 +++++++++++++++++++++++-- apps/desktop/desktop_native/Cargo.toml | 2 +- 2 files changed, 477 insertions(+), 44 deletions(-) diff --git a/apps/desktop/desktop_native/Cargo.lock b/apps/desktop/desktop_native/Cargo.lock index cdb96c10c9d..df958a349fb 100644 --- a/apps/desktop/desktop_native/Cargo.lock +++ b/apps/desktop/desktop_native/Cargo.lock @@ -147,6 +147,23 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ashpd" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cbdf310d77fd3aaee6ea2093db7011dc2d35d2eb3481e5607f1f8d942ed99df" +dependencies = [ + "enumflags2", + "futures-channel", + "futures-util", + "rand 0.9.1", + "serde", + "serde_repr", + "tokio", + "url", + "zbus 5.6.0", +] + [[package]] name = "askama" version = "0.12.1" @@ -266,17 +283,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "async-net" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" -dependencies = [ - "async-io", - "blocking", - "futures-lite", -] - [[package]] name = "async-process" version = "2.3.0" @@ -739,7 +745,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "typenum", ] @@ -917,7 +923,7 @@ dependencies = [ "oo7", "pin-project", "pkcs8", - "rand", + "rand 0.8.5", "rsa", "russh-cryptovec", "scopeguard", @@ -935,7 +941,7 @@ dependencies = [ "widestring", "windows 0.61.1", "windows-future", - "zbus", + "zbus 4.4.0", "zbus_polkit", "zeroizing-alloc", ] @@ -1020,6 +1026,17 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "doctest-file" version = "1.0.0" @@ -1166,6 +1183,15 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + [[package]] name = "fs-err" version = "2.11.0" @@ -1413,6 +1439,145 @@ dependencies = [ "windows 0.57.0", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + [[package]] name = "indexmap" version = "2.7.1" @@ -1537,6 +1702,12 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +[[package]] +name = "litemap" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" + [[package]] name = "lock_api" version = "0.4.12" @@ -1773,7 +1944,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand", + "rand 0.8.5", "serde", "smallvec", "zeroize", @@ -1960,35 +2131,33 @@ checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] name = "oo7" -version = "0.3.3" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc6ce4692fbfd044ce22ca07dcab1a30fa12432ca2aa5b1294eca50d3332a24" +checksum = "6cb23d3ec3527d65a83be1c1795cb883c52cfa57147d42acc797127df56fc489" dependencies = [ "aes", - "async-fs", - "async-io", - "async-lock", - "async-net", - "blocking", + "ashpd", "cbc", "cipher", "digest", "endi", - "futures-lite", "futures-util", + "getrandom 0.3.1", "hkdf", "hmac", "md-5", "num", "num-bigint-dig", "pbkdf2", - "rand", + "rand 0.9.1", "serde", "sha2", "subtle", - "zbus", + "tokio", + "zbus 5.6.0", + "zbus_macros 5.6.0", "zeroize", - "zvariant", + "zvariant 5.5.1", ] [[package]] @@ -2070,7 +2239,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -2099,6 +2268,12 @@ dependencies = [ "base64ct", ] +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + [[package]] name = "petgraph" version = "0.6.5" @@ -2186,7 +2361,7 @@ checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ "der", "pkcs5", - "rand_core", + "rand_core 0.6.4", "spki", ] @@ -2298,8 +2473,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", ] [[package]] @@ -2309,7 +2494,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", ] [[package]] @@ -2321,6 +2516,15 @@ dependencies = [ "getrandom 0.2.15", ] +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.1", +] + [[package]] name = "rayon" version = "1.10.0" @@ -2409,7 +2613,7 @@ dependencies = [ "num-traits", "pkcs1", "pkcs8", - "rand_core", + "rand_core 0.6.4", "sha2", "signature", "spki", @@ -2638,7 +2842,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -2742,7 +2946,7 @@ dependencies = [ "bcrypt-pbkdf", "ed25519-dalek", "num-bigint-dig", - "rand_core", + "rand_core 0.6.4", "rsa", "sha2", "signature", @@ -2752,6 +2956,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" @@ -2781,6 +2991,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sysinfo" version = "0.33.1" @@ -2900,6 +3121,16 @@ dependencies = [ "time-core", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tokio" version = "1.43.1" @@ -2911,8 +3142,10 @@ dependencies = [ "libc", "mio", "pin-project-lite", + "signal-hook-registry", "socket2", "tokio-macros", + "tracing", "windows-sys 0.52.0", ] @@ -3202,6 +3435,30 @@ dependencies = [ "subtle", ] +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -3769,6 +4026,18 @@ dependencies = [ "wayland-protocols-wlr", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "x11rb" version = "0.13.1" @@ -3796,6 +4065,30 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "zbus" version = "4.4.0" @@ -3820,7 +4113,7 @@ dependencies = [ "hex", "nix 0.29.0", "ordered-stream", - "rand", + "rand 0.8.5", "serde", "serde_repr", "sha1", @@ -3829,9 +4122,37 @@ dependencies = [ "uds_windows", "windows-sys 0.52.0", "xdg-home", - "zbus_macros", - "zbus_names", - "zvariant", + "zbus_macros 4.4.0", + "zbus_names 3.0.0", + "zvariant 4.2.0", +] + +[[package]] +name = "zbus" +version = "5.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2522b82023923eecb0b366da727ec883ace092e7887b61d3da5139f26b44da58" +dependencies = [ + "async-broadcast", + "async-recursion", + "async-trait", + "enumflags2", + "event-listener", + "futures-core", + "futures-lite", + "hex", + "nix 0.29.0", + "ordered-stream", + "serde", + "serde_repr", + "tokio", + "tracing", + "uds_windows", + "windows-sys 0.59.0", + "winnow", + "zbus_macros 5.6.0", + "zbus_names 4.2.0", + "zvariant 5.5.1", ] [[package]] @@ -3844,7 +4165,22 @@ dependencies = [ "proc-macro2", "quote", "syn", - "zvariant_utils", + "zvariant_utils 2.1.0", +] + +[[package]] +name = "zbus_macros" +version = "5.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d2e12843c75108c00c618c2e8ef9675b50b6ec095b36dc965f2e5aed463c15" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", + "zbus_names 4.2.0", + "zvariant 5.5.1", + "zvariant_utils 3.2.0", ] [[package]] @@ -3855,7 +4191,19 @@ checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" dependencies = [ "serde", "static_assertions", - "zvariant", + "zvariant 4.2.0", +] + +[[package]] +name = "zbus_names" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" +dependencies = [ + "serde", + "static_assertions", + "winnow", + "zvariant 5.5.1", ] [[package]] @@ -3868,7 +4216,7 @@ dependencies = [ "serde", "serde_repr", "static_assertions", - "zbus", + "zbus 4.4.0", ] [[package]] @@ -3892,6 +4240,27 @@ dependencies = [ "syn", ] +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "zeroize" version = "1.8.1" @@ -3918,6 +4287,28 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebff5e6b81c1c7dca2d0bd333b2006da48cb37dbcae5a8da888f31fcb3c19934" +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "zvariant" version = "4.2.0" @@ -3928,7 +4319,22 @@ dependencies = [ "enumflags2", "serde", "static_assertions", - "zvariant_derive", + "zvariant_derive 4.2.0", +] + +[[package]] +name = "zvariant" +version = "5.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "557e89d54880377a507c94cd5452f20e35d14325faf9d2958ebeadce0966c1b2" +dependencies = [ + "endi", + "enumflags2", + "serde", + "url", + "winnow", + "zvariant_derive 5.5.1", + "zvariant_utils 3.2.0", ] [[package]] @@ -3941,7 +4347,20 @@ dependencies = [ "proc-macro2", "quote", "syn", - "zvariant_utils", + "zvariant_utils 2.1.0", +] + +[[package]] +name = "zvariant_derive" +version = "5.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "757779842a0d242061d24c28be589ce392e45350dfb9186dfd7a042a2e19870c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", + "zvariant_utils 3.2.0", ] [[package]] @@ -3954,3 +4373,17 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zvariant_utils" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16edfee43e5d7b553b77872d99bc36afdda75c223ca7ad5e3fbecd82ca5fc34" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "static_assertions", + "syn", + "winnow", +] diff --git a/apps/desktop/desktop_native/Cargo.toml b/apps/desktop/desktop_native/Cargo.toml index fdab4c05c0f..0a863b95fa2 100644 --- a/apps/desktop/desktop_native/Cargo.toml +++ b/apps/desktop/desktop_native/Cargo.toml @@ -33,7 +33,7 @@ log = "=0.4.25" napi = "=2.16.15" napi-build = "=2.1.4" napi-derive = "=2.16.13" -oo7 = "=0.3.3" +oo7 = "=0.4.3" oslog = "=0.2.0" pin-project = "=1.1.10" pkcs8 = "=0.10.2" From 21da5180387da1d920b9220942dff4b8631c4df9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 8 May 2025 17:06:03 +0000 Subject: [PATCH 05/11] [deps] UI Foundation: Update remark-gfm to v4.0.1 (#14467) 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 887a6861d53..615603c1f75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -162,7 +162,7 @@ "prettier": "3.5.3", "prettier-plugin-tailwindcss": "0.6.11", "process": "0.11.10", - "remark-gfm": "4.0.0", + "remark-gfm": "4.0.1", "rimraf": "6.0.1", "sass": "1.83.4", "sass-loader": "16.0.4", @@ -31490,9 +31490,9 @@ } }, "node_modules/remark-gfm": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", - "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index a5880e53927..7a98d4e3d1e 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,7 @@ "prettier": "3.5.3", "prettier-plugin-tailwindcss": "0.6.11", "process": "0.11.10", - "remark-gfm": "4.0.0", + "remark-gfm": "4.0.1", "rimraf": "6.0.1", "sass": "1.83.4", "sass-loader": "16.0.4", From 87a1f4e8ac928edfb05a283372550d0792c71827 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 8 May 2025 13:13:29 -0400 Subject: [PATCH 06/11] [deps] Platform: Update webpack to v5.99.7 (#14490) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 78 ++++++++--------------------------------------- package.json | 2 +- 2 files changed, 14 insertions(+), 66 deletions(-) diff --git a/package-lock.json b/package-lock.json index 615603c1f75..823be6819e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -179,7 +179,7 @@ "url": "0.11.4", "util": "0.12.5", "wait-on": "8.0.3", - "webpack": "5.97.1", + "webpack": "5.99.7", "webpack-cli": "6.0.1", "webpack-dev-server": "5.2.0", "webpack-node-externals": "3.0.0" @@ -32259,9 +32259,9 @@ } }, "node_modules/schema-utils": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", - "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", "dev": true, "license": "MIT", "dependencies": { @@ -36640,14 +36640,15 @@ } }, "node_modules/webpack": { - "version": "5.97.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz", - "integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==", + "version": "5.99.7", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.7.tgz", + "integrity": "sha512-CNqKBRMQjwcmKR0idID5va1qlhrqVUKpovi+Ec79ksW8ux7iS1+A6VqzfZXgVYCFRKl7XL5ap3ZoMpwBJxcg0w==", "dev": true, "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", @@ -36664,9 +36665,9 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", + "schema-utils": "^4.3.2", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", + "terser-webpack-plugin": "^5.3.11", "watchpack": "^2.4.1", "webpack-sources": "^3.2.3" }, @@ -37112,39 +37113,12 @@ "license": "MIT" }, "node_modules/webpack/node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", "dev": true, "license": "MIT" }, - "node_modules/webpack/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, "node_modules/webpack/node_modules/browserslist": { "version": "4.24.4", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", @@ -37209,32 +37183,6 @@ "dev": true, "license": "MIT" }, - "node_modules/webpack/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", diff --git a/package.json b/package.json index 7a98d4e3d1e..b59397dd704 100644 --- a/package.json +++ b/package.json @@ -141,7 +141,7 @@ "url": "0.11.4", "util": "0.12.5", "wait-on": "8.0.3", - "webpack": "5.97.1", + "webpack": "5.99.7", "webpack-cli": "6.0.1", "webpack-dev-server": "5.2.0", "webpack-node-externals": "3.0.0" From e610ba5c826bdfc9012b735b19640e1ab5b0feca Mon Sep 17 00:00:00 2001 From: Jordan Aasen <166539328+jaasen-livefront@users.noreply.github.com> Date: Thu, 8 May 2025 10:57:16 -0700 Subject: [PATCH 07/11] [PM-21280] - hide setings UI changes behind feature flag (#14665) * hide setings UI changes behind feature flag * protect observable. remove pipe --- .../popup/settings/about-page/about-page-v2.component.html | 6 ++++++ .../popup/settings/about-page/about-page-v2.component.ts | 7 +++++++ .../src/tools/popup/settings/settings-v2.component.html | 4 ++-- .../src/tools/popup/settings/settings-v2.component.ts | 7 +++++++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/apps/browser/src/tools/popup/settings/about-page/about-page-v2.component.html b/apps/browser/src/tools/popup/settings/about-page/about-page-v2.component.html index 9bba3994357..839681889a8 100644 --- a/apps/browser/src/tools/popup/settings/about-page/about-page-v2.component.html +++ b/apps/browser/src/tools/popup/settings/about-page/about-page-v2.component.html @@ -23,6 +23,12 @@ + + + {{ "moreFromBitwarden" | i18n }} + + +