diff --git a/app/api/secure_store.native.ts b/app/api/secure_store.native.ts new file mode 100644 index 0000000000..25508024f1 --- /dev/null +++ b/app/api/secure_store.native.ts @@ -0,0 +1,31 @@ +import { Platform } from 'react-native' +import ExpoSecureStore from 'expo-secure-store' +import { ISecureStore, getKey } from './secure_store' + +class NativeSecureStore implements ISecureStore { + /** + * @param key {string} of item with 'environment' and 'network' prefixed + * @return {string | null} + */ + async getItem (key: string): Promise { + return await ExpoSecureStore.getItemAsync(await getKey(key)) + } + + /** + * @param key {string} of item with 'environment' and 'network' prefixed + * @param value {string} to set + */ + async setItem (key: string, value: string): Promise { + return await ExpoSecureStore.setItemAsync(await getKey(key), value) + } + + /** + * @param key {string} of item with 'environment' and 'network' prefixed + */ + async removeItem (key: string): Promise { + await ExpoSecureStore.deleteItemAsync(await getKey(key)) + } +} + +console.log(Platform.OS) +export const SecureStorage = new NativeSecureStore() diff --git a/app/api/secure_store.ts b/app/api/secure_store.ts new file mode 100644 index 0000000000..e12a4d9e0f --- /dev/null +++ b/app/api/secure_store.ts @@ -0,0 +1,42 @@ +import { getEnvironment } from '../environment' +import { getNetwork } from './storage' +import AsyncStorage from '@react-native-async-storage/async-storage' + +export async function getKey (key: string): Promise { + const env = getEnvironment() + const network = await getNetwork() + return `${env.name}.${network}.${key}` +} + +export interface ISecureStore { + getItem: (key: string) => Promise + setItem: (key: string, value: string) => Promise + removeItem: (key: string) => Promise +} + +class WebAsyncStorage implements ISecureStore { + /** + * @param key {string} of item with 'environment' and 'network' prefixed + * @return {string | null} + */ + async getItem (key: string): Promise { + return await AsyncStorage.getItem(await getKey(key)) + } + + /** + * @param key {string} of item with 'environment' and 'network' prefixed + * @param value {string} to set + */ + async setItem (key: string, value: string): Promise { + return await AsyncStorage.setItem(await getKey(key), value) + } + + /** + * @param key {string} of item with 'environment' and 'network' prefixed + */ + async removeItem (key: string): Promise { + await AsyncStorage.removeItem(await getKey(key)) + } +} + +export const SecureStorage = new WebAsyncStorage() diff --git a/app/api/wallet/persistence.test.ts b/app/api/wallet/persistence.test.ts index ebbf4b1336..a57fd2fb59 100644 --- a/app/api/wallet/persistence.test.ts +++ b/app/api/wallet/persistence.test.ts @@ -1,7 +1,13 @@ -import AsyncStorage from "@react-native-async-storage/async-storage"; +import AsyncStorage from '@react-native-async-storage/async-storage'; import { EnvironmentNetwork } from "../../environment"; import { WalletPersistence, WalletType } from "./persistence"; +jest.mock('react-native/Libraries/Utilities/Platform', () => ({ + OS: 'web', + select: opts => opts.web +})) + +// web has no SecureStore implementation, fallback to AsyncStorage const getItem = jest.spyOn(AsyncStorage, 'getItem') const setItem = jest.spyOn(AsyncStorage, 'setItem') diff --git a/app/api/wallet/persistence.ts b/app/api/wallet/persistence.ts index bfac342e25..d1584a1ecf 100644 --- a/app/api/wallet/persistence.ts +++ b/app/api/wallet/persistence.ts @@ -1,4 +1,5 @@ -import { getItem, setItem } from '../storage' +// import { getItem, setItem } from '../storage' +import { SecureStorage } from '../secure_store' const KEY = 'WALLET' @@ -18,7 +19,7 @@ export interface WalletData { } async function get (): Promise { - const json = await getItem(KEY) + const json = await SecureStorage.getItem(KEY) if (json !== null) { return JSON.parse(json) } @@ -27,7 +28,7 @@ async function get (): Promise { } async function set (wallets: WalletData[]): Promise { - await setItem(KEY, JSON.stringify(wallets)) + await SecureStorage.setItem(KEY, JSON.stringify(wallets)) } async function add (data: WalletData): Promise { diff --git a/package-lock.json b/package-lock.json index 08b99239a7..9443bf2f0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,6 +38,7 @@ "expo-linking": "~2.3.1", "expo-localization": "~10.2.0", "expo-random": "~11.2.0", + "expo-secure-store": "^10.2.0", "expo-splash-screen": "~0.11.2", "expo-status-bar": "~1.0.4", "expo-updates": "~0.8.1", @@ -16054,6 +16055,11 @@ "base64-js": "^1.3.0" } }, + "node_modules/expo-secure-store": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/expo-secure-store/-/expo-secure-store-10.2.0.tgz", + "integrity": "sha512-yNahMY3qzEotAYdsE02ps4yGfDay2twasHfsI/7gJB9SrwXYFx5bJuCDk8uTo8jsm6psvDjO+9VMM2DSPHik2A==" + }, "node_modules/expo-splash-screen": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/expo-splash-screen/-/expo-splash-screen-0.11.2.tgz", @@ -51799,6 +51805,11 @@ "base64-js": "^1.3.0" } }, + "expo-secure-store": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/expo-secure-store/-/expo-secure-store-10.2.0.tgz", + "integrity": "sha512-yNahMY3qzEotAYdsE02ps4yGfDay2twasHfsI/7gJB9SrwXYFx5bJuCDk8uTo8jsm6psvDjO+9VMM2DSPHik2A==" + }, "expo-splash-screen": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/expo-splash-screen/-/expo-splash-screen-0.11.2.tgz", diff --git a/package.json b/package.json index f3619dd66b..6e11b5858b 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "expo-linking": "~2.3.1", "expo-localization": "~10.2.0", "expo-random": "~11.2.0", + "expo-secure-store": "^10.2.0", "expo-splash-screen": "~0.11.2", "expo-status-bar": "~1.0.4", "expo-updates": "~0.8.1",