UNPKG

@turnkey/sdk-react-native

Version:
270 lines (267 loc) 9.29 kB
import * as Keychain from 'react-native-keychain'; import { TurnkeyReactNativeError } from './errors.mjs'; import { StorageKeys } from './constants.mjs'; // This package leverages `react-native-keychain` to securely store session data. // We use `Keychain.getGenericPassword()` to retrieve stored values, where: // - `service` is used as a key to reference the stored data. // - `credentials.password` is used to hold sensitive data, such as session keys or encrypted session objects. // // Note: `credentials.password` does not need to contain a literal password; // it is simply a secure storage location for sensitive string data. /** * Retrieves the embedded key from secure storage. * * - Attempts to retrieve the stored embedded private key using Keychain. * - Optionally deletes the key from storage after retrieval if `deleteKey` is true. * * @param deleteKey - Whether to remove the embedded key after retrieval (defaults to false). * @param storageKey - The service key for the embedded key. * @returns The embedded private key if found, otherwise null. * @throws {TurnkeyReactNativeError} If retrieving or deleting the key fails. */ const getEmbeddedKey = async (deleteKey = false, storageKey) => { try { const credentials = await Keychain.getGenericPassword({ service: storageKey, }); if (credentials) { if (deleteKey) { await Keychain.resetGenericPassword({ service: storageKey, }); } return credentials.password; } return null; } catch (error) { throw new TurnkeyReactNativeError("Failed to get embedded key", error); } }; /** * Saves the provided embedded key (private key) securely in storage. * * - Uses Keychain to store the private key for the given service key. * * @param key - The private key to store securely. * @param storageKey - The service key under which to store the embedded key. * @throws {TurnkeyReactNativeError} If saving the key fails. */ const saveEmbeddedKey = async (key, storageKey) => { try { await Keychain.setGenericPassword(storageKey, key, { accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED_THIS_DEVICE_ONLY, service: storageKey, }); } catch (error) { throw new TurnkeyReactNativeError("Could not save the embedded key.", error); } }; /** * Retrieves a stored session from secure storage. * * @param sessionKey The unique key identifying the session. * @returns The session object if found, otherwise `null`. * @throws If retrieving the session fails. */ const getSession = async (sessionKey) => { try { const credentials = await Keychain.getGenericPassword({ service: sessionKey, }); return credentials ? JSON.parse(credentials.password) : null; } catch (error) { throw new TurnkeyReactNativeError(`Failed to get session for sessionKey "${sessionKey}"`, error); } }; /** * Saves a session securely in storage. * * @param session The session object to store securely. * @param sessionKey The unique key under which the session is stored. * @throws If saving the session fails. */ const saveSession = async (session, sessionKey) => { try { await Keychain.setGenericPassword(sessionKey, JSON.stringify(session), { accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED_THIS_DEVICE_ONLY, service: sessionKey, }); } catch (error) { throw new TurnkeyReactNativeError("Could not save the session", error); } }; /** * Deletes a session from secure storage. * * @param sessionKey The unique key identifying the session to reset. * @throws If deleting the session fails. */ const deleteSession = async (sessionKey) => { try { await Keychain.resetGenericPassword({ service: sessionKey }); } catch (error) { throw new TurnkeyReactNativeError("Could not delete the session.", error); } }; /** * Retrieves the selected session key from secure storage. * * @returns The selected session key as a string, or `null` if not found. * @throws If retrieving the session key fails. */ const getSelectedSessionKey = async () => { try { const credentials = await Keychain.getGenericPassword({ service: StorageKeys.SelectedSession, }); return credentials ? credentials.password : null; } catch (error) { throw new TurnkeyReactNativeError("Failed to get selected session key", error); } }; /** * Saves the selected session key to secure storage. * * @param sessionKey The session key to mark as selected. * @throws If saving the session key fails. */ const saveSelectedSessionKey = async (sessionKey) => { try { await Keychain.setGenericPassword(StorageKeys.SelectedSession, sessionKey, { accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED_THIS_DEVICE_ONLY, service: StorageKeys.SelectedSession, }); } catch (error) { throw new TurnkeyReactNativeError("Failed to save selected session key", error); } }; /** * Clears the selected session key from secure storage. * * @throws If deleting the session key fails. */ const clearSelectedSessionKey = async () => { try { await Keychain.resetGenericPassword({ service: StorageKeys.SelectedSession, }); } catch (error) { throw new TurnkeyReactNativeError("Failed to clear selected session key", error); } }; /** * Adds a session key to the session list in secure storage. * * - Retrieves the existing session list. * - Appends the new session key if it does not already exist. * - Stores the updated session list. * * @param sessionKey The session key to add. * @throws If the session key already exists or saving fails. */ const addSessionKey = async (sessionKey) => { try { const credentials = await Keychain.getGenericPassword({ service: StorageKeys.SessionKeys, }); let keys = []; if (credentials) { try { keys = JSON.parse(credentials.password); if (!Array.isArray(keys)) { throw new Error("Session list is corrupted."); } } catch { throw new TurnkeyReactNativeError("Failed to parse session list."); } } if (keys.includes(sessionKey)) { return; } keys.push(sessionKey); await Keychain.setGenericPassword(StorageKeys.SessionKeys, JSON.stringify(keys), { accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED_THIS_DEVICE_ONLY, service: StorageKeys.SessionKeys, }); } catch (error) { throw new TurnkeyReactNativeError("Failed to add session key.", error); } }; /** * Retrieves all session keys stored in secure storage. * * @returns An array of session keys. * @throws If retrieving the session list fails. */ const getSessionKeys = async () => { try { const credentials = await Keychain.getGenericPassword({ service: StorageKeys.SessionKeys, }); if (!credentials) { return []; } try { const keys = JSON.parse(credentials.password); if (!Array.isArray(keys)) { throw new Error("Session list is corrupted."); } return keys; } catch { throw new TurnkeyReactNativeError("Failed to parse session list."); } } catch (error) { throw new TurnkeyReactNativeError("Failed to retrieve session list.", error); } }; /** * Removes a session key from the session list in secure storage. * * - Fetches the existing session list. * - Removes the specified session key. * - Saves the updated session list back to secure storage. * * @param sessionKey The session key to remove. * @throws If removing the session key fails. */ const removeSessionKey = async (sessionKey) => { try { const credentials = await Keychain.getGenericPassword({ service: StorageKeys.SessionKeys, }); let keys = []; if (credentials) { try { keys = JSON.parse(credentials.password); if (!Array.isArray(keys)) { throw new Error("Session list is corrupted."); } } catch { throw new TurnkeyReactNativeError("Failed to parse session list."); } } const updatedKeys = keys.filter((key) => key !== sessionKey); await Keychain.setGenericPassword(StorageKeys.SessionKeys, JSON.stringify(updatedKeys), { accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED_THIS_DEVICE_ONLY, service: StorageKeys.SessionKeys, }); } catch (error) { throw new TurnkeyReactNativeError("Failed to remove session key.", error); } }; export { addSessionKey, clearSelectedSessionKey, deleteSession, getEmbeddedKey, getSelectedSessionKey, getSession, getSessionKeys, removeSessionKey, saveEmbeddedKey, saveSelectedSessionKey, saveSession }; //# sourceMappingURL=storage.mjs.map