diff --git a/src/utils/config.ts b/src/utils/config.ts index 41813ef..5d427dd 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -1,3 +1,4 @@ +import { Platform } from 'react-native'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { setItemAsync, getItemAsync } from 'expo-secure-store'; @@ -300,10 +301,8 @@ export const getStorage: (slot: string, useMysticCrypt?: boolean) => Promise< cached, ); if (cached) return cached; - const val = useMysticCrypt - ? await getItemAsync(slot, { requireAuthentication: !__DEV__ }) - : await AsyncStorage.getItem(slot); + const val = await _getStorage(slot, useMysticCrypt); console.log('get storage 2 - slot + val', slot, val); return val ? JSON.parse(val) : null; } catch (e: unknown) { @@ -314,6 +313,27 @@ export const getStorage: (slot: string, useMysticCrypt?: boolean) => Promise< return null; } }; + +const _getStorage = async (slot: string, useMysticCrypt?: boolean) => { + if (Platform.OS === 'web') { + // all web storage is secure cookies + return getCookie(slot); + } + + // on mobile could be secure cloud storage or local app storage + return useMysticCrypt + ? await getItemAsync(slot, { requireAuthentication: !__DEV__ }) + : await AsyncStorage.getItem(slot); +}; + +const getCookie = (slot: string) => { + const allCookies = document.cookie.split('; '); + return allCookies.find((c) => { + const [name, value] = c.split('='); + return name === slot ? decodeURIComponent(value) : null; + }); +}; + /** * @function * @name saveMysticCrypt @@ -359,7 +379,7 @@ export const saveStorage: ( // do not merge if not requested or primitive types if (!shouldMerge || typeof value === 'string' || typeof value === 'number') { - await AsyncStorage.setItem(key, JSON.stringify(value)); + await _saveStorage(key, JSON.stringify(value)); updateCache({ slot: key }, value); return value; } @@ -382,8 +402,7 @@ export const saveStorage: ( ? concat(existingVal, value) : concat(defaultVal ?? [], value); - // TODO need to store in secure cookies on web not local storage - await AsyncStorage.setItem(key, JSON.stringify(newVal)); + await _saveStorage(key, JSON.stringify(newVal)); updateCache({ slot: key }, value); return newVal; } else { @@ -396,8 +415,7 @@ export const saveStorage: ( ? merge(existingVal, value) : merge(defaultVal ?? {}, value); - // TODO need to store in secure cookies on web not local storage - await AsyncStorage.setItem(key, JSON.stringify(newVal)); + await _saveStorage(key, JSON.stringify(newVal)); updateCache({ slot: key }, value); return newVal; } @@ -408,6 +426,22 @@ export const saveStorage: ( } }; +const _saveStorage = async (slot: string, val: string): Promise => { + // cookies are forever Mostly so priavte keys dont get deleted. here bc gets hoisted anywauy + const expirationDate = new Date(2100, 0, 1).toUTCString(); + switch (Platform.OS) { + case 'web': + // Fully secured to this domain to prevent XSS/etc. attacks. + document.cookie = `${slot}=${val};expires=${expirationDate};path=/;secure;samesite=strict`; + return; + case 'ios': + case 'android': + default: + await AsyncStorage.setItem(slot, val); + return; + } +}; + export const logLastDataQuery = ({ itemId, activities,