admin管理员组

文章数量:1406924

I'm using zustand with persist plugin to store the state of my application. I want to use localstorage but the cache has to be encrypted.

For encryption, I'm using encrypt-storage. For encryption keys, I want to make an API call to the backend and initialise the encrypt storage.

The problem is while the API call is being made, the storage is still undefined. How to properly initialise zustand with encrypt-storage ?

Here is what I have tried :

import { EncryptStorage } from "encrypt-storage";
import { create } from "zustand";
import { devtools, persist, } from "zustand/middleware";
import { createJSONStorage } from "zustand/middleware"


const fake_api = (ms: number) => new Promise(resolve => {
  setTimeout(resolve, ms)
})

export function KeyResolver(callback: () => void) {
  const fn = async () => {
    //
    await fake_api(2000);
    console.log("encryption key retrieved")
    encryptStorage.EKEY = 'secret-key-value';
    encryptStorage.storage = new EncryptStorage(encryptStorage.EKEY, {
      stateManagementUse: true,
    });
    callback();
  };
  if (!encryptStorage.EKEY) {
    fn();
  }
}

interface IEncryptStorage {
  storage: undefined | EncryptStorage,
  EKEY: null | string,
}

export const encryptStorage: IEncryptStorage = {
  storage: undefined,
  EKEY: null,

}


const useOptimiserStore = create<IOptimiserStore>()(
  devtools(
    persist(
      (set) => ({
        ...initialOtimiserStoreState,
        _hasHydrated: false, 
        setHyderated: (val) => set({ _hasHydrated: val })
      }),
      {
        name: "optimiser-storage",

       
        // @ts-expect-error
        storage: createJSONStorage(() => encryptStorage.storage),

        onRehydrateStorage: () => {
          KeyResolver(() => {
            useOptimiserStore.getState().setHyderated(true)
          });

        }
      }
    ),
    {
      name: "optimiser-storage",
    }
  )
);

// And i'm using it inside my ponent like this: 
const Component = () => {

  const hasHyderated = useOptimiserStore(state => state._hasHydrated);

  if (!hasHyderated) {
    return <>retreiving encryption keys </>
  }

  return <div> ... </div>


}

But I get the following error:

Uncaught TypeError: can't access property "setItem", storage is undefined

I'm using zustand with persist plugin to store the state of my application. I want to use localstorage but the cache has to be encrypted.

For encryption, I'm using encrypt-storage. For encryption keys, I want to make an API call to the backend and initialise the encrypt storage.

The problem is while the API call is being made, the storage is still undefined. How to properly initialise zustand with encrypt-storage ?

Here is what I have tried :

import { EncryptStorage } from "encrypt-storage";
import { create } from "zustand";
import { devtools, persist, } from "zustand/middleware";
import { createJSONStorage } from "zustand/middleware"


const fake_api = (ms: number) => new Promise(resolve => {
  setTimeout(resolve, ms)
})

export function KeyResolver(callback: () => void) {
  const fn = async () => {
    //
    await fake_api(2000);
    console.log("encryption key retrieved")
    encryptStorage.EKEY = 'secret-key-value';
    encryptStorage.storage = new EncryptStorage(encryptStorage.EKEY, {
      stateManagementUse: true,
    });
    callback();
  };
  if (!encryptStorage.EKEY) {
    fn();
  }
}

interface IEncryptStorage {
  storage: undefined | EncryptStorage,
  EKEY: null | string,
}

export const encryptStorage: IEncryptStorage = {
  storage: undefined,
  EKEY: null,

}


const useOptimiserStore = create<IOptimiserStore>()(
  devtools(
    persist(
      (set) => ({
        ...initialOtimiserStoreState,
        _hasHydrated: false, 
        setHyderated: (val) => set({ _hasHydrated: val })
      }),
      {
        name: "optimiser-storage",

       
        // @ts-expect-error
        storage: createJSONStorage(() => encryptStorage.storage),

        onRehydrateStorage: () => {
          KeyResolver(() => {
            useOptimiserStore.getState().setHyderated(true)
          });

        }
      }
    ),
    {
      name: "optimiser-storage",
    }
  )
);

// And i'm using it inside my ponent like this: 
const Component = () => {

  const hasHyderated = useOptimiserStore(state => state._hasHydrated);

  if (!hasHyderated) {
    return <>retreiving encryption keys </>
  }

  return <div> ... </div>


}

But I get the following error:

Uncaught TypeError: can't access property "setItem", storage is undefined

Share Improve this question asked Feb 7, 2023 at 7:45 VoneoneVoneone 211 silver badge5 bronze badges 3
  • Why does it need to be encrypted? Any client-side encryption is trivially bypassed by a mildly technical user. – AKX Commented Feb 7, 2023 at 7:48
  • @AKX Basically its a webapp for designing factory layouts. I'm using canvas for this. Now I'm using locastorage to save what the user has already drawn. I don't want to hide the information from the user but store the cache in a somewhat secure way. – Voneone Commented Feb 7, 2023 at 7:56
  • But... again, why? What are you protecting against, what's the threat model? – AKX Commented Feb 7, 2023 at 10:10
Add a ment  | 

2 Answers 2

Reset to default 6

for anyone who is wondering how to implement.

import * as SecureStore from "expo-secure-store";
import { create } from "zustand";
import { StateStorage, createJSONStorage, persist } from "zustand/middleware";

const SecureStorage: StateStorage = {
  getItem: async (name: string): Promise<string | null> => {
    return (await SecureStore.getItemAsync(name)) || null;
  },
  setItem: async (name: string, value: string): Promise<void> => {
    await SecureStore.setItemAsync(name, value);
  },
  removeItem: async (name: string): Promise<void> => {
    await SecureStore.deleteItemAsync(name);
  },
};

interface IAppStore {
  bears: number;
  increase: (by: number) => void;
}

export const useAppStore = create<IAppStore>()(
  persist(
    (set) => ({
      bears: 0,
      increase: (by) => set((state) => ({ bears: state.bears + by })),
    }),
    {
      name: "bear-storage",
      storage: createJSONStorage(() => SecureStorage),
    }
  )
);

I managed to make it work by implementing a custom storage engine.

https://docs.pmnd.rs/zustand/integrations/persisting-store-data#how-can-i-use-a-custom-storage-engine

本文标签: javascriptHow to use encryptstorage with zustand in reactStack Overflow