From a022c58b16249acae66acd16061be051cb387fca Mon Sep 17 00:00:00 2001 From: Matt Gibson Date: Mon, 29 Aug 2022 12:46:42 -0600 Subject: [PATCH] Add more factories (#3381) * Add more factories Revert main.background factory usage. We could still do this, but factories must init their services and so need to be async, which is not compatible with initializing in constructors * Fix conflicts --- .../browser/src/background/main.background.ts | 88 +++++++------------ .../service_factories/api-service.factory.ts | 47 ++++++++++ .../app-id-service.factory.ts | 23 +++++ .../service_factories/auth-service.factory.ts | 66 ++++++++++++++ .../cipher-service.factory.ts | 54 ++++++++++++ .../crypto-function-service.factory.ts | 2 +- .../crypto-service.factory.ts | 43 +++++++++ .../encrypt-service.factory.ts | 8 +- .../environment-service.factory.ts | 8 +- .../service_factories/factory-options.ts | 12 ++- .../file-upload-service.factory.ts | 28 ++++++ .../service_factories/i18n-service.factory.ts | 30 +++++++ .../key-connector-service.factory.ts | 54 ++++++++++++ .../key-generation-service.factory.ts | 4 +- .../service_factories/log-service.factory.ts | 2 +- .../messaging-service.factory.ts | 16 ++++ .../organization-service.factory.ts | 22 +++++ .../platform-utils-service.factory.ts | 34 +++++++ .../settings-service.factory.ts | 21 +++++ .../state-migration-service.factory.ts | 8 +- .../state-service.factory.ts | 22 ++--- .../storage-service.factory.ts | 12 +-- .../token-service.factory.ts | 21 +++++ .../two-factor-service.factory.ts | 33 +++++++ .../src/listeners/onInstallListener.ts | 4 +- 25 files changed, 570 insertions(+), 92 deletions(-) create mode 100644 apps/browser/src/background/service_factories/api-service.factory.ts create mode 100644 apps/browser/src/background/service_factories/app-id-service.factory.ts create mode 100644 apps/browser/src/background/service_factories/auth-service.factory.ts create mode 100644 apps/browser/src/background/service_factories/cipher-service.factory.ts create mode 100644 apps/browser/src/background/service_factories/crypto-service.factory.ts create mode 100644 apps/browser/src/background/service_factories/file-upload-service.factory.ts create mode 100644 apps/browser/src/background/service_factories/i18n-service.factory.ts create mode 100644 apps/browser/src/background/service_factories/key-connector-service.factory.ts create mode 100644 apps/browser/src/background/service_factories/messaging-service.factory.ts create mode 100644 apps/browser/src/background/service_factories/organization-service.factory.ts create mode 100644 apps/browser/src/background/service_factories/platform-utils-service.factory.ts create mode 100644 apps/browser/src/background/service_factories/settings-service.factory.ts create mode 100644 apps/browser/src/background/service_factories/token-service.factory.ts create mode 100644 apps/browser/src/background/service_factories/two-factor-service.factory.ts diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 278cf01739..8bcfad8b62 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -47,6 +47,7 @@ import { AuditService } from "@bitwarden/common/services/audit.service"; import { AuthService } from "@bitwarden/common/services/auth.service"; import { CipherService } from "@bitwarden/common/services/cipher.service"; import { CollectionService } from "@bitwarden/common/services/collection.service"; +import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service"; import { ContainerService } from "@bitwarden/common/services/container.service"; import { EncryptService } from "@bitwarden/common/services/encrypt.service"; import { EventService } from "@bitwarden/common/services/event.service"; @@ -54,6 +55,7 @@ import { ExportService } from "@bitwarden/common/services/export.service"; import { FileUploadService } from "@bitwarden/common/services/fileUpload.service"; import { FolderApiService } from "@bitwarden/common/services/folder/folder-api.service"; import { KeyConnectorService } from "@bitwarden/common/services/keyConnector.service"; +import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service"; import { NotificationsService } from "@bitwarden/common/services/notifications.service"; import { OrganizationService } from "@bitwarden/common/services/organization.service"; import { PasswordGenerationService } from "@bitwarden/common/services/passwordGeneration.service"; @@ -72,6 +74,7 @@ import { TwoFactorService } from "@bitwarden/common/services/twoFactor.service"; import { UserVerificationApiService } from "@bitwarden/common/services/userVerification/userVerification-api.service"; import { UserVerificationService } from "@bitwarden/common/services/userVerification/userVerification.service"; import { UsernameGenerationService } from "@bitwarden/common/services/usernameGeneration.service"; +import { WebCryptoFunctionService } from "@bitwarden/common/services/webCryptoFunction.service"; import { BrowserApi } from "../browser/browserApi"; import { SafariApp } from "../browser/safariApp"; @@ -82,11 +85,15 @@ import { StateService as StateServiceAbstraction } from "../services/abstraction import AutofillService from "../services/autofill.service"; import { BrowserEnvironmentService } from "../services/browser-environment.service"; import { BrowserCryptoService } from "../services/browserCrypto.service"; +import BrowserLocalStorageService from "../services/browserLocalStorage.service"; import BrowserMessagingService from "../services/browserMessaging.service"; import BrowserMessagingPrivateModeBackgroundService from "../services/browserMessagingPrivateModeBackground.service"; import BrowserPlatformUtilsService from "../services/browserPlatformUtils.service"; import { FolderService } from "../services/folders/folder.service"; import I18nService from "../services/i18n.service"; +import { KeyGenerationService } from "../services/keyGeneration.service"; +import { LocalBackedSessionStorageService } from "../services/localBackedSessionStorage.service"; +import { StateService } from "../services/state.service"; import { VaultFilterService } from "../services/vaultFilter.service"; import VaultTimeoutService from "../services/vaultTimeout.service"; @@ -97,17 +104,6 @@ import IconDetails from "./models/iconDetails"; import { NativeMessagingBackground } from "./nativeMessaging.background"; import NotificationBackground from "./notification.background"; import RuntimeBackground from "./runtime.background"; -import { cryptoFunctionServiceFactory } from "./service_factories/crypto-function-service.factory"; -import { encryptServiceFactory } from "./service_factories/encrypt-service.factory"; -import { environmentServiceFactory } from "./service_factories/environment-service.factory"; -import { logServiceFactory } from "./service_factories/log-service.factory"; -import { stateMigrationServiceFactory } from "./service_factories/state-migration-service.factory"; -import { stateServiceFactory } from "./service_factories/state-service.factory"; -import { - diskStorageServiceFactory, - memoryStorageServiceFactory, - secureStorageServiceFactory, -} from "./service_factories/storage-service.factory"; import TabsBackground from "./tabs.background"; import WebRequestBackground from "./webRequest.background"; @@ -199,40 +195,33 @@ export default class MainBackground { const logoutCallback = async (expired: boolean, userId?: string) => await this.logout(expired, userId); - const services: Record = {}; - const factoryOptions = { - logServiceOptions: { - isDev: false, - }, - cryptoFunctionServiceOptions: { - win: window, - }, - stateMigrationServiceOptions: { - stateFactory: new StateFactory(GlobalState, Account), - }, - stateServiceOptions: { - stateFactory: new StateFactory(GlobalState, Account), - }, - }; - this.messagingService = isPrivateMode ? new BrowserMessagingPrivateModeBackgroundService() : new BrowserMessagingService(); - this.logService = logServiceFactory(services, factoryOptions); - this.cryptoFunctionService = cryptoFunctionServiceFactory(services, factoryOptions); - this.storageService = diskStorageServiceFactory(services, factoryOptions); - this.secureStorageService = secureStorageServiceFactory(services, factoryOptions); - this.memoryStorageService = memoryStorageServiceFactory(services, { - ...factoryOptions, - encryptServiceOptions: { - logMacFailures: false, - }, - }); - this.stateMigrationService = stateMigrationServiceFactory(services, factoryOptions); - this.stateService = stateServiceFactory(services, { - ...factoryOptions, - encryptServiceOptions: { logMacFailures: false }, - }); + this.logService = new ConsoleLogService(false); + this.cryptoFunctionService = new WebCryptoFunctionService(window); + this.storageService = new BrowserLocalStorageService(); + this.secureStorageService = new BrowserLocalStorageService(); + this.memoryStorageService = + chrome.runtime.getManifest().manifest_version == 3 + ? new LocalBackedSessionStorageService( + new EncryptService(this.cryptoFunctionService, this.logService, false), + new KeyGenerationService(this.cryptoFunctionService) + ) + : new MemoryStorageService(); + this.stateMigrationService = new StateMigrationService( + this.storageService, + this.secureStorageService, + new StateFactory(GlobalState, Account) + ); + this.stateService = new StateService( + this.storageService, + this.secureStorageService, + this.memoryStorageService, + this.logService, + this.stateMigrationService, + new StateFactory(GlobalState, Account) + ); this.platformUtilsService = new BrowserPlatformUtilsService( this.messagingService, (clipboardValue, clearMs) => { @@ -255,13 +244,7 @@ export default class MainBackground { } ); this.i18nService = new I18nService(BrowserApi.getUILanguage(window)); - this.encryptService = encryptServiceFactory(services, { - ...factoryOptions, - encryptServiceOptions: { - logMacFailures: true, - }, - alwaysInitializeNewService: true, - }); // Update encrypt service with new instances + this.encryptService = new EncryptService(this.cryptoFunctionService, this.logService, true); this.cryptoService = new BrowserCryptoService( this.cryptoFunctionService, this.encryptService, @@ -271,12 +254,7 @@ export default class MainBackground { ); this.tokenService = new TokenService(this.stateService); this.appIdService = new AppIdService(this.storageService); - this.environmentService = environmentServiceFactory(services, { - ...factoryOptions, - encryptServiceOptions: { - logMacFailures: false, - }, - }); + this.environmentService = new BrowserEnvironmentService(this.stateService, this.logService); this.apiService = new ApiService( this.tokenService, this.platformUtilsService, diff --git a/apps/browser/src/background/service_factories/api-service.factory.ts b/apps/browser/src/background/service_factories/api-service.factory.ts new file mode 100644 index 0000000000..cee76c4e1d --- /dev/null +++ b/apps/browser/src/background/service_factories/api-service.factory.ts @@ -0,0 +1,47 @@ +import { ApiService as AbstractApiService } from "@bitwarden/common/abstractions/api.service"; +import { ApiService } from "@bitwarden/common/services/api.service"; + +import { AppIdServiceInitOptions, appIdServiceFactory } from "./app-id-service.factory"; +import { + environmentServiceFactory, + EnvironmentServiceInitOptions, +} from "./environment-service.factory"; +import { CachedServices, factory, FactoryOptions } from "./factory-options"; +import { + PlatformUtilsServiceInitOptions, + platformUtilsServiceFactory, +} from "./platform-utils-service.factory"; +import { TokenServiceInitOptions, tokenServiceFactory } from "./token-service.factory"; + +type ApiServiceFactoryOptions = FactoryOptions & { + apiServiceOptions: { + logoutCallback: (expired: boolean) => Promise; + customUserAgent?: string; + }; +}; + +export type ApiServiceInitOptions = ApiServiceFactoryOptions & + TokenServiceInitOptions & + PlatformUtilsServiceInitOptions & + EnvironmentServiceInitOptions & + AppIdServiceInitOptions; + +export function apiServiceFactory( + cache: { apiService?: AbstractApiService } & CachedServices, + opts: ApiServiceInitOptions +): Promise { + return factory( + cache, + "apiService", + opts, + async () => + new ApiService( + await tokenServiceFactory(cache, opts), + await platformUtilsServiceFactory(cache, opts), + await environmentServiceFactory(cache, opts), + await appIdServiceFactory(cache, opts), + opts.apiServiceOptions.logoutCallback, + opts.apiServiceOptions.customUserAgent + ) + ); +} diff --git a/apps/browser/src/background/service_factories/app-id-service.factory.ts b/apps/browser/src/background/service_factories/app-id-service.factory.ts new file mode 100644 index 0000000000..743c8eb5bc --- /dev/null +++ b/apps/browser/src/background/service_factories/app-id-service.factory.ts @@ -0,0 +1,23 @@ +import { DiskStorageOptions } from "@koa/multer"; + +import { AppIdService as AbstractAppIdService } from "@bitwarden/common/abstractions/appId.service"; +import { AppIdService } from "@bitwarden/common/services/appId.service"; + +import { FactoryOptions, CachedServices, factory } from "./factory-options"; +import { diskStorageServiceFactory } from "./storage-service.factory"; + +type AppIdServiceFactoryOptions = FactoryOptions; + +export type AppIdServiceInitOptions = AppIdServiceFactoryOptions & DiskStorageOptions; + +export function appIdServiceFactory( + cache: { appIdService?: AbstractAppIdService } & CachedServices, + opts: AppIdServiceInitOptions +): Promise { + return factory( + cache, + "appIdService", + opts, + async () => new AppIdService(await diskStorageServiceFactory(cache, opts)) + ); +} diff --git a/apps/browser/src/background/service_factories/auth-service.factory.ts b/apps/browser/src/background/service_factories/auth-service.factory.ts new file mode 100644 index 0000000000..6f4fb322b0 --- /dev/null +++ b/apps/browser/src/background/service_factories/auth-service.factory.ts @@ -0,0 +1,66 @@ +import { AuthService as AbstractAuthService } from "@bitwarden/common/abstractions/auth.service"; +import { AuthService } from "@bitwarden/common/services/auth.service"; + +import { apiServiceFactory, ApiServiceInitOptions } from "./api-service.factory"; +import { appIdServiceFactory } from "./app-id-service.factory"; +import { cryptoServiceFactory, CryptoServiceInitOptions } from "./crypto-service.factory"; +import { + environmentServiceFactory, + EnvironmentServiceInitOptions, +} from "./environment-service.factory"; +import { CachedServices, factory, FactoryOptions } from "./factory-options"; +import { I18nServiceInitOptions, i18nServiceFactory } from "./i18n-service.factory"; +import { + KeyConnectorServiceInitOptions, + keyConnectorServiceFactory, +} from "./key-connector-service.factory"; +import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory"; +import { MessagingServiceInitOptions, messagingServiceFactory } from "./messaging-service.factory"; +import { + PlatformUtilsServiceInitOptions, + platformUtilsServiceFactory, +} from "./platform-utils-service.factory"; +import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory"; +import { TokenServiceInitOptions, tokenServiceFactory } from "./token-service.factory"; +import { TwoFactorServiceInitOptions, twoFactorServiceFactory } from "./two-factor-service.factory"; + +type AuthServiceFactoyOptions = FactoryOptions; + +export type AuthServiceInitOptions = AuthServiceFactoyOptions & + CryptoServiceInitOptions & + ApiServiceInitOptions & + TokenServiceInitOptions & + PlatformUtilsServiceInitOptions & + MessagingServiceInitOptions & + LogServiceInitOptions & + KeyConnectorServiceInitOptions & + EnvironmentServiceInitOptions & + StateServiceInitOptions & + TwoFactorServiceInitOptions & + I18nServiceInitOptions; + +export function authServiceFactory( + cache: { authService?: AbstractAuthService } & CachedServices, + opts: AuthServiceInitOptions +): Promise { + return factory( + cache, + "authService", + opts, + async () => + new AuthService( + await cryptoServiceFactory(cache, opts), + await apiServiceFactory(cache, opts), + await tokenServiceFactory(cache, opts), + await appIdServiceFactory(cache, opts), + await platformUtilsServiceFactory(cache, opts), + await messagingServiceFactory(cache, opts), + await logServiceFactory(cache, opts), + await keyConnectorServiceFactory(cache, opts), + await environmentServiceFactory(cache, opts), + await stateServiceFactory(cache, opts), + await twoFactorServiceFactory(cache, opts), + await i18nServiceFactory(cache, opts) + ) + ); +} diff --git a/apps/browser/src/background/service_factories/cipher-service.factory.ts b/apps/browser/src/background/service_factories/cipher-service.factory.ts new file mode 100644 index 0000000000..149ac54fc8 --- /dev/null +++ b/apps/browser/src/background/service_factories/cipher-service.factory.ts @@ -0,0 +1,54 @@ +import { CipherService as AbstractCipherService } from "@bitwarden/common/abstractions/cipher.service"; +import { SearchService } from "@bitwarden/common/abstractions/search.service"; +import { CipherService } from "@bitwarden/common/services/cipher.service"; + +import { apiServiceFactory, ApiServiceInitOptions } from "./api-service.factory"; +import { cryptoServiceFactory, CryptoServiceInitOptions } from "./crypto-service.factory"; +import { CachedServices, factory, FactoryOptions } from "./factory-options"; +import { + FileUploadServiceInitOptions, + fileUploadServiceFactory, +} from "./file-upload-service.factory"; +import { i18nServiceFactory, I18nServiceInitOptions } from "./i18n-service.factory"; +import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory"; +import { SettingsServiceInitOptions, settingsServiceFactory } from "./settings-service.factory"; +import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory"; + +type CipherServiceFactoryOptions = FactoryOptions & { + cipherServiceOptions?: { + searchServiceFactory?: () => SearchService; + }; +}; + +export type CipherServiceInitOptions = CipherServiceFactoryOptions & + CryptoServiceInitOptions & + SettingsServiceInitOptions & + ApiServiceInitOptions & + FileUploadServiceInitOptions & + I18nServiceInitOptions & + LogServiceInitOptions & + StateServiceInitOptions; + +export function cipherServiceFactory( + cache: { cipherService?: AbstractCipherService } & CachedServices, + opts: CipherServiceInitOptions +): Promise { + return factory( + cache, + "cipherService", + opts, + async () => + new CipherService( + await cryptoServiceFactory(cache, opts), + await settingsServiceFactory(cache, opts), + await apiServiceFactory(cache, opts), + await fileUploadServiceFactory(cache, opts), + await i18nServiceFactory(cache, opts), + opts.cipherServiceOptions.searchServiceFactory === undefined + ? () => cache.searchService + : opts.cipherServiceOptions.searchServiceFactory, + await logServiceFactory(cache, opts), + await stateServiceFactory(cache, opts) + ) + ); +} diff --git a/apps/browser/src/background/service_factories/crypto-function-service.factory.ts b/apps/browser/src/background/service_factories/crypto-function-service.factory.ts index fa0fd5d9a0..d7611c86a1 100644 --- a/apps/browser/src/background/service_factories/crypto-function-service.factory.ts +++ b/apps/browser/src/background/service_factories/crypto-function-service.factory.ts @@ -14,7 +14,7 @@ export type CryptoFunctionServiceInitOptions = CryptoFunctionServiceFactoryOptio export function cryptoFunctionServiceFactory( cache: { cryptoFunctionService?: CryptoFunctionService } & CachedServices, opts: CryptoFunctionServiceFactoryOptions -): CryptoFunctionService { +): Promise { return factory( cache, "cryptoFunctionService", diff --git a/apps/browser/src/background/service_factories/crypto-service.factory.ts b/apps/browser/src/background/service_factories/crypto-service.factory.ts new file mode 100644 index 0000000000..b61b72ec04 --- /dev/null +++ b/apps/browser/src/background/service_factories/crypto-service.factory.ts @@ -0,0 +1,43 @@ +import { CryptoService as AbstractCryptoService } from "@bitwarden/common/abstractions/crypto.service"; +import { CryptoService } from "@bitwarden/common/services/crypto.service"; + +import { + cryptoFunctionServiceFactory, + CryptoFunctionServiceInitOptions, +} from "./crypto-function-service.factory"; +import { encryptServiceFactory, EncryptServiceInitOptions } from "./encrypt-service.factory"; +import { FactoryOptions, CachedServices, factory } from "./factory-options"; +import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory"; +import { + platformUtilsServiceFactory, + PlatformUtilsServiceInitOptions, +} from "./platform-utils-service.factory"; +import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory"; + +type CryptoServiceFactoryOptions = FactoryOptions; + +export type CryptoServiceInitOptions = CryptoServiceFactoryOptions & + CryptoFunctionServiceInitOptions & + EncryptServiceInitOptions & + PlatformUtilsServiceInitOptions & + LogServiceInitOptions & + StateServiceInitOptions; + +export function cryptoServiceFactory( + cache: { cryptoService?: AbstractCryptoService } & CachedServices, + opts: CryptoServiceInitOptions +): Promise { + return factory( + cache, + "cryptoService", + opts, + async () => + new CryptoService( + await cryptoFunctionServiceFactory(cache, opts), + await encryptServiceFactory(cache, opts), + await platformUtilsServiceFactory(cache, opts), + await logServiceFactory(cache, opts), + await stateServiceFactory(cache, opts) + ) + ); +} diff --git a/apps/browser/src/background/service_factories/encrypt-service.factory.ts b/apps/browser/src/background/service_factories/encrypt-service.factory.ts index c8f529b0ec..fffc9f9d29 100644 --- a/apps/browser/src/background/service_factories/encrypt-service.factory.ts +++ b/apps/browser/src/background/service_factories/encrypt-service.factory.ts @@ -20,15 +20,15 @@ export type EncryptServiceInitOptions = EncryptServiceFactoryOptions & export function encryptServiceFactory( cache: { encryptService?: EncryptService } & CachedServices, opts: EncryptServiceInitOptions -): EncryptService { +): Promise { return factory( cache, "encryptService", opts, - () => + async () => new EncryptService( - cryptoFunctionServiceFactory(cache, opts), - logServiceFactory(cache, opts), + await cryptoFunctionServiceFactory(cache, opts), + await logServiceFactory(cache, opts), opts.encryptServiceOptions.logMacFailures ) ); diff --git a/apps/browser/src/background/service_factories/environment-service.factory.ts b/apps/browser/src/background/service_factories/environment-service.factory.ts index 4116583970..5150c7bd4a 100644 --- a/apps/browser/src/background/service_factories/environment-service.factory.ts +++ b/apps/browser/src/background/service_factories/environment-service.factory.ts @@ -16,15 +16,15 @@ export type EnvironmentServiceInitOptions = EnvironmentServiceFactoryOptions & export function environmentServiceFactory( cache: { environmentService?: BrowserEnvironmentService } & CachedServices, opts: EnvironmentServiceInitOptions -): BrowserEnvironmentService { +): Promise { return factory( cache, "environmentService", opts, - () => + async () => new BrowserEnvironmentService( - stateServiceFactory(cache, opts), - logServiceFactory(cache, opts) + await stateServiceFactory(cache, opts), + await logServiceFactory(cache, opts) ) ); } diff --git a/apps/browser/src/background/service_factories/factory-options.ts b/apps/browser/src/background/service_factories/factory-options.ts index a78d607854..12129e4e67 100644 --- a/apps/browser/src/background/service_factories/factory-options.ts +++ b/apps/browser/src/background/service_factories/factory-options.ts @@ -6,14 +6,20 @@ export type FactoryOptions = { [optionsKey: string]: unknown; }; -export function factory< +export async function factory< TCache extends CachedServices, TName extends keyof TCache, TOpts extends FactoryOptions ->(cachedServices: TCache, name: TName, opts: TOpts, factory: () => TCache[TName]): TCache[TName] { +>( + cachedServices: TCache, + name: TName, + opts: TOpts, + factory: () => TCache[TName] | Promise +): Promise { let instance = cachedServices[name]; if (opts.alwaysInitializeNewService || !instance) { - instance = factory(); + const instanceOrPromise = factory(); + instance = instanceOrPromise instanceof Promise ? await instanceOrPromise : instanceOrPromise; } if (!opts.doNotStoreInitializedService) { diff --git a/apps/browser/src/background/service_factories/file-upload-service.factory.ts b/apps/browser/src/background/service_factories/file-upload-service.factory.ts new file mode 100644 index 0000000000..0aa04126d9 --- /dev/null +++ b/apps/browser/src/background/service_factories/file-upload-service.factory.ts @@ -0,0 +1,28 @@ +import { FileUploadService as AbstractFileUploadService } from "@bitwarden/common/abstractions/fileUpload.service"; +import { FileUploadService } from "@bitwarden/common/services/fileUpload.service"; + +import { apiServiceFactory, ApiServiceInitOptions } from "./api-service.factory"; +import { FactoryOptions, CachedServices, factory } from "./factory-options"; +import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory"; + +type FileUploadServiceFactoyOptions = FactoryOptions; + +export type FileUploadServiceInitOptions = FileUploadServiceFactoyOptions & + LogServiceInitOptions & + ApiServiceInitOptions; + +export function fileUploadServiceFactory( + cache: { fileUploadService?: AbstractFileUploadService } & CachedServices, + opts: FileUploadServiceInitOptions +): Promise { + return factory( + cache, + "fileUploadService", + opts, + async () => + new FileUploadService( + await logServiceFactory(cache, opts), + await apiServiceFactory(cache, opts) + ) + ); +} diff --git a/apps/browser/src/background/service_factories/i18n-service.factory.ts b/apps/browser/src/background/service_factories/i18n-service.factory.ts new file mode 100644 index 0000000000..1ba61d70b3 --- /dev/null +++ b/apps/browser/src/background/service_factories/i18n-service.factory.ts @@ -0,0 +1,30 @@ +import { I18nService as AbstractI18nService } from "@bitwarden/common/abstractions/i18n.service"; +import { I18nService as BaseI18nService } from "@bitwarden/common/services/i18n.service"; + +import I18nService from "../../services/i18n.service"; + +import { FactoryOptions, CachedServices, factory } from "./factory-options"; + +type I18nServiceFactoryOptions = FactoryOptions & { + i18nServiceOptions: { + systemLanguage: string; + }; +}; + +export type I18nServiceInitOptions = I18nServiceFactoryOptions; + +export async function i18nServiceFactory( + cache: { i18nService?: AbstractI18nService } & CachedServices, + opts: I18nServiceInitOptions +): Promise { + const service = await factory( + cache, + "i18nService", + opts, + () => new I18nService(opts.i18nServiceOptions.systemLanguage) + ); + if (!(service as BaseI18nService as any).inited) { + await (service as BaseI18nService).init(); + } + return service; +} diff --git a/apps/browser/src/background/service_factories/key-connector-service.factory.ts b/apps/browser/src/background/service_factories/key-connector-service.factory.ts new file mode 100644 index 0000000000..80a0df6a0a --- /dev/null +++ b/apps/browser/src/background/service_factories/key-connector-service.factory.ts @@ -0,0 +1,54 @@ +import { KeyConnectorService as AbstractKeyConnectorService } from "@bitwarden/common/abstractions/keyConnector.service"; +import { KeyConnectorService } from "@bitwarden/common/services/keyConnector.service"; + +import { apiServiceFactory, ApiServiceInitOptions } from "./api-service.factory"; +import { + cryptoFunctionServiceFactory, + CryptoFunctionServiceInitOptions, +} from "./crypto-function-service.factory"; +import { CryptoServiceInitOptions, cryptoServiceFactory } from "./crypto-service.factory"; +import { FactoryOptions, CachedServices, factory } from "./factory-options"; +import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory"; +import { + OrganizationServiceInitOptions, + organizationServiceFactory, +} from "./organization-service.factory"; +import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory"; +import { tokenServiceFactory, TokenServiceInitOptions } from "./token-service.factory"; + +type KeyConnectorServiceFactoryOptions = FactoryOptions & { + keyConnectorServiceOptions: { + logoutCallback: (expired: boolean, userId?: string) => Promise; + }; +}; + +export type KeyConnectorServiceInitOptions = KeyConnectorServiceFactoryOptions & + StateServiceInitOptions & + CryptoServiceInitOptions & + ApiServiceInitOptions & + TokenServiceInitOptions & + LogServiceInitOptions & + OrganizationServiceInitOptions & + CryptoFunctionServiceInitOptions; + +export function keyConnectorServiceFactory( + cache: { keyConnectorService?: AbstractKeyConnectorService } & CachedServices, + opts: KeyConnectorServiceInitOptions +): Promise { + return factory( + cache, + "keyConnectorService", + opts, + async () => + new KeyConnectorService( + await stateServiceFactory(cache, opts), + await cryptoServiceFactory(cache, opts), + await apiServiceFactory(cache, opts), + await tokenServiceFactory(cache, opts), + await logServiceFactory(cache, opts), + await organizationServiceFactory(cache, opts), + await cryptoFunctionServiceFactory(cache, opts), + opts.keyConnectorServiceOptions.logoutCallback + ) + ); +} diff --git a/apps/browser/src/background/service_factories/key-generation-service.factory.ts b/apps/browser/src/background/service_factories/key-generation-service.factory.ts index 89fe5f3066..d6d31b6326 100644 --- a/apps/browser/src/background/service_factories/key-generation-service.factory.ts +++ b/apps/browser/src/background/service_factories/key-generation-service.factory.ts @@ -14,11 +14,11 @@ export type KeyGenerationServiceInitOptions = KeyGenerationServiceFactoryOptions export function keyGenerationServiceFactory( cache: { keyGenerationService?: KeyGenerationService } & CachedServices, opts: KeyGenerationServiceInitOptions -): KeyGenerationService { +): Promise { return factory( cache, "keyGenerationService", opts, - () => new KeyGenerationService(cryptoFunctionServiceFactory(cache, opts)) + async () => new KeyGenerationService(await cryptoFunctionServiceFactory(cache, opts)) ); } diff --git a/apps/browser/src/background/service_factories/log-service.factory.ts b/apps/browser/src/background/service_factories/log-service.factory.ts index 407aadd12f..f8c7f9cad2 100644 --- a/apps/browser/src/background/service_factories/log-service.factory.ts +++ b/apps/browser/src/background/service_factories/log-service.factory.ts @@ -16,7 +16,7 @@ export type LogServiceInitOptions = LogServiceFactoryOptions; export function logServiceFactory( cache: { logService?: LogService } & CachedServices, opts: LogServiceInitOptions -): LogService { +): Promise { return factory( cache, "logService", diff --git a/apps/browser/src/background/service_factories/messaging-service.factory.ts b/apps/browser/src/background/service_factories/messaging-service.factory.ts new file mode 100644 index 0000000000..633f1b2d57 --- /dev/null +++ b/apps/browser/src/background/service_factories/messaging-service.factory.ts @@ -0,0 +1,16 @@ +import { MessagingService as AbstractMessagingService } from "@bitwarden/common/abstractions/messaging.service"; + +import BrowserMessagingService from "../../services/browserMessaging.service"; + +import { CachedServices, factory, FactoryOptions } from "./factory-options"; + +type MessagingServiceFactoryOptions = FactoryOptions; + +export type MessagingServiceInitOptions = MessagingServiceFactoryOptions; + +export function messagingServiceFactory( + cache: { messagingService?: AbstractMessagingService } & CachedServices, + opts: MessagingServiceInitOptions +): Promise { + return factory(cache, "messagingService", opts, () => new BrowserMessagingService()); +} diff --git a/apps/browser/src/background/service_factories/organization-service.factory.ts b/apps/browser/src/background/service_factories/organization-service.factory.ts new file mode 100644 index 0000000000..87692e6439 --- /dev/null +++ b/apps/browser/src/background/service_factories/organization-service.factory.ts @@ -0,0 +1,22 @@ +import { OrganizationService as AbstractOrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/services/organization.service"; + +import { FactoryOptions, CachedServices, factory } from "./factory-options"; +import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory"; + +type OrganizationServiceFactoryOptions = FactoryOptions; + +export type OrganizationServiceInitOptions = OrganizationServiceFactoryOptions & + StateServiceInitOptions; + +export function organizationServiceFactory( + cache: { organizationService?: AbstractOrganizationService } & CachedServices, + opts: OrganizationServiceInitOptions +): Promise { + return factory( + cache, + "organizationService", + opts, + async () => new OrganizationService(await stateServiceFactory(cache, opts)) + ); +} diff --git a/apps/browser/src/background/service_factories/platform-utils-service.factory.ts b/apps/browser/src/background/service_factories/platform-utils-service.factory.ts new file mode 100644 index 0000000000..6d85f12636 --- /dev/null +++ b/apps/browser/src/background/service_factories/platform-utils-service.factory.ts @@ -0,0 +1,34 @@ +import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; + +import BrowserPlatformUtilsService from "../../services/browserPlatformUtils.service"; + +import { CachedServices, factory, FactoryOptions } from "./factory-options"; +import { MessagingServiceInitOptions, messagingServiceFactory } from "./messaging-service.factory"; + +type PlatformUtilsServiceFactoryOptions = FactoryOptions & { + platformUtilsServiceOptions: { + clipboardWriteCallback: (clipboardValue: string, clearMs: number) => Promise; + biometricCallback: () => Promise; + win: Window & typeof globalThis; + }; +}; + +export type PlatformUtilsServiceInitOptions = PlatformUtilsServiceFactoryOptions & + MessagingServiceInitOptions; + +export function platformUtilsServiceFactory( + cache: { platformUtilsService?: PlatformUtilsService } & CachedServices, + opts: PlatformUtilsServiceInitOptions +): Promise { + return factory( + cache, + "platformUtilsService", + opts, + async () => + new BrowserPlatformUtilsService( + await messagingServiceFactory(cache, opts), + opts.platformUtilsServiceOptions.clipboardWriteCallback, + opts.platformUtilsServiceOptions.biometricCallback + ) + ); +} diff --git a/apps/browser/src/background/service_factories/settings-service.factory.ts b/apps/browser/src/background/service_factories/settings-service.factory.ts new file mode 100644 index 0000000000..745a6d08d6 --- /dev/null +++ b/apps/browser/src/background/service_factories/settings-service.factory.ts @@ -0,0 +1,21 @@ +import { SettingsService as AbstractSettingsService } from "@bitwarden/common/abstractions/settings.service"; +import { SettingsService } from "@bitwarden/common/services/settings.service"; + +import { FactoryOptions, CachedServices, factory } from "./factory-options"; +import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory"; + +type SettingsServiceFactoryOptions = FactoryOptions; + +export type SettingsServiceInitOptions = SettingsServiceFactoryOptions & StateServiceInitOptions; + +export function settingsServiceFactory( + cache: { settingsService?: AbstractSettingsService } & CachedServices, + opts: SettingsServiceInitOptions +): Promise { + return factory( + cache, + "settingsService", + opts, + async () => new SettingsService(await stateServiceFactory(cache, opts)) + ); +} diff --git a/apps/browser/src/background/service_factories/state-migration-service.factory.ts b/apps/browser/src/background/service_factories/state-migration-service.factory.ts index cffa7ee765..ae21298b72 100644 --- a/apps/browser/src/background/service_factories/state-migration-service.factory.ts +++ b/apps/browser/src/background/service_factories/state-migration-service.factory.ts @@ -25,15 +25,15 @@ export type StateMigrationServiceInitOptions = StateMigrationServiceFactoryOptio export function stateMigrationServiceFactory( cache: { stateMigrationService?: StateMigrationService } & CachedServices, opts: StateMigrationServiceInitOptions -): StateMigrationService { +): Promise { return factory( cache, "stateMigrationService", opts, - () => + async () => new StateMigrationService( - diskStorageServiceFactory(cache, opts), - secureStorageServiceFactory(cache, opts), + await diskStorageServiceFactory(cache, opts), + await secureStorageServiceFactory(cache, opts), opts.stateMigrationServiceOptions.stateFactory ) ); diff --git a/apps/browser/src/background/service_factories/state-service.factory.ts b/apps/browser/src/background/service_factories/state-service.factory.ts index f936afbbc1..202148cd74 100644 --- a/apps/browser/src/background/service_factories/state-service.factory.ts +++ b/apps/browser/src/background/service_factories/state-service.factory.ts @@ -33,23 +33,25 @@ export type StateServiceInitOptions = StateServiceFactoryOptions & LogServiceInitOptions & StateMigrationServiceInitOptions; -export function stateServiceFactory( +export async function stateServiceFactory( cache: { stateService?: StateService } & CachedServices, opts: StateServiceInitOptions -): StateService { - return factory( +): Promise { + const service = await factory( cache, "stateService", opts, - () => - new StateService( - diskStorageServiceFactory(cache, opts), - secureStorageServiceFactory(cache, opts), - memoryStorageServiceFactory(cache, opts), - logServiceFactory(cache, opts), - stateMigrationServiceFactory(cache, opts), + async () => + await new StateService( + await diskStorageServiceFactory(cache, opts), + await secureStorageServiceFactory(cache, opts), + await memoryStorageServiceFactory(cache, opts), + await logServiceFactory(cache, opts), + await stateMigrationServiceFactory(cache, opts), opts.stateServiceOptions.stateFactory, opts.stateServiceOptions.useAccountCache ) ); + service.init(); + return service; } diff --git a/apps/browser/src/background/service_factories/storage-service.factory.ts b/apps/browser/src/background/service_factories/storage-service.factory.ts index 8ef7e1e93a..09ee4c7371 100644 --- a/apps/browser/src/background/service_factories/storage-service.factory.ts +++ b/apps/browser/src/background/service_factories/storage-service.factory.ts @@ -22,26 +22,26 @@ export type MemoryStorageServiceInitOptions = StorageServiceFactoryOptions & export function diskStorageServiceFactory( cache: { diskStorageService?: AbstractStorageService } & CachedServices, opts: DiskStorageServiceInitOptions -): AbstractStorageService { +): Promise { return factory(cache, "diskStorageService", opts, () => new BrowserLocalStorageService()); } export function secureStorageServiceFactory( cache: { secureStorageService?: AbstractStorageService } & CachedServices, opts: SecureStorageServiceInitOptions -): AbstractStorageService { +): Promise { return factory(cache, "secureStorageService", opts, () => new BrowserLocalStorageService()); } export function memoryStorageServiceFactory( cache: { memoryStorageService?: AbstractStorageService } & CachedServices, opts: MemoryStorageServiceInitOptions -): AbstractStorageService { - return factory(cache, "memoryStorageService", opts, () => { +): Promise { + return factory(cache, "memoryStorageService", opts, async () => { if (chrome.runtime.getManifest().manifest_version == 3) { return new LocalBackedSessionStorageService( - encryptServiceFactory(cache, opts), - keyGenerationServiceFactory(cache, opts) + await encryptServiceFactory(cache, opts), + await keyGenerationServiceFactory(cache, opts) ); } return new MemoryStorageService(); diff --git a/apps/browser/src/background/service_factories/token-service.factory.ts b/apps/browser/src/background/service_factories/token-service.factory.ts new file mode 100644 index 0000000000..2b642985e2 --- /dev/null +++ b/apps/browser/src/background/service_factories/token-service.factory.ts @@ -0,0 +1,21 @@ +import { TokenService as AbstractTokenService } from "@bitwarden/common/abstractions/token.service"; +import { TokenService } from "@bitwarden/common/services/token.service"; + +import { CachedServices, factory, FactoryOptions } from "./factory-options"; +import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory"; + +type TokenServiceFactoryOptions = FactoryOptions; + +export type TokenServiceInitOptions = TokenServiceFactoryOptions & StateServiceInitOptions; + +export function tokenServiceFactory( + cache: { tokenService?: AbstractTokenService } & CachedServices, + opts: TokenServiceInitOptions +): Promise { + return factory( + cache, + "tokenService", + opts, + async () => new TokenService(await stateServiceFactory(cache, opts)) + ); +} diff --git a/apps/browser/src/background/service_factories/two-factor-service.factory.ts b/apps/browser/src/background/service_factories/two-factor-service.factory.ts new file mode 100644 index 0000000000..07bed5400b --- /dev/null +++ b/apps/browser/src/background/service_factories/two-factor-service.factory.ts @@ -0,0 +1,33 @@ +import { TwoFactorService as AbstractTwoFactorService } from "@bitwarden/common/abstractions/twoFactor.service"; +import { TwoFactorService } from "@bitwarden/common/services/twoFactor.service"; + +import { FactoryOptions, CachedServices, factory } from "./factory-options"; +import { I18nServiceInitOptions, i18nServiceFactory } from "./i18n-service.factory"; +import { + platformUtilsServiceFactory, + PlatformUtilsServiceInitOptions, +} from "./platform-utils-service.factory"; + +type TwoFactorServiceFactoryOptions = FactoryOptions; + +export type TwoFactorServiceInitOptions = TwoFactorServiceFactoryOptions & + I18nServiceInitOptions & + PlatformUtilsServiceInitOptions; + +export async function twoFactorServiceFactory( + cache: { twoFactorService?: AbstractTwoFactorService } & CachedServices, + opts: TwoFactorServiceInitOptions +): Promise { + const service = await factory( + cache, + "twoFactorService", + opts, + async () => + new TwoFactorService( + await i18nServiceFactory(cache, opts), + await platformUtilsServiceFactory(cache, opts) + ) + ); + await service.init(); + return service; +} diff --git a/apps/browser/src/listeners/onInstallListener.ts b/apps/browser/src/listeners/onInstallListener.ts index 8d871b7788..63414d633f 100644 --- a/apps/browser/src/listeners/onInstallListener.ts +++ b/apps/browser/src/listeners/onInstallListener.ts @@ -5,7 +5,7 @@ import { environmentServiceFactory } from "../background/service_factories/envir import { BrowserApi } from "../browser/browserApi"; import { Account } from "../models/account"; -export function onInstallListener(details: chrome.runtime.InstalledDetails) { +export async function onInstallListener(details: chrome.runtime.InstalledDetails) { const cache = {}; const opts = { encryptServiceOptions: { @@ -24,7 +24,7 @@ export function onInstallListener(details: chrome.runtime.InstalledDetails) { stateFactory: new StateFactory(GlobalState, Account), }, }; - const environmentService = environmentServiceFactory(cache, opts); + const environmentService = await environmentServiceFactory(cache, opts); setTimeout(async () => { if (details.reason != null && details.reason === "install") {