1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-28 10:33:31 +00:00

Merge remote-tracking branch 'origin' into auth/pm-18720/change-password-component-non-dialog-v3

This commit is contained in:
Patrick Pimentel
2025-06-23 15:39:09 -04:00
619 changed files with 24974 additions and 5442 deletions

View File

@@ -6,3 +6,4 @@ export * from "./user-decryption-options.service.abstraction";
export * from "./auth-request.service.abstraction";
export * from "./login-approval-component.service.abstraction";
export * from "./login-success-handler.service";
export * from "./logout.service";

View File

@@ -0,0 +1,19 @@
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { UserId } from "@bitwarden/common/types/guid";
import { LogoutReason } from "../types";
export interface NewActiveUser {
userId: UserId;
authenticationStatus: AuthenticationStatus;
}
export abstract class LogoutService {
/**
* Logs out the user.
* @param userId The user id.
* @param logoutReason The optional reason for logging out.
* @returns The new active user or undefined if there isn't a new active account.
*/
abstract logout(userId: UserId, logoutReason?: LogoutReason): Promise<NewActiveUser | undefined>;
}

View File

@@ -166,7 +166,7 @@ describe("AuthRequestLoginStrategy", () => {
decMasterKeyHash,
mockUserId,
);
expect(keyService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(
expect(masterPasswordService.mock.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(
tokenResponse.key,
mockUserId,
);
@@ -194,7 +194,7 @@ describe("AuthRequestLoginStrategy", () => {
expect(masterPasswordService.mock.setMasterKeyHash).not.toHaveBeenCalled();
// setMasterKeyEncryptedUserKey, setUserKey, and setPrivateKey should still be called
expect(keyService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(
expect(masterPasswordService.mock.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(
tokenResponse.key,
mockUserId,
);

View File

@@ -95,7 +95,9 @@ export class AuthRequestLoginStrategy extends LoginStrategy {
const authRequestCredentials = this.cache.value.authRequestCredentials;
// User now may or may not have a master password
// but set the master key encrypted user key if it exists regardless
await this.keyService.setMasterKeyEncryptedUserKey(response.key, userId);
if (response.key) {
await this.masterPasswordService.setMasterKeyEncryptedUserKey(response.key, userId);
}
if (authRequestCredentials.decryptedUserKey) {
await this.keyService.setUserKey(authRequestCredentials.decryptedUserKey, userId);

View File

@@ -202,7 +202,10 @@ describe("PasswordLoginStrategy", () => {
localHashedPassword,
userId,
);
expect(keyService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(tokenResponse.key, userId);
expect(masterPasswordService.mock.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(
tokenResponse.key,
userId,
);
expect(keyService.setUserKey).toHaveBeenCalledWith(userKey, userId);
expect(keyService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey, userId);
});

View File

@@ -127,7 +127,10 @@ export class PasswordLoginStrategy extends LoginStrategy {
if (this.encryptionKeyMigrationRequired(response)) {
return;
}
await this.keyService.setMasterKeyEncryptedUserKey(response.key, userId);
if (response.key) {
await this.masterPasswordService.setMasterKeyEncryptedUserKey(response.key, userId);
}
const masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId));
if (masterKey) {

View File

@@ -196,8 +196,11 @@ describe("SsoLoginStrategy", () => {
await ssoLoginStrategy.logIn(credentials);
// Assert
expect(keyService.setMasterKeyEncryptedUserKey).toHaveBeenCalledTimes(1);
expect(keyService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(tokenResponse.key, userId);
expect(masterPasswordService.mock.setMasterKeyEncryptedUserKey).toHaveBeenCalledTimes(1);
expect(masterPasswordService.mock.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(
tokenResponse.key,
userId,
);
});
describe("Trusted Device Decryption", () => {

View File

@@ -185,7 +185,10 @@ export class SsoLoginStrategy extends LoginStrategy {
if (masterKeyEncryptedUserKey) {
// set the master key encrypted user key if it exists
await this.keyService.setMasterKeyEncryptedUserKey(masterKeyEncryptedUserKey, userId);
await this.masterPasswordService.setMasterKeyEncryptedUserKey(
masterKeyEncryptedUserKey,
userId,
);
}
const userDecryptionOptions = tokenResponse?.userDecryptionOptions;

View File

@@ -176,7 +176,10 @@ describe("UserApiLoginStrategy", () => {
await apiLogInStrategy.logIn(credentials);
expect(keyService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(tokenResponse.key, userId);
expect(masterPasswordService.mock.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(
tokenResponse.key,
userId,
);
expect(keyService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey, userId);
});

View File

@@ -63,7 +63,9 @@ export class UserApiLoginStrategy extends LoginStrategy {
response: IdentityTokenResponse,
userId: UserId,
): Promise<void> {
await this.keyService.setMasterKeyEncryptedUserKey(response.key, userId);
if (response.key) {
await this.masterPasswordService.setMasterKeyEncryptedUserKey(response.key, userId);
}
if (response.apiUseKeyConnector) {
const masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId));

View File

@@ -237,8 +237,8 @@ describe("WebAuthnLoginStrategy", () => {
// Assert
// Master key encrypted user key should be set
expect(keyService.setMasterKeyEncryptedUserKey).toHaveBeenCalledTimes(1);
expect(keyService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(
expect(masterPasswordService.mock.setMasterKeyEncryptedUserKey).toHaveBeenCalledTimes(1);
expect(masterPasswordService.mock.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(
idTokenResponse.key,
userId,
);

View File

@@ -66,7 +66,10 @@ export class WebAuthnLoginStrategy extends LoginStrategy {
if (masterKeyEncryptedUserKey) {
// set the master key encrypted user key if it exists
await this.keyService.setMasterKeyEncryptedUserKey(masterKeyEncryptedUserKey, userId);
await this.masterPasswordService.setMasterKeyEncryptedUserKey(
masterKeyEncryptedUserKey,
userId,
);
}
const userDecryptionOptions = idTokenResponse?.userDecryptionOptions;

View File

@@ -7,3 +7,4 @@ export * from "./auth-request/auth-request-api.service";
export * from "./accounts/lock.service";
export * from "./login-success-handler/default-login-success-handler.service";
export * from "./sso-redirect/sso-url.service";
export * from "./logout/default-logout.service";

View File

@@ -0,0 +1,40 @@
import { MockProxy, mock } from "jest-mock-extended";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { UserId } from "@bitwarden/common/types/guid";
import { LogoutService } from "../../abstractions";
import { LogoutReason } from "../../types";
import { DefaultLogoutService } from "./default-logout.service";
describe("DefaultLogoutService", () => {
let logoutService: LogoutService;
let messagingService: MockProxy<MessagingService>;
beforeEach(() => {
messagingService = mock<MessagingService>();
logoutService = new DefaultLogoutService(messagingService);
});
it("instantiates", () => {
expect(logoutService).not.toBeFalsy();
});
describe("logout", () => {
it("sends logout message without a logout reason when not provided", async () => {
const userId = "1" as UserId;
await logoutService.logout(userId);
expect(messagingService.send).toHaveBeenCalledWith("logout", { userId });
});
it("sends logout message with a logout reason when provided", async () => {
const userId = "1" as UserId;
const logoutReason: LogoutReason = "vaultTimeout";
await logoutService.logout(userId, logoutReason);
expect(messagingService.send).toHaveBeenCalledWith("logout", { userId, logoutReason });
});
});
});

View File

@@ -0,0 +1,14 @@
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { UserId } from "@bitwarden/common/types/guid";
import { LogoutService, NewActiveUser } from "../../abstractions/logout.service";
import { LogoutReason } from "../../types";
export class DefaultLogoutService implements LogoutService {
constructor(protected messagingService: MessagingService) {}
async logout(userId: UserId, logoutReason?: LogoutReason): Promise<NewActiveUser | undefined> {
this.messagingService.send("logout", { userId, logoutReason });
return undefined;
}
}