diff --git a/native/account/fullscreen-siwe-panel.react.js b/native/account/fullscreen-siwe-panel.react.js
index 348208cf4..f1fce696f 100644
--- a/native/account/fullscreen-siwe-panel.react.js
+++ b/native/account/fullscreen-siwe-panel.react.js
@@ -1,124 +1,124 @@
// @flow
import { useNavigation } from '@react-navigation/native';
import invariant from 'invariant';
import * as React from 'react';
import { ActivityIndicator, View } from 'react-native';
import { setDataLoadedActionType } from 'lib/actions/client-db-store-actions.js';
import type { SIWEResult } from 'lib/types/siwe-types.js';
import { ServerError } from 'lib/utils/errors.js';
import { useDispatch } from 'lib/utils/redux-utils.js';
import { useGetEthereumAccountFromSIWEResult } from './registration/ethereum-utils.js';
import { RegistrationContext } from './registration/registration-context.js';
import { enableNewRegistrationMode } from './registration/registration-types.js';
-import { useSIWEServerCall } from './siwe-hooks.js';
+import { useLegacySIWEServerCall } from './siwe-hooks.js';
import SIWEPanel from './siwe-panel.react.js';
import {
AccountDoesNotExistRouteName,
RegistrationRouteName,
} from '../navigation/route-names.js';
import { UnknownErrorAlertDetails } from '../utils/alert-messages.js';
import Alert from '../utils/alert.js';
type Props = {
+goBackToPrompt: () => mixed,
+closing: boolean,
};
function FullscreenSIWEPanel(props: Props): React.Node {
const [loading, setLoading] = React.useState(true);
const activity = loading ? : null;
const activityContainer = React.useMemo(
() => ({
flex: 1,
}),
[],
);
const registrationContext = React.useContext(RegistrationContext);
invariant(registrationContext, 'registrationContext should be set');
const { setSkipEthereumLoginOnce } = registrationContext;
const getEthereumAccountFromSIWEResult =
useGetEthereumAccountFromSIWEResult();
const { navigate } = useNavigation();
const { goBackToPrompt } = props;
const onAccountDoesNotExist = React.useCallback(
async (result: SIWEResult) => {
await getEthereumAccountFromSIWEResult(result);
setSkipEthereumLoginOnce(true);
goBackToPrompt();
navigate<'Registration'>(RegistrationRouteName, {
screen: AccountDoesNotExistRouteName,
});
},
[
getEthereumAccountFromSIWEResult,
navigate,
goBackToPrompt,
setSkipEthereumLoginOnce,
],
);
- const siweServerCall = useSIWEServerCall();
+ const legacySiweServerCall = useLegacySIWEServerCall();
const successRef = React.useRef(false);
const dispatch = useDispatch();
const onSuccess = React.useCallback(
async (result: SIWEResult) => {
successRef.current = true;
try {
- await siweServerCall({
+ await legacySiweServerCall({
...result,
doNotRegister: enableNewRegistrationMode,
});
} catch (e) {
if (
e instanceof ServerError &&
e.message === 'account_does_not_exist'
) {
await onAccountDoesNotExist(result);
return;
}
Alert.alert(
UnknownErrorAlertDetails.title,
UnknownErrorAlertDetails.message,
[{ text: 'OK', onPress: goBackToPrompt }],
{ cancelable: false },
);
throw e;
}
dispatch({
type: setDataLoadedActionType,
payload: {
dataLoaded: true,
},
});
},
- [siweServerCall, dispatch, goBackToPrompt, onAccountDoesNotExist],
+ [legacySiweServerCall, dispatch, goBackToPrompt, onAccountDoesNotExist],
);
const ifBeforeSuccessGoBackToPrompt = React.useCallback(() => {
if (!successRef.current) {
goBackToPrompt();
}
}, [goBackToPrompt]);
const { closing } = props;
return (
<>
{activity}
>
);
}
export default FullscreenSIWEPanel;
diff --git a/native/account/registration/existing-ethereum-account.react.js b/native/account/registration/existing-ethereum-account.react.js
index 63dc2e83b..2050b52d8 100644
--- a/native/account/registration/existing-ethereum-account.react.js
+++ b/native/account/registration/existing-ethereum-account.react.js
@@ -1,145 +1,145 @@
// @flow
import * as React from 'react';
import { Text, View } from 'react-native';
import { setDataLoadedActionType } from 'lib/actions/client-db-store-actions.js';
import { siweAuthActionTypes } from 'lib/actions/siwe-actions.js';
import { useENSName } from 'lib/hooks/ens-cache.js';
import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js';
import type { SIWEResult } from 'lib/types/siwe-types.js';
import { useDispatch } from 'lib/utils/redux-utils.js';
import RegistrationButtonContainer from './registration-button-container.react.js';
import RegistrationButton from './registration-button.react.js';
import RegistrationContainer from './registration-container.react.js';
import RegistrationContentContainer from './registration-content-container.react.js';
import type { RegistrationNavigationProp } from './registration-navigator.react.js';
import type { NavigationRoute } from '../../navigation/route-names.js';
import { useSelector } from '../../redux/redux-utils.js';
import { useStyles } from '../../themes/colors.js';
import { UnknownErrorAlertDetails } from '../../utils/alert-messages.js';
import Alert from '../../utils/alert.js';
-import { useSIWEServerCall } from '../siwe-hooks.js';
+import { useLegacySIWEServerCall } from '../siwe-hooks.js';
const siweAuthLoadingStatusSelector =
createLoadingStatusSelector(siweAuthActionTypes);
export type ExistingEthereumAccountParams = SIWEResult;
type Props = {
+navigation: RegistrationNavigationProp<'ExistingEthereumAccount'>,
+route: NavigationRoute<'ExistingEthereumAccount'>,
};
function ExistingEthereumAccount(props: Props): React.Node {
- const siweServerCall = useSIWEServerCall();
+ const legacySiweServerCall = useLegacySIWEServerCall();
const { params } = props.route;
const dispatch = useDispatch();
const onProceedToLogIn = React.useCallback(async () => {
try {
- await siweServerCall({ ...params, doNotRegister: true });
+ await legacySiweServerCall({ ...params, doNotRegister: true });
} catch (e) {
Alert.alert(
UnknownErrorAlertDetails.title,
UnknownErrorAlertDetails.message,
[{ text: 'OK' }],
{
cancelable: false,
},
);
throw e;
}
dispatch({
type: setDataLoadedActionType,
payload: {
dataLoaded: true,
},
});
- }, [siweServerCall, params, dispatch]);
+ }, [legacySiweServerCall, params, dispatch]);
const siweAuthCallLoading = useSelector(
state => siweAuthLoadingStatusSelector(state) === 'loading',
);
const { address } = params;
const walletIdentifier = useENSName(address);
const walletIdentifierTitle =
walletIdentifier === address ? 'Ethereum wallet' : 'ENS name';
const { goBack } = props.navigation;
const styles = useStyles(unboundStyles);
return (
Account already exists for wallet
You can proceed to log in with this wallet, or go back and use a
different wallet.
{walletIdentifierTitle}
{walletIdentifier}
);
}
const unboundStyles = {
header: {
fontSize: 24,
color: 'panelForegroundLabel',
paddingBottom: 16,
},
body: {
fontFamily: 'Arial',
fontSize: 15,
lineHeight: 20,
color: 'panelForegroundSecondaryLabel',
paddingBottom: 40,
},
walletTile: {
backgroundColor: 'panelForeground',
borderRadius: 8,
padding: 24,
alignItems: 'center',
},
walletIdentifierTitleText: {
fontSize: 17,
color: 'panelForegroundLabel',
textAlign: 'center',
},
walletIdentifier: {
backgroundColor: 'panelSecondaryForeground',
paddingVertical: 8,
paddingHorizontal: 24,
borderRadius: 56,
marginTop: 8,
alignItems: 'center',
},
walletIdentifierText: {
fontSize: 15,
color: 'panelForegroundLabel',
},
};
export default ExistingEthereumAccount;
diff --git a/native/account/registration/registration-server-call.js b/native/account/registration/registration-server-call.js
index afc043764..bedfd42da 100644
--- a/native/account/registration/registration-server-call.js
+++ b/native/account/registration/registration-server-call.js
@@ -1,297 +1,297 @@
// @flow
import * as React from 'react';
import { setDataLoadedActionType } from 'lib/actions/client-db-store-actions.js';
import {
keyserverRegisterActionTypes,
keyserverRegister,
useIdentityRegister,
identityRegisterActionTypes,
} from 'lib/actions/user-actions.js';
import type { LogInStartingPayload } from 'lib/types/account-types.js';
import { useLegacyAshoatKeyserverCall } from 'lib/utils/action-utils.js';
import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js';
import { useDispatch } from 'lib/utils/redux-utils.js';
import { usingCommServicesAccessToken } from 'lib/utils/services-utils.js';
import { setURLPrefix } from 'lib/utils/url-utils.js';
import type {
RegistrationServerCallInput,
UsernameAccountSelection,
AvatarData,
} from './registration-types.js';
import {
useNativeSetUserAvatar,
useUploadSelectedMedia,
} from '../../avatars/avatar-hooks.js';
import { useSelector } from '../../redux/redux-utils.js';
import { nativeLogInExtraInfoSelector } from '../../selectors/account-selectors.js';
import {
AppOutOfDateAlertDetails,
UsernameReservedAlertDetails,
UsernameTakenAlertDetails,
UnknownErrorAlertDetails,
} from '../../utils/alert-messages.js';
import Alert from '../../utils/alert.js';
import { setNativeCredentials } from '../native-credentials.js';
-import { useSIWEServerCall } from '../siwe-hooks.js';
+import { useLegacySIWEServerCall } from '../siwe-hooks.js';
// We can't just do everything in one async callback, since the server calls
// would get bound to Redux state from before the registration. The registration
// flow has multiple steps where critical Redux state is changed, where
// subsequent steps depend on accessing the updated Redux state.
// To address this, we break the registration process up into multiple steps.
// When each step completes we update the currentStep state, and we have Redux
// selectors that trigger useEffects for subsequent steps when relevant data
// starts to appear in Redux.
type CurrentStep =
| { +step: 'inactive' }
| {
+step: 'waiting_for_registration_call',
+avatarData: ?AvatarData,
+resolve: () => void,
+reject: Error => void,
};
const inactiveStep = { step: 'inactive' };
function useRegistrationServerCall(): RegistrationServerCallInput => Promise {
const [currentStep, setCurrentStep] =
React.useState(inactiveStep);
// STEP 1: ACCOUNT REGISTRATION
const logInExtraInfo = useSelector(nativeLogInExtraInfoSelector);
const dispatchActionPromise = useDispatchActionPromise();
const callKeyserverRegister = useLegacyAshoatKeyserverCall(keyserverRegister);
const callIdentityRegister = useIdentityRegister();
const identityRegisterUsernameAccount = React.useCallback(
async (accountSelection: UsernameAccountSelection) => {
const identityRegisterPromise = (async () => {
try {
const result = await callIdentityRegister(
accountSelection.username,
accountSelection.password,
);
await setNativeCredentials({
username: accountSelection.username,
password: accountSelection.password,
});
return result;
} catch (e) {
if (e.message === 'username reserved') {
Alert.alert(
UsernameReservedAlertDetails.title,
UsernameReservedAlertDetails.message,
);
} else if (e.message === 'username already exists') {
Alert.alert(
UsernameTakenAlertDetails.title,
UsernameTakenAlertDetails.message,
);
} else if (e.message === 'Unsupported version') {
Alert.alert(
AppOutOfDateAlertDetails.title,
AppOutOfDateAlertDetails.message,
);
} else {
Alert.alert(
UnknownErrorAlertDetails.title,
UnknownErrorAlertDetails.message,
);
}
throw e;
}
})();
void dispatchActionPromise(
identityRegisterActionTypes,
identityRegisterPromise,
);
await identityRegisterPromise;
},
[callIdentityRegister, dispatchActionPromise],
);
const keyserverRegisterUsernameAccount = React.useCallback(
async (
accountSelection: UsernameAccountSelection,
keyserverURL: string,
) => {
const extraInfo = await logInExtraInfo();
const keyserverRegisterPromise = (async () => {
try {
const result = await callKeyserverRegister(
{
...extraInfo,
username: accountSelection.username,
password: accountSelection.password,
},
{
urlPrefixOverride: keyserverURL,
},
);
await setNativeCredentials({
username: result.currentUserInfo.username,
password: accountSelection.password,
});
return result;
} catch (e) {
if (e.message === 'username_reserved') {
Alert.alert(
UsernameReservedAlertDetails.title,
UsernameReservedAlertDetails.message,
);
} else if (e.message === 'username_taken') {
Alert.alert(
UsernameTakenAlertDetails.title,
UsernameTakenAlertDetails.message,
);
} else if (e.message === 'client_version_unsupported') {
Alert.alert(
AppOutOfDateAlertDetails.title,
AppOutOfDateAlertDetails.message,
);
} else {
Alert.alert(
UnknownErrorAlertDetails.title,
UnknownErrorAlertDetails.message,
);
}
throw e;
}
})();
void dispatchActionPromise(
keyserverRegisterActionTypes,
keyserverRegisterPromise,
undefined,
({ calendarQuery: extraInfo.calendarQuery }: LogInStartingPayload),
);
await keyserverRegisterPromise;
},
[logInExtraInfo, callKeyserverRegister, dispatchActionPromise],
);
- const siweServerCall = useSIWEServerCall();
+ const legacySiweServerCall = useLegacySIWEServerCall();
const dispatch = useDispatch();
const returnedFunc = React.useCallback(
(input: RegistrationServerCallInput) =>
new Promise(
// eslint-disable-next-line no-async-promise-executor
async (resolve, reject) => {
try {
if (currentStep.step !== 'inactive') {
return;
}
const { accountSelection, avatarData, keyserverURL } = input;
if (
accountSelection.accountType === 'username' &&
!usingCommServicesAccessToken
) {
await keyserverRegisterUsernameAccount(
accountSelection,
keyserverURL,
);
} else if (accountSelection.accountType === 'username') {
await identityRegisterUsernameAccount(accountSelection);
} else {
try {
- await siweServerCall(accountSelection, {
+ await legacySiweServerCall(accountSelection, {
urlPrefixOverride: keyserverURL,
});
} catch (e) {
Alert.alert(
UnknownErrorAlertDetails.title,
UnknownErrorAlertDetails.message,
);
throw e;
}
}
dispatch({
type: setURLPrefix,
payload: keyserverURL,
});
setCurrentStep({
step: 'waiting_for_registration_call',
avatarData,
resolve,
reject,
});
} catch (e) {
reject(e);
}
},
),
[
currentStep,
keyserverRegisterUsernameAccount,
identityRegisterUsernameAccount,
- siweServerCall,
+ legacySiweServerCall,
dispatch,
],
);
// STEP 2: SETTING AVATAR
const uploadSelectedMedia = useUploadSelectedMedia();
const nativeSetUserAvatar = useNativeSetUserAvatar();
const hasCurrentUserInfo = useSelector(
state => !!state.currentUserInfo && !state.currentUserInfo.anonymous,
);
const avatarBeingSetRef = React.useRef(false);
React.useEffect(() => {
if (
!hasCurrentUserInfo ||
currentStep.step !== 'waiting_for_registration_call' ||
avatarBeingSetRef.current
) {
return;
}
avatarBeingSetRef.current = true;
const { avatarData, resolve } = currentStep;
void (async () => {
try {
if (!avatarData) {
return;
}
let updateUserAvatarRequest;
if (!avatarData.needsUpload) {
({ updateUserAvatarRequest } = avatarData);
} else {
const { mediaSelection } = avatarData;
updateUserAvatarRequest = await uploadSelectedMedia(mediaSelection);
if (!updateUserAvatarRequest) {
return;
}
}
await nativeSetUserAvatar(updateUserAvatarRequest);
} finally {
dispatch({
type: setDataLoadedActionType,
payload: {
dataLoaded: true,
},
});
setCurrentStep(inactiveStep);
avatarBeingSetRef.current = false;
resolve();
}
})();
}, [
currentStep,
hasCurrentUserInfo,
uploadSelectedMedia,
nativeSetUserAvatar,
dispatch,
]);
return returnedFunc;
}
export { useRegistrationServerCall };
diff --git a/native/account/siwe-hooks.js b/native/account/siwe-hooks.js
index f39013361..506d676b3 100644
--- a/native/account/siwe-hooks.js
+++ b/native/account/siwe-hooks.js
@@ -1,96 +1,96 @@
// @flow
import * as React from 'react';
import { siweAuth, siweAuthActionTypes } from 'lib/actions/siwe-actions.js';
import { useInitialNotificationsEncryptedMessage } from 'lib/shared/crypto-utils.js';
import type {
LogInStartingPayload,
LogInExtraInfo,
} from 'lib/types/account-types.js';
import { useLegacyAshoatKeyserverCall } from 'lib/utils/action-utils.js';
import type { CallSingleKeyserverEndpointOptions } from 'lib/utils/call-single-keyserver-endpoint.js';
import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js';
import { ashoatKeyserverID } from 'lib/utils/validation-utils.js';
import { useSelector } from '../redux/redux-utils.js';
import { nativeLogInExtraInfoSelector } from '../selectors/account-selectors.js';
import { nativeNotificationsSessionCreator } from '../utils/crypto-utils.js';
type SIWEServerCallParams = {
+message: string,
+signature: string,
+doNotRegister?: boolean,
...
};
-function useSIWEServerCall(): (
+function useLegacySIWEServerCall(): (
SIWEServerCallParams,
?CallSingleKeyserverEndpointOptions,
) => Promise {
const siweAuthCall = useLegacyAshoatKeyserverCall(siweAuth);
const callSIWE = React.useCallback(
(
message: string,
signature: string,
extraInfo: $ReadOnly<{ ...LogInExtraInfo, +doNotRegister?: boolean }>,
callSingleKeyserverEndpointOptions: ?CallSingleKeyserverEndpointOptions,
) =>
siweAuthCall(
{
message,
signature,
...extraInfo,
},
callSingleKeyserverEndpointOptions,
),
[siweAuthCall],
);
const logInExtraInfo = useSelector(nativeLogInExtraInfoSelector);
const getInitialNotificationsEncryptedMessage =
useInitialNotificationsEncryptedMessage(nativeNotificationsSessionCreator);
const dispatchActionPromise = useDispatchActionPromise();
return React.useCallback(
async (
{ message, signature, doNotRegister },
callSingleKeyserverEndpointOptions,
) => {
const extraInfo = await logInExtraInfo();
const initialNotificationsEncryptedMessage =
await getInitialNotificationsEncryptedMessage(ashoatKeyserverID, {
callSingleKeyserverEndpointOptions,
});
const siwePromise = callSIWE(
message,
signature,
{
...extraInfo,
initialNotificationsEncryptedMessage,
doNotRegister,
},
callSingleKeyserverEndpointOptions,
);
void dispatchActionPromise(
siweAuthActionTypes,
siwePromise,
undefined,
({ calendarQuery: extraInfo.calendarQuery }: LogInStartingPayload),
);
await siwePromise;
},
[
logInExtraInfo,
dispatchActionPromise,
callSIWE,
getInitialNotificationsEncryptedMessage,
],
);
}
-export { useSIWEServerCall };
+export { useLegacySIWEServerCall };