Changeset View
Changeset View
Standalone View
Standalone View
native/data/sqlite-data-handler.js
// @flow | // @flow | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { Alert } from 'react-native'; | import { Alert } from 'react-native'; | ||||
import ExitApp from 'react-native-exit-app'; | import ExitApp from 'react-native-exit-app'; | ||||
import { useDispatch } from 'react-redux'; | import { useDispatch } from 'react-redux'; | ||||
import { setClientDBStoreActionType } from 'lib/actions/client-db-store-actions'; | import { setClientDBStoreActionType } from 'lib/actions/client-db-store-actions'; | ||||
import { isLoggedIn } from 'lib/selectors/user-selectors'; | import { isLoggedIn } from 'lib/selectors/user-selectors'; | ||||
import { logInActionSources } from 'lib/types/account-types'; | import { | ||||
logInActionSources, | |||||
type LogInActionSource, | |||||
} from 'lib/types/account-types'; | |||||
import { fetchNewCookieFromNativeCredentials } from 'lib/utils/action-utils'; | import { fetchNewCookieFromNativeCredentials } from 'lib/utils/action-utils'; | ||||
import { getMessageForException } from 'lib/utils/errors'; | import { getMessageForException } from 'lib/utils/errors'; | ||||
import { convertClientDBThreadInfosToRawThreadInfos } from 'lib/utils/thread-ops-utils'; | import { convertClientDBThreadInfosToRawThreadInfos } from 'lib/utils/thread-ops-utils'; | ||||
import { commCoreModule } from '../native-modules'; | import { commCoreModule } from '../native-modules'; | ||||
import { setStoreLoadedActionType } from '../redux/action-types'; | import { setStoreLoadedActionType } from '../redux/action-types'; | ||||
import { useSelector } from '../redux/redux-utils'; | import { useSelector } from '../redux/redux-utils'; | ||||
import { StaffContext } from '../staff/staff-context'; | import { StaffContext } from '../staff/staff-context'; | ||||
Show All 11 Lines | function SQLiteDataHandler(): React.Node { | ||||
const urlPrefix = useSelector(state => state.urlPrefix); | const urlPrefix = useSelector(state => state.urlPrefix); | ||||
const staffCanSee = useStaffCanSee(); | const staffCanSee = useStaffCanSee(); | ||||
const { staffUserHasBeenLoggedIn } = React.useContext(StaffContext); | const { staffUserHasBeenLoggedIn } = React.useContext(StaffContext); | ||||
const loggedIn = useSelector(isLoggedIn); | const loggedIn = useSelector(isLoggedIn); | ||||
const currentLoggedInUserID = useSelector(state => | const currentLoggedInUserID = useSelector(state => | ||||
state.currentUserInfo?.anonymous ? undefined : state.currentUserInfo?.id, | state.currentUserInfo?.anonymous ? undefined : state.currentUserInfo?.id, | ||||
); | ); | ||||
const handleSensitiveData = React.useCallback(async () => { | const callFetchNewCookieFromNativeCredentials = React.useCallback( | ||||
async (source: LogInActionSource) => { | |||||
try { | try { | ||||
const databaseCurrentUserInfoID = await commCoreModule.getCurrentUserID(); | await fetchNewCookieFromNativeCredentials( | ||||
if ( | dispatch, | ||||
databaseCurrentUserInfoID && | cookie, | ||||
databaseCurrentUserInfoID !== currentLoggedInUserID | urlPrefix, | ||||
) { | source, | ||||
); | |||||
dispatch({ type: setStoreLoadedActionType }); | |||||
} catch (fetchCookieException) { | |||||
if (staffCanSee) { | |||||
Alert.alert( | |||||
`Error fetching new cookie from native credentials: ${ | |||||
getMessageForException(fetchCookieException) ?? | |||||
'{no exception message}' | |||||
}. Please kill the app.`, | |||||
); | |||||
} else { | |||||
ExitApp.exitApp(); | |||||
} | |||||
} | |||||
}, | |||||
[cookie, dispatch, staffCanSee, urlPrefix], | |||||
); | |||||
const callClearSensitiveData = React.useCallback( | |||||
async (triggeredBy: string) => { | |||||
if (staffCanSee || staffUserHasBeenLoggedIn) { | if (staffCanSee || staffUserHasBeenLoggedIn) { | ||||
Alert.alert('Starting SQLite database deletion process'); | Alert.alert('Starting SQLite database deletion process'); | ||||
} | } | ||||
await commCoreModule.clearSensitiveData(); | await commCoreModule.clearSensitiveData(); | ||||
if (staffCanSee || staffUserHasBeenLoggedIn) { | if (staffCanSee || staffUserHasBeenLoggedIn) { | ||||
Alert.alert( | Alert.alert( | ||||
'SQLite database successfully deleted', | 'SQLite database successfully deleted', | ||||
'SQLite database deletion was triggered by change in logged-in user credentials', | `SQLite database deletion was triggered by ${triggeredBy}`, | ||||
); | ); | ||||
} | } | ||||
}, | |||||
[staffCanSee, staffUserHasBeenLoggedIn], | |||||
); | |||||
const handleSensitiveData = React.useCallback(async () => { | |||||
try { | |||||
const databaseCurrentUserInfoID = await commCoreModule.getCurrentUserID(); | |||||
if ( | |||||
databaseCurrentUserInfoID && | |||||
databaseCurrentUserInfoID !== currentLoggedInUserID | |||||
) { | |||||
await callClearSensitiveData('change in logged-in user credentials'); | |||||
} | } | ||||
if (currentLoggedInUserID) { | if (currentLoggedInUserID) { | ||||
await commCoreModule.setCurrentUserID(currentLoggedInUserID); | await commCoreModule.setCurrentUserID(currentLoggedInUserID); | ||||
} | } | ||||
const databaseDeviceID = await commCoreModule.getDeviceID(); | const databaseDeviceID = await commCoreModule.getDeviceID(); | ||||
if (!databaseDeviceID) { | if (!databaseDeviceID) { | ||||
await commCoreModule.setDeviceID('MOBILE'); | await commCoreModule.setDeviceID('MOBILE'); | ||||
} | } | ||||
} catch (e) { | } catch (e) { | ||||
if (isTaskCancelledError(e)) { | if (isTaskCancelledError(e)) { | ||||
return; | return; | ||||
} | } | ||||
if (__DEV__) { | if (__DEV__) { | ||||
throw e; | throw e; | ||||
} else { | } else { | ||||
console.log(e); | console.log(e); | ||||
ExitApp.exitApp(); | ExitApp.exitApp(); | ||||
} | } | ||||
} | } | ||||
}, [currentLoggedInUserID, staffCanSee, staffUserHasBeenLoggedIn]); | }, [callClearSensitiveData, currentLoggedInUserID]); | ||||
React.useEffect(() => { | React.useEffect(() => { | ||||
if (!rehydrateConcluded) { | if (!rehydrateConcluded) { | ||||
return; | return; | ||||
} | } | ||||
const databaseNeedsDeletion = commCoreModule.checkIfDatabaseNeedsDeletion(); | |||||
if (databaseNeedsDeletion) { | |||||
(async () => { | |||||
try { | |||||
await callClearSensitiveData('detecting corrupted database'); | |||||
} catch (e) { | |||||
if (__DEV__) { | |||||
throw e; | |||||
} else { | |||||
console.log(e); | |||||
ExitApp.exitApp(); | |||||
} | |||||
} | |||||
await callFetchNewCookieFromNativeCredentials( | |||||
logInActionSources.corruptedDatabaseDeletion, | |||||
); | |||||
})(); | |||||
return; | |||||
} | |||||
const sensitiveDataHandled = handleSensitiveData(); | const sensitiveDataHandled = handleSensitiveData(); | ||||
if (storeLoaded) { | if (storeLoaded) { | ||||
return; | return; | ||||
} | } | ||||
if (!loggedIn) { | if (!loggedIn) { | ||||
dispatch({ type: setStoreLoadedActionType }); | dispatch({ type: setStoreLoadedActionType }); | ||||
return; | return; | ||||
} | } | ||||
Show All 25 Lines | (async () => { | ||||
if (staffCanSee) { | if (staffCanSee) { | ||||
Alert.alert( | Alert.alert( | ||||
`Error setting threadStore or messageStore: ${ | `Error setting threadStore or messageStore: ${ | ||||
getMessageForException(setStoreException) ?? | getMessageForException(setStoreException) ?? | ||||
'{no exception message}' | '{no exception message}' | ||||
}`, | }`, | ||||
); | ); | ||||
} | } | ||||
try { | await callFetchNewCookieFromNativeCredentials( | ||||
await fetchNewCookieFromNativeCredentials( | |||||
dispatch, | |||||
cookie, | |||||
urlPrefix, | |||||
logInActionSources.sqliteLoadFailure, | logInActionSources.sqliteLoadFailure, | ||||
); | ); | ||||
dispatch({ type: setStoreLoadedActionType }); | |||||
} catch (fetchCookieException) { | |||||
if (staffCanSee) { | |||||
Alert.alert( | |||||
`Error fetching new cookie from native credentials: ${ | |||||
getMessageForException(fetchCookieException) ?? | |||||
'{no exception message}' | |||||
}. Please kill the app.`, | |||||
); | |||||
} else { | |||||
ExitApp.exitApp(); | |||||
} | |||||
} | |||||
} | } | ||||
})(); | })(); | ||||
}, [ | }, [ | ||||
currentLoggedInUserID, | currentLoggedInUserID, | ||||
handleSensitiveData, | handleSensitiveData, | ||||
loggedIn, | loggedIn, | ||||
cookie, | cookie, | ||||
ashoat: We're no longer using several of these directly in the dep list, so they can be removed. I'm… | |||||
dispatch, | dispatch, | ||||
rehydrateConcluded, | rehydrateConcluded, | ||||
staffCanSee, | staffCanSee, | ||||
storeLoaded, | storeLoaded, | ||||
urlPrefix, | urlPrefix, | ||||
staffUserHasBeenLoggedIn, | |||||
ashoatUnsubmitted Not Done Inline ActionsIt's not clear why this one was added to the dep list... it doesn't appear to be used in the effect ashoat: It's not clear why this one was added to the dep list... it doesn't appear to be used in the… | |||||
callFetchNewCookieFromNativeCredentials, | |||||
callClearSensitiveData, | |||||
]); | ]); | ||||
return null; | return null; | ||||
} | } | ||||
export { SQLiteDataHandler }; | export { SQLiteDataHandler }; |
We're no longer using several of these directly in the dep list, so they can be removed. I'm actually not sure why the React hook ESLint rules didn't catch this