Clear local storage settings handler cache on logout (#8454)

This commit is contained in:
Michael Telatynski 2022-05-02 03:23:43 +01:00 committed by GitHub
parent 3a245a0cbe
commit 633229ca26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 22 deletions

View File

@ -61,6 +61,7 @@ import { setSentryUser } from "./sentry";
import SdkConfig from "./SdkConfig"; import SdkConfig from "./SdkConfig";
import { DialogOpener } from "./utils/DialogOpener"; import { DialogOpener } from "./utils/DialogOpener";
import { Action } from "./dispatcher/actions"; import { Action } from "./dispatcher/actions";
import AbstractLocalStorageSettingsHandler from "./settings/handlers/AbstractLocalStorageSettingsHandler";
const HOMESERVER_URL_KEY = "mx_hs_url"; const HOMESERVER_URL_KEY = "mx_hs_url";
const ID_SERVER_URL_KEY = "mx_is_url"; const ID_SERVER_URL_KEY = "mx_is_url";
@ -878,6 +879,7 @@ async function clearStorage(opts?: { deleteEverything?: boolean }): Promise<void
const registrationTime = window.localStorage.getItem("mx_registration_time"); const registrationTime = window.localStorage.getItem("mx_registration_time");
window.localStorage.clear(); window.localStorage.clear();
AbstractLocalStorageSettingsHandler.clear();
try { try {
await StorageManager.idbDelete("account", "mx_access_token"); await StorageManager.idbDelete("account", "mx_access_token");

View File

@ -21,39 +21,51 @@ import SettingsHandler from "./SettingsHandler";
* by caching the values and listening for localStorage updates from other tabs. * by caching the values and listening for localStorage updates from other tabs.
*/ */
export default abstract class AbstractLocalStorageSettingsHandler extends SettingsHandler { export default abstract class AbstractLocalStorageSettingsHandler extends SettingsHandler {
private itemCache = new Map<string, any>(); // Shared cache between all subclass instances
private objectCache = new Map<string, object>(); private static itemCache = new Map<string, any>();
private static objectCache = new Map<string, object>();
private static storageListenerBound = false;
private static onStorageEvent = (e: StorageEvent) => {
if (e.key === null) {
AbstractLocalStorageSettingsHandler.clear();
} else {
AbstractLocalStorageSettingsHandler.itemCache.delete(e.key);
AbstractLocalStorageSettingsHandler.objectCache.delete(e.key);
}
};
// Expose the clear event for Lifecycle to call, the storage listener only fires for changes from other tabs
public static clear() {
AbstractLocalStorageSettingsHandler.itemCache.clear();
AbstractLocalStorageSettingsHandler.objectCache.clear();
}
protected constructor() { protected constructor() {
super(); super();
// Listen for storage changes from other tabs to bust the cache if (!AbstractLocalStorageSettingsHandler.storageListenerBound) {
window.addEventListener("storage", (e: StorageEvent) => { AbstractLocalStorageSettingsHandler.storageListenerBound = true;
if (e.key === null) { // Listen for storage changes from other tabs to bust the cache
this.itemCache.clear(); window.addEventListener("storage", AbstractLocalStorageSettingsHandler.onStorageEvent);
this.objectCache.clear(); }
} else {
this.itemCache.delete(e.key);
this.objectCache.delete(e.key);
}
});
} }
protected getItem(key: string): any { protected getItem(key: string): any {
if (!this.itemCache.has(key)) { if (!AbstractLocalStorageSettingsHandler.itemCache.has(key)) {
const value = localStorage.getItem(key); const value = localStorage.getItem(key);
this.itemCache.set(key, value); AbstractLocalStorageSettingsHandler.itemCache.set(key, value);
return value; return value;
} }
return this.itemCache.get(key); return AbstractLocalStorageSettingsHandler.itemCache.get(key);
} }
protected getObject<T extends object>(key: string): T | null { protected getObject<T extends object>(key: string): T | null {
if (!this.objectCache.has(key)) { if (!AbstractLocalStorageSettingsHandler.objectCache.has(key)) {
try { try {
const value = JSON.parse(localStorage.getItem(key)); const value = JSON.parse(localStorage.getItem(key));
this.objectCache.set(key, value); AbstractLocalStorageSettingsHandler.objectCache.set(key, value);
return value; return value;
} catch (err) { } catch (err) {
console.error("Failed to parse localStorage object", err); console.error("Failed to parse localStorage object", err);
@ -61,24 +73,24 @@ export default abstract class AbstractLocalStorageSettingsHandler extends Settin
} }
} }
return this.objectCache.get(key) as T; return AbstractLocalStorageSettingsHandler.objectCache.get(key) as T;
} }
protected setItem(key: string, value: any): void { protected setItem(key: string, value: any): void {
this.itemCache.set(key, value); AbstractLocalStorageSettingsHandler.itemCache.set(key, value);
localStorage.setItem(key, value); localStorage.setItem(key, value);
} }
protected setObject(key: string, value: object): void { protected setObject(key: string, value: object): void {
this.objectCache.set(key, value); AbstractLocalStorageSettingsHandler.objectCache.set(key, value);
localStorage.setItem(key, JSON.stringify(value)); localStorage.setItem(key, JSON.stringify(value));
} }
// handles both items and objects // handles both items and objects
protected removeItem(key: string): void { protected removeItem(key: string): void {
localStorage.removeItem(key); localStorage.removeItem(key);
this.itemCache.delete(key); AbstractLocalStorageSettingsHandler.itemCache.delete(key);
this.objectCache.delete(key); AbstractLocalStorageSettingsHandler.objectCache.delete(key);
} }
public isSupported(): boolean { public isSupported(): boolean {