1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 15:53:27 +00:00

JSON stringify memory items (#7731)

* JSON stringify memory items

stringification is required so they can be reliably sent through messaging

* Simplify null handling
This commit is contained in:
Matt Gibson
2024-01-29 14:42:58 -05:00
committed by GitHub
parent 76183c839a
commit 1da6733e71
9 changed files with 150 additions and 17 deletions

View File

@@ -0,0 +1,53 @@
import { MemoryStorageService } from "./memory-storage.service";
describe("MemoryStorageService", () => {
let sut: MemoryStorageService;
const key = "key";
const value = { test: "value" };
beforeEach(() => {
sut = new MemoryStorageService();
});
afterEach(() => {
jest.resetAllMocks();
});
describe("get", () => {
it("should return null if the key does not exist", async () => {
const result = await sut.get(key);
expect(result).toBeNull();
});
it("should return the value if the key exists", async () => {
await sut.save(key, value);
const result = await sut.get(key);
expect(result).toEqual(value);
});
it("should json parse stored values", async () => {
sut["store"][key] = JSON.stringify({ test: "value" });
const result = await sut.get(key);
expect(result).toEqual({ test: "value" });
});
});
describe("save", () => {
it("should store the value as json string", async () => {
const value = { test: "value" };
await sut.save(key, value);
expect(sut["store"][key]).toEqual(JSON.stringify(value));
});
});
describe("remove", () => {
it("should remove a value from store", async () => {
await sut.save(key, value);
await sut.remove(key);
expect(Object.keys(sut["store"])).not.toContain(key);
});
});
});

View File

@@ -0,0 +1,56 @@
import { Subject } from "rxjs";
import {
AbstractMemoryStorageService,
ObservableStorageService,
StorageUpdate,
} from "../../abstractions/storage.service";
export class MemoryStorageService
extends AbstractMemoryStorageService
implements ObservableStorageService
{
protected store: Record<string, string> = {};
private updatesSubject = new Subject<StorageUpdate>();
get valuesRequireDeserialization(): boolean {
return true;
}
get updates$() {
return this.updatesSubject.asObservable();
}
get<T>(key: string): Promise<T> {
const json = this.store[key];
if (json) {
const obj = JSON.parse(json as string);
return Promise.resolve(obj as T);
}
return Promise.resolve(null);
}
async has(key: string): Promise<boolean> {
return (await this.get(key)) != null;
}
save<T>(key: string, obj: T): Promise<void> {
if (obj == null) {
return this.remove(key);
}
// TODO: Remove once foreground/background contexts are separated in browser
// Needed to ensure ownership of all memory by the context running the storage service
this.store[key] = JSON.stringify(obj);
this.updatesSubject.next({ key, updateType: "save" });
return Promise.resolve();
}
remove(key: string): Promise<void> {
delete this.store[key];
this.updatesSubject.next({ key, updateType: "remove" });
return Promise.resolve();
}
getBypassCache<T>(key: string): Promise<T> {
return this.get<T>(key);
}
}