[AC-2329] [BEEEP] Use safeProvider in desktop services module (#8457)

This commit is contained in:
Thomas Rittson 2024-03-28 08:44:08 +10:00 committed by GitHub
parent b3b344866e
commit d10c14791d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 198 additions and 147 deletions

View File

@ -1,8 +1,8 @@
import { APP_INITIALIZER, InjectionToken, NgModule } from "@angular/core";
import { APP_INITIALIZER, NgModule } from "@angular/core";
import { SafeProvider, safeProvider } from "@bitwarden/angular/platform/utils/safe-provider";
import {
SECURE_STORAGE,
STATE_FACTORY,
STATE_SERVICE_USE_CACHE,
LOCALES_DIRECTORY,
SYSTEM_LANGUAGE,
@ -12,6 +12,8 @@ import {
WINDOW,
SUPPORTS_SECURE_STORAGE,
SYSTEM_THEME_OBSERVABLE,
SafeInjectionToken,
STATE_FACTORY,
} from "@bitwarden/angular/services/injection-tokens";
import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module";
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
@ -77,153 +79,187 @@ import { DesktopFileDownloadService } from "./desktop-file-download.service";
import { InitService } from "./init.service";
import { RendererCryptoFunctionService } from "./renderer-crypto-function.service";
const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
const RELOAD_CALLBACK = new SafeInjectionToken<() => any>("RELOAD_CALLBACK");
// Desktop has its own Account definition which must be used in its StateService
const DESKTOP_STATE_FACTORY = new SafeInjectionToken<StateFactory<GlobalState, Account>>(
"DESKTOP_STATE_FACTORY",
);
/**
* Provider definitions used in the ngModule.
* Add your provider definition here using the safeProvider function as a wrapper. This will give you type safety.
* If you need help please ask for it, do NOT change the type of this array.
*/
const safeProviders: SafeProvider[] = [
safeProvider(InitService),
safeProvider(NativeMessagingService),
safeProvider(SearchBarService),
safeProvider(LoginGuard),
safeProvider(DialogService),
safeProvider({
provide: APP_INITIALIZER as SafeInjectionToken<() => void>,
useFactory: (initService: InitService) => initService.init(),
deps: [InitService],
multi: true,
}),
safeProvider({
provide: DESKTOP_STATE_FACTORY,
useValue: new StateFactory(GlobalState, Account),
}),
safeProvider({
provide: STATE_FACTORY,
useValue: null,
}),
safeProvider({
provide: RELOAD_CALLBACK,
useValue: null,
}),
safeProvider({
provide: LogServiceAbstraction,
useClass: ElectronLogRendererService,
deps: [],
}),
safeProvider({
provide: PlatformUtilsServiceAbstraction,
useClass: ElectronPlatformUtilsService,
deps: [I18nServiceAbstraction, MessagingServiceAbstraction],
}),
safeProvider({
// We manually override the value of SUPPORTS_SECURE_STORAGE here to avoid
// the TokenService having to inject the PlatformUtilsService which introduces a
// circular dependency on Desktop only.
provide: SUPPORTS_SECURE_STORAGE,
useValue: ELECTRON_SUPPORTS_SECURE_STORAGE,
}),
safeProvider({
provide: I18nServiceAbstraction,
useClass: I18nRendererService,
deps: [SYSTEM_LANGUAGE, LOCALES_DIRECTORY, GlobalStateProvider],
}),
safeProvider({
provide: MessagingServiceAbstraction,
useClass: ElectronRendererMessagingService,
deps: [BroadcasterServiceAbstraction],
}),
safeProvider({
provide: AbstractStorageService,
useClass: ElectronRendererStorageService,
deps: [],
}),
safeProvider({
provide: SECURE_STORAGE,
useClass: ElectronRendererSecureStorageService,
deps: [],
}),
safeProvider({ provide: MEMORY_STORAGE, useClass: MemoryStorageService, deps: [] }),
safeProvider({
provide: OBSERVABLE_MEMORY_STORAGE,
useClass: MemoryStorageServiceForStateProviders,
deps: [],
}),
safeProvider({ provide: OBSERVABLE_DISK_STORAGE, useExisting: AbstractStorageService }),
safeProvider({
provide: SystemServiceAbstraction,
useClass: SystemService,
deps: [
MessagingServiceAbstraction,
PlatformUtilsServiceAbstraction,
RELOAD_CALLBACK,
StateServiceAbstraction,
AutofillSettingsServiceAbstraction,
VaultTimeoutSettingsService,
BiometricStateService,
],
}),
safeProvider({
provide: StateServiceAbstraction,
useClass: ElectronStateService,
deps: [
AbstractStorageService,
SECURE_STORAGE,
MEMORY_STORAGE,
LogService,
DESKTOP_STATE_FACTORY,
AccountServiceAbstraction,
EnvironmentService,
TokenService,
MigrationRunner,
STATE_SERVICE_USE_CACHE,
],
}),
safeProvider({
provide: FileDownloadService,
useClass: DesktopFileDownloadService,
deps: [],
}),
safeProvider({
provide: SYSTEM_THEME_OBSERVABLE,
useFactory: () => fromIpcSystemTheme(),
deps: [],
}),
safeProvider({
provide: EncryptedMessageHandlerService,
deps: [
StateServiceAbstraction,
AuthServiceAbstraction,
CipherServiceAbstraction,
PolicyServiceAbstraction,
MessagingServiceAbstraction,
PasswordGenerationServiceAbstraction,
],
}),
safeProvider({
provide: NativeMessageHandlerService,
deps: [
StateServiceAbstraction,
CryptoServiceAbstraction,
CryptoFunctionServiceAbstraction,
MessagingServiceAbstraction,
EncryptedMessageHandlerService,
DialogService,
DesktopAutofillSettingsService,
],
}),
safeProvider({
provide: LoginServiceAbstraction,
useClass: LoginService,
deps: [StateServiceAbstraction],
}),
safeProvider({
provide: CryptoFunctionServiceAbstraction,
useClass: RendererCryptoFunctionService,
deps: [WINDOW],
}),
safeProvider({
provide: CryptoServiceAbstraction,
useClass: ElectronCryptoService,
deps: [
KeyGenerationServiceAbstraction,
CryptoFunctionServiceAbstraction,
EncryptService,
PlatformUtilsServiceAbstraction,
LogService,
StateServiceAbstraction,
AccountServiceAbstraction,
StateProvider,
BiometricStateService,
],
}),
safeProvider({
provide: DesktopSettingsService,
deps: [StateProvider],
}),
safeProvider({
provide: DesktopAutofillSettingsService,
deps: [StateProvider],
}),
];
@NgModule({
imports: [JslibServicesModule],
declarations: [],
providers: [
InitService,
NativeMessagingService,
SearchBarService,
LoginGuard,
DialogService,
{
provide: APP_INITIALIZER,
useFactory: (initService: InitService) => initService.init(),
deps: [InitService],
multi: true,
},
{
provide: STATE_FACTORY,
useValue: new StateFactory(GlobalState, Account),
},
{
provide: RELOAD_CALLBACK,
useValue: null,
},
{ provide: LogServiceAbstraction, useClass: ElectronLogRendererService, deps: [] },
{
provide: PlatformUtilsServiceAbstraction,
useClass: ElectronPlatformUtilsService,
deps: [I18nServiceAbstraction, MessagingServiceAbstraction],
},
{
// We manually override the value of SUPPORTS_SECURE_STORAGE here to avoid
// the TokenService having to inject the PlatformUtilsService which introduces a
// circular dependency on Desktop only.
provide: SUPPORTS_SECURE_STORAGE,
useValue: ELECTRON_SUPPORTS_SECURE_STORAGE,
},
{
provide: I18nServiceAbstraction,
useClass: I18nRendererService,
deps: [SYSTEM_LANGUAGE, LOCALES_DIRECTORY, GlobalStateProvider],
},
{
provide: MessagingServiceAbstraction,
useClass: ElectronRendererMessagingService,
deps: [BroadcasterServiceAbstraction],
},
{ provide: AbstractStorageService, useClass: ElectronRendererStorageService },
{ provide: SECURE_STORAGE, useClass: ElectronRendererSecureStorageService },
{ provide: MEMORY_STORAGE, useClass: MemoryStorageService },
{ provide: OBSERVABLE_MEMORY_STORAGE, useClass: MemoryStorageServiceForStateProviders },
{ provide: OBSERVABLE_DISK_STORAGE, useExisting: AbstractStorageService },
{
provide: SystemServiceAbstraction,
useClass: SystemService,
deps: [
MessagingServiceAbstraction,
PlatformUtilsServiceAbstraction,
RELOAD_CALLBACK,
StateServiceAbstraction,
AutofillSettingsServiceAbstraction,
VaultTimeoutSettingsService,
BiometricStateService,
],
},
{
provide: StateServiceAbstraction,
useClass: ElectronStateService,
deps: [
AbstractStorageService,
SECURE_STORAGE,
MEMORY_STORAGE,
LogService,
STATE_FACTORY,
AccountServiceAbstraction,
EnvironmentService,
TokenService,
MigrationRunner,
STATE_SERVICE_USE_CACHE,
],
},
{
provide: FileDownloadService,
useClass: DesktopFileDownloadService,
},
{
provide: SYSTEM_THEME_OBSERVABLE,
useFactory: () => fromIpcSystemTheme(),
},
{
provide: EncryptedMessageHandlerService,
deps: [
StateServiceAbstraction,
AuthServiceAbstraction,
CipherServiceAbstraction,
PolicyServiceAbstraction,
MessagingServiceAbstraction,
PasswordGenerationServiceAbstraction,
],
},
{
provide: NativeMessageHandlerService,
deps: [
StateServiceAbstraction,
CryptoServiceAbstraction,
CryptoFunctionServiceAbstraction,
MessagingServiceAbstraction,
EncryptedMessageHandlerService,
DialogService,
],
},
{
provide: LoginServiceAbstraction,
useClass: LoginService,
deps: [StateServiceAbstraction],
},
{
provide: CryptoFunctionServiceAbstraction,
useClass: RendererCryptoFunctionService,
deps: [WINDOW],
},
{
provide: CryptoServiceAbstraction,
useClass: ElectronCryptoService,
deps: [
KeyGenerationServiceAbstraction,
CryptoFunctionServiceAbstraction,
EncryptService,
PlatformUtilsServiceAbstraction,
LogService,
StateServiceAbstraction,
AccountServiceAbstraction,
StateProvider,
BiometricStateService,
],
},
{
provide: DesktopSettingsService,
useClass: DesktopSettingsService,
deps: [StateProvider],
},
{
provide: DesktopAutofillSettingsService,
useClass: DesktopAutofillSettingsService,
deps: [StateProvider],
},
],
// Do not register your dependency here! Add it to the typesafeProviders array using the helper function
providers: safeProviders,
})
export class ServicesModule {}

View File

@ -5,10 +5,10 @@ import { NativeMessagingVersion } from "@bitwarden/common/enums";
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { StateService } from "@bitwarden/common/platform/services/state.service";
import { DialogService } from "@bitwarden/components";
import { VerifyNativeMessagingDialogComponent } from "../app/components/verify-native-messaging-dialog.component";

View File

@ -74,6 +74,17 @@ type SafeExistingProvider<
useExisting: I;
};
/**
* Represents a dependency where there is no abstract token, the token is the implementation
*/
type SafeConcreteProvider<
I extends Constructor<any>,
D extends MapParametersToDeps<ConstructorParameters<I>>,
> = {
provide: I;
deps: D;
};
/**
* A factory function that creates a provider for the ngModule providers array.
* This guarantees type safety for your provider definition. It does nothing at runtime.
@ -97,11 +108,15 @@ export const safeProvider = <
IExisting extends
| Constructor<ProviderInstanceType<AExisting>>
| AbstractConstructor<ProviderInstanceType<AExisting>>,
// types for no token
IConcrete extends Constructor<any>,
DConcrete extends MapParametersToDeps<ConstructorParameters<IConcrete>>,
>(
provider:
| SafeClassProvider<AClass, IClass, DClass>
| SafeValueProvider<AValue, VValue>
| SafeFactoryProvider<AFactory, IFactory, DFactory>
| SafeExistingProvider<AExisting, IExisting>
| SafeConcreteProvider<IConcrete, DConcrete>
| Constructor<unknown>,
): SafeProvider => provider as SafeProvider;