mirror of
https://github.com/bitwarden/browser.git
synced 2025-01-02 18:17:46 +01:00
Add updates$ stream to existing storageServices
This commit is contained in:
parent
604671d70c
commit
823d9546fe
@ -1,6 +1,6 @@
|
|||||||
import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service";
|
import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service";
|
||||||
|
|
||||||
export default abstract class AbstractChromeStorageService implements AbstractStorageService {
|
export default abstract class AbstractChromeStorageService extends AbstractStorageService {
|
||||||
protected abstract chromeStorageApi: chrome.storage.StorageArea;
|
protected abstract chromeStorageApi: chrome.storage.StorageArea;
|
||||||
|
|
||||||
async get<T>(key: string): Promise<T> {
|
async get<T>(key: string): Promise<T> {
|
||||||
@ -22,11 +22,7 @@ export default abstract class AbstractChromeStorageService implements AbstractSt
|
|||||||
async save(key: string, obj: any): Promise<void> {
|
async save(key: string, obj: any): Promise<void> {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
// Fix safari not liking null in set
|
// Fix safari not liking null in set
|
||||||
return new Promise<void>((resolve) => {
|
return this.remove(key);
|
||||||
this.chromeStorageApi.remove(key, () => {
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj instanceof Set) {
|
if (obj instanceof Set) {
|
||||||
@ -36,6 +32,7 @@ export default abstract class AbstractChromeStorageService implements AbstractSt
|
|||||||
const keyedObj = { [key]: obj };
|
const keyedObj = { [key]: obj };
|
||||||
return new Promise<void>((resolve) => {
|
return new Promise<void>((resolve) => {
|
||||||
this.chromeStorageApi.set(keyedObj, () => {
|
this.chromeStorageApi.set(keyedObj, () => {
|
||||||
|
this.updatesSubject.next({ key, value: obj, updateType: "save" });
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -44,6 +41,7 @@ export default abstract class AbstractChromeStorageService implements AbstractSt
|
|||||||
async remove(key: string): Promise<void> {
|
async remove(key: string): Promise<void> {
|
||||||
return new Promise<void>((resolve) => {
|
return new Promise<void>((resolve) => {
|
||||||
this.chromeStorageApi.remove(key, () => {
|
this.chromeStorageApi.remove(key, () => {
|
||||||
|
this.updatesSubject.next({ key, value: null, updateType: "remove" });
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -19,7 +19,7 @@ const retries: OperationOptions = {
|
|||||||
factor: 2,
|
factor: 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
export class LowdbStorageService implements AbstractStorageService {
|
export class LowdbStorageService extends AbstractStorageService {
|
||||||
protected dataFilePath: string;
|
protected dataFilePath: string;
|
||||||
private db: lowdb.LowdbSync<any>;
|
private db: lowdb.LowdbSync<any>;
|
||||||
private defaults: any;
|
private defaults: any;
|
||||||
@ -32,6 +32,7 @@ export class LowdbStorageService implements AbstractStorageService {
|
|||||||
private allowCache = false,
|
private allowCache = false,
|
||||||
private requireLock = false
|
private requireLock = false
|
||||||
) {
|
) {
|
||||||
|
super();
|
||||||
this.defaults = defaults;
|
this.defaults = defaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,21 +120,23 @@ export class LowdbStorageService implements AbstractStorageService {
|
|||||||
return this.get(key).then((v) => v != null);
|
return this.get(key).then((v) => v != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
async save(key: string, obj: any): Promise<any> {
|
async save(key: string, obj: any): Promise<void> {
|
||||||
await this.waitForReady();
|
await this.waitForReady();
|
||||||
return this.lockDbFile(() => {
|
return this.lockDbFile(() => {
|
||||||
this.readForNoCache();
|
this.readForNoCache();
|
||||||
this.db.set(key, obj).write();
|
this.db.set(key, obj).write();
|
||||||
|
this.updatesSubject.next({ key, value: obj, updateType: "save" });
|
||||||
this.logService.debug(`Successfully wrote ${key} to db`);
|
this.logService.debug(`Successfully wrote ${key} to db`);
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove(key: string): Promise<any> {
|
async remove(key: string): Promise<void> {
|
||||||
await this.waitForReady();
|
await this.waitForReady();
|
||||||
return this.lockDbFile(() => {
|
return this.lockDbFile(() => {
|
||||||
this.readForNoCache();
|
this.readForNoCache();
|
||||||
this.db.unset(key).write();
|
this.db.unset(key).write();
|
||||||
|
this.updatesSubject.next({ key, value: null, updateType: "remove" });
|
||||||
this.logService.debug(`Successfully removed ${key} from db`);
|
this.logService.debug(`Successfully removed ${key} from db`);
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
|
@ -5,12 +5,14 @@ import { Utils } from "@bitwarden/common/platform/misc/utils";
|
|||||||
import { EncArrayBuffer } from "@bitwarden/common/platform/models/domain/enc-array-buffer";
|
import { EncArrayBuffer } from "@bitwarden/common/platform/models/domain/enc-array-buffer";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
|
|
||||||
export class NodeEnvSecureStorageService implements AbstractStorageService {
|
export class NodeEnvSecureStorageService extends AbstractStorageService {
|
||||||
constructor(
|
constructor(
|
||||||
private storageService: AbstractStorageService,
|
private storageService: AbstractStorageService,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
private cryptoService: () => CryptoService
|
private cryptoService: () => CryptoService
|
||||||
) {}
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
async get<T>(key: string): Promise<T> {
|
async get<T>(key: string): Promise<T> {
|
||||||
const value = await this.storageService.get<string>(this.makeProtectedStorageKey(key));
|
const value = await this.storageService.get<string>(this.makeProtectedStorageKey(key));
|
||||||
@ -25,7 +27,7 @@ export class NodeEnvSecureStorageService implements AbstractStorageService {
|
|||||||
return (await this.get(key)) != null;
|
return (await this.get(key)) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async save(key: string, obj: any): Promise<any> {
|
async save(key: string, obj: any): Promise<void> {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return this.remove(key);
|
return this.remove(key);
|
||||||
}
|
}
|
||||||
@ -35,10 +37,13 @@ export class NodeEnvSecureStorageService implements AbstractStorageService {
|
|||||||
}
|
}
|
||||||
const protectedObj = await this.encrypt(obj);
|
const protectedObj = await this.encrypt(obj);
|
||||||
await this.storageService.save(this.makeProtectedStorageKey(key), protectedObj);
|
await this.storageService.save(this.makeProtectedStorageKey(key), protectedObj);
|
||||||
|
this.updatesSubject.next({ key, value: obj, updateType: "save" });
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(key: string): Promise<any> {
|
async remove(key: string): Promise<void> {
|
||||||
return this.storageService.remove(this.makeProtectedStorageKey(key));
|
await this.storageService.remove(this.makeProtectedStorageKey(key));
|
||||||
|
this.updatesSubject.next({ key, value: null, updateType: "remove" });
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async encrypt(plainValue: string): Promise<string> {
|
private async encrypt(plainValue: string): Promise<string> {
|
||||||
|
@ -3,7 +3,7 @@ import { ipcRenderer } from "electron";
|
|||||||
import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service";
|
import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service";
|
||||||
import { StorageOptions } from "@bitwarden/common/platform/models/domain/storage-options";
|
import { StorageOptions } from "@bitwarden/common/platform/models/domain/storage-options";
|
||||||
|
|
||||||
export class ElectronRendererSecureStorageService implements AbstractStorageService {
|
export class ElectronRendererSecureStorageService extends AbstractStorageService {
|
||||||
async get<T>(key: string, options?: StorageOptions): Promise<T> {
|
async get<T>(key: string, options?: StorageOptions): Promise<T> {
|
||||||
const val = await ipcRenderer.invoke("keytar", {
|
const val = await ipcRenderer.invoke("keytar", {
|
||||||
action: "getPassword",
|
action: "getPassword",
|
||||||
@ -22,20 +22,22 @@ export class ElectronRendererSecureStorageService implements AbstractStorageServ
|
|||||||
return !!val;
|
return !!val;
|
||||||
}
|
}
|
||||||
|
|
||||||
async save(key: string, obj: any, options?: StorageOptions): Promise<any> {
|
async save<T>(key: string, obj: T, options?: StorageOptions): Promise<void> {
|
||||||
await ipcRenderer.invoke("keytar", {
|
await ipcRenderer.invoke("keytar", {
|
||||||
action: "setPassword",
|
action: "setPassword",
|
||||||
key: key,
|
key: key,
|
||||||
keySuffix: options?.keySuffix ?? "",
|
keySuffix: options?.keySuffix ?? "",
|
||||||
value: JSON.stringify(obj),
|
value: JSON.stringify(obj),
|
||||||
});
|
});
|
||||||
|
this.updatesSubject.next({ key, value: obj, updateType: "save" });
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove(key: string, options?: StorageOptions): Promise<any> {
|
async remove(key: string, options?: StorageOptions): Promise<void> {
|
||||||
await ipcRenderer.invoke("keytar", {
|
await ipcRenderer.invoke("keytar", {
|
||||||
action: "deletePassword",
|
action: "deletePassword",
|
||||||
key: key,
|
key: key,
|
||||||
keySuffix: options?.keySuffix ?? "",
|
keySuffix: options?.keySuffix ?? "",
|
||||||
});
|
});
|
||||||
|
this.updatesSubject.next({ key, value: null, updateType: "remove" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { ipcRenderer } from "electron";
|
|||||||
|
|
||||||
import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service";
|
import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service";
|
||||||
|
|
||||||
export class ElectronRendererStorageService implements AbstractStorageService {
|
export class ElectronRendererStorageService extends AbstractStorageService {
|
||||||
get<T>(key: string): Promise<T> {
|
get<T>(key: string): Promise<T> {
|
||||||
return ipcRenderer.invoke("storageService", {
|
return ipcRenderer.invoke("storageService", {
|
||||||
action: "get",
|
action: "get",
|
||||||
@ -17,18 +17,20 @@ export class ElectronRendererStorageService implements AbstractStorageService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
save(key: string, obj: any): Promise<any> {
|
async save<T>(key: string, obj: T): Promise<void> {
|
||||||
return ipcRenderer.invoke("storageService", {
|
await ipcRenderer.invoke("storageService", {
|
||||||
action: "save",
|
action: "save",
|
||||||
key: key,
|
key: key,
|
||||||
obj: obj,
|
obj: obj,
|
||||||
});
|
});
|
||||||
|
this.updatesSubject.next({ key, value: obj, updateType: "save" });
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(key: string): Promise<any> {
|
async remove(key: string): Promise<void> {
|
||||||
return ipcRenderer.invoke("storageService", {
|
await ipcRenderer.invoke("storageService", {
|
||||||
action: "remove",
|
action: "remove",
|
||||||
key: key,
|
key: key,
|
||||||
});
|
});
|
||||||
|
this.updatesSubject.next({ key, value: null, updateType: "remove" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,10 +33,11 @@ interface SaveOptions extends BaseOptions<"save"> {
|
|||||||
|
|
||||||
type Options = BaseOptions<"get"> | BaseOptions<"has"> | SaveOptions | BaseOptions<"remove">;
|
type Options = BaseOptions<"get"> | BaseOptions<"has"> | SaveOptions | BaseOptions<"remove">;
|
||||||
|
|
||||||
export class ElectronStorageService implements AbstractStorageService {
|
export class ElectronStorageService extends AbstractStorageService {
|
||||||
private store: ElectronStore;
|
private store: ElectronStore;
|
||||||
|
|
||||||
constructor(dir: string, defaults = {}) {
|
constructor(dir: string, defaults = {}) {
|
||||||
|
super();
|
||||||
if (!fs.existsSync(dir)) {
|
if (!fs.existsSync(dir)) {
|
||||||
NodeUtils.mkdirpSync(dir, "700");
|
NodeUtils.mkdirpSync(dir, "700");
|
||||||
}
|
}
|
||||||
@ -75,11 +76,13 @@ export class ElectronStorageService implements AbstractStorageService {
|
|||||||
obj = Array.from(obj);
|
obj = Array.from(obj);
|
||||||
}
|
}
|
||||||
this.store.set(key, obj);
|
this.store.set(key, obj);
|
||||||
|
this.updatesSubject.next({ key, value: obj, updateType: "save" });
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(key: string): Promise<void> {
|
remove(key: string): Promise<void> {
|
||||||
this.store.delete(key);
|
this.store.delete(key);
|
||||||
|
this.updatesSubject.next({ key, value: null, updateType: "remove" });
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/
|
|||||||
import { StorageOptions } from "@bitwarden/common/platform/models/domain/storage-options";
|
import { StorageOptions } from "@bitwarden/common/platform/models/domain/storage-options";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class HtmlStorageService implements AbstractStorageService {
|
export class HtmlStorageService extends AbstractStorageService {
|
||||||
get defaultOptions(): StorageOptions {
|
get defaultOptions(): StorageOptions {
|
||||||
return { htmlStorageLocation: HtmlStorageLocation.Session };
|
return { htmlStorageLocation: HtmlStorageLocation.Session };
|
||||||
}
|
}
|
||||||
@ -52,6 +52,7 @@ export class HtmlStorageService implements AbstractStorageService {
|
|||||||
window.sessionStorage.setItem(key, json);
|
window.sessionStorage.setItem(key, json);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
this.updatesSubject.next({ key, value: obj, updateType: "save" });
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,6 +66,7 @@ export class HtmlStorageService implements AbstractStorageService {
|
|||||||
window.sessionStorage.removeItem(key);
|
window.sessionStorage.removeItem(key);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
this.updatesSubject.next({ key, value: null, updateType: "remove" });
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,16 @@
|
|||||||
|
import { Subject } from "rxjs";
|
||||||
|
|
||||||
import { MemoryStorageOptions, StorageOptions } from "../models/domain/storage-options";
|
import { MemoryStorageOptions, StorageOptions } from "../models/domain/storage-options";
|
||||||
|
|
||||||
|
export type StorageUpdateType = "save" | "remove";
|
||||||
|
|
||||||
export abstract class AbstractStorageService {
|
export abstract class AbstractStorageService {
|
||||||
|
protected readonly updatesSubject = new Subject<{
|
||||||
|
key: string;
|
||||||
|
value: unknown;
|
||||||
|
updateType: StorageUpdateType;
|
||||||
|
}>();
|
||||||
|
readonly updates$ = this.updatesSubject.asObservable();
|
||||||
abstract get<T>(key: string, options?: StorageOptions): Promise<T>;
|
abstract get<T>(key: string, options?: StorageOptions): Promise<T>;
|
||||||
abstract has(key: string, options?: StorageOptions): Promise<boolean>;
|
abstract has(key: string, options?: StorageOptions): Promise<boolean>;
|
||||||
abstract save<T>(key: string, obj: T, options?: StorageOptions): Promise<void>;
|
abstract save<T>(key: string, obj: T, options?: StorageOptions): Promise<void>;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { AbstractMemoryStorageService } from "../abstractions/storage.service";
|
import { AbstractMemoryStorageService } from "../abstractions/storage.service";
|
||||||
|
|
||||||
export class MemoryStorageService extends AbstractMemoryStorageService {
|
export class MemoryStorageService extends AbstractMemoryStorageService {
|
||||||
private store = new Map<string, any>();
|
private store = new Map<string, unknown>();
|
||||||
|
|
||||||
get<T>(key: string): Promise<T> {
|
get<T>(key: string): Promise<T> {
|
||||||
if (this.store.has(key)) {
|
if (this.store.has(key)) {
|
||||||
@ -15,16 +15,18 @@ export class MemoryStorageService extends AbstractMemoryStorageService {
|
|||||||
return (await this.get(key)) != null;
|
return (await this.get(key)) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
save(key: string, obj: any): Promise<any> {
|
save<T>(key: string, obj: T): Promise<void> {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return this.remove(key);
|
return this.remove(key);
|
||||||
}
|
}
|
||||||
this.store.set(key, obj);
|
this.store.set(key, obj);
|
||||||
|
this.updatesSubject.next({ key, value: obj, updateType: "save" });
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(key: string): Promise<any> {
|
remove(key: string): Promise<void> {
|
||||||
this.store.delete(key);
|
this.store.delete(key);
|
||||||
|
this.updatesSubject.next({ key, value: null, updateType: "remove" });
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user