1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-11 14:04:03 +00:00

Rename ActiveUserState -> UserState

These classes need to handle storage update calls to more than just the
active user. The interface will expand to support this
This commit is contained in:
Matt Gibson
2023-10-04 19:39:34 -04:00
parent 21046fd856
commit 0f5fbb8837
9 changed files with 58 additions and 59 deletions

View File

@@ -64,7 +64,6 @@ import { TokenService } from "@bitwarden/common/auth/services/token.service";
import { TwoFactorService } from "@bitwarden/common/auth/services/two-factor.service";
import { UserVerificationApiService } from "@bitwarden/common/auth/services/user-verification/user-verification-api.service";
import { UserVerificationService } from "@bitwarden/common/auth/services/user-verification/user-verification.service";
import { ActiveUserStateProvider } from "@bitwarden/common/platform/abstractions/active-user-state.provider";
import { AppIdService as AppIdServiceAbstraction } from "@bitwarden/common/platform/abstractions/app-id.service";
import { BroadcasterService as BroadcasterServiceAbstraction } from "@bitwarden/common/platform/abstractions/broadcaster.service";
import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction";
@@ -80,6 +79,7 @@ import { MessagingService as MessagingServiceAbstraction } from "@bitwarden/comm
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { StateService as StateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service";
import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service";
import { UserStateProvider } from "@bitwarden/common/platform/abstractions/user-state.provider";
import { ValidationService as ValidationServiceAbstraction } from "@bitwarden/common/platform/abstractions/validation.service";
import { StateFactory } from "@bitwarden/common/platform/factories/state-factory";
import { flagEnabled } from "@bitwarden/common/platform/misc/flags";
@@ -92,7 +92,7 @@ import { ConsoleLogService } from "@bitwarden/common/platform/services/console-l
import { CryptoService } from "@bitwarden/common/platform/services/crypto.service";
import { EncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/encrypt.service.implementation";
import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/multithread-encrypt.service.implementation";
import { DefaultActiveUserStateProvider } from "@bitwarden/common/platform/services/default-active-user-state.provider";
import { DefaultUserStateProvider } from "@bitwarden/common/platform/services/default-user-state.provider";
import { EnvironmentService } from "@bitwarden/common/platform/services/environment.service";
import { FileUploadService } from "@bitwarden/common/platform/services/file-upload/file-upload.service";
import { StateService } from "@bitwarden/common/platform/services/state.service";
@@ -303,7 +303,7 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
CryptoServiceAbstraction,
I18nServiceAbstraction,
CipherServiceAbstraction,
ActiveUserStateProvider,
UserStateProvider,
StateServiceAbstraction,
],
},
@@ -722,8 +722,8 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
deps: [CryptoServiceAbstraction],
},
{
provide: ActiveUserStateProvider,
useClass: DefaultActiveUserStateProvider,
provide: UserStateProvider,
useClass: DefaultUserStateProvider,
deps: [
// TODO: Do other storage services
AccountServiceAbstraction,

View File

@@ -1,8 +1,8 @@
import { BehaviorSubject, firstValueFrom } from "rxjs";
import { ActiveUserState } from "../src/platform/interfaces/active-user-state";
import { UserState } from "../src/platform/interfaces/user-state";
export class TestUserState<T> implements ActiveUserState<T> {
export class TestUserState<T> implements UserState<T> {
private _state$: BehaviorSubject<T>;
get state$() {
return this._state$.asObservable();

View File

@@ -1,6 +0,0 @@
import { ActiveUserState } from "../interfaces/active-user-state";
import { KeyDefinition } from "../types/key-definition";
export abstract class ActiveUserStateProvider {
create: <T>(keyDefinition: KeyDefinition<T>) => ActiveUserState<T>;
}

View File

@@ -0,0 +1,6 @@
import { UserState } from "../interfaces/user-state";
import { KeyDefinition } from "../types/key-definition";
export abstract class UserStateProvider {
create: <T>(keyDefinition: KeyDefinition<T>) => UserState<T>;
}

View File

@@ -1,9 +1,9 @@
import { Observable } from "rxjs";
import { DerivedActiveUserState } from "../services/default-active-user-state.provider";
import { DerivedUserState } from "../services/default-user-state.provider";
import { DerivedStateDefinition } from "../types/derived-state-definition";
export interface ActiveUserState<T> {
export interface UserState<T> {
readonly state$: Observable<T>;
readonly getFromState: () => Promise<T>;
/**
@@ -14,5 +14,5 @@ export interface ActiveUserState<T> {
readonly update: (configureState: (state: T) => T) => Promise<T>;
createDerived: <TTo>(
derivedStateDefinition: DerivedStateDefinition<T, TTo>
) => DerivedActiveUserState<T, TTo>;
) => DerivedUserState<T, TTo>;
}

View File

@@ -9,7 +9,7 @@ import { AbstractMemoryStorageService } from "../abstractions/storage.service";
import { KeyDefinition } from "../types/key-definition";
import { StateDefinition } from "../types/state-definition";
import { DefaultActiveUserStateProvider } from "./default-active-user-state.provider";
import { DefaultUserStateProvider } from "./default-user-state.provider";
class TestState {
date: Date;
@@ -42,7 +42,7 @@ describe("DefaultStateProvider", () => {
const activeAccountSubject = new BehaviorSubject<{ id: UserId } & AccountInfo>(undefined);
let activeUserStateProvider: DefaultActiveUserStateProvider;
let userStateProvider: DefaultUserStateProvider;
beforeEach(() => {
mockReset(accountService);
@@ -51,7 +51,7 @@ describe("DefaultStateProvider", () => {
accountService.activeAccount$ = activeAccountSubject;
activeUserStateProvider = new DefaultActiveUserStateProvider(
userStateProvider = new DefaultUserStateProvider(
accountService,
null, // Not testing derived state
null, // Not testing memory storage
@@ -68,7 +68,7 @@ describe("DefaultStateProvider", () => {
} as Jsonify<TestState>);
});
const fakeDomainState = activeUserStateProvider.create(testKeyDefinition);
const fakeDomainState = userStateProvider.create(testKeyDefinition);
const subscribeCallback = jest.fn<void, [TestState]>();
const subscription = fakeDomainState.state$.subscribe(subscribeCallback);

View File

@@ -11,13 +11,13 @@ import {
import { Jsonify } from "type-fest";
import { AccountService } from "../../auth/abstractions/account.service";
import { ActiveUserStateProvider } from "../abstractions/active-user-state.provider";
import { EncryptService } from "../abstractions/encrypt.service";
import {
AbstractMemoryStorageService,
AbstractStorageService,
} from "../abstractions/storage.service";
import { ActiveUserState } from "../interfaces/active-user-state";
import { UserStateProvider } from "../abstractions/user-state.provider";
import { UserState } from "../interfaces/user-state";
import { userKeyBuilder } from "../misc/key-builders";
import { UserKey } from "../models/domain/symmetric-crypto-key";
import { KeyDefinition } from "../types/key-definition";
@@ -32,7 +32,7 @@ class DerivedStateDefinition<TFrom, TTo> {
constructor(readonly converter: (data: TFrom, context: ConverterContext) => Promise<TTo>) {}
}
export class DerivedActiveUserState<TFrom, TTo> {
export class DerivedUserState<TFrom, TTo> {
state$: Observable<TTo>;
// TODO: Probably needs to take state service
@@ -42,9 +42,9 @@ export class DerivedActiveUserState<TFrom, TTo> {
constructor(
private derivedStateDefinition: DerivedStateDefinition<TFrom, TTo>,
private encryptService: EncryptService,
private activeUserState: ActiveUserState<TFrom>
private userState: UserState<TFrom>
) {
this.state$ = activeUserState.state$.pipe(
this.state$ = userState.state$.pipe(
switchMap(async (from) => {
// TODO: How do I get the key?
const convertedData = await derivedStateDefinition.converter(
@@ -57,7 +57,7 @@ export class DerivedActiveUserState<TFrom, TTo> {
}
async getFromState(): Promise<TTo> {
const encryptedFromState = await this.activeUserState.getFromState();
const encryptedFromState = await this.userState.getFromState();
const context = new ConverterContext(null, this.encryptService);
@@ -66,7 +66,7 @@ export class DerivedActiveUserState<TFrom, TTo> {
}
}
class DefaultActiveUserState<T> implements ActiveUserState<T> {
class DefaultUserState<T> implements UserState<T> {
private seededInitial = false;
private formattedKey$: Observable<string>;
@@ -154,8 +154,8 @@ class DefaultActiveUserState<T> implements ActiveUserState<T> {
createDerived<TTo>(
derivedStateDefinition: DerivedStateDefinition<T, TTo>
): DerivedActiveUserState<T, TTo> {
return new DerivedActiveUserState<T, TTo>(derivedStateDefinition, this.encryptService, this);
): DerivedUserState<T, TTo> {
return new DerivedUserState<T, TTo>(derivedStateDefinition, this.encryptService, this);
}
private async createKey(): Promise<string> {
@@ -184,8 +184,8 @@ class DefaultActiveUserState<T> implements ActiveUserState<T> {
}
}
export class DefaultActiveUserStateProvider implements ActiveUserStateProvider {
private userStateCache: Record<string, DefaultActiveUserState<unknown>> = {};
export class DefaultUserStateProvider implements UserStateProvider {
private userStateCache: Record<string, DefaultUserState<unknown>> = {};
constructor(
private accountService: AccountService, // Inject the lightest weight service that provides accountUserId$
@@ -195,16 +195,16 @@ export class DefaultActiveUserStateProvider implements ActiveUserStateProvider {
private secureStorage: AbstractStorageService
) {}
create<T>(keyDefinition: KeyDefinition<T>): DefaultActiveUserState<T> {
create<T>(keyDefinition: KeyDefinition<T>): DefaultUserState<T> {
const locationDomainKey = `${keyDefinition.stateDefinition.storageLocation}_${keyDefinition.stateDefinition.name}_${keyDefinition.key}`;
const existingActiveUserState = this.userStateCache[locationDomainKey];
if (existingActiveUserState != null) {
const existingUserState = this.userStateCache[locationDomainKey];
if (existingUserState != null) {
// I have to cast out of the unknown generic but this should be safe if rules
// around domain token are made
return existingActiveUserState as DefaultActiveUserState<T>;
return existingUserState as DefaultUserState<T>;
}
const newActiveUserState = new DefaultActiveUserState<T>(
const newUserState = new DefaultUserState<T>(
keyDefinition,
this.accountService,
this.encryptService,
@@ -212,7 +212,7 @@ export class DefaultActiveUserStateProvider implements ActiveUserStateProvider {
this.secureStorage,
this.diskStorage
);
this.userStateCache[locationDomainKey] = newActiveUserState;
return newActiveUserState;
this.userStateCache[locationDomainKey] = newUserState;
return newUserState;
}
}

View File

@@ -3,14 +3,14 @@ import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
import { mock } from "jest-mock-extended";
import { BehaviorSubject, firstValueFrom } from "rxjs";
import { TestUserState as TestActiveUserState } from "../../../../spec/test-active-user-state";
import { ActiveUserStateProvider } from "../../../platform/abstractions/active-user-state.provider";
import { TestUserState } from "../../../../spec/test-active-user-state";
import { CryptoService } from "../../../platform/abstractions/crypto.service";
import { EncryptService } from "../../../platform/abstractions/encrypt.service";
import { I18nService } from "../../../platform/abstractions/i18n.service";
import { UserStateProvider } from "../../../platform/abstractions/user-state.provider";
import { EncString } from "../../../platform/models/domain/enc-string";
import { ContainerService } from "../../../platform/services/container.service";
import { DerivedActiveUserState } from "../../../platform/services/default-active-user-state.provider";
import { DerivedUserState } from "../../../platform/services/default-user-state.provider";
import { StateService } from "../../../platform/services/state.service";
import { CipherService } from "../../abstractions/cipher.service";
import { FolderData } from "../../models/data/folder.data";
@@ -28,10 +28,9 @@ describe("Folder Service", () => {
let stateService: SubstituteOf<StateService>;
let activeAccount: BehaviorSubject<string>;
let activeAccountUnlocked: BehaviorSubject<boolean>;
const activeUserStateProvider = mock<ActiveUserStateProvider>();
let activeUserState: TestActiveUserState<Record<string, FolderData>>;
const derivedActiveUserState =
mock<DerivedActiveUserState<Record<string, FolderData>, FolderView[]>>();
const userStateProvider = mock<UserStateProvider>();
let userState: TestUserState<Record<string, FolderData>>;
const derivedUserState = mock<DerivedUserState<Record<string, FolderData>, FolderView[]>>();
let folderViews$: BehaviorSubject<FolderView[]>;
beforeEach(() => {
@@ -51,19 +50,19 @@ describe("Folder Service", () => {
stateService.activeAccountUnlocked$.returns(activeAccountUnlocked);
(window as any).bitwardenContainerService = new ContainerService(cryptoService, encryptService);
activeUserState = new TestActiveUserState({});
activeUserState.next(initialState);
activeUserStateProvider.create.mockReturnValue(activeUserState);
activeUserState.createDerived.mockReturnValue(derivedActiveUserState);
userState = new TestUserState({});
userState.next(initialState);
userStateProvider.create.mockReturnValue(userState);
userState.createDerived.mockReturnValue(derivedUserState);
folderViews$ = new BehaviorSubject([]);
derivedActiveUserState.state$ = folderViews$;
derivedUserState.state$ = folderViews$;
folderService = new FolderService(
cryptoService,
i18nService,
cipherService,
activeUserStateProvider,
userStateProvider,
stateService
);
});
@@ -71,7 +70,7 @@ describe("Folder Service", () => {
afterEach(() => {
jest.resetAllMocks();
folderViews$.complete();
activeUserState.complete();
userState.complete();
});
test("encrypt", async () => {

View File

@@ -1,13 +1,13 @@
import { Observable, firstValueFrom, map } from "rxjs";
import { ActiveUserStateProvider } from "../../../platform/abstractions/active-user-state.provider";
import { CryptoService } from "../../../platform/abstractions/crypto.service";
import { I18nService } from "../../../platform/abstractions/i18n.service";
import { StateService } from "../../../platform/abstractions/state.service";
import { ActiveUserState } from "../../../platform/interfaces/active-user-state";
import { UserStateProvider } from "../../../platform/abstractions/user-state.provider";
import { UserState } from "../../../platform/interfaces/user-state";
import { Utils } from "../../../platform/misc/utils";
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
import { DerivedActiveUserState } from "../../../platform/services/default-active-user-state.provider";
import { DerivedUserState } from "../../../platform/services/default-user-state.provider";
import { CipherService } from "../../../vault/abstractions/cipher.service";
import { InternalFolderService as InternalFolderServiceAbstraction } from "../../../vault/abstractions/folder/folder.service.abstraction";
import { CipherData } from "../../../vault/models/data/cipher.data";
@@ -17,8 +17,8 @@ import { FolderView } from "../../../vault/models/view/folder.view";
import { FOLDERS } from "../../types/key-definitions";
export class FolderService implements InternalFolderServiceAbstraction {
folderState: ActiveUserState<Record<string, FolderData>>;
decryptedFolderState: DerivedActiveUserState<Record<string, FolderData>, FolderView[]>;
folderState: UserState<Record<string, FolderData>>;
decryptedFolderState: DerivedUserState<Record<string, FolderData>, FolderView[]>;
folders$: Observable<Folder[]>;
folderViews$: Observable<FolderView[]>;
@@ -27,7 +27,7 @@ export class FolderService implements InternalFolderServiceAbstraction {
private cryptoService: CryptoService,
private i18nService: I18nService,
private cipherService: CipherService,
private activeUserStateProvider: ActiveUserStateProvider,
private userStateProvider: UserStateProvider,
private stateService: StateService
) {
(window as any).services ||= {};
@@ -41,7 +41,7 @@ export class FolderService implements InternalFolderServiceAbstraction {
}
);
this.folderState = this.activeUserStateProvider.create(FOLDERS);
this.folderState = this.userStateProvider.create(FOLDERS);
this.folders$ = this.folderState.state$.pipe(
map((foldersMap) => {