Skip to content

Commit

Permalink
[native] Fall back to v1 login when the user doesn't have a backup
Browse files Browse the repository at this point in the history
Summary:
Check if the user has a backup. When they don't have it, use the v1 login flow.

https://linear.app/comm/issue/ENG-9620/client-restore-flow-fall-back-to-v1-when-missing-backup

Depends on D14165

Test Plan:
Because pf https://linear.app/comm/issue/ENG-10039/allow-checking-if-a-user-has-a-backup I had to hack it a bit: instead of calling `retrieveLatestBackupInfo` I hardcoded its return value to null. Then for both password and SIWE user verified that it is possible to log in.

Reviewers: kamil, bartek
  • Loading branch information
palys-swm committed Dec 20, 2024
1 parent c44920a commit 1e5c4a7
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 9 deletions.
85 changes: 81 additions & 4 deletions native/account/restore-password-account-screen.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,26 @@
import * as React from 'react';
import { Text, TextInput, View } from 'react-native';

import { usePasswordLogIn } from 'lib/hooks/login-hooks.js';
import { getMessageForException } from 'lib/utils/errors.js';

import { setNativeCredentials } from './native-credentials.js';
import PromptButton from './prompt-button.react.js';
import RegistrationButtonContainer from './registration/registration-button-container.react.js';
import RegistrationContainer from './registration/registration-container.react.js';
import RegistrationContentContainer from './registration/registration-content-container.react.js';
import RegistrationTextInput from './registration/registration-text-input.react.js';
import type { SignInNavigationProp } from './sign-in-navigator.react.js';
import { useClientBackup } from '../backup/use-client-backup.js';
import type { NavigationRoute } from '../navigation/route-names.js';
import { RestoreBackupScreenRouteName } from '../navigation/route-names.js';
import { useStyles } from '../themes/colors.js';
import {
appOutOfDateAlertDetails,
unknownErrorAlertDetails,
userNotFoundAlertDetails,
} from '../utils/alert-messages.js';
import Alert from '../utils/alert.js';

type Props = {
+navigation: SignInNavigationProp<'RestorePasswordAccountScreen'>,
Expand All @@ -27,18 +38,83 @@ function RestorePasswordAccountScreen(props: Props): React.Node {
passwordInputRef.current?.focus();
}, []);

const usernameInputRef = React.useRef<?React.ElementRef<typeof TextInput>>();
const focusUsernameInput = React.useCallback(() => {
usernameInputRef.current?.focus();
}, []);

const onUnsuccessfulLoginAlertAcknowledged = React.useCallback(() => {
setUsername('');
setPassword('');
focusUsernameInput();
}, [focusUsernameInput]);

const identityPasswordLogIn = usePasswordLogIn();
const { retrieveLatestBackupInfo } = useClientBackup();
const areCredentialsPresent = !!username && !!password;
const onProceed = React.useCallback(() => {
if (areCredentialsPresent) {
const [isProcessing, setIsProcessing] = React.useState(false);
const onProceed = React.useCallback(async () => {
if (!areCredentialsPresent) {
return;
}
setIsProcessing(true);
try {
const latestBackupInfo = await retrieveLatestBackupInfo(username);
if (!latestBackupInfo) {
await identityPasswordLogIn(username, password);
await setNativeCredentials({
username,
password,
});
return;
}
props.navigation.navigate(RestoreBackupScreenRouteName, {
userIdentifier: username,
credentials: {
type: 'password',
password,
},
});
} catch (e) {
const messageForException = getMessageForException(e);
let alertMessage = unknownErrorAlertDetails;
let onPress = null;
if (
messageForException === 'user_not_found' ||
messageForException === 'login_failed'
) {
alertMessage = userNotFoundAlertDetails;
onPress = onUnsuccessfulLoginAlertAcknowledged;
} else if (
messageForException === 'unsupported_version' ||
messageForException === 'client_version_unsupported' ||
messageForException === 'use_new_flow'
) {
alertMessage = appOutOfDateAlertDetails;
}
Alert.alert(
alertMessage.title,
alertMessage.message,
[{ text: 'OK', onPress }],
{ cancelable: false },
);
} finally {
setIsProcessing(false);
}
}, [areCredentialsPresent, password, props.navigation, username]);
}, [
areCredentialsPresent,
identityPasswordLogIn,
onUnsuccessfulLoginAlertAcknowledged,
password,
props.navigation,
retrieveLatestBackupInfo,
username,
]);

let restoreButtonVariant = 'loading';
if (!isProcessing) {
restoreButtonVariant = areCredentialsPresent ? 'enabled' : 'disabled';
}

const styles = useStyles(unboundStyles);
return (
Expand All @@ -57,6 +133,7 @@ function RestorePasswordAccountScreen(props: Props): React.Node {
autoComplete="username"
returnKeyType="next"
onSubmitEditing={focusPasswordInput}
ref={usernameInputRef}
/>
<RegistrationTextInput
value={password}
Expand All @@ -77,7 +154,7 @@ function RestorePasswordAccountScreen(props: Props): React.Node {
<PromptButton
text="Restore"
onPress={onProceed}
variant={areCredentialsPresent ? 'enabled' : 'disabled'}
variant={restoreButtonVariant}
/>
</View>
</RegistrationButtonContainer>
Expand Down
43 changes: 38 additions & 5 deletions native/account/restore-prompt-screen.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import * as React from 'react';
import { Text, View } from 'react-native';

import { useWalletLogIn } from 'lib/hooks/login-hooks.js';
import type { SIWEResult } from 'lib/types/siwe-types.js';
import { getMessageForException } from 'lib/utils/errors.js';

Expand All @@ -20,7 +21,10 @@ import {
RestorePasswordAccountScreenRouteName,
} from '../navigation/route-names.js';
import { useColors, useStyles } from '../themes/colors.js';
import { unknownErrorAlertDetails } from '../utils/alert-messages.js';
import {
appOutOfDateAlertDetails,
unknownErrorAlertDetails,
} from '../utils/alert-messages.js';
import Alert from '../utils/alert.js';
import RestoreIcon from '../vectors/restore-icon.react.js';

Expand All @@ -40,12 +44,19 @@ function RestorePromptScreen(props: Props): React.Node {
props.navigation.navigate(RestorePasswordAccountScreenRouteName);
}, [props.navigation]);

const [authInProgress, setAuthInProgress] = React.useState(false);
const { retrieveLatestBackupInfo } = useClientBackup();
const walletLogIn = useWalletLogIn();
const onSIWESuccess = React.useCallback(
async (result: SIWEResult) => {
try {
setAuthInProgress(true);
const { address, signature, message } = result;
const backupInfo = await retrieveLatestBackupInfo(address);
if (!backupInfo) {
await walletLogIn(result.address, result.message, result.signature);
return;
}
const { siweBackupData } = backupInfo;

if (!siweBackupData) {
Expand All @@ -71,16 +82,30 @@ function RestorePromptScreen(props: Props): React.Node {
console.log(
`SIWE restore error: ${messageForException ?? 'unknown error'}`,
);
const alertDetails = unknownErrorAlertDetails;
let alertDetails = unknownErrorAlertDetails;
if (
messageForException === 'unsupported_version' ||
messageForException === 'client_version_unsupported' ||
messageForException === 'use_new_flow'
) {
alertDetails = appOutOfDateAlertDetails;
} else if (messageForException === 'nonce_expired') {
alertDetails = {
title: 'Login attempt timed out',
message: 'Please try again',
};
}
Alert.alert(
alertDetails.title,
alertDetails.message,
[{ text: 'OK', onPress: props.navigation.goBack }],
{ cancelable: false },
);
} finally {
setAuthInProgress(false);
}
},
[props.navigation, retrieveLatestBackupInfo],
[props.navigation, retrieveLatestBackupInfo, walletLogIn],
);

const {
Expand All @@ -104,6 +129,12 @@ function RestorePromptScreen(props: Props): React.Node {
);
}

const openSIWEPanel = React.useCallback(() => {
if (!authInProgress) {
openPanel();
}
}, [authInProgress, openPanel]);

const colors = useColors();
return (
<>
Expand All @@ -130,8 +161,10 @@ function RestorePromptScreen(props: Props): React.Node {
<View style={styles.buttonContainer}>
<PromptButton
text="Restore with Ethereum"
onPress={openPanel}
variant={panelState === 'opening' ? 'loading' : 'siwe'}
onPress={openSIWEPanel}
variant={
panelState === 'opening' || authInProgress ? 'loading' : 'siwe'
}
/>
</View>
<View style={styles.buttonContainer}>
Expand Down

0 comments on commit 1e5c4a7

Please sign in to comment.