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") {