diff --git a/jslib b/jslib index f6e3481fe96..d7e554653a7 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit f6e3481fe96690a3c52f7701d92b4e57f69f976a +Subproject commit d7e554653a7e593f8cdaf7e2fe926eb04fb5d5c5 diff --git a/src/app/accounts/two-factor.component.ts b/src/app/accounts/two-factor.component.ts index 5c75577b231..9c860553cb5 100644 --- a/src/app/accounts/two-factor.component.ts +++ b/src/app/accounts/two-factor.component.ts @@ -4,6 +4,7 @@ import { ActivatedRoute, Router } from "@angular/router"; import { TwoFactorComponent as BaseTwoFactorComponent } from "jslib-angular/components/two-factor.component"; import { ModalService } from "jslib-angular/services/modal.service"; import { ApiService } from "jslib-common/abstractions/api.service"; +import { AppIdService } from "jslib-common/abstractions/appId.service"; import { AuthService } from "jslib-common/abstractions/auth.service"; import { EnvironmentService } from "jslib-common/abstractions/environment.service"; import { I18nService } from "jslib-common/abstractions/i18n.service"; @@ -37,7 +38,8 @@ export class TwoFactorComponent extends BaseTwoFactorComponent { route: ActivatedRoute, logService: LogService, twoFactorService: TwoFactorService, - private routerService: RouterService + private routerService: RouterService, + appIdService: AppIdService ) { super( authService, @@ -50,7 +52,8 @@ export class TwoFactorComponent extends BaseTwoFactorComponent { stateService, route, logService, - twoFactorService + twoFactorService, + appIdService ); this.onSuccessfulLoginNavigate = this.goAfterLogIn; } diff --git a/src/app/services/init.service.ts b/src/app/services/init.service.ts new file mode 100644 index 00000000000..eacfea9773b --- /dev/null +++ b/src/app/services/init.service.ts @@ -0,0 +1,69 @@ +import { Inject, Injectable } from "@angular/core"; + +import { WINDOW } from "jslib-angular/services/jslib-services.module"; +import { CryptoService as CryptoServiceAbstraction } from "jslib-common/abstractions/crypto.service"; +import { + EnvironmentService as EnvironmentServiceAbstraction, + Urls, +} from "jslib-common/abstractions/environment.service"; +import { EventService as EventLoggingServiceAbstraction } from "jslib-common/abstractions/event.service"; +import { I18nService as I18nServiceAbstraction } from "jslib-common/abstractions/i18n.service"; +import { NotificationsService as NotificationsServiceAbstraction } from "jslib-common/abstractions/notifications.service"; +import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "jslib-common/abstractions/platformUtils.service"; +import { StateService as StateServiceAbstraction } from "jslib-common/abstractions/state.service"; +import { TwoFactorService as TwoFactorServiceAbstraction } from "jslib-common/abstractions/twoFactor.service"; +import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "jslib-common/abstractions/vaultTimeout.service"; +import { ThemeType } from "jslib-common/enums/themeType"; +import { ContainerService } from "jslib-common/services/container.service"; +import { EventService as EventLoggingService } from "jslib-common/services/event.service"; +import { VaultTimeoutService as VaultTimeoutService } from "jslib-common/services/vaultTimeout.service"; + +import { I18nService as I18nService } from "../../services/i18n.service"; + +@Injectable() +export class InitService { + constructor( + @Inject(WINDOW) private win: Window, + private environmentService: EnvironmentServiceAbstraction, + private notificationsService: NotificationsServiceAbstraction, + private vaultTimeoutService: VaultTimeoutServiceAbstraction, + private i18nService: I18nServiceAbstraction, + private eventLoggingService: EventLoggingServiceAbstraction, + private twoFactorService: TwoFactorServiceAbstraction, + private stateService: StateServiceAbstraction, + private platformUtilsService: PlatformUtilsServiceAbstraction, + private cryptoService: CryptoServiceAbstraction + ) {} + + init() { + return async () => { + await this.stateService.init(); + + const urls = process.env.URLS as Urls; + urls.base ??= this.win.location.origin; + this.environmentService.setUrls(urls); + + setTimeout(() => this.notificationsService.init(), 3000); + + (this.vaultTimeoutService as VaultTimeoutService).init(true); + const locale = await this.stateService.getLocale(); + await (this.i18nService as I18nService).init(locale); + (this.eventLoggingService as EventLoggingService).init(true); + this.twoFactorService.init(); + const htmlEl = this.win.document.documentElement; + htmlEl.classList.add("locale_" + this.i18nService.translationLocale); + + // Initial theme is set in index.html which must be updated if there are any changes to theming logic + this.platformUtilsService.onDefaultSystemThemeChange(async (sysTheme) => { + const bwTheme = await this.stateService.getTheme(); + if (bwTheme === ThemeType.System) { + htmlEl.classList.remove("theme_" + ThemeType.Light, "theme_" + ThemeType.Dark); + htmlEl.classList.add("theme_" + sysTheme); + } + }); + + const containerService = new ContainerService(this.cryptoService); + containerService.attachToWindow(this.win); + }; + } +} diff --git a/src/app/services/services.module.ts b/src/app/services/services.module.ts index cb632358251..4c5ae2049f6 100644 --- a/src/app/services/services.module.ts +++ b/src/app/services/services.module.ts @@ -1,38 +1,32 @@ import { APP_INITIALIZER, NgModule } from "@angular/core"; import { ToastrModule } from "ngx-toastr"; -import { JslibServicesModule } from "jslib-angular/services/jslib-services.module"; +import { + JslibServicesModule, + WINDOW, + SECURE_STORAGE, + STATE_FACTORY, + STATE_SERVICE_USE_CACHE, + LOCALES_DIRECTORY, + SYSTEM_LANGUAGE, +} from "jslib-angular/services/jslib-services.module"; import { ModalService as ModalServiceAbstraction } from "jslib-angular/services/modal.service"; import { ApiService as ApiServiceAbstraction } from "jslib-common/abstractions/api.service"; import { CipherService as CipherServiceAbstraction } from "jslib-common/abstractions/cipher.service"; import { CollectionService as CollectionServiceAbstraction } from "jslib-common/abstractions/collection.service"; import { CryptoService as CryptoServiceAbstraction } from "jslib-common/abstractions/crypto.service"; -import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "jslib-common/abstractions/cryptoFunction.service"; -import { - EnvironmentService as EnvironmentServiceAbstraction, - Urls, -} from "jslib-common/abstractions/environment.service"; -import { EventService as EventLoggingServiceAbstraction } from "jslib-common/abstractions/event.service"; import { FolderService as FolderServiceAbstraction } from "jslib-common/abstractions/folder.service"; import { I18nService as I18nServiceAbstraction } from "jslib-common/abstractions/i18n.service"; import { ImportService as ImportServiceAbstraction } from "jslib-common/abstractions/import.service"; import { LogService } from "jslib-common/abstractions/log.service"; import { MessagingService as MessagingServiceAbstraction } from "jslib-common/abstractions/messaging.service"; -import { NotificationsService as NotificationsServiceAbstraction } from "jslib-common/abstractions/notifications.service"; import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "jslib-common/abstractions/passwordReprompt.service"; import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "jslib-common/abstractions/platformUtils.service"; import { StateService as BaseStateServiceAbstraction } from "jslib-common/abstractions/state.service"; import { StateMigrationService as StateMigrationServiceAbstraction } from "jslib-common/abstractions/stateMigration.service"; import { StorageService as StorageServiceAbstraction } from "jslib-common/abstractions/storage.service"; -import { TwoFactorService as TwoFactorServiceAbstraction } from "jslib-common/abstractions/twoFactor.service"; -import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "jslib-common/abstractions/vaultTimeout.service"; -import { ThemeType } from "jslib-common/enums/themeType"; import { StateFactory } from "jslib-common/factories/stateFactory"; -import { ContainerService } from "jslib-common/services/container.service"; -import { CryptoService } from "jslib-common/services/crypto.service"; -import { EventService as EventLoggingService } from "jslib-common/services/event.service"; import { ImportService } from "jslib-common/services/import.service"; -import { VaultTimeoutService } from "jslib-common/services/vaultTimeout.service"; import { StateService as StateServiceAbstraction } from "../../abstractions/state.service"; import { Account } from "../../models/account"; @@ -48,107 +42,52 @@ import { WebPlatformUtilsService } from "../../services/webPlatformUtils.service import { HomeGuard } from "../guards/home.guard"; import { EventService } from "./event.service"; +import { InitService } from "./init.service"; import { ModalService } from "./modal.service"; import { OrganizationGuardService } from "./organization-guard.service"; import { OrganizationTypeGuardService } from "./organization-type-guard.service"; import { PolicyListService } from "./policy-list.service"; import { RouterService } from "./router.service"; -export function initFactory( - window: Window, - environmentService: EnvironmentServiceAbstraction, - notificationsService: NotificationsServiceAbstraction, - vaultTimeoutService: VaultTimeoutService, - i18nService: I18nService, - eventLoggingService: EventLoggingService, - twoFactorService: TwoFactorServiceAbstraction, - stateService: StateServiceAbstraction, - platformUtilsService: PlatformUtilsServiceAbstraction, - cryptoService: CryptoServiceAbstraction -): () => void { - return async () => { - await stateService.init(); - - const urls = process.env.URLS as Urls; - urls.base ??= window.location.origin; - environmentService.setUrls(urls); - - setTimeout(() => notificationsService.init(), 3000); - - vaultTimeoutService.init(true); - const locale = await stateService.getLocale(); - await i18nService.init(locale); - eventLoggingService.init(true); - twoFactorService.init(); - const htmlEl = window.document.documentElement; - htmlEl.classList.add("locale_" + i18nService.translationLocale); - - // Initial theme is set in index.html which must be updated if there are any changes to theming logic - platformUtilsService.onDefaultSystemThemeChange(async (sysTheme) => { - const bwTheme = await stateService.getTheme(); - if (bwTheme === ThemeType.System) { - htmlEl.classList.remove("theme_" + ThemeType.Light, "theme_" + ThemeType.Dark); - htmlEl.classList.add("theme_" + sysTheme); - } - }); - - const containerService = new ContainerService(cryptoService); - containerService.attachToWindow(window); - }; -} - @NgModule({ imports: [ToastrModule, JslibServicesModule], declarations: [], providers: [ - { - provide: APP_INITIALIZER, - useFactory: initFactory, - deps: [ - "WINDOW", - EnvironmentServiceAbstraction, - NotificationsServiceAbstraction, - VaultTimeoutServiceAbstraction, - I18nServiceAbstraction, - EventLoggingServiceAbstraction, - TwoFactorServiceAbstraction, - StateServiceAbstraction, - PlatformUtilsServiceAbstraction, - CryptoServiceAbstraction, - ], - multi: true, - }, + InitService, OrganizationGuardService, OrganizationTypeGuardService, RouterService, EventService, PolicyListService, + { + provide: APP_INITIALIZER, + useFactory: (initService: InitService) => initService.init(), + deps: [InitService], + multi: true, + }, + { + provide: STATE_FACTORY, + useValue: new StateFactory(GlobalState, Account), + }, + { + provide: STATE_SERVICE_USE_CACHE, + useValue: false, + }, { provide: I18nServiceAbstraction, - useFactory: (window: Window) => new I18nService(window.navigator.language, "locales"), - deps: ["WINDOW"], + useClass: I18nService, + deps: [SYSTEM_LANGUAGE, LOCALES_DIRECTORY], }, { provide: StorageServiceAbstraction, useClass: HtmlStorageService }, { - provide: "SECURE_STORAGE", + provide: SECURE_STORAGE, // TODO: platformUtilsService.isDev has a helper for this, but using that service here results in a circular dependency. // We have a tech debt item in the backlog to break up platformUtilsService, but in the meantime simply checking the environement here is less cumbersome. useClass: process.env.NODE_ENV === "development" ? HtmlStorageService : MemoryStorageService, }, { provide: PlatformUtilsServiceAbstraction, - useFactory: ( - i18nService: I18nServiceAbstraction, - messagingService: MessagingServiceAbstraction, - logService: LogService, - stateService: StateServiceAbstraction - ) => new WebPlatformUtilsService(i18nService, messagingService, logService, stateService), - deps: [ - I18nServiceAbstraction, - MessagingServiceAbstraction, - LogService, - StateServiceAbstraction, - ], + useClass: WebPlatformUtilsService, }, { provide: MessagingServiceAbstraction, useClass: BroadcasterMessagingService }, { provide: ModalServiceAbstraction, useClass: ModalService }, @@ -165,50 +104,21 @@ export function initFactory( CryptoServiceAbstraction, ], }, - { - provide: CryptoServiceAbstraction, - useClass: CryptoService, - deps: [ - CryptoFunctionServiceAbstraction, - PlatformUtilsServiceAbstraction, - LogService, - StateServiceAbstraction, - ], - }, { provide: StateMigrationServiceAbstraction, - useFactory: ( - storageService: StorageServiceAbstraction, - secureStorageService: StorageServiceAbstraction - ) => - new StateMigrationService( - storageService, - secureStorageService, - new StateFactory(GlobalState, Account) - ), - deps: [StorageServiceAbstraction, "SECURE_STORAGE"], + useClass: StateMigrationService, + deps: [StorageServiceAbstraction, SECURE_STORAGE, STATE_FACTORY], }, { provide: StateServiceAbstraction, - useFactory: ( - storageService: StorageServiceAbstraction, - secureStorageService: StorageServiceAbstraction, - logService: LogService, - stateMigrationService: StateMigrationServiceAbstraction - ) => - new StateService( - storageService, - secureStorageService, - logService, - stateMigrationService, - new StateFactory(GlobalState, Account), - false - ), + useClass: StateService, deps: [ StorageServiceAbstraction, - "SECURE_STORAGE", + SECURE_STORAGE, LogService, StateMigrationServiceAbstraction, + STATE_FACTORY, + STATE_SERVICE_USE_CACHE, ], }, { diff --git a/src/app/tools/generator.component.ts b/src/app/tools/generator.component.ts index 30aeb5753ff..daef4fea2c4 100644 --- a/src/app/tools/generator.component.ts +++ b/src/app/tools/generator.component.ts @@ -4,6 +4,7 @@ import { ActivatedRoute } from "@angular/router"; import { GeneratorComponent as BaseGeneratorComponent } from "jslib-angular/components/generator.component"; import { ModalService } from "jslib-angular/services/modal.service"; import { I18nService } from "jslib-common/abstractions/i18n.service"; +import { LogService } from "jslib-common/abstractions/log.service"; import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { StateService } from "jslib-common/abstractions/state.service"; @@ -26,6 +27,7 @@ export class GeneratorComponent extends BaseGeneratorComponent { platformUtilsService: PlatformUtilsService, i18nService: I18nService, route: ActivatedRoute, + logService: LogService, private modalService: ModalService ) { super( @@ -34,6 +36,7 @@ export class GeneratorComponent extends BaseGeneratorComponent { platformUtilsService, stateService, i18nService, + logService, route, window ); diff --git a/src/services/webPlatformUtils.service.ts b/src/services/webPlatformUtils.service.ts index 0c9b56fae14..755600a15ab 100644 --- a/src/services/webPlatformUtils.service.ts +++ b/src/services/webPlatformUtils.service.ts @@ -1,3 +1,4 @@ +import { Injectable } from "@angular/core"; import Swal, { SweetAlertIcon } from "sweetalert2"; import { I18nService } from "jslib-common/abstractions/i18n.service"; @@ -9,6 +10,7 @@ import { ClientType } from "jslib-common/enums/clientType"; import { DeviceType } from "jslib-common/enums/deviceType"; import { ThemeType } from "jslib-common/enums/themeType"; +@Injectable() export class WebPlatformUtilsService implements PlatformUtilsService { private browserCache: DeviceType = null; private prefersColorSchemeDark = window.matchMedia("(prefers-color-scheme: dark)");