import { globalState } from '../app/global-state'; // Shim for SSR class LocalStorageInMemory { private _storage: any = {}; get length(): number { return this._storage.length; } clear(): void { this._storage = {}; } getItem(key: string): string | null { return this._storage[key]; } key(index: number): string | null { return Object.keys(this._storage)[index]; } removeItem(key: string): void { this._storage[key] = null; } setItem(key: string, value: string): void { this._storage[key] = value; } } const storage = globalState.localStorage ?? new LocalStorageInMemory(); if (!(storage as unknown as any).isPatched && globalState.localStorage != null) { try { delete (globalState as any).localStorage; (globalState as any).localStorage = {}; class LocalStorageImpl { isPatched = true; get length(): number { return storage.length; } clear(): void { storage.clear(); } getItem(key: string): string | null { return storage.getItem(`public.${key.replace('public.', '')}`); } key(index: number): string | null { return storage.key(index); } removeItem(key: string): void { storage.removeItem(`public.${key}`); } setItem(key: string, value: string): void { storage.setItem(`public.${key}`, value); } } let newStorage = new LocalStorageImpl(); if (globalState.Proxy && globalState.Reflect) { newStorage = new globalState.Proxy(newStorage, { get(target, prop: any) { if ((storage as any)[prop] != null) { return globalState.Reflect.get(target, prop); } else { return storage.getItem(`public.${prop}`); } }, set( target, prop, value, ) { storage.setItem(`public.${prop as any}`, value); return true; }, }); } (globalState as any).localStorage = newStorage; } catch (error) { } } /** * Provides secure LocalStorage mechanism that is less vunerable to XSS */ export default class StorageProvider { /** * Obtains stored string * @param key Storage key * @param defaultValue Default value if no value is stored yet */ static getString(key: string, defaultValue?: string): string { return storage.getItem(`private.${key}`) || defaultValue; } /** * Obtains stored number * @param key Storage key * @param defaultValue Default value if no value is stored yet */ static getNumber(key: string, defaultValue?: number): number { const retVal = StorageProvider.getString(key); let numVal: number; try { numVal = Number(retVal); } catch (e) { numVal = null; } if (numVal != null && !isNaN(numVal)) { return numVal; } else { return defaultValue; } } /** * Obtains stored object * @param key Storage key * @param defaultValue Default value if no value is stored yet */ static getObject(key: string, defaultValue?: T): T { const retVal = StorageProvider.getString(key); try { return JSON.parse(retVal); } catch (e) { return defaultValue; } } /** * Saves string into isolated local storage * @param key Storage key * @param value String to store */ static setString(key: string, value: string): void { storage.setItem(`private.${key}`, value); } /** * Saves number into isolated local storage * @param key Storage key * @param value Number to store */ static setNumber(key: string, value: number): void { StorageProvider.setString(key, value as any); } /** * Saves object into isolated local storage * @param key Storage key * @param value Object to store */ static setObject(key: string, obj: T): void { let storeVal: string; try { storeVal = JSON.stringify(obj); } catch (e) { storeVal = null; } StorageProvider.setString(key, storeVal); } /** * Removes item from the storage * @param key Storage key */ static remove(key: string): void { storage.removeItem(`private.${key}`); } }