mirror of
https://github.com/bitwarden/browser.git
synced 2025-02-21 02:11:54 +01:00
Merge branch 'main' into vault/pm-5273
# Conflicts: # libs/angular/src/services/jslib-services.module.ts
This commit is contained in:
commit
fff8d0610e
@ -1,9 +1,6 @@
|
|||||||
import { Injectable } from "@angular/core";
|
|
||||||
|
|
||||||
import { ThemingService } from "@bitwarden/angular/platform/services/theming/theming.service";
|
import { ThemingService } from "@bitwarden/angular/platform/services/theming/theming.service";
|
||||||
import { ThemeType } from "@bitwarden/common/platform/enums";
|
import { ThemeType } from "@bitwarden/common/platform/enums";
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class DesktopThemingService extends ThemingService {
|
export class DesktopThemingService extends ThemingService {
|
||||||
protected async getSystemTheme(): Promise<ThemeType> {
|
protected async getSystemTheme(): Promise<ThemeType> {
|
||||||
return await ipc.platform.getSystemTheme();
|
return await ipc.platform.getSystemTheme();
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
import { DOCUMENT } from "@angular/common";
|
||||||
import { APP_INITIALIZER, InjectionToken, NgModule } from "@angular/core";
|
import { APP_INITIALIZER, InjectionToken, NgModule } from "@angular/core";
|
||||||
|
|
||||||
import { AbstractThemingService } from "@bitwarden/angular/platform/services/theming/theming.service.abstraction";
|
import { AbstractThemingService } from "@bitwarden/angular/platform/services/theming/theming.service.abstraction";
|
||||||
|
import { safeProvider } from "@bitwarden/angular/platform/utils/safe-provider";
|
||||||
import {
|
import {
|
||||||
SECURE_STORAGE,
|
SECURE_STORAGE,
|
||||||
STATE_FACTORY,
|
STATE_FACTORY,
|
||||||
@ -11,6 +13,7 @@ import {
|
|||||||
OBSERVABLE_MEMORY_STORAGE,
|
OBSERVABLE_MEMORY_STORAGE,
|
||||||
OBSERVABLE_DISK_STORAGE,
|
OBSERVABLE_DISK_STORAGE,
|
||||||
WINDOW,
|
WINDOW,
|
||||||
|
SafeInjectionToken,
|
||||||
} from "@bitwarden/angular/services/injection-tokens";
|
} from "@bitwarden/angular/services/injection-tokens";
|
||||||
import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module";
|
import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module";
|
||||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
|
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
|
||||||
@ -148,10 +151,11 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
|
|||||||
provide: FileDownloadService,
|
provide: FileDownloadService,
|
||||||
useClass: DesktopFileDownloadService,
|
useClass: DesktopFileDownloadService,
|
||||||
},
|
},
|
||||||
{
|
safeProvider({
|
||||||
provide: AbstractThemingService,
|
provide: AbstractThemingService,
|
||||||
useClass: DesktopThemingService,
|
useClass: DesktopThemingService,
|
||||||
},
|
deps: [StateServiceAbstraction, WINDOW, DOCUMENT as SafeInjectionToken<Document>],
|
||||||
|
}),
|
||||||
{
|
{
|
||||||
provide: EncryptedMessageHandlerService,
|
provide: EncryptedMessageHandlerService,
|
||||||
deps: [
|
deps: [
|
||||||
|
@ -1,25 +1,20 @@
|
|||||||
import { DOCUMENT } from "@angular/common";
|
|
||||||
import { Inject, Injectable } from "@angular/core";
|
|
||||||
import { BehaviorSubject, filter, fromEvent, Observable } from "rxjs";
|
import { BehaviorSubject, filter, fromEvent, Observable } from "rxjs";
|
||||||
|
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { ThemeType } from "@bitwarden/common/platform/enums";
|
import { ThemeType } from "@bitwarden/common/platform/enums";
|
||||||
|
|
||||||
import { WINDOW } from "../../../services/injection-tokens";
|
|
||||||
|
|
||||||
import { Theme } from "./theme";
|
import { Theme } from "./theme";
|
||||||
import { ThemeBuilder } from "./theme-builder";
|
import { ThemeBuilder } from "./theme-builder";
|
||||||
import { AbstractThemingService } from "./theming.service.abstraction";
|
import { AbstractThemingService } from "./theming.service.abstraction";
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class ThemingService implements AbstractThemingService {
|
export class ThemingService implements AbstractThemingService {
|
||||||
private _theme = new BehaviorSubject<ThemeBuilder | null>(null);
|
private _theme = new BehaviorSubject<ThemeBuilder | null>(null);
|
||||||
theme$: Observable<Theme> = this._theme.pipe(filter((x) => x !== null));
|
theme$: Observable<Theme> = this._theme.pipe(filter((x) => x !== null));
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
@Inject(WINDOW) private window: Window,
|
private window: Window,
|
||||||
@Inject(DOCUMENT) private document: Document,
|
private document: Document,
|
||||||
) {
|
) {
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
|
114
libs/angular/src/platform/utils/safe-provider.ts
Normal file
114
libs/angular/src/platform/utils/safe-provider.ts
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
import { Provider } from "@angular/core";
|
||||||
|
import { Constructor, Opaque } from "type-fest";
|
||||||
|
|
||||||
|
import { SafeInjectionToken } from "../../services/injection-tokens";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The return type of our dependency helper functions.
|
||||||
|
* Used to distinguish a type safe provider definition from a non-type safe provider definition.
|
||||||
|
*/
|
||||||
|
export type SafeProvider = Opaque<Provider>;
|
||||||
|
|
||||||
|
// TODO: type-fest also provides a type like this when we upgrade >= 3.7.0
|
||||||
|
type AbstractConstructor<T> = abstract new (...args: any) => T;
|
||||||
|
|
||||||
|
type MapParametersToDeps<T> = {
|
||||||
|
[K in keyof T]: AbstractConstructor<T[K]> | SafeInjectionToken<T[K]>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SafeInjectionTokenType<T> = T extends SafeInjectionToken<infer J> ? J : never;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a dependency provided with the useClass option.
|
||||||
|
*/
|
||||||
|
type SafeClassProvider<
|
||||||
|
A extends AbstractConstructor<any>,
|
||||||
|
I extends Constructor<InstanceType<A>>,
|
||||||
|
D extends MapParametersToDeps<ConstructorParameters<I>>,
|
||||||
|
> = {
|
||||||
|
provide: A;
|
||||||
|
useClass: I;
|
||||||
|
deps: D;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a dependency provided with the useValue option.
|
||||||
|
*/
|
||||||
|
type SafeValueProvider<A extends SafeInjectionToken<any>, V extends SafeInjectionTokenType<A>> = {
|
||||||
|
provide: A;
|
||||||
|
useValue: V;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a dependency provided with the useFactory option where a SafeInjectionToken is used as the token.
|
||||||
|
*/
|
||||||
|
type SafeFactoryProviderWithToken<
|
||||||
|
A extends SafeInjectionToken<any>,
|
||||||
|
I extends (...args: any) => InstanceType<SafeInjectionTokenType<A>>,
|
||||||
|
D extends MapParametersToDeps<Parameters<I>>,
|
||||||
|
> = {
|
||||||
|
provide: A;
|
||||||
|
useFactory: I;
|
||||||
|
deps: D;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a dependency provided with the useFactory option where an abstract class is used as the token.
|
||||||
|
*/
|
||||||
|
type SafeFactoryProviderWithClass<
|
||||||
|
A extends AbstractConstructor<any>,
|
||||||
|
I extends (...args: any) => InstanceType<A>,
|
||||||
|
D extends MapParametersToDeps<Parameters<I>>,
|
||||||
|
> = {
|
||||||
|
provide: A;
|
||||||
|
useFactory: I;
|
||||||
|
deps: D;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a dependency provided with the useExisting option.
|
||||||
|
*/
|
||||||
|
type SafeExistingProvider<
|
||||||
|
A extends Constructor<any> | AbstractConstructor<any>,
|
||||||
|
I extends Constructor<InstanceType<A>> | AbstractConstructor<InstanceType<A>>,
|
||||||
|
> = {
|
||||||
|
provide: A;
|
||||||
|
useExisting: I;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* @param provider Your provider object in the usual shape (e.g. using useClass, useValue, useFactory, etc.)
|
||||||
|
* @returns The exact same object without modification (pass-through).
|
||||||
|
*/
|
||||||
|
export const safeProvider = <
|
||||||
|
// types for useClass
|
||||||
|
AClass extends AbstractConstructor<any>,
|
||||||
|
IClass extends Constructor<InstanceType<AClass>>,
|
||||||
|
DClass extends MapParametersToDeps<ConstructorParameters<IClass>>,
|
||||||
|
// types for useValue
|
||||||
|
AValue extends SafeInjectionToken<any>,
|
||||||
|
VValue extends SafeInjectionTokenType<AValue>,
|
||||||
|
// types for useFactoryWithToken
|
||||||
|
AFactoryToken extends SafeInjectionToken<any>,
|
||||||
|
IFactoryToken extends (...args: any) => InstanceType<SafeInjectionTokenType<AFactoryToken>>,
|
||||||
|
DFactoryToken extends MapParametersToDeps<Parameters<IFactoryToken>>,
|
||||||
|
// types for useFactoryWithClass
|
||||||
|
AFactoryClass extends AbstractConstructor<any>,
|
||||||
|
IFactoryClass extends (...args: any) => InstanceType<AFactoryClass>,
|
||||||
|
DFactoryClass extends MapParametersToDeps<Parameters<IFactoryClass>>,
|
||||||
|
// types for useExisting
|
||||||
|
AExisting extends Constructor<any> | AbstractConstructor<any>,
|
||||||
|
IExisting extends
|
||||||
|
| Constructor<InstanceType<AExisting>>
|
||||||
|
| AbstractConstructor<InstanceType<AExisting>>,
|
||||||
|
>(
|
||||||
|
provider:
|
||||||
|
| SafeClassProvider<AClass, IClass, DClass>
|
||||||
|
| SafeValueProvider<AValue, VValue>
|
||||||
|
| SafeFactoryProviderWithToken<AFactoryToken, IFactoryToken, DFactoryToken>
|
||||||
|
| SafeFactoryProviderWithClass<AFactoryClass, IFactoryClass, DFactoryClass>
|
||||||
|
| SafeExistingProvider<AExisting, IExisting>
|
||||||
|
| Constructor<unknown>,
|
||||||
|
): SafeProvider => provider as SafeProvider;
|
@ -7,26 +7,39 @@ import {
|
|||||||
} from "@bitwarden/common/platform/abstractions/storage.service";
|
} from "@bitwarden/common/platform/abstractions/storage.service";
|
||||||
import { StateFactory } from "@bitwarden/common/platform/factories/state-factory";
|
import { StateFactory } from "@bitwarden/common/platform/factories/state-factory";
|
||||||
|
|
||||||
export const WINDOW = new InjectionToken<Window>("WINDOW");
|
declare const tag: unique symbol;
|
||||||
export const OBSERVABLE_MEMORY_STORAGE = new InjectionToken<
|
/**
|
||||||
|
* A (more) typesafe version of InjectionToken which will more strictly enforce the generic type parameter.
|
||||||
|
* @remarks The default angular implementation does not use the generic type to define the structure of the object,
|
||||||
|
* so the structural type system will not complain about a mismatch in the type parameter.
|
||||||
|
* This is solved by assigning T to an arbitrary private property.
|
||||||
|
*/
|
||||||
|
export class SafeInjectionToken<T> extends InjectionToken<T> {
|
||||||
|
private readonly [tag]: T;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const WINDOW = new SafeInjectionToken<Window>("WINDOW");
|
||||||
|
export const OBSERVABLE_MEMORY_STORAGE = new SafeInjectionToken<
|
||||||
AbstractMemoryStorageService & ObservableStorageService
|
AbstractMemoryStorageService & ObservableStorageService
|
||||||
>("OBSERVABLE_MEMORY_STORAGE");
|
>("OBSERVABLE_MEMORY_STORAGE");
|
||||||
export const OBSERVABLE_DISK_STORAGE = new InjectionToken<
|
export const OBSERVABLE_DISK_STORAGE = new SafeInjectionToken<
|
||||||
AbstractStorageService & ObservableStorageService
|
AbstractStorageService & ObservableStorageService
|
||||||
>("OBSERVABLE_DISK_STORAGE");
|
>("OBSERVABLE_DISK_STORAGE");
|
||||||
export const OBSERVABLE_DISK_LOCAL_STORAGE = new InjectionToken<
|
export const OBSERVABLE_DISK_LOCAL_STORAGE = new SafeInjectionToken<
|
||||||
AbstractStorageService & ObservableStorageService
|
AbstractStorageService & ObservableStorageService
|
||||||
>("OBSERVABLE_DISK_LOCAL_STORAGE");
|
>("OBSERVABLE_DISK_LOCAL_STORAGE");
|
||||||
export const MEMORY_STORAGE = new InjectionToken<AbstractMemoryStorageService>("MEMORY_STORAGE");
|
export const MEMORY_STORAGE = new SafeInjectionToken<AbstractMemoryStorageService>(
|
||||||
export const SECURE_STORAGE = new InjectionToken<AbstractStorageService>("SECURE_STORAGE");
|
"MEMORY_STORAGE",
|
||||||
export const STATE_FACTORY = new InjectionToken<StateFactory>("STATE_FACTORY");
|
);
|
||||||
export const STATE_SERVICE_USE_CACHE = new InjectionToken<boolean>("STATE_SERVICE_USE_CACHE");
|
export const SECURE_STORAGE = new SafeInjectionToken<AbstractStorageService>("SECURE_STORAGE");
|
||||||
export const LOGOUT_CALLBACK = new InjectionToken<
|
export const STATE_FACTORY = new SafeInjectionToken<StateFactory>("STATE_FACTORY");
|
||||||
|
export const STATE_SERVICE_USE_CACHE = new SafeInjectionToken<boolean>("STATE_SERVICE_USE_CACHE");
|
||||||
|
export const LOGOUT_CALLBACK = new SafeInjectionToken<
|
||||||
(expired: boolean, userId?: string) => Promise<void>
|
(expired: boolean, userId?: string) => Promise<void>
|
||||||
>("LOGOUT_CALLBACK");
|
>("LOGOUT_CALLBACK");
|
||||||
export const LOCKED_CALLBACK = new InjectionToken<(userId?: string) => Promise<void>>(
|
export const LOCKED_CALLBACK = new SafeInjectionToken<(userId?: string) => Promise<void>>(
|
||||||
"LOCKED_CALLBACK",
|
"LOCKED_CALLBACK",
|
||||||
);
|
);
|
||||||
export const LOCALES_DIRECTORY = new InjectionToken<string>("LOCALES_DIRECTORY");
|
export const LOCALES_DIRECTORY = new SafeInjectionToken<string>("LOCALES_DIRECTORY");
|
||||||
export const SYSTEM_LANGUAGE = new InjectionToken<string>("SYSTEM_LANGUAGE");
|
export const SYSTEM_LANGUAGE = new SafeInjectionToken<string>("SYSTEM_LANGUAGE");
|
||||||
export const LOG_MAC_FAILURES = new InjectionToken<string>("LOG_MAC_FAILURES");
|
export const LOG_MAC_FAILURES = new SafeInjectionToken<boolean>("LOG_MAC_FAILURES");
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user