Skip to content

Commit

Permalink
[native] Read native credentials during restore flow
Browse files Browse the repository at this point in the history
Summary:
When a user restores their account, we should try to fill the input using native credentials - just like we do for the login flow.

https://linear.app/comm/issue/ENG-10046/use-native-credentials-on-the-password-restore-screen

Depends on D14182

Test Plan: Register a password account, wipe state, open restore password screen - the input should contain credentials of the registered account.

Reviewers: kamil, bartek

Reviewed By: kamil

Subscribers: ashoat

Differential Revision: https://phab.comm.dev/D14183
  • Loading branch information
palys-swm committed Jan 8, 2025
1 parent 4778815 commit deda5b6
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 19 deletions.
2 changes: 1 addition & 1 deletion native/account/native-credentials.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
resetInternetCredentials,
} from 'react-native-keychain';

type UserCredentials = {
export type UserCredentials = {
+username: string,
+password: string,
};
Expand Down
71 changes: 53 additions & 18 deletions native/account/restore-password-account-screen.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ 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 {
fetchNativeCredentials,
setNativeCredentials,
} from './native-credentials.js';
import type { UserCredentials } 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';
Expand All @@ -30,8 +34,41 @@ type Props = {
};

function RestorePasswordAccountScreen(props: Props): React.Node {
const [username, setUsername] = React.useState('');
const [password, setPassword] = React.useState('');
const [credentials, setCredentials] = React.useState<UserCredentials>({
username: '',
password: '',
});
const setUsername = React.useCallback(
(username: string) =>
setCredentials(prevCredentials => ({
...prevCredentials,
username,
})),
[],
);
const setPassword = React.useCallback(
(password: string) =>
setCredentials(prevCredentials => ({
...prevCredentials,
password,
})),
[],
);

React.useEffect(() => {
void (async () => {
const nativeCredentials = await fetchNativeCredentials();
if (!nativeCredentials) {
return;
}
setCredentials(prevCredentials => {
if (!prevCredentials.username && !prevCredentials.password) {
return nativeCredentials;
}
return prevCredentials;
});
})();
}, []);

const passwordInputRef = React.useRef<?React.ElementRef<typeof TextInput>>();
const focusPasswordInput = React.useCallback(() => {
Expand All @@ -44,35 +81,34 @@ function RestorePasswordAccountScreen(props: Props): React.Node {
}, []);

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

const identityPasswordLogIn = usePasswordLogIn();
const { retrieveLatestBackupInfo } = useClientBackup();
const areCredentialsPresent = !!username && !!password;
const areCredentialsPresent =
!!credentials.username && !!credentials.password;
const [isProcessing, setIsProcessing] = React.useState(false);
const onProceed = React.useCallback(async () => {
if (!areCredentialsPresent) {
return;
}
setIsProcessing(true);
try {
const latestBackupInfo = await retrieveLatestBackupInfo(username);
const latestBackupInfo = await retrieveLatestBackupInfo(
credentials.username,
);
if (!latestBackupInfo) {
await identityPasswordLogIn(username, password);
await setNativeCredentials({
username,
password,
});
await identityPasswordLogIn(credentials.username, credentials.password);
await setNativeCredentials(credentials);
return;
}
props.navigation.navigate(RestoreBackupScreenRouteName, {
userIdentifier: username,
userIdentifier: credentials.username,
credentials: {
type: 'password',
password,
password: credentials.password,
},
});
} catch (e) {
Expand Down Expand Up @@ -103,12 +139,11 @@ function RestorePasswordAccountScreen(props: Props): React.Node {
}
}, [
areCredentialsPresent,
credentials,
identityPasswordLogIn,
onUnsuccessfulLoginAlertAcknowledged,
password,
props.navigation,
retrieveLatestBackupInfo,
username,
]);

let restoreButtonVariant = 'loading';
Expand All @@ -122,7 +157,7 @@ function RestorePasswordAccountScreen(props: Props): React.Node {
<RegistrationContentContainer>
<Text style={styles.header}>Restore with password</Text>
<RegistrationTextInput
value={username}
value={credentials.username}
onChangeText={setUsername}
placeholder="Username"
autoFocus={true}
Expand All @@ -136,7 +171,7 @@ function RestorePasswordAccountScreen(props: Props): React.Node {
ref={usernameInputRef}
/>
<RegistrationTextInput
value={password}
value={credentials.password}
onChangeText={setPassword}
placeholder="Password"
secureTextEntry={true}
Expand Down

0 comments on commit deda5b6

Please sign in to comment.