From b396dda4068df6dd18a92d7d7f6c7a4b2d4a753d Mon Sep 17 00:00:00 2001 From: Github Actions Date: Fri, 24 Jan 2025 17:59:54 +0000 Subject: [PATCH 1/4] 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 6eee556f6a0..202ec1c4fe1 100644 --- a/apps/browser/package.json +++ b/apps/browser/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/browser", - "version": "2025.1.2", + "version": "2025.1.3", "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 c7d12ddb7a6..6a2e017d06c 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": "__MSG_appName__", - "version": "2025.1.2", + "version": "2025.1.3", "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 6fdcc4e037e..f97823cae60 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": "__MSG_appName__", - "version": "2025.1.2", + "version": "2025.1.3", "description": "__MSG_extDesc__", "default_locale": "en", "author": "Bitwarden Inc.", diff --git a/package-lock.json b/package-lock.json index 56b78c410f8..af4b0bbf8c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -192,7 +192,7 @@ }, "apps/browser": { "name": "@bitwarden/browser", - "version": "2025.1.2" + "version": "2025.1.3" }, "apps/cli": { "name": "@bitwarden/cli", From b1744c4e0a647a2c31f5ef809438472328e0b997 Mon Sep 17 00:00:00 2001 From: Shane Melton Date: Fri, 24 Jan 2025 10:12:52 -0800 Subject: [PATCH 2/4] [PM-17541] Fix folder service key definition (#13060) * [PM-17541] Switch folder key definition back to "folders" and add migration script for users that have switched to the incorrect key * [PM-17541] Fix import path * [PM-17541] Fix implicit any in spec file --- libs/common/src/state-migrations/migrate.ts | 6 +- .../69-migrate-incorrect-folder-key.spec.ts | 98 +++++++++++++++++++ .../69-migrate-incorrect-folder-key.ts | 45 +++++++++ .../vault/services/key-state/folder.state.ts | 2 +- 4 files changed, 148 insertions(+), 3 deletions(-) create mode 100644 libs/common/src/state-migrations/migrations/69-migrate-incorrect-folder-key.spec.ts create mode 100644 libs/common/src/state-migrations/migrations/69-migrate-incorrect-folder-key.ts diff --git a/libs/common/src/state-migrations/migrate.ts b/libs/common/src/state-migrations/migrate.ts index 81b1016a53d..169de447f10 100644 --- a/libs/common/src/state-migrations/migrate.ts +++ b/libs/common/src/state-migrations/migrate.ts @@ -66,13 +66,14 @@ import { ForwarderOptionsMigrator } from "./migrations/65-migrate-forwarder-sett import { MoveFinalDesktopSettingsMigrator } from "./migrations/66-move-final-desktop-settings"; import { RemoveUnassignedItemsBannerDismissed } from "./migrations/67-remove-unassigned-items-banner-dismissed"; import { MoveLastSyncDate } from "./migrations/68-move-last-sync-date"; +import { MigrateIncorrectFolderKey } from "./migrations/69-migrate-incorrect-folder-key"; import { MoveBiometricAutoPromptToAccount } from "./migrations/7-move-biometric-auto-prompt-to-account"; import { MoveStateVersionMigrator } from "./migrations/8-move-state-version"; import { MoveBrowserSettingsToGlobal } from "./migrations/9-move-browser-settings-to-global"; import { MinVersionMigrator } from "./migrations/min-version"; export const MIN_VERSION = 3; -export const CURRENT_VERSION = 68; +export const CURRENT_VERSION = 69; export type MinVersion = typeof MIN_VERSION; export function createMigrationBuilder() { @@ -142,7 +143,8 @@ export function createMigrationBuilder() { .with(ForwarderOptionsMigrator, 64, 65) .with(MoveFinalDesktopSettingsMigrator, 65, 66) .with(RemoveUnassignedItemsBannerDismissed, 66, 67) - .with(MoveLastSyncDate, 67, CURRENT_VERSION); + .with(MoveLastSyncDate, 67, 68) + .with(MigrateIncorrectFolderKey, 68, CURRENT_VERSION); } export async function currentVersion( diff --git a/libs/common/src/state-migrations/migrations/69-migrate-incorrect-folder-key.spec.ts b/libs/common/src/state-migrations/migrations/69-migrate-incorrect-folder-key.spec.ts new file mode 100644 index 00000000000..e5dec943f78 --- /dev/null +++ b/libs/common/src/state-migrations/migrations/69-migrate-incorrect-folder-key.spec.ts @@ -0,0 +1,98 @@ +import { runMigrator } from "../migration-helper.spec"; + +import { MigrateIncorrectFolderKey } from "./69-migrate-incorrect-folder-key"; + +function exampleJSON() { + return { + global_account_accounts: { + user1: null as any, + user2: null as any, + }, + user_user1_folder_folder: { + // Incorrect "folder" key + folderId1: { + id: "folderId1", + name: "folder-name-1", + revisionDate: "folder-revision-date-1", + }, + folderId2: { + id: "folderId2", + name: "folder-name-2", + revisionDate: "folder-revision-date-2", + }, + }, + user_user2_folder_folder: null as any, + }; +} + +describe("MigrateIncorrectFolderKey", () => { + const sut = new MigrateIncorrectFolderKey(68, 69); + it("migrates data", async () => { + const output = await runMigrator(sut, exampleJSON()); + + expect(output).toEqual({ + global_account_accounts: { + user1: null, + user2: null, + }, + user_user1_folder_folders: { + // Correct "folders" key + folderId1: { + id: "folderId1", + name: "folder-name-1", + revisionDate: "folder-revision-date-1", + }, + folderId2: { + id: "folderId2", + name: "folder-name-2", + revisionDate: "folder-revision-date-2", + }, + }, + }); + }); + + it("rolls back data", async () => { + const output = await runMigrator( + sut, + { + global_account_accounts: { + user1: null, + user2: null, + }, + user_user1_folder_folders: { + folderId1: { + id: "folderId1", + name: "folder-name-1", + revisionDate: "folder-revision-date-1", + }, + folderId2: { + id: "folderId2", + name: "folder-name-2", + revisionDate: "folder-revision-date-2", + }, + }, + }, + "rollback", + ); + + expect(output).toEqual({ + global_account_accounts: { + user1: null, + user2: null, + }, + user_user1_folder_folder: { + // Incorrect "folder" key + folderId1: { + id: "folderId1", + name: "folder-name-1", + revisionDate: "folder-revision-date-1", + }, + folderId2: { + id: "folderId2", + name: "folder-name-2", + revisionDate: "folder-revision-date-2", + }, + }, + }); + }); +}); diff --git a/libs/common/src/state-migrations/migrations/69-migrate-incorrect-folder-key.ts b/libs/common/src/state-migrations/migrations/69-migrate-incorrect-folder-key.ts new file mode 100644 index 00000000000..046c0cf0dfa --- /dev/null +++ b/libs/common/src/state-migrations/migrations/69-migrate-incorrect-folder-key.ts @@ -0,0 +1,45 @@ +import { + KeyDefinitionLike, + MigrationHelper, +} from "@bitwarden/common/state-migrations/migration-helper"; +import { Migrator } from "@bitwarden/common/state-migrations/migrator"; + +const BAD_FOLDER_KEY: KeyDefinitionLike = { + key: "folder", // We inadvertently changed the key from "folders" to "folder" + stateDefinition: { + name: "folder", + }, +}; + +const GOOD_FOLDER_KEY: KeyDefinitionLike = { + key: "folders", // We should keep the key as "folders" + stateDefinition: { + name: "folder", + }, +}; + +export class MigrateIncorrectFolderKey extends Migrator<68, 69> { + async migrate(helper: MigrationHelper): Promise { + async function migrateUser(userId: string) { + const value = await helper.getFromUser(userId, BAD_FOLDER_KEY); + if (value != null) { + await helper.setToUser(userId, GOOD_FOLDER_KEY, value); + } + await helper.removeFromUser(userId, BAD_FOLDER_KEY); + } + const users = await helper.getKnownUserIds(); + await Promise.all(users.map((userId) => migrateUser(userId))); + } + + async rollback(helper: MigrationHelper): Promise { + async function rollbackUser(userId: string) { + const value = await helper.getFromUser(userId, GOOD_FOLDER_KEY); + if (value != null) { + await helper.setToUser(userId, BAD_FOLDER_KEY, value); + } + await helper.removeFromUser(userId, GOOD_FOLDER_KEY); + } + const users = await helper.getKnownUserIds(); + await Promise.all(users.map((userId) => rollbackUser(userId))); + } +} diff --git a/libs/common/src/vault/services/key-state/folder.state.ts b/libs/common/src/vault/services/key-state/folder.state.ts index 99ad8e5ae35..b3e61f5bf31 100644 --- a/libs/common/src/vault/services/key-state/folder.state.ts +++ b/libs/common/src/vault/services/key-state/folder.state.ts @@ -6,7 +6,7 @@ import { FolderView } from "../../models/view/folder.view"; export const FOLDER_ENCRYPTED_FOLDERS = UserKeyDefinition.record( FOLDER_DISK, - "folder", + "folders", { deserializer: (obj: Jsonify) => FolderData.fromJSON(obj), clearOn: ["logout"], From 6acaa6c711c78807c0cb07342afcaff7eee5aff8 Mon Sep 17 00:00:00 2001 From: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com> Date: Fri, 24 Jan 2025 13:20:42 -0500 Subject: [PATCH 3/4] Auth/PM-17197 - UnauthGuard Trusted Devices Lock State Refactor (#12938) * PM-17197 - Refactor DeviceTrustService to deprecate active user state as I need to call with a user id per latest best practice * PM-17197 - Refactor Unauth Guard to be aware of TDE lock state + use active user best practice. --- .../src/auth/guards/unauth.guard.spec.ts | 76 ++++++++++++++++--- libs/angular/src/auth/guards/unauth.guard.ts | 63 +++++++++++---- .../device-trust.service.abstraction.ts | 11 +++ .../device-trust.service.implementation.ts | 12 ++- .../services/device-trust.service.spec.ts | 43 ++++++++++- 5 files changed, 177 insertions(+), 28 deletions(-) diff --git a/libs/angular/src/auth/guards/unauth.guard.spec.ts b/libs/angular/src/auth/guards/unauth.guard.spec.ts index 6d8619f4d43..ec36b146a03 100644 --- a/libs/angular/src/auth/guards/unauth.guard.spec.ts +++ b/libs/angular/src/auth/guards/unauth.guard.spec.ts @@ -5,17 +5,48 @@ import { MockProxy, mock } from "jest-mock-extended"; import { BehaviorSubject } from "rxjs"; import { EmptyComponent } from "@bitwarden/angular/platform/guard/feature-flag.guard.spec"; +import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; +import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { UserId } from "@bitwarden/common/types/guid"; +import { KeyService } from "@bitwarden/key-management"; import { unauthGuardFn } from "./unauth.guard"; describe("UnauthGuard", () => { - const setup = (authStatus: AuthenticationStatus) => { + const activeUser: Account = { + id: "fake_user_id" as UserId, + email: "test@email.com", + emailVerified: true, + name: "Test User", + }; + + const setup = ( + activeUser: Account | null, + authStatus: AuthenticationStatus | null = null, + tdeEnabled: boolean = false, + everHadUserKey: boolean = false, + ) => { + const accountService: MockProxy = mock(); const authService: MockProxy = mock(); - authService.getAuthStatus.mockResolvedValue(authStatus); - const activeAccountStatusObservable = new BehaviorSubject(authStatus); - authService.activeAccountStatus$ = activeAccountStatusObservable; + const keyService: MockProxy = mock(); + const deviceTrustService: MockProxy = + mock(); + const logService: MockProxy = mock(); + + accountService.activeAccount$ = new BehaviorSubject(activeUser); + + if (authStatus !== null) { + const activeAccountStatusObservable = new BehaviorSubject(authStatus); + authService.authStatusFor$.mockReturnValue(activeAccountStatusObservable); + } + + keyService.everHadUserKey$ = new BehaviorSubject(everHadUserKey); + deviceTrustService.supportsDeviceTrustByUserId$.mockReturnValue( + new BehaviorSubject(tdeEnabled), + ); const testBed = TestBed.configureTestingModule({ imports: [ @@ -30,6 +61,7 @@ describe("UnauthGuard", () => { { path: "lock", component: EmptyComponent }, { path: "testhomepage", component: EmptyComponent }, { path: "testlocked", component: EmptyComponent }, + { path: "login-initiated", component: EmptyComponent }, { path: "testOverrides", component: EmptyComponent, @@ -39,7 +71,13 @@ describe("UnauthGuard", () => { }, ]), ], - providers: [{ provide: AuthService, useValue: authService }], + providers: [ + { provide: AccountService, useValue: accountService }, + { provide: AuthService, useValue: authService }, + { provide: KeyService, useValue: keyService }, + { provide: DeviceTrustServiceAbstraction, useValue: deviceTrustService }, + { provide: LogService, useValue: logService }, + ], }); return { @@ -48,40 +86,54 @@ describe("UnauthGuard", () => { }; it("should be created", () => { - const { router } = setup(AuthenticationStatus.LoggedOut); + const { router } = setup(null, AuthenticationStatus.LoggedOut); expect(router).toBeTruthy(); }); it("should redirect to /vault for guarded routes when logged in and unlocked", async () => { - const { router } = setup(AuthenticationStatus.Unlocked); + const { router } = setup(activeUser, AuthenticationStatus.Unlocked); await router.navigateByUrl("unauth-guarded-route"); expect(router.url).toBe("/vault"); }); - it("should allow access to guarded routes when logged out", async () => { - const { router } = setup(AuthenticationStatus.LoggedOut); + it("should allow access to guarded routes when account is null", async () => { + const { router } = setup(null); await router.navigateByUrl("unauth-guarded-route"); expect(router.url).toBe("/unauth-guarded-route"); }); + it("should allow access to guarded routes when logged out", async () => { + const { router } = setup(null, AuthenticationStatus.LoggedOut); + + await router.navigateByUrl("unauth-guarded-route"); + expect(router.url).toBe("/unauth-guarded-route"); + }); + + it("should redirect to /login-initiated when locked, TDE is enabled, and the user hasn't decrypted yet", async () => { + const { router } = setup(activeUser, AuthenticationStatus.Locked, true, false); + + await router.navigateByUrl("unauth-guarded-route"); + expect(router.url).toBe("/login-initiated"); + }); + it("should redirect to /lock for guarded routes when locked", async () => { - const { router } = setup(AuthenticationStatus.Locked); + const { router } = setup(activeUser, AuthenticationStatus.Locked); await router.navigateByUrl("unauth-guarded-route"); expect(router.url).toBe("/lock"); }); it("should redirect to /testhomepage for guarded routes when testOverrides are provided and the account is unlocked", async () => { - const { router } = setup(AuthenticationStatus.Unlocked); + const { router } = setup(activeUser, AuthenticationStatus.Unlocked); await router.navigateByUrl("testOverrides"); expect(router.url).toBe("/testhomepage"); }); it("should redirect to /testlocked for guarded routes when testOverrides are provided and the account is locked", async () => { - const { router } = setup(AuthenticationStatus.Locked); + const { router } = setup(activeUser, AuthenticationStatus.Locked); await router.navigateByUrl("testOverrides"); expect(router.url).toBe("/testlocked"); diff --git a/libs/angular/src/auth/guards/unauth.guard.ts b/libs/angular/src/auth/guards/unauth.guard.ts index f96668773ef..1ac0eebb458 100644 --- a/libs/angular/src/auth/guards/unauth.guard.ts +++ b/libs/angular/src/auth/guards/unauth.guard.ts @@ -1,9 +1,13 @@ import { inject } from "@angular/core"; -import { CanActivateFn, Router, UrlTree } from "@angular/router"; -import { Observable, map } from "rxjs"; +import { ActivatedRouteSnapshot, CanActivateFn, Router, UrlTree } from "@angular/router"; +import { firstValueFrom } from "rxjs"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; +import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { KeyService } from "@bitwarden/key-management"; type UnauthRoutes = { homepage: () => string; @@ -15,23 +19,54 @@ const defaultRoutes: UnauthRoutes = { locked: "/lock", }; -function unauthGuard(routes: UnauthRoutes): Observable { +// TODO: PM-17195 - Investigate consolidating unauthGuard and redirectGuard into AuthStatusGuard +async function unauthGuard( + route: ActivatedRouteSnapshot, + routes: UnauthRoutes, +): Promise { + const accountService = inject(AccountService); const authService = inject(AuthService); const router = inject(Router); + const keyService = inject(KeyService); + const deviceTrustService = inject(DeviceTrustServiceAbstraction); + const logService = inject(LogService); - return authService.activeAccountStatus$.pipe( - map((status) => { - if (status == null || status === AuthenticationStatus.LoggedOut) { - return true; - } else if (status === AuthenticationStatus.Locked) { - return router.createUrlTree([routes.locked]); - } else { - return router.createUrlTree([routes.homepage()]); - } - }), + const activeUser = await firstValueFrom(accountService.activeAccount$); + + if (!activeUser) { + return true; + } + + const authStatus = await firstValueFrom(authService.authStatusFor$(activeUser.id)); + + if (authStatus == null || authStatus === AuthenticationStatus.LoggedOut) { + return true; + } + + if (authStatus === AuthenticationStatus.Unlocked) { + return router.createUrlTree([routes.homepage()]); + } + + const tdeEnabled = await firstValueFrom( + deviceTrustService.supportsDeviceTrustByUserId$(activeUser.id), ); + const everHadUserKey = await firstValueFrom(keyService.everHadUserKey$); + + // If locked, TDE is enabled, and the user hasn't decrypted yet, then redirect to the + // login decryption options component. + if (authStatus === AuthenticationStatus.Locked && tdeEnabled && !everHadUserKey) { + logService.info( + "Sending user to TDE decryption options. AuthStatus is %s. TDE support is %s. Ever had user key is %s.", + AuthenticationStatus[authStatus], + tdeEnabled, + everHadUserKey, + ); + return router.createUrlTree(["/login-initiated"]); + } + + return router.createUrlTree([routes.locked]); } export function unauthGuardFn(overrides: Partial = {}): CanActivateFn { - return () => unauthGuard({ ...defaultRoutes, ...overrides }); + return async (route) => unauthGuard(route, { ...defaultRoutes, ...overrides }); } diff --git a/libs/common/src/auth/abstractions/device-trust.service.abstraction.ts b/libs/common/src/auth/abstractions/device-trust.service.abstraction.ts index 13963b03bea..24a5d4e8413 100644 --- a/libs/common/src/auth/abstractions/device-trust.service.abstraction.ts +++ b/libs/common/src/auth/abstractions/device-trust.service.abstraction.ts @@ -9,7 +9,18 @@ import { DeviceKey, UserKey } from "../../types/key"; import { DeviceResponse } from "./devices/responses/device.response"; export abstract class DeviceTrustServiceAbstraction { + /** + * @deprecated - use supportsDeviceTrustByUserId instead as active user state is being deprecated + * by Platform + * @description Checks if the device trust feature is supported for the active user. + */ supportsDeviceTrust$: Observable; + + /** + * @description Checks if the device trust feature is supported for the given user. + */ + supportsDeviceTrustByUserId$: (userId: UserId) => Observable; + /** * @description Retrieves the users choice to trust the device which can only happen after decryption * Note: this value should only be used once and then reset diff --git a/libs/common/src/auth/services/device-trust.service.implementation.ts b/libs/common/src/auth/services/device-trust.service.implementation.ts index a94c8b6e422..15c12b7a39a 100644 --- a/libs/common/src/auth/services/device-trust.service.implementation.ts +++ b/libs/common/src/auth/services/device-trust.service.implementation.ts @@ -81,7 +81,17 @@ export class DeviceTrustService implements DeviceTrustServiceAbstraction { private configService: ConfigService, ) { this.supportsDeviceTrust$ = this.userDecryptionOptionsService.userDecryptionOptions$.pipe( - map((options) => options?.trustedDeviceOption != null ?? false), + map((options) => { + return options?.trustedDeviceOption != null ?? false; + }), + ); + } + + supportsDeviceTrustByUserId$(userId: UserId): Observable { + return this.userDecryptionOptionsService.userDecryptionOptionsById$(userId).pipe( + map((options) => { + return options?.trustedDeviceOption != null ?? false; + }), ); } diff --git a/libs/common/src/auth/services/device-trust.service.spec.ts b/libs/common/src/auth/services/device-trust.service.spec.ts index 943653e3129..9f344e203c9 100644 --- a/libs/common/src/auth/services/device-trust.service.spec.ts +++ b/libs/common/src/auth/services/device-trust.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 { matches, mock } from "jest-mock-extended"; -import { BehaviorSubject, of } from "rxjs"; +import { BehaviorSubject, firstValueFrom, of } from "rxjs"; import { UserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common"; @@ -74,17 +76,56 @@ describe("deviceTrustService", () => { userId: mockUserId, }; + let userDecryptionOptions: UserDecryptionOptions; + beforeEach(() => { jest.clearAllMocks(); const supportsSecureStorage = false; // default to false; tests will override as needed // By default all the tests will have a mocked active user in state provider. deviceTrustService = createDeviceTrustService(mockUserId, supportsSecureStorage); + + userDecryptionOptions = new UserDecryptionOptions(); }); it("instantiates", () => { expect(deviceTrustService).not.toBeFalsy(); }); + describe("supportsDeviceTrustByUserId$", () => { + it("returns true when the user has a non-null trusted device decryption option", async () => { + // Arrange + userDecryptionOptions.trustedDeviceOption = { + hasAdminApproval: false, + hasLoginApprovingDevice: false, + hasManageResetPasswordPermission: false, + isTdeOffboarding: false, + }; + + userDecryptionOptionsService.userDecryptionOptionsById$.mockReturnValue( + new BehaviorSubject(userDecryptionOptions), + ); + + const result = await firstValueFrom( + deviceTrustService.supportsDeviceTrustByUserId$(mockUserId), + ); + expect(result).toBe(true); + }); + + it("returns false when the user has a null trusted device decryption option", async () => { + // Arrange + userDecryptionOptions.trustedDeviceOption = null; + + userDecryptionOptionsService.userDecryptionOptionsById$.mockReturnValue( + new BehaviorSubject(userDecryptionOptions), + ); + + const result = await firstValueFrom( + deviceTrustService.supportsDeviceTrustByUserId$(mockUserId), + ); + expect(result).toBe(false); + }); + }); + describe("User Trust Device Choice For Decryption", () => { describe("getShouldTrustDevice", () => { it("gets the user trust device choice for decryption", async () => { From 315e1338d5522523d74387cd1eb5b99da48047a6 Mon Sep 17 00:00:00 2001 From: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com> Date: Fri, 24 Jan 2025 13:25:51 -0500 Subject: [PATCH 4/4] PM-17466 - RegistrationFinishComp - Add call to loginSuccessHandlerService after successful login (#13059) --- .../registration-finish/registration-finish.component.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) 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 31b3f7db92a..c419e1f427f 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 @@ -16,7 +16,11 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service" import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; import { ToastService } from "@bitwarden/components"; -import { LoginStrategyServiceAbstraction, PasswordLoginCredentials } from "../../../common"; +import { + LoginStrategyServiceAbstraction, + LoginSuccessHandlerService, + PasswordLoginCredentials, +} from "../../../common"; import { AnonLayoutWrapperDataService } from "../../anon-layout/anon-layout-wrapper-data.service"; import { InputPasswordComponent } from "../../input-password/input-password.component"; import { PasswordInputResult } from "../../input-password/password-input-result"; @@ -68,6 +72,7 @@ export class RegistrationFinishComponent implements OnInit, OnDestroy { private loginStrategyService: LoginStrategyServiceAbstraction, private logService: LogService, private anonLayoutWrapperDataService: AnonLayoutWrapperDataService, + private loginSuccessHandlerService: LoginSuccessHandlerService, ) {} async ngOnInit() { @@ -189,6 +194,8 @@ export class RegistrationFinishComponent implements OnInit, OnDestroy { message: this.i18nService.t("youHaveBeenLoggedIn"), }); + await this.loginSuccessHandlerService.run(authenticationResult.userId); + await this.router.navigate(["/vault"]); } catch (e) { // If login errors, redirect to login page per product. Don't show error