1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-08 04:33:38 +00:00

key connector service unit tests

This commit is contained in:
Maciej Zieniuk
2025-03-25 20:34:58 +00:00
parent 7bed47b6d1
commit f066313354

View File

@@ -1,9 +1,8 @@
import { mock } from "jest-mock-extended";
import { firstValueFrom, of } from "rxjs";
import { firstValueFrom, of, timeout, TimeoutError } from "rxjs";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { OrganizationUserType } from "@bitwarden/common/admin-console/enums";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { KeyService } from "@bitwarden/key-management";
import { FakeAccountService, FakeStateProvider, mockAccountServiceWith } from "../../../../spec";
@@ -22,11 +21,7 @@ import { MasterKey } from "../../../types/key";
import { FakeMasterPasswordService } from "../../master-password/services/fake-master-password.service";
import { KeyConnectorUserKeyRequest } from "../models/key-connector-user-key.request";
import {
USES_KEY_CONNECTOR,
CONVERT_ACCOUNT_TO_KEY_CONNECTOR,
KeyConnectorService,
} from "./key-connector.service";
import { USES_KEY_CONNECTOR, KeyConnectorService } from "./key-connector.service";
describe("KeyConnectorService", () => {
let keyConnectorService: KeyConnectorService;
@@ -37,7 +32,6 @@ describe("KeyConnectorService", () => {
const logService = mock<LogService>();
const organizationService = mock<OrganizationService>();
const keyGenerationService = mock<KeyGenerationService>();
const messagingService = mock<MessagingService>();
let stateProvider: FakeStateProvider;
@@ -69,7 +63,6 @@ describe("KeyConnectorService", () => {
keyGenerationService,
async () => {},
stateProvider,
messagingService,
);
});
@@ -233,108 +226,6 @@ describe("KeyConnectorService", () => {
});
});
describe("setConvertAccountRequired", () => {
it("should update the convertAccountToKeyConnectorState with the provided value", async () => {
const state = stateProvider.activeUser.getFake(CONVERT_ACCOUNT_TO_KEY_CONNECTOR);
state.nextState(false);
const newValue = true;
await keyConnectorService.setConvertAccountRequired(newValue, mockUserId);
expect(await firstValueFrom(state.state$)).toBe(newValue);
});
it("should remove the convertAccountToKeyConnectorState", async () => {
const state = stateProvider.activeUser.getFake(CONVERT_ACCOUNT_TO_KEY_CONNECTOR);
state.nextState(false);
const newValue: boolean | null = null;
await keyConnectorService.setConvertAccountRequired(newValue, mockUserId);
expect(await firstValueFrom(state.state$)).toBe(newValue);
});
});
describe("userNeedsMigration", () => {
it("should return true if the user needs migration", async () => {
// token
tokenService.getIsExternal.mockResolvedValue(true);
// create organization object
const data = organizationData(
true,
true,
"https://key-connector-url.com",
OrganizationUserType.User,
false,
);
// uses KeyConnector
const state = stateProvider.singleUser.getFake(mockUserId, USES_KEY_CONNECTOR);
state.nextState(false);
const result = await keyConnectorService.userNeedsMigration(mockUserId, [data]);
expect(result).toBe(true);
});
it("should return false when not logged in with sso", async () => {
tokenService.getIsExternal.mockResolvedValue(false);
const data = organizationData(
true,
true,
"https://key-connector-url.com",
OrganizationUserType.User,
false,
);
const state = stateProvider.singleUser.getFake(mockUserId, USES_KEY_CONNECTOR);
state.nextState(false);
const result = await keyConnectorService.userNeedsMigration(mockUserId, [data]);
expect(result).toBe(false);
});
it("should return false when key connector not enabled in organization", async () => {
tokenService.getIsExternal.mockResolvedValue(true);
const data = organizationData(
true,
false,
"https://key-connector-url.com",
OrganizationUserType.User,
false,
);
const state = stateProvider.singleUser.getFake(mockUserId, USES_KEY_CONNECTOR);
state.nextState(false);
const result = await keyConnectorService.userNeedsMigration(mockUserId, [data]);
expect(result).toBe(false);
});
it("should return false when user does not need key connector", async () => {
tokenService.getIsExternal.mockResolvedValue(true);
const data = organizationData(
true,
true,
"https://key-connector-url.com",
OrganizationUserType.User,
false,
);
const state = stateProvider.singleUser.getFake(mockUserId, USES_KEY_CONNECTOR);
state.nextState(true);
const result = await keyConnectorService.userNeedsMigration(mockUserId, [data]);
expect(result).toBe(false);
});
});
describe("setMasterKeyFromUrl", () => {
it("should set the master key from the provided URL", async () => {
// Arrange
@@ -436,6 +327,136 @@ describe("KeyConnectorService", () => {
});
});
describe("convertAccountRequired$", () => {
beforeEach(async () => {
const organization = organizationData(
true,
true,
"https://key-connector-url.com",
OrganizationUserType.User,
false,
);
organizationService.organizations$.mockReturnValue(of([organization]));
await stateProvider.getUser(mockUserId, USES_KEY_CONNECTOR).update(() => false);
tokenService.getIsExternal.mockResolvedValue(true);
tokenService.hasAccessToken$.mockReturnValue(of(true));
});
it("should return true when user logged in with sso, belong to organization using key connector and user does not use key connector", async () => {
await expect(
firstValueFrom(keyConnectorService.convertAccountRequired$.pipe(timeout(100))),
).resolves.toEqual(true);
});
it("should return false when user logged in with password", async () => {
tokenService.getIsExternal.mockResolvedValue(false);
await expect(
firstValueFrom(keyConnectorService.convertAccountRequired$.pipe(timeout(100))),
).resolves.toEqual(false);
});
it("should return false when organization's key connector disabled", async () => {
const organization = organizationData(
true,
false,
"https://key-connector-url.com",
OrganizationUserType.User,
false,
);
organizationService.organizations$.mockReturnValue(of([organization]));
await expect(
firstValueFrom(keyConnectorService.convertAccountRequired$.pipe(timeout(100))),
).resolves.toEqual(false);
});
it("should return false when user is admin of the organization", async () => {
const organization = organizationData(
true,
true,
"https://key-connector-url.com",
OrganizationUserType.Admin,
false,
);
organizationService.organizations$.mockReturnValue(of([organization]));
await expect(
firstValueFrom(keyConnectorService.convertAccountRequired$.pipe(timeout(100))),
).resolves.toEqual(false);
});
it("should return false when user is owner of the organization", async () => {
const organization = organizationData(
true,
true,
"https://key-connector-url.com",
OrganizationUserType.Owner,
false,
);
organizationService.organizations$.mockReturnValue(of([organization]));
await expect(
firstValueFrom(keyConnectorService.convertAccountRequired$.pipe(timeout(100))),
).resolves.toEqual(false);
});
it("should return false when user is provider user of the organization", async () => {
const organization = organizationData(
true,
true,
"https://key-connector-url.com",
OrganizationUserType.User,
true,
);
organizationService.organizations$.mockReturnValue(of([organization]));
await expect(
firstValueFrom(keyConnectorService.convertAccountRequired$.pipe(timeout(100))),
).resolves.toEqual(false);
});
it("should return false when user already uses key connector", async () => {
await stateProvider.getUser(mockUserId, USES_KEY_CONNECTOR).update(() => true);
await expect(
firstValueFrom(keyConnectorService.convertAccountRequired$.pipe(timeout(100))),
).resolves.toEqual(false);
});
it("should not return any value when user not logged in", async () => {
await accountService.switchAccount(null as unknown as UserId);
await expect(
firstValueFrom(keyConnectorService.convertAccountRequired$.pipe(timeout(100))),
).rejects.toBeInstanceOf(TimeoutError);
});
it("should not return any value when organization state is empty", async () => {
organizationService.organizations$.mockReturnValue(of(null as unknown as Organization[]));
await expect(
firstValueFrom(keyConnectorService.convertAccountRequired$.pipe(timeout(100))),
).rejects.toBeInstanceOf(TimeoutError);
});
it("should not return any value when user is not using key connector", async () => {
await stateProvider.getUser(mockUserId, USES_KEY_CONNECTOR).update(() => null);
await expect(
firstValueFrom(keyConnectorService.convertAccountRequired$.pipe(timeout(100))),
).rejects.toBeInstanceOf(TimeoutError);
});
it("should not return any value when user does not have access token", async () => {
tokenService.hasAccessToken$.mockReturnValue(of(false));
await expect(
firstValueFrom(keyConnectorService.convertAccountRequired$.pipe(timeout(100))),
).rejects.toBeInstanceOf(TimeoutError);
});
});
function organizationData(
usesKeyConnector: boolean,
keyConnectorEnabled: boolean,