nbubna / store

A better way to use localStorage and sessionStorage
MIT License
1.91k stars 109 forks source link

Is there anyway to obtain what storage I'm passing to the plugin? #114

Closed Alsan closed 8 months ago

Alsan commented 2 years ago

Here is my code:

import { browser } from '$app/environment';
import { arrayBufferToBase64, base64ToUint8Array } from './stringutil';
import store from 'store2';

if (browser) {
  const encoder = new TextEncoder();
  const decoder = new TextDecoder();
  const iv = window.crypto.getRandomValues(new Uint8Array(12));
  const algorithm = { iv, name: 'AES-GCM' };
  const keyOption = { name: 'AES-GCM', length: 256 };
  const encryptionKey = await window.crypto.subtle.generateKey(keyOption, true, ['encrypt', 'decrypt']);

  (function (_) {
    _.fn('encrypt', async (key: string, val: string): Promise<string> => {
      const encodedVal = encoder.encode(val as string);
      const encryptedBuf = await window.crypto.subtle.encrypt(algorithm, encryptionKey, encodedVal);
      const encryptedVal = arrayBufferToBase64(encryptedBuf);
      return store.set(key, encryptedVal);
    });

    _.fn('decrypt', async (key: string): Promise<string> => {
      const encryptedVal: string = store.get(key);
      const encryptedBuf = base64ToUint8Array(encryptedVal);
      const decryptedVal = await window.crypto.subtle.decrypt(algorithm, encryptionKey, encryptedBuf);
      return decoder.decode(decryptedVal);
    });
  })(store._);
}

// the test call...
await store.encrypt('a1', 'alsan');
await store.session.encrypt('a1', 'alsan');

As you can see, the storeage is hardcoded, not querying from the passing in interface. So, how can I get the right storage?

Another question, I found that I can pass a function as the alt parameter to the get/set method to do the same thing (something like post-process of retrieved value), not that clean but work. There's an exceptional case is when the value retrieved is null, the passing in function to the get method wouldn't be called, why?

nbubna commented 2 years ago

All extension functions have all the privileges and standing of built-in functions. So they are actually executed directly on the store instance upon which they are called.

That means, that rather than go back thru the root instance (e.g. store.set(key, encryptedVal)) you can call set on this: this.set(key, encryptedVal).

That said, if you ever want direct access to the storage area itself, that would this._area from within the execution context of your extension function. However, do consider that an undocumented API, not subject to semver rules. Of course, it also hasn't changed in over a decade, so it's probably safe until such time as i write a new major version. Which, given my current life, won't be soon.

nbubna commented 2 years ago

So far as passing a function in as the alt parameter to get/set calls, those are for custom JSON reviver/replacer functions. So we don't call those functions for null values because we know there's no JSON to parse/stringify.

It was specifically meant to expose that feature of the JSON API thru store2, not to be a generic post-process function.