mirror of
https://github.com/bitwarden/browser
synced 2026-01-07 11:03:30 +00:00
[PM-5404, PM-3518] Migrate user decryption options to new service (#7344)
* create new user decryption options service * rename new service to user decryption options * add hasMasterPassword to user decryption options service * migrate device trust service to new user decryption options service * add migration for user-decryption-options * migrate sync service and calls to trust-device-service * rename abstraction file * migrate two factor component * migrate two factor spec * migrate sso component * migrate set-password component * migrate base login decryption component * migrate organization options component * fix component imports * add missing imports - remove state service calls - add update user decryption options method * remove acct decryption options from account * lint * fix tests and linting * fix browser * fix desktop * add user decryption options service to cli * remove default value from migration * bump migration number * fix merge conflict * fix vault timeout settings * fix cli * more fixes * add user decryption options service to deps of vault timeout settings service * update login strategy service with user decryption options * remove early return from sync bandaid for user decryption options * move user decryption options service to lib/auth * move user decryption options to libs/auth * fix reference * fix browser * check user decryption options after 2fa check * update migration and revert tsconfig changes * add more documentation * clear user decryption options on logout * fix tests by creating helper for user decryption options * fix tests * pr feedback * fix factory * update migration * add tests * update missed migration num in test
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
export * from "./pin-crypto/pin-crypto.service.implementation";
|
||||
export * from "./login-strategies/login-strategy.service";
|
||||
export * from "./user-decryption-options/user-decryption-options.service";
|
||||
export * from "./auth-request/auth-request.service";
|
||||
|
||||
@@ -25,8 +25,12 @@ import { KdfType } from "@bitwarden/common/platform/enums";
|
||||
import { FakeGlobalState, FakeGlobalStateProvider } from "@bitwarden/common/spec";
|
||||
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
||||
|
||||
import { AuthRequestServiceAbstraction } from "../../abstractions";
|
||||
import {
|
||||
AuthRequestServiceAbstraction,
|
||||
InternalUserDecryptionOptionsServiceAbstraction,
|
||||
} from "../../abstractions";
|
||||
import { PasswordLoginCredentials } from "../../models";
|
||||
import { UserDecryptionOptionsService } from "../user-decryption-options/user-decryption-options.service";
|
||||
|
||||
import { LoginStrategyService } from "./login-strategy.service";
|
||||
import { CACHE_EXPIRATION_KEY } from "./login-strategy.state";
|
||||
@@ -51,6 +55,7 @@ describe("LoginStrategyService", () => {
|
||||
let policyService: MockProxy<PolicyService>;
|
||||
let deviceTrustCryptoService: MockProxy<DeviceTrustCryptoServiceAbstraction>;
|
||||
let authRequestService: MockProxy<AuthRequestServiceAbstraction>;
|
||||
let userDecryptionOptionsService: MockProxy<InternalUserDecryptionOptionsServiceAbstraction>;
|
||||
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
||||
|
||||
let stateProvider: FakeGlobalStateProvider;
|
||||
@@ -74,6 +79,7 @@ describe("LoginStrategyService", () => {
|
||||
policyService = mock<PolicyService>();
|
||||
deviceTrustCryptoService = mock<DeviceTrustCryptoServiceAbstraction>();
|
||||
authRequestService = mock<AuthRequestServiceAbstraction>();
|
||||
userDecryptionOptionsService = mock<UserDecryptionOptionsService>();
|
||||
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
||||
stateProvider = new FakeGlobalStateProvider();
|
||||
|
||||
@@ -95,6 +101,7 @@ describe("LoginStrategyService", () => {
|
||||
policyService,
|
||||
deviceTrustCryptoService,
|
||||
authRequestService,
|
||||
userDecryptionOptionsService,
|
||||
stateProvider,
|
||||
billingAccountProfileStateService,
|
||||
);
|
||||
|
||||
@@ -40,6 +40,7 @@ import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/pass
|
||||
import { MasterKey } from "@bitwarden/common/types/key";
|
||||
|
||||
import { AuthRequestServiceAbstraction, LoginStrategyServiceAbstraction } from "../../abstractions";
|
||||
import { InternalUserDecryptionOptionsServiceAbstraction } from "../../abstractions/user-decryption-options.service.abstraction";
|
||||
import { AuthRequestLoginStrategy } from "../../login-strategies/auth-request-login.strategy";
|
||||
import { PasswordLoginStrategy } from "../../login-strategies/password-login.strategy";
|
||||
import { SsoLoginStrategy } from "../../login-strategies/sso-login.strategy";
|
||||
@@ -101,6 +102,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
||||
protected policyService: PolicyService,
|
||||
protected deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction,
|
||||
protected authRequestService: AuthRequestServiceAbstraction,
|
||||
protected userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||
protected stateProvider: GlobalStateProvider,
|
||||
protected billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
) {
|
||||
@@ -354,6 +356,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
||||
this.logService,
|
||||
this.stateService,
|
||||
this.twoFactorService,
|
||||
this.userDecryptionOptionsService,
|
||||
this.passwordStrengthService,
|
||||
this.policyService,
|
||||
this,
|
||||
@@ -371,6 +374,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
||||
this.logService,
|
||||
this.stateService,
|
||||
this.twoFactorService,
|
||||
this.userDecryptionOptionsService,
|
||||
this.keyConnectorService,
|
||||
this.deviceTrustCryptoService,
|
||||
this.authRequestService,
|
||||
@@ -389,6 +393,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
||||
this.logService,
|
||||
this.stateService,
|
||||
this.twoFactorService,
|
||||
this.userDecryptionOptionsService,
|
||||
this.environmentService,
|
||||
this.keyConnectorService,
|
||||
this.billingAccountProfileStateService,
|
||||
@@ -405,6 +410,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
||||
this.logService,
|
||||
this.stateService,
|
||||
this.twoFactorService,
|
||||
this.userDecryptionOptionsService,
|
||||
this.deviceTrustCryptoService,
|
||||
this.billingAccountProfileStateService,
|
||||
);
|
||||
@@ -420,6 +426,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
||||
this.logService,
|
||||
this.stateService,
|
||||
this.twoFactorService,
|
||||
this.userDecryptionOptionsService,
|
||||
this.billingAccountProfileStateService,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import {
|
||||
FakeAccountService,
|
||||
FakeStateProvider,
|
||||
mockAccountServiceWith,
|
||||
} from "@bitwarden/common/spec";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
|
||||
import {
|
||||
USER_DECRYPTION_OPTIONS,
|
||||
UserDecryptionOptionsService,
|
||||
} from "./user-decryption-options.service";
|
||||
|
||||
describe("UserDecryptionOptionsService", () => {
|
||||
let sut: UserDecryptionOptionsService;
|
||||
|
||||
const fakeUserId = Utils.newGuid() as UserId;
|
||||
let fakeAccountService: FakeAccountService;
|
||||
let fakeStateProvider: FakeStateProvider;
|
||||
|
||||
beforeEach(() => {
|
||||
fakeAccountService = mockAccountServiceWith(fakeUserId);
|
||||
fakeStateProvider = new FakeStateProvider(fakeAccountService);
|
||||
|
||||
sut = new UserDecryptionOptionsService(fakeStateProvider);
|
||||
});
|
||||
|
||||
const userDecryptionOptions = {
|
||||
hasMasterPassword: true,
|
||||
trustedDeviceOption: {
|
||||
hasAdminApproval: false,
|
||||
hasLoginApprovingDevice: false,
|
||||
hasManageResetPasswordPermission: true,
|
||||
},
|
||||
keyConnectorOption: {
|
||||
keyConnectorUrl: "https://keyconnector.bitwarden.com",
|
||||
},
|
||||
};
|
||||
|
||||
describe("userDecryptionOptions$", () => {
|
||||
it("should return the active user's decryption options", async () => {
|
||||
await fakeStateProvider.setUserState(USER_DECRYPTION_OPTIONS, userDecryptionOptions);
|
||||
|
||||
const result = await firstValueFrom(sut.userDecryptionOptions$);
|
||||
|
||||
expect(result).toEqual(userDecryptionOptions);
|
||||
});
|
||||
});
|
||||
|
||||
describe("hasMasterPassword$", () => {
|
||||
it("should return the hasMasterPassword property of the active user's decryption options", async () => {
|
||||
await fakeStateProvider.setUserState(USER_DECRYPTION_OPTIONS, userDecryptionOptions);
|
||||
|
||||
const result = await firstValueFrom(sut.hasMasterPassword$);
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("userDecryptionOptionsById$", () => {
|
||||
it("should return the user decryption options for the given user", async () => {
|
||||
const givenUser = Utils.newGuid() as UserId;
|
||||
await fakeAccountService.addAccount(givenUser, {
|
||||
name: "Test User 1",
|
||||
email: "test1@email.com",
|
||||
status: AuthenticationStatus.Locked,
|
||||
});
|
||||
await fakeStateProvider.setUserState(
|
||||
USER_DECRYPTION_OPTIONS,
|
||||
userDecryptionOptions,
|
||||
givenUser,
|
||||
);
|
||||
|
||||
const result = await firstValueFrom(sut.userDecryptionOptionsById$(givenUser));
|
||||
|
||||
expect(result).toEqual(userDecryptionOptions);
|
||||
});
|
||||
});
|
||||
|
||||
describe("setUserDecryptionOptions", () => {
|
||||
it("should set the active user's decryption options", async () => {
|
||||
await sut.setUserDecryptionOptions(userDecryptionOptions);
|
||||
|
||||
const result = await firstValueFrom(
|
||||
fakeStateProvider.getActive(USER_DECRYPTION_OPTIONS).state$,
|
||||
);
|
||||
|
||||
expect(result).toEqual(userDecryptionOptions);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
import { map } from "rxjs";
|
||||
|
||||
import {
|
||||
ActiveUserState,
|
||||
StateProvider,
|
||||
USER_DECRYPTION_OPTIONS_DISK,
|
||||
UserKeyDefinition,
|
||||
} from "@bitwarden/common/platform/state";
|
||||
import { UserId } from "@bitwarden/common/src/types/guid";
|
||||
|
||||
import { InternalUserDecryptionOptionsServiceAbstraction } from "../../abstractions/user-decryption-options.service.abstraction";
|
||||
import { UserDecryptionOptions } from "../../models";
|
||||
|
||||
export const USER_DECRYPTION_OPTIONS = new UserKeyDefinition<UserDecryptionOptions>(
|
||||
USER_DECRYPTION_OPTIONS_DISK,
|
||||
"decryptionOptions",
|
||||
{
|
||||
deserializer: (decryptionOptions) => UserDecryptionOptions.fromJSON(decryptionOptions),
|
||||
clearOn: ["logout"],
|
||||
},
|
||||
);
|
||||
|
||||
export class UserDecryptionOptionsService
|
||||
implements InternalUserDecryptionOptionsServiceAbstraction
|
||||
{
|
||||
private userDecryptionOptionsState: ActiveUserState<UserDecryptionOptions>;
|
||||
|
||||
userDecryptionOptions$;
|
||||
hasMasterPassword$;
|
||||
|
||||
constructor(private stateProvider: StateProvider) {
|
||||
this.userDecryptionOptionsState = this.stateProvider.getActive(USER_DECRYPTION_OPTIONS);
|
||||
|
||||
this.userDecryptionOptions$ = this.userDecryptionOptionsState.state$;
|
||||
this.hasMasterPassword$ = this.userDecryptionOptions$.pipe(
|
||||
map((options) => options?.hasMasterPassword ?? false),
|
||||
);
|
||||
}
|
||||
|
||||
userDecryptionOptionsById$(userId: UserId) {
|
||||
return this.stateProvider.getUser(userId, USER_DECRYPTION_OPTIONS).state$;
|
||||
}
|
||||
|
||||
async setUserDecryptionOptions(userDecryptionOptions: UserDecryptionOptions): Promise<void> {
|
||||
await this.userDecryptionOptionsState.update((_) => userDecryptionOptions);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user