Skip to content

Commit

Permalink
add cookies as storage pattern on web to prevent insecure local stora…
Browse files Browse the repository at this point in the history
…ge for pks
  • Loading branch information
kibagateaux committed Aug 3, 2024
1 parent a8cbdd5 commit 7c4fd98
Showing 1 changed file with 42 additions and 8 deletions.
50 changes: 42 additions & 8 deletions src/utils/config.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand Down Expand Up @@ -300,10 +301,8 @@ export const getStorage: <T>(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) {
Expand All @@ -314,6 +313,27 @@ export const getStorage: <T>(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
Expand Down Expand Up @@ -359,7 +379,7 @@ export const saveStorage: <T>(

// 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;
}
Expand All @@ -382,8 +402,7 @@ export const saveStorage: <T>(
? 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 {
Expand All @@ -396,8 +415,7 @@ export const saveStorage: <T>(
? 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;
}
Expand All @@ -408,6 +426,22 @@ export const saveStorage: <T>(
}
};

const _saveStorage = async (slot: string, val: string): Promise<void> => {
// 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,
Expand Down

0 comments on commit 7c4fd98

Please sign in to comment.