1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-02 00:23:35 +00:00

Add State Provider Framework (#6640)

* Add StateDefinition

Add a class for encapsulation information about state
this will often be for a domain but creations of this will
exist outside of a specific domain, hence just the name State.

* Add KeyDefinition

This adds a type that extends state definition into another sub-key
and forces creators to define the data that will be stored and how
to read the data that they expect to be stored.

* Add key-builders helper functions

Adds to function to help building keys for both keys scoped
to a specific user and for keys scoped to global storage.

Co-authored-by: Matt Gibson <MGibson1@users.noreply.github.com>

* Add updates$ stream to existing storageServices

Original commit by Matt: 823d9546fe
Co-authored-by: Matt Gibson <MGibson1@users.noreply.github.com>

* Add fromChromeEvent helper

Create a helper that creats an Observable from a chrome event
and removes the listener when the subscription is completed.

* Implement `updates$` property for chrome storage

Use fromChromeEvent to create an observable from chrome
event and map that into our expected shape.

* Add GlobalState Abstractions

* Add UserState Abstractions

* Add Default Implementations of User/Global state

Co-authored-by: Matt Gibson <MGibson1@users.noreply.github.com>

* Add Barrel File for state

Co-authored-by: Matt Gibson <MGibson1@users.noreply.github.com>

* Fix ChromeStorageServices

* Rework fromChromeEvent

Rework fromChromeEvent so we have to lie to TS less and
remove unneeded generics. I did this by caring less about
the function and more about the parameters only.

Co-authored-by: Matt Gibson <MGibson1@users.noreply.github.com>

* Fix UserStateProvider Test

* Add Inner Mock & Assert Calls

* Update Tests to use new keys

Use different key format

* Prefer returns over mutations in update

* Update Tests

* Address PR Feedback

* Be stricter with userId parameter

* Add Better Way To Determine if it was a remove

* Fix Web & Browser Storage Services

* Fix Desktop & CLI Storage Services

* Fix Test Storage Service

* Use createKey Helper

* Prefer implement to extending

* Determine storage location in providers

* Export default providers publicly

* Fix user state tests

* Name tests

* Fix CLI

* Prefer Implement In Chrome Storage

* Remove Secure Storage Option

Also throw an exception for subscribes to the secure storage observable.

* Update apps/browser/src/platform/browser/from-chrome-event.ts

Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com>

* Enforce state module barrel file

* Fix Linting Error

* Allow state module import from other modules

* Globally Unregister fromChromeEvent Listeners

Changed fromChromeEvent to add its listeners through the BrowserApi, so that
they will be unregistered when safari closes.

* Test default global state

* Use Proper Casing in Parameter

* Address Feedback

* Update libs/common/src/platform/state/key-definition.ts

Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com>

* Add `buildCacheKey` Method

* Fix lint errors

* Add Comment

Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com>

* Use Generic in callback parameter

* Refactor Out DerivedStateDefinition

* Persist Listener Return Type

* Add Ticket Link

---------

Co-authored-by: Matt Gibson <MGibson1@users.noreply.github.com>
Co-authored-by: Matt Gibson <mgibson@bitwarden.com>
Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com>
This commit is contained in:
Justin Baur
2023-11-09 17:06:42 -05:00
committed by GitHub
parent 801141f90e
commit e1b5b83723
36 changed files with 1352 additions and 68 deletions

View File

@@ -1,7 +1,15 @@
import { throwError } from "rxjs";
import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service";
import { StorageOptions } from "@bitwarden/common/platform/models/domain/storage-options";
export class ElectronRendererSecureStorageService implements AbstractStorageService {
get updates$() {
return throwError(
() => new Error("Secure storage implementations cannot have their updates subscribed to.")
);
}
async get<T>(key: string, options?: StorageOptions): Promise<T> {
const val = await ipc.platform.passwords.get(key, options?.keySuffix ?? "");
return val != null ? (JSON.parse(val) as T) : null;
@@ -12,11 +20,11 @@ export class ElectronRendererSecureStorageService implements AbstractStorageServ
return !!val;
}
async save(key: string, obj: any, options?: StorageOptions): Promise<any> {
async save<T>(key: string, obj: T, options?: StorageOptions): Promise<void> {
await ipc.platform.passwords.set(key, options?.keySuffix ?? "", JSON.stringify(obj));
}
async remove(key: string, options?: StorageOptions): Promise<any> {
async remove(key: string, options?: StorageOptions): Promise<void> {
await ipc.platform.passwords.delete(key, options?.keySuffix ?? "");
}
}

View File

@@ -1,6 +1,17 @@
import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service";
import { Subject } from "rxjs";
import {
AbstractStorageService,
StorageUpdate,
} from "@bitwarden/common/platform/abstractions/storage.service";
export class ElectronRendererStorageService implements AbstractStorageService {
private updatesSubject = new Subject<StorageUpdate>();
get updates$() {
return this.updatesSubject.asObservable();
}
get<T>(key: string): Promise<T> {
return ipc.platform.storage.get(key);
}
@@ -9,11 +20,13 @@ export class ElectronRendererStorageService implements AbstractStorageService {
return ipc.platform.storage.has(key);
}
save(key: string, obj: any): Promise<any> {
return ipc.platform.storage.save(key, obj);
async save<T>(key: string, obj: T): Promise<void> {
await ipc.platform.storage.save(key, obj);
this.updatesSubject.next({ key, value: obj, updateType: "save" });
}
remove(key: string): Promise<any> {
return ipc.platform.storage.remove(key);
async remove(key: string): Promise<void> {
await ipc.platform.storage.remove(key);
this.updatesSubject.next({ key, value: null, updateType: "remove" });
}
}

View File

@@ -1,9 +1,13 @@
import * as fs from "fs";
import { ipcMain } from "electron";
import { Subject } from "rxjs";
import { NodeUtils } from "@bitwarden/common/misc/nodeUtils";
import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service";
import {
AbstractStorageService,
StorageUpdate,
} from "@bitwarden/common/platform/abstractions/storage.service";
// See: https://github.com/sindresorhus/electron-store/blob/main/index.d.ts
interface ElectronStoreOptions {
@@ -35,6 +39,7 @@ type Options = BaseOptions<"get"> | BaseOptions<"has"> | SaveOptions | BaseOptio
export class ElectronStorageService implements AbstractStorageService {
private store: ElectronStore;
private updatesSubject = new Subject<StorageUpdate>();
constructor(dir: string, defaults = {}) {
if (!fs.existsSync(dir)) {
@@ -60,6 +65,10 @@ export class ElectronStorageService implements AbstractStorageService {
});
}
get updates$() {
return this.updatesSubject.asObservable();
}
get<T>(key: string): Promise<T> {
const val = this.store.get(key) as T;
return Promise.resolve(val != null ? val : null);
@@ -75,11 +84,13 @@ export class ElectronStorageService implements AbstractStorageService {
obj = Array.from(obj);
}
this.store.set(key, obj);
this.updatesSubject.next({ key, value: obj, updateType: "save" });
return Promise.resolve();
}
remove(key: string): Promise<void> {
this.store.delete(key);
this.updatesSubject.next({ key, value: null, updateType: "remove" });
return Promise.resolve();
}
}