diff --git a/native/account/logged-out-staff-info.react.js b/native/account/logged-out-staff-info.react.js
index d5d002e86..3faef34ad 100644
--- a/native/account/logged-out-staff-info.react.js
+++ b/native/account/logged-out-staff-info.react.js
@@ -1,119 +1,119 @@
// @flow
import * as React from 'react';
import { Text, View } from 'react-native';
import SWMansionIcon from '../components/swmansion-icon.react.js';
-import { StaffContext } from '../staff/staff-context.js';
+import { useStaffContext } from '../staff/staff-context.provider.react.js';
import { useStyles, useColors } from '../themes/colors.js';
import { isStaffRelease, useStaffCanSee } from '../utils/staff-utils.js';
function LoggedOutStaffInfo(): React.Node {
const staffCanSee = useStaffCanSee();
- const { staffUserHasBeenLoggedIn } = React.useContext(StaffContext);
+ const { staffUserHasBeenLoggedIn } = useStaffContext();
const styles = useStyles(unboundStyles);
const colors = useColors();
const checkIcon = React.useMemo(
() => (
),
[colors.vibrantGreenButton],
);
const crossIcon = React.useMemo(
() => (
),
[colors.vibrantRedButton],
);
const isDevBuildStyle = React.useMemo(() => {
return [
styles.infoText,
__DEV__ ? styles.infoTextTrue : styles.infoTextFalse,
];
}, [styles.infoText, styles.infoTextFalse, styles.infoTextTrue]);
const isStaffReleaseStyle = React.useMemo(() => {
return [
styles.infoText,
isStaffRelease ? styles.infoTextTrue : styles.infoTextFalse,
];
}, [styles.infoText, styles.infoTextFalse, styles.infoTextTrue]);
const hasStaffUserLoggedInStyle = React.useMemo(() => {
return [
styles.infoText,
staffUserHasBeenLoggedIn ? styles.infoTextTrue : styles.infoTextFalse,
];
}, [
staffUserHasBeenLoggedIn,
styles.infoText,
styles.infoTextFalse,
styles.infoTextTrue,
]);
let loggedOutStaffInfo = null;
if (staffCanSee || staffUserHasBeenLoggedIn) {
loggedOutStaffInfo = (
{__DEV__ ? checkIcon : crossIcon}
__DEV__
{isStaffRelease ? checkIcon : crossIcon}
isStaffRelease
{staffUserHasBeenLoggedIn ? checkIcon : crossIcon}
staffUserHasBeenLoggedIn
);
}
return loggedOutStaffInfo;
}
const unboundStyles = {
cell: {
flexDirection: 'row',
alignItems: 'center',
},
infoBadge: {
backgroundColor: 'codeBackground',
borderRadius: 6,
justifyContent: 'flex-start',
marginBottom: 10,
marginTop: 10,
marginLeft: 4,
marginRight: 4,
padding: 8,
},
infoText: {
fontFamily: 'OpenSans-Semibold',
fontSize: 14,
lineHeight: 24,
paddingLeft: 4,
textAlign: 'left',
},
infoTextFalse: {
color: 'vibrantRedButton',
},
infoTextTrue: {
color: 'vibrantGreenButton',
},
};
export default LoggedOutStaffInfo;
diff --git a/native/data/sqlite-data-handler.js b/native/data/sqlite-data-handler.js
index 893dcb336..c25f1a36f 100644
--- a/native/data/sqlite-data-handler.js
+++ b/native/data/sqlite-data-handler.js
@@ -1,235 +1,235 @@
// @flow
import invariant from 'invariant';
import * as React from 'react';
import { setClientDBStoreActionType } from 'lib/actions/client-db-store-actions.js';
import { MediaCacheContext } from 'lib/components/media-cache-provider.react.js';
import { resolveKeyserverSessionInvalidation } from 'lib/keyserver-conn/recovery-utils.js';
import { reportStoreOpsHandlers } from 'lib/ops/report-store-ops.js';
import { threadStoreOpsHandlers } from 'lib/ops/thread-store-ops.js';
import { userStoreOpsHandlers } from 'lib/ops/user-store-ops.js';
import {
cookieSelector,
urlPrefixSelector,
} from 'lib/selectors/keyserver-selectors.js';
import { isLoggedIn } from 'lib/selectors/user-selectors.js';
import { useInitialNotificationsEncryptedMessage } from 'lib/shared/crypto-utils.js';
import {
logInActionSources,
type LogInActionSource,
} from 'lib/types/account-types.js';
import { getMessageForException } from 'lib/utils/errors.js';
import { useDispatch } from 'lib/utils/redux-utils.js';
import { ashoatKeyserverID } from 'lib/utils/validation-utils.js';
import { filesystemMediaCache } from '../media/media-cache.js';
import { commCoreModule } from '../native-modules.js';
import { setStoreLoadedActionType } from '../redux/action-types.js';
import { useSelector } from '../redux/redux-utils.js';
-import { StaffContext } from '../staff/staff-context.js';
+import { useStaffContext } from '../staff/staff-context.provider.react.js';
import Alert from '../utils/alert.js';
import { nativeNotificationsSessionCreator } from '../utils/crypto-utils.js';
import { isTaskCancelledError } from '../utils/error-handling.js';
import { useStaffCanSee } from '../utils/staff-utils.js';
async function clearSensitiveData() {
await commCoreModule.clearSensitiveData();
try {
await filesystemMediaCache.clearCache();
} catch {
throw new Error('clear_media_cache_failed');
}
}
function SQLiteDataHandler(): React.Node {
const storeLoaded = useSelector(state => state.storeLoaded);
const dispatch = useDispatch();
const rehydrateConcluded = useSelector(
state => !!(state._persist && state._persist.rehydrated),
);
const cookie = useSelector(cookieSelector(ashoatKeyserverID));
const urlPrefix = useSelector(urlPrefixSelector(ashoatKeyserverID));
invariant(urlPrefix, "missing urlPrefix for ashoat's keyserver");
const staffCanSee = useStaffCanSee();
- const { staffUserHasBeenLoggedIn } = React.useContext(StaffContext);
+ const { staffUserHasBeenLoggedIn } = useStaffContext();
const loggedIn = useSelector(isLoggedIn);
const currentLoggedInUserID = useSelector(state =>
state.currentUserInfo?.anonymous ? undefined : state.currentUserInfo?.id,
);
const mediaCacheContext = React.useContext(MediaCacheContext);
const getInitialNotificationsEncryptedMessage =
useInitialNotificationsEncryptedMessage(nativeNotificationsSessionCreator);
const callFetchNewCookieFromNativeCredentials = React.useCallback(
async (source: LogInActionSource) => {
try {
await resolveKeyserverSessionInvalidation(
dispatch,
cookie,
urlPrefix,
source,
ashoatKeyserverID,
getInitialNotificationsEncryptedMessage,
);
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 {
commCoreModule.terminate();
}
}
},
[
cookie,
dispatch,
staffCanSee,
urlPrefix,
getInitialNotificationsEncryptedMessage,
],
);
const callClearSensitiveData = React.useCallback(
async (triggeredBy: string) => {
await clearSensitiveData();
console.log(`SQLite database deletion was triggered by ${triggeredBy}`);
},
[],
);
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) {
await commCoreModule.setCurrentUserID(currentLoggedInUserID);
}
} catch (e) {
if (isTaskCancelledError(e)) {
return;
}
if (__DEV__) {
throw e;
}
console.log(e);
if (e.message !== 'clear_media_cache_failed') {
commCoreModule.terminate();
}
}
}, [callClearSensitiveData, currentLoggedInUserID]);
React.useEffect(() => {
if (!rehydrateConcluded) {
return;
}
const databaseNeedsDeletion = commCoreModule.checkIfDatabaseNeedsDeletion();
if (databaseNeedsDeletion) {
void (async () => {
try {
await callClearSensitiveData('detecting corrupted database');
} catch (e) {
if (__DEV__) {
throw e;
}
console.log(e);
if (e.message !== 'clear_media_cache_failed') {
commCoreModule.terminate();
}
}
await callFetchNewCookieFromNativeCredentials(
logInActionSources.corruptedDatabaseDeletion,
);
})();
return;
}
const sensitiveDataHandled = handleSensitiveData();
if (storeLoaded) {
return;
}
if (!loggedIn) {
dispatch({ type: setStoreLoadedActionType });
return;
}
void (async () => {
await Promise.all([
sensitiveDataHandled,
mediaCacheContext?.evictCache(),
]);
try {
const {
threads,
messages,
drafts,
messageStoreThreads,
reports,
users,
} = await commCoreModule.getClientDBStore();
const threadInfosFromDB =
threadStoreOpsHandlers.translateClientDBData(threads);
const reportsFromDb =
reportStoreOpsHandlers.translateClientDBData(reports);
const usersFromDb = userStoreOpsHandlers.translateClientDBData(users);
dispatch({
type: setClientDBStoreActionType,
payload: {
drafts,
messages,
threadStore: { threadInfos: threadInfosFromDB },
currentUserID: currentLoggedInUserID,
messageStoreThreads,
reports: reportsFromDb,
users: usersFromDb,
},
});
} catch (setStoreException) {
if (isTaskCancelledError(setStoreException)) {
dispatch({ type: setStoreLoadedActionType });
return;
}
if (staffCanSee) {
Alert.alert(
'Error setting threadStore or messageStore',
getMessageForException(setStoreException) ??
'{no exception message}',
);
}
await callFetchNewCookieFromNativeCredentials(
logInActionSources.sqliteLoadFailure,
);
}
})();
}, [
currentLoggedInUserID,
handleSensitiveData,
loggedIn,
cookie,
dispatch,
rehydrateConcluded,
staffCanSee,
storeLoaded,
urlPrefix,
staffUserHasBeenLoggedIn,
callFetchNewCookieFromNativeCredentials,
callClearSensitiveData,
mediaCacheContext,
]);
return null;
}
export { SQLiteDataHandler, clearSensitiveData };
diff --git a/native/profile/build-info.react.js b/native/profile/build-info.react.js
index 9ca6ea9b6..a85c31705 100644
--- a/native/profile/build-info.react.js
+++ b/native/profile/build-info.react.js
@@ -1,122 +1,122 @@
// @flow
import * as React from 'react';
import { View, Text } from 'react-native';
import { ScrollView } from 'react-native-gesture-handler';
import { useIsCurrentUserStaff } from 'lib/shared/staff-utils.js';
import type { ProfileNavigationProp } from './profile.react.js';
import type { NavigationRoute } from '../navigation/route-names.js';
import { persistConfig, codeVersion } from '../redux/persist.js';
-import { StaffContext } from '../staff/staff-context.js';
+import { useStaffContext } from '../staff/staff-context.provider.react.js';
import { useStyles } from '../themes/colors.js';
import { isStaffRelease, useStaffCanSee } from '../utils/staff-utils.js';
type Props = {
+navigation: ProfileNavigationProp<'BuildInfo'>,
+route: NavigationRoute<'BuildInfo'>,
};
// eslint-disable-next-line no-unused-vars
function BuildInfo(props: Props): React.Node {
const isCurrentUserStaff = useIsCurrentUserStaff();
- const { staffUserHasBeenLoggedIn } = React.useContext(StaffContext);
+ const { staffUserHasBeenLoggedIn } = useStaffContext();
const styles = useStyles(unboundStyles);
const staffCanSee = useStaffCanSee();
let staffCanSeeRows;
if (staffCanSee || staffUserHasBeenLoggedIn) {
staffCanSeeRows = (
<>
__DEV__
{__DEV__ ? 'TRUE' : 'FALSE'}
Staff Release
{isStaffRelease ? 'TRUE' : 'FALSE'}
isCurrentUserStaff
{isCurrentUserStaff ? 'TRUE' : 'FALSE'}
hasStaffUserLoggedIn
{staffUserHasBeenLoggedIn ? 'TRUE' : 'FALSE'}
>
);
}
return (
Code version
{codeVersion}
State version
{persistConfig.version}
{staffCanSeeRows}
Thank you for using Comm!
);
}
const unboundStyles = {
label: {
color: 'panelForegroundTertiaryLabel',
fontSize: 16,
paddingRight: 12,
},
releaseText: {
color: 'orange',
fontSize: 16,
},
row: {
flexDirection: 'row',
justifyContent: 'space-between',
paddingVertical: 6,
},
scrollView: {
backgroundColor: 'panelBackground',
},
scrollViewContentContainer: {
paddingTop: 24,
},
section: {
backgroundColor: 'panelForeground',
borderBottomWidth: 1,
borderColor: 'panelForegroundBorder',
borderTopWidth: 1,
marginBottom: 24,
paddingHorizontal: 24,
paddingVertical: 6,
},
text: {
color: 'panelForegroundLabel',
fontSize: 16,
},
thanksText: {
color: 'panelForegroundLabel',
flex: 1,
fontSize: 16,
textAlign: 'center',
},
};
export default BuildInfo;
diff --git a/native/staff/staff-context.js b/native/staff/staff-context.js
deleted file mode 100644
index a90ac04f2..000000000
--- a/native/staff/staff-context.js
+++ /dev/null
@@ -1,13 +0,0 @@
-// @flow
-
-import * as React from 'react';
-
-export type StaffContextType = {
- +staffUserHasBeenLoggedIn: boolean,
-};
-
-const StaffContext: React.Context = React.createContext({
- staffUserHasBeenLoggedIn: false,
-});
-
-export { StaffContext };
diff --git a/native/staff/staff-context.provider.react.js b/native/staff/staff-context.provider.react.js
index 329b92342..33312c82b 100644
--- a/native/staff/staff-context.provider.react.js
+++ b/native/staff/staff-context.provider.react.js
@@ -1,36 +1,45 @@
// @flow
import * as React from 'react';
import { useIsCurrentUserStaff } from 'lib/shared/staff-utils.js';
-import { StaffContext, type StaffContextType } from './staff-context.js';
+export type StaffContextType = {
+ +staffUserHasBeenLoggedIn: boolean,
+};
+
+const StaffContext: React.Context =
+ React.createContext({
+ staffUserHasBeenLoggedIn: false,
+ });
type Props = {
+children: React.Node,
};
function StaffContextProvider(props: Props): React.Node {
const [staffUserHasBeenLoggedIn, setStaffUserHasBeenLoggedIn] =
React.useState(false);
const isCurrentUserStaff = useIsCurrentUserStaff();
React.useEffect(() => {
if (isCurrentUserStaff) {
setStaffUserHasBeenLoggedIn(true);
}
}, [isCurrentUserStaff]);
const staffContextValue: StaffContextType = React.useMemo(
() => ({ staffUserHasBeenLoggedIn }),
[staffUserHasBeenLoggedIn],
);
return (
{props.children}
);
}
-export { StaffContextProvider };
+const useStaffContext = (): StaffContextType => React.useContext(StaffContext);
+
+export { StaffContextProvider, useStaffContext };