mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 07:43:35 +00:00
[PM-5829] Add disk-local option for web (#7669)
* Add `disk-local` option for web * Fix `web` DI * Update libs/common/src/platform/state/state-definition.ts Co-authored-by: Matt Gibson <mgibson@bitwarden.com> * Rely On Default Implementation for Most of Cache Key --------- Co-authored-by: Matt Gibson <mgibson@bitwarden.com>
This commit is contained in:
@@ -10,9 +10,11 @@ import {
|
||||
MEMORY_STORAGE,
|
||||
OBSERVABLE_MEMORY_STORAGE,
|
||||
OBSERVABLE_DISK_STORAGE,
|
||||
OBSERVABLE_DISK_LOCAL_STORAGE,
|
||||
} from "@bitwarden/angular/services/injection-tokens";
|
||||
import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module";
|
||||
import { ModalService as ModalServiceAbstraction } from "@bitwarden/angular/services/modal.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { LoginService as LoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/login.service";
|
||||
import { LoginService } from "@bitwarden/common/auth/services/login.service";
|
||||
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
||||
@@ -23,10 +25,19 @@ import { StateService as BaseStateServiceAbstraction } from "@bitwarden/common/p
|
||||
import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service";
|
||||
import { StateFactory } from "@bitwarden/common/platform/factories/state-factory";
|
||||
import { MemoryStorageService } from "@bitwarden/common/platform/services/memory-storage.service";
|
||||
import {
|
||||
ActiveUserStateProvider,
|
||||
GlobalStateProvider,
|
||||
SingleUserStateProvider,
|
||||
} from "@bitwarden/common/platform/state";
|
||||
|
||||
import { PolicyListService } from "../admin-console/core/policy-list.service";
|
||||
import { HtmlStorageService } from "../core/html-storage.service";
|
||||
import { I18nService } from "../core/i18n.service";
|
||||
import { WebActiveUserStateProvider } from "../platform/web-active-user-state.provider";
|
||||
import { WebGlobalStateProvider } from "../platform/web-global-state.provider";
|
||||
import { WebSingleUserStateProvider } from "../platform/web-single-user-state.provider";
|
||||
import { WindowStorageService } from "../platform/window-storage.service";
|
||||
import { CollectionAdminService } from "../vault/core/collection-admin.service";
|
||||
|
||||
import { BroadcasterMessagingService } from "./broadcaster-messaging.service";
|
||||
@@ -77,7 +88,10 @@ import { WebPlatformUtilsService } from "./web-platform-utils.service";
|
||||
useClass: MemoryStorageService,
|
||||
},
|
||||
{ provide: OBSERVABLE_MEMORY_STORAGE, useExisting: MEMORY_STORAGE },
|
||||
{ provide: OBSERVABLE_DISK_STORAGE, useExisting: AbstractStorageService },
|
||||
{
|
||||
provide: OBSERVABLE_DISK_STORAGE,
|
||||
useFactory: () => new WindowStorageService(window.sessionStorage),
|
||||
},
|
||||
{
|
||||
provide: PlatformUtilsServiceAbstraction,
|
||||
useClass: WebPlatformUtilsService,
|
||||
@@ -99,6 +113,30 @@ import { WebPlatformUtilsService } from "./web-platform-utils.service";
|
||||
deps: [StateService],
|
||||
},
|
||||
CollectionAdminService,
|
||||
{
|
||||
provide: OBSERVABLE_DISK_LOCAL_STORAGE,
|
||||
useFactory: () => new WindowStorageService(window.localStorage),
|
||||
},
|
||||
{
|
||||
provide: SingleUserStateProvider,
|
||||
useClass: WebSingleUserStateProvider,
|
||||
deps: [MEMORY_STORAGE, OBSERVABLE_DISK_STORAGE, OBSERVABLE_DISK_LOCAL_STORAGE],
|
||||
},
|
||||
{
|
||||
provide: ActiveUserStateProvider,
|
||||
useClass: WebActiveUserStateProvider,
|
||||
deps: [
|
||||
AccountService,
|
||||
MEMORY_STORAGE,
|
||||
OBSERVABLE_DISK_STORAGE,
|
||||
OBSERVABLE_DISK_LOCAL_STORAGE,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: GlobalStateProvider,
|
||||
useClass: WebGlobalStateProvider,
|
||||
deps: [MEMORY_STORAGE, OBSERVABLE_DISK_STORAGE, OBSERVABLE_DISK_LOCAL_STORAGE],
|
||||
},
|
||||
],
|
||||
})
|
||||
export class CoreModule {
|
||||
|
||||
44
apps/web/src/app/platform/web-active-user-state.provider.ts
Normal file
44
apps/web/src/app/platform/web-active-user-state.provider.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import {
|
||||
AbstractMemoryStorageService,
|
||||
AbstractStorageService,
|
||||
ObservableStorageService,
|
||||
} from "@bitwarden/common/platform/abstractions/storage.service";
|
||||
import { KeyDefinition } from "@bitwarden/common/platform/state";
|
||||
/* eslint-disable import/no-restricted-paths -- Needed to extend class & in platform owned code */
|
||||
import { DefaultActiveUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-active-user-state.provider";
|
||||
import { StateDefinition } from "@bitwarden/common/platform/state/state-definition";
|
||||
/* eslint-enable import/no-restricted-paths */
|
||||
|
||||
export class WebActiveUserStateProvider extends DefaultActiveUserStateProvider {
|
||||
constructor(
|
||||
accountService: AccountService,
|
||||
memoryStorage: AbstractMemoryStorageService & ObservableStorageService,
|
||||
sessionStorage: AbstractStorageService & ObservableStorageService,
|
||||
private readonly diskLocalStorage: AbstractStorageService & ObservableStorageService,
|
||||
) {
|
||||
super(accountService, memoryStorage, sessionStorage);
|
||||
}
|
||||
|
||||
protected override getLocationString(keyDefinition: KeyDefinition<unknown>): string {
|
||||
return (
|
||||
keyDefinition.stateDefinition.storageLocationOverrides["web"] ??
|
||||
keyDefinition.stateDefinition.defaultStorageLocation
|
||||
);
|
||||
}
|
||||
|
||||
protected override getLocation(
|
||||
stateDefinition: StateDefinition,
|
||||
): AbstractStorageService & ObservableStorageService {
|
||||
const location =
|
||||
stateDefinition.storageLocationOverrides["web"] ?? stateDefinition.defaultStorageLocation;
|
||||
switch (location) {
|
||||
case "disk":
|
||||
return this.diskStorage;
|
||||
case "memory":
|
||||
return this.memoryStorage;
|
||||
case "disk-local":
|
||||
return this.diskLocalStorage;
|
||||
}
|
||||
}
|
||||
}
|
||||
42
apps/web/src/app/platform/web-global-state.provider.ts
Normal file
42
apps/web/src/app/platform/web-global-state.provider.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import {
|
||||
AbstractMemoryStorageService,
|
||||
AbstractStorageService,
|
||||
ObservableStorageService,
|
||||
} from "@bitwarden/common/platform/abstractions/storage.service";
|
||||
import { KeyDefinition } from "@bitwarden/common/platform/state";
|
||||
/* eslint-disable import/no-restricted-paths -- Needed to extend class & in platform owned code*/
|
||||
import { DefaultGlobalStateProvider } from "@bitwarden/common/platform/state/implementations/default-global-state.provider";
|
||||
import { StateDefinition } from "@bitwarden/common/platform/state/state-definition";
|
||||
/* eslint-enable import/no-restricted-paths */
|
||||
|
||||
export class WebGlobalStateProvider extends DefaultGlobalStateProvider {
|
||||
constructor(
|
||||
memoryStorage: AbstractMemoryStorageService & ObservableStorageService,
|
||||
sessionStorage: AbstractStorageService & ObservableStorageService,
|
||||
private readonly diskLocalStorage: AbstractStorageService & ObservableStorageService,
|
||||
) {
|
||||
super(memoryStorage, sessionStorage);
|
||||
}
|
||||
|
||||
protected getLocationString(keyDefinition: KeyDefinition<unknown>): string {
|
||||
return (
|
||||
keyDefinition.stateDefinition.storageLocationOverrides["web"] ??
|
||||
keyDefinition.stateDefinition.defaultStorageLocation
|
||||
);
|
||||
}
|
||||
|
||||
protected override getLocation(
|
||||
stateDefinition: StateDefinition,
|
||||
): AbstractStorageService & ObservableStorageService {
|
||||
const location =
|
||||
stateDefinition.storageLocationOverrides["web"] ?? stateDefinition.defaultStorageLocation;
|
||||
switch (location) {
|
||||
case "disk":
|
||||
return this.diskStorage;
|
||||
case "memory":
|
||||
return this.memoryStorage;
|
||||
case "disk-local":
|
||||
return this.diskLocalStorage;
|
||||
}
|
||||
}
|
||||
}
|
||||
43
apps/web/src/app/platform/web-single-user-state.provider.ts
Normal file
43
apps/web/src/app/platform/web-single-user-state.provider.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import {
|
||||
AbstractMemoryStorageService,
|
||||
AbstractStorageService,
|
||||
ObservableStorageService,
|
||||
} from "@bitwarden/common/platform/abstractions/storage.service";
|
||||
import { KeyDefinition } from "@bitwarden/common/platform/state";
|
||||
/* eslint-disable import/no-restricted-paths -- Needed to extend service & and in platform owned file */
|
||||
import { DefaultSingleUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-single-user-state.provider";
|
||||
import { StateDefinition } from "@bitwarden/common/platform/state/state-definition";
|
||||
/* eslint-enable import/no-restricted-paths */
|
||||
|
||||
export class WebSingleUserStateProvider extends DefaultSingleUserStateProvider {
|
||||
constructor(
|
||||
memoryStorageService: AbstractMemoryStorageService & ObservableStorageService,
|
||||
sessionStorageService: AbstractStorageService & ObservableStorageService,
|
||||
private readonly diskLocalStorageService: AbstractStorageService & ObservableStorageService,
|
||||
) {
|
||||
super(memoryStorageService, sessionStorageService);
|
||||
}
|
||||
|
||||
protected override getLocationString(keyDefinition: KeyDefinition<unknown>): string {
|
||||
return (
|
||||
keyDefinition.stateDefinition.storageLocationOverrides["web"] ??
|
||||
keyDefinition.stateDefinition.defaultStorageLocation
|
||||
);
|
||||
}
|
||||
|
||||
protected override getLocation(
|
||||
stateDefinition: StateDefinition,
|
||||
): AbstractStorageService & ObservableStorageService {
|
||||
const location =
|
||||
stateDefinition.storageLocationOverrides["web"] ?? stateDefinition.defaultStorageLocation;
|
||||
|
||||
switch (location) {
|
||||
case "disk":
|
||||
return this.diskStorage;
|
||||
case "memory":
|
||||
return this.memoryStorage;
|
||||
case "disk-local":
|
||||
return this.diskLocalStorageService;
|
||||
}
|
||||
}
|
||||
}
|
||||
53
apps/web/src/app/platform/window-storage.service.ts
Normal file
53
apps/web/src/app/platform/window-storage.service.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { Observable, Subject } from "rxjs";
|
||||
|
||||
import {
|
||||
AbstractStorageService,
|
||||
ObservableStorageService,
|
||||
StorageUpdate,
|
||||
} from "@bitwarden/common/platform/abstractions/storage.service";
|
||||
import { StorageOptions } from "@bitwarden/common/platform/models/domain/storage-options";
|
||||
|
||||
export class WindowStorageService implements AbstractStorageService, ObservableStorageService {
|
||||
private readonly updatesSubject = new Subject<StorageUpdate>();
|
||||
|
||||
updates$: Observable<StorageUpdate>;
|
||||
constructor(private readonly storage: Storage) {
|
||||
this.updates$ = this.updatesSubject.asObservable();
|
||||
}
|
||||
|
||||
get valuesRequireDeserialization(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
get<T>(key: string, options?: StorageOptions): Promise<T> {
|
||||
const jsonValue = this.storage.getItem(key);
|
||||
if (jsonValue != null) {
|
||||
return Promise.resolve(JSON.parse(jsonValue) as T);
|
||||
}
|
||||
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
async has(key: string, options?: StorageOptions): Promise<boolean> {
|
||||
return (await this.get(key, options)) != null;
|
||||
}
|
||||
|
||||
save<T>(key: string, obj: T, options?: StorageOptions): Promise<void> {
|
||||
if (obj == null) {
|
||||
return this.remove(key, options);
|
||||
}
|
||||
|
||||
if (obj instanceof Set) {
|
||||
obj = Array.from(obj) as T;
|
||||
}
|
||||
|
||||
this.storage.setItem(key, JSON.stringify(obj));
|
||||
this.updatesSubject.next({ key, updateType: "save" });
|
||||
}
|
||||
|
||||
remove(key: string, options?: StorageOptions): Promise<void> {
|
||||
this.storage.removeItem(key);
|
||||
this.updatesSubject.next({ key, updateType: "remove" });
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user