Last active
July 13, 2025 09:55
-
-
Save burdiuz/867899714ed8b8e0726f253ad22fe11d to your computer and use it in GitHub Desktop.
LocalSotrage > SessionStorage redirect
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (() => { | |
| const wrapKey = (key) => `_ch_lock_state_:${key}`; | |
| const isWrappedKey = (key) => typeof key === "string" && /_:.+$/.test(key); | |
| const unwrapKey = (key) => key.match(/_:(.+)$/)[1]; | |
| const unwrapIfKey = (key) => | |
| isWrappedKey(key) ? key.match(/_:(.+)$/)[1] : key; | |
| const getItem = (target) => (key) => target[wrapKey(key)]; | |
| const hasItem = (target) => (key) => Object.hasOwn(target, wrapKey(key)); | |
| const setItem = (target) => (key, value) => (target[wrapKey(key)] = value); | |
| const removeItem = (target) => (key) => delete target[wrapKey(key)]; | |
| const getKeys = (target) => | |
| Object.keys(target).filter(isWrappedKey).map(unwrapKey); | |
| const getKey = (target) => (key) => { | |
| const index = Number.parseInt(key); | |
| const list = getKeys(target); | |
| return Number.isNaN(index) ? list[0] : list[index]; | |
| }; | |
| const STRING_TAG = "__Fake__Storage"; | |
| const originalLocalStorage = window.localStorage; | |
| const receiverStorage = window.sessionStorage; | |
| const fakeStorage = new Proxy(receiverStorage, { | |
| get(storage, key, receiver) { | |
| switch (key) { | |
| case "length": | |
| return getKeys(storage).length; | |
| case "clear": | |
| getKeys(storage).forEach(removeItem(storage)); | |
| return undefined; | |
| case "getItem": | |
| return getItem(storage); | |
| case "setItem": | |
| return setItem(storage); | |
| case "removeItem": | |
| return removeItem(storage); | |
| case "key": | |
| return getKey(storage); | |
| case Symbol.toStringTag: | |
| return STRING_TAG; | |
| case "toString": | |
| case "toLocaleString": | |
| return () => `[object ${STRING_TAG}]`; | |
| case Symbol.toPrimitive: | |
| return undefined; | |
| case "valueOf": | |
| return () => receiver; | |
| default: | |
| return storage[typeof key === "string" ? wrapKey(key) : key]; | |
| } | |
| }, | |
| has(storage, key) { | |
| return hasItem(storage)(key) || key in Object.getPrototypeOf(storage); | |
| }, | |
| set(storage, key, newValue, receiver) { | |
| switch (key) { | |
| case "length": | |
| // read-only value, cannot overwrite | |
| break; | |
| default: | |
| return setItem(storage)(key, newValue); | |
| } | |
| }, | |
| getOwnPropertyDescriptor(storage, key) { | |
| return Object.getOwnPropertyDescriptor(storage, wrapKey(key)); | |
| }, | |
| ownKeys(storage) { | |
| return getKeys(storage); | |
| }, | |
| }); | |
| window.chRestoreOriginalLocalStorage = () => { | |
| // set original local storage | |
| Object.defineProperty(window, "localStorage", { | |
| get: () => originalLocalStorage, | |
| configurable: true, | |
| enumerable: true, | |
| }); | |
| // unreference this function | |
| delete window.chRestoreOriginalLocalStorage; | |
| // copy values stored in receiver storage to local storage | |
| Object.entries(fakeStorage).forEach(([key, value]) => { | |
| originalLocalStorage[key] = value; | |
| // delete values from receiver storage | |
| delete receiverStorage[wrapKey(key)]; | |
| }); | |
| }; | |
| Object.defineProperty(window, "localStorage", { | |
| get: () => fakeStorage, | |
| configurable: true, | |
| enumerable: true, | |
| }); | |
| // copy values from local storage to receiver storage | |
| Object.entries(originalLocalStorage).forEach(([key, value]) => { | |
| fakeStorage[key] = value; | |
| /* | |
| * In case if app stored a reference to original local storage, | |
| * we want values them to be undefined instead of serving outdated values. | |
| */ | |
| delete originalLocalStorage[key]; | |
| }); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment