From 2559cba482dbe76d0fa09fd1daf234a873ec27aa Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 14 Jan 2025 12:01:19 +0000 Subject: [PATCH] Clear account idb table on logout (#28996) * Clear account idb table on logout to remove old deactivated refresh token when logging out Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Simplify code Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix test Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/Lifecycle.ts | 4 +- src/utils/StorageAccess.ts | 70 +++++++++++++++++-------------- test/unit-tests/Lifecycle-test.ts | 7 +++- 3 files changed, 46 insertions(+), 35 deletions(-) diff --git a/src/Lifecycle.ts b/src/Lifecycle.ts index cdb7d391151..80b08c8840f 100644 --- a/src/Lifecycle.ts +++ b/src/Lifecycle.ts @@ -1049,9 +1049,9 @@ async function clearStorage(opts?: { deleteEverything?: boolean }): Promise { }); } +async function idbTransaction( + table: string, + mode: IDBTransactionMode, + fn: (objectStore: IDBObjectStore) => IDBRequest, +): Promise { + if (!idb) { + await idbInit(); + } + return new Promise((resolve, reject) => { + const txn = idb!.transaction([table], mode); + txn.onerror = reject; + + const objectStore = txn.objectStore(table); + const request = fn(objectStore); + request.onerror = reject; + request.onsuccess = (): void => { + resolve(request.result); + }; + }); +} + /** * Loads an item from an IndexedDB table within the underlying `matrix-react-sdk` database. * @@ -57,17 +78,7 @@ export async function idbLoad(table: string, key: string | string[]): Promise { - const txn = idb!.transaction([table], "readonly"); - txn.onerror = reject; - - const objectStore = txn.objectStore(table); - const request = objectStore.get(key); - request.onerror = reject; - request.onsuccess = (event): void => { - resolve(request.result); - }; - }); + return idbTransaction(table, "readonly", (objectStore) => objectStore.get(key)); } /** @@ -84,17 +95,7 @@ export async function idbSave(table: string, key: string | string[], data: any): if (!idb) { await idbInit(); } - return new Promise((resolve, reject) => { - const txn = idb!.transaction([table], "readwrite"); - txn.onerror = reject; - - const objectStore = txn.objectStore(table); - const request = objectStore.put(data, key); - request.onerror = reject; - request.onsuccess = (event): void => { - resolve(); - }; - }); + return idbTransaction(table, "readwrite", (objectStore) => objectStore.put(data, key)); } /** @@ -110,15 +111,20 @@ export async function idbDelete(table: string, key: string | string[]): Promise< if (!idb) { await idbInit(); } - return new Promise((resolve, reject) => { - const txn = idb!.transaction([table], "readwrite"); - txn.onerror = reject; + return idbTransaction(table, "readwrite", (objectStore) => objectStore.delete(key)); +} - const objectStore = txn.objectStore(table); - const request = objectStore.delete(key); - request.onerror = reject; - request.onsuccess = (): void => { - resolve(); - }; - }); +/** + * Clears all records from an IndexedDB table within the underlying `matrix-react-sdk` database. + * + * If IndexedDB access is not supported in the environment, an error is thrown. + * + * @param {string} table The name of the object store where the records are stored. + * @returns {Promise} A Promise that resolves when the record(s) have been successfully deleted. + */ +export async function idbClear(table: string): Promise { + if (!idb) { + await idbInit(); + } + return idbTransaction(table, "readwrite", (objectStore) => objectStore.clear()); } diff --git a/test/unit-tests/Lifecycle-test.ts b/test/unit-tests/Lifecycle-test.ts index 65dda6fec10..ba5885c414c 100644 --- a/test/unit-tests/Lifecycle-test.ts +++ b/test/unit-tests/Lifecycle-test.ts @@ -143,6 +143,11 @@ describe("Lifecycle", () => { const table = mockStore[tableKey]; delete table?.[key as string]; }); + jest.spyOn(StorageAccess, "idbClear") + .mockClear() + .mockImplementation(async (tableKey: string) => { + mockStore[tableKey] = {}; + }); }; const homeserverUrl = "https://server.org"; @@ -613,7 +618,7 @@ describe("Lifecycle", () => { it("should clear stores", async () => { await setLoggedIn(credentials); - expect(StorageAccess.idbDelete).toHaveBeenCalledWith("account", "mx_access_token"); + expect(StorageAccess.idbClear).toHaveBeenCalledWith("account"); expect(sessionStorage.clear).toHaveBeenCalled(); expect(mockClient.clearStores).toHaveBeenCalled(); });