Skip to content

Commit

Permalink
Fix biometrics (#518)
Browse files Browse the repository at this point in the history
* Erasing biometrics when creating a new account/import account
* Moved screens and components to TS
  • Loading branch information
ignaciosantise authored Oct 25, 2022
1 parent c00496d commit 987de48
Show file tree
Hide file tree
Showing 23 changed files with 133 additions and 112 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,32 @@
import { HeaderHeightContext } from '@react-navigation/elements';
import React from 'react';
import { ScrollViewProps } from 'react-native';
import {
KeyboardAvoidingView,
Platform,
SafeAreaView,
ScrollView,
StyleProp,
ViewStyle,
} from 'react-native';

import styles from './styles';

interface Props {
children: React.ReactNode;
keyboardShouldPersistTaps?:
| boolean
| 'always'
| 'never'
| 'handled'
| undefined;
keyboardStyle?: StyleProp<ViewStyle>;
safeAreaStyle?: StyleProp<ViewStyle>;
scrollviewRef?: React.RefObject<ScrollView>;
scrollViewProps?: ScrollViewProps;
contentStyle?: StyleProp<ViewStyle>;
}

function KeyboardScrollView({
children,
keyboardShouldPersistTaps,
Expand All @@ -17,7 +35,7 @@ function KeyboardScrollView({
scrollviewRef,
scrollViewProps,
contentStyle,
}) {
}: Props) {
return (
<HeaderHeightContext.Consumer>
{headerHeight => (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BlurView } from '@react-native-community/blur';
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Image, View } from 'react-native';
import { Image, Pressable, View } from 'react-native';

import KeyImg from '@/assets/icons/key.png';
import ListItem from '@/commonComponents/ListItem';
Expand All @@ -11,7 +11,12 @@ import { TestIds } from '@/constants/testIds';
import Text from '../Text';
import styles from './styles';

const SeedPhrase = ({ mnemonic, onReveal = () => null }) => {
interface Props {
mnemonic: string[];
onReveal?: () => void;
}

const SeedPhrase = ({ mnemonic, onReveal = () => {} }: Props) => {
const { t } = useTranslation();
const [reveal, setReveal] = useState(false);
const revealSeedPhrase = () => {
Expand All @@ -20,11 +25,11 @@ const SeedPhrase = ({ mnemonic, onReveal = () => null }) => {
};

return (
<View
<Pressable
style={styles.container}
onPress={revealSeedPhrase}
testID={TestIds.COMMON.SEED_PHRASE_VIEW}>
{mnemonic.map((word, i) => (
{mnemonic.map((word: string, i: number) => (
<View style={styles.item} key={word}>
<ListItem number={i + 1} text={word} />
</View>
Expand All @@ -33,7 +38,7 @@ const SeedPhrase = ({ mnemonic, onReveal = () => null }) => {
<>
<BlurView
style={styles.absolute}
blurType={'dark'}
blurType="dark"
reducedTransparencyFallbackColor="black"
overlayColor="transparent">
<Touchable onPress={revealSeedPhrase} style={styles.absolute}>
Expand All @@ -43,7 +48,7 @@ const SeedPhrase = ({ mnemonic, onReveal = () => null }) => {
</BlurView>
</>
)}
</View>
</Pressable>
);
};

Expand Down
File renamed without changes.
15 changes: 9 additions & 6 deletions src/interfaces/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ import { ConnectedApp, WalletConnectCallRequest } from './redux';
export type RootStackParamList = {
[Routes.NFTS]: undefined;
[Routes.TOKENS]: undefined;
[Routes.PROFILE_SCREEN]: undefined;
[Routes.PROFILE]: undefined;
[Routes.SWIPE_LAYOUT]: undefined;
[Routes.LOGIN_SCREEN]: { manualLock: boolean };
[Routes.WELCOME_SCREEN]: undefined;
[Routes.CREATE_PASSWORD]: undefined;
[Routes.IMPORT_SEED_PHRASE]: undefined;
[Routes.BACKUP_SEED_PHRASE]: undefined;
[Routes.LOGIN]: { manualLock: boolean };
[Routes.WELCOME]: undefined;
[Routes.CREATE_PASSWORD]: { flow: 'create' | 'import' };
[Routes.IMPORT_SEED_PHRASE]: {
password: string;
shouldSaveBiometrics: boolean;
};
[Routes.BACKUP_SEED_PHRASE]: { mnemonic: string };
[Routes.CONNECTION_ERROR]: undefined;
[Routes.WALLET_CONNECT_INITIAL_CONNECTION]: WalletConnectCallRequest;
[Routes.WALLET_CONNECT_FLOWS]: undefined;
Expand Down
6 changes: 3 additions & 3 deletions src/navigation/Routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ enum Routes {
// Tabs Screens:
NFTS = 'NFTs',
TOKENS = 'Tokens',
PROFILE_SCREEN = 'Profile',
PROFILE = 'Profile',
SWIPE_LAYOUT = 'SwipeLayout',
// Auth Screens:
LOGIN_SCREEN = 'LoginScreen',
WELCOME_SCREEN = 'WelcomeScreen',
LOGIN = 'Login',
WELCOME = 'Welcome',
CREATE_PASSWORD = 'CreatePassword',
IMPORT_SEED_PHRASE = 'ImportSeedPhrase',
BACKUP_SEED_PHRASE = 'BackupSeedPhrase',
Expand Down
8 changes: 4 additions & 4 deletions src/navigation/navigators/RootStackNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@ function RootStackNavigator() {
const initialRoute = keyring.isInitialized
? keyring.isUnlocked
? Routes.SWIPE_LAYOUT
: Routes.LOGIN_SCREEN
: Routes.WELCOME_SCREEN;
: Routes.LOGIN
: Routes.WELCOME;

return (
<Stack.Navigator
initialRouteName={initialRoute}
screenOptions={rootStackOptions}>
<Stack.Group>
<Stack.Screen name={Routes.WELCOME_SCREEN} component={Welcome} />
<Stack.Screen name={Routes.LOGIN_SCREEN} component={Login} />
<Stack.Screen name={Routes.WELCOME} component={Welcome} />
<Stack.Screen name={Routes.LOGIN} component={Login} />
<Stack.Screen
name={Routes.CREATE_PASSWORD}
component={CreatePassword}
Expand Down
4 changes: 2 additions & 2 deletions src/navigation/navigators/SwipeNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const SwipeNavigator = () => {
const goToLogin = () => {
navigation.reset({
index: 1,
routes: [{ name: Routes.LOGIN_SCREEN, params: { manualLock: true } }],
routes: [{ name: Routes.LOGIN, params: { manualLock: true } }],
});
};

Expand All @@ -45,7 +45,7 @@ const SwipeNavigator = () => {
initialRouteName={Routes.TOKENS}
tabBarPosition="bottom"
tabBar={renderBottom}>
<Swipe.Screen component={ProfileScreen} name={Routes.PROFILE_SCREEN} />
<Swipe.Screen component={ProfileScreen} name={Routes.PROFILE} />
<Swipe.Screen component={Tokens} name={Routes.TOKENS} />
{ENABLE_NFTS && <Swipe.Screen component={NFTs} name={Routes.NFTS} />}
</Swipe.Navigator>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Image, ScrollView, View } from 'react-native';
import { Image, ScrollView } from 'react-native';

import PlugLogo from '@/assets/icons/plug-logo-full.png';
import Copy from '@/commonComponents/Copy';
import Header from '@/commonComponents/Header';
import SeedPhrase from '@/commonComponents/SeedPhrase';
import RainbowButton from '@/components/buttons/RainbowButton';
import ActionButton from '@/components/common/ActionButton';
import Text from '@/components/common/Text';
import { ScreenProps } from '@/interfaces/navigation';
import { Container } from '@/layout';
import Routes from '@/navigation/Routes';

import styles from './styles';

const BackupSeedPhrase = ({ route, navigation }) => {
const { goBack } = navigation;
const BackupSeedPhrase = ({
route,
navigation,
}: ScreenProps<Routes.BACKUP_SEED_PHRASE>) => {
const { t } = useTranslation();
const { mnemonic } = route?.params || {};
const [revealed, setRevealed] = useState(false);
Expand All @@ -26,19 +28,8 @@ const BackupSeedPhrase = ({ route, navigation }) => {
return (
<Container>
<Header
left={<ActionButton onPress={goBack} label={t('common.back')} />}
center={
<View style={{ width: 70, height: 33 }}>
<Image
style={{
flex: 1,
width: null,
height: null,
resizeMode: 'contain',
}}
source={PlugLogo}
/>
</View>
<Image style={styles.logo} source={PlugLogo} resizeMode="contain" />
}
/>
<ScrollView
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,8 @@ export default StyleSheet.create({
marginTop: 30,
alignSelf: 'center',
},
logo: {
width: 70,
height: 33,
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,3 @@ export const createPasswordRules = {
message: t('validations.passMinLength'),
},
};

export const createPasswordFields = {
password: 'password',
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,36 @@ import { useTranslation } from 'react-i18next';
import { Image, Keyboard, Switch, View } from 'react-native';

import PlugLogo from '@/assets/icons/plug-logo-full.png';
import Header from '@/commonComponents/Header';
import PasswordInput from '@/commonComponents/PasswordInput';
import RainbowButton from '@/components/buttons/RainbowButton';
import ActionButton from '@/components/common/ActionButton';
import { ActionButton, Header, PasswordInput, Text } from '@/components/common';
import KeyboardScrollView from '@/components/common/KeyboardScrollView';
import Text from '@/components/common/Text';
import { Colors } from '@/constants/theme';
import useKeychain from '@/hooks/useKeychain';
import { ScreenProps } from '@/interfaces/navigation';
import { Container } from '@/layout';
import Routes from '@/navigation/Routes';
import { useAppDispatch, useAppSelector } from '@/redux/hooks';
import { createWallet } from '@/redux/slices/keyring';

import {
createPasswordFields,
createPasswordRules,
MIN_LENGTH_MESSAGE,
} from './constants';
import { createPasswordRules, MIN_LENGTH_MESSAGE } from './constants';
import styles from './styles';

const CreatePassword = ({ route, navigation }) => {
type FormValues = {
password: string;
};

const CreatePassword = ({
route,
navigation,
}: ScreenProps<Routes.CREATE_PASSWORD>) => {
const { t } = useTranslation();
const { isSensorAvailable, saveBiometrics } = useKeychain();
const { isSensorAvailable, saveBiometrics, resetBiometrics } = useKeychain();
const {
control,
handleSubmit,
formState: { errors },
getValues,
} = useForm({
} = useForm<FormValues>({
defaultValues: { password: '' },
mode: 'onChange',
criteriaMode: 'all',
Expand All @@ -51,15 +52,15 @@ const CreatePassword = ({ route, navigation }) => {

useEffect(() => {
isSensorAvailable().then(isAvailable => {
setBiometryAvailable(isAvailable);
setBiometryAvailable(!!isAvailable);
});
}, []);

const handleCreate = async data => {
const password = data?.password;
const handleCreate = async (data: FormValues) => {
const password = data.password;
setLoading(true);
const shouldSaveBiometrics = biometryAvailable && biometrics;
if (flow === 'import') {
const shouldSaveBiometrics = biometryAvailable && biometrics;
navigation.navigate(Routes.IMPORT_SEED_PHRASE, {
password,
shouldSaveBiometrics,
Expand All @@ -71,8 +72,10 @@ const CreatePassword = ({ route, navigation }) => {
.unwrap()
.then(async result => {
if (result?.mnemonic) {
if (biometryAvailable && biometrics) {
if (shouldSaveBiometrics) {
await saveBiometrics(password);
} else {
resetBiometrics();
}
navigation.navigate(Routes.BACKUP_SEED_PHRASE, {
mnemonic: result.mnemonic,
Expand All @@ -93,17 +96,19 @@ const CreatePassword = ({ route, navigation }) => {
<ActionButton onPress={() => goBack()} label={t('common.back')} />
}
center={
<View style={styles.plugLogoContainer}>
<Image style={styles.plugLogo} source={PlugLogo} />
</View>
<Image
style={styles.plugLogo}
source={PlugLogo}
resizeMode="contain"
/>
}
/>
<KeyboardScrollView keyboardShouldPersistTaps="always">
<View style={styles.container}>
<Text style={styles.title}>{t('createPassword.title')}</Text>
<Text style={styles.subtitle}>{t('createPassword.subtitle')}</Text>
<Controller
name={createPasswordFields.password}
name="password"
control={control}
rules={createPasswordRules}
render={({ field: { onChange, onBlur, value } }) => (
Expand All @@ -123,7 +128,7 @@ const CreatePassword = ({ route, navigation }) => {
/>
<ErrorMessage
errors={errors}
name={createPasswordFields.password}
name="password"
render={({ message, messages }) => {
const choosenMessage = messages?.pattern
? messages?.pattern
Expand All @@ -135,7 +140,7 @@ const CreatePassword = ({ route, navigation }) => {
<Text
style={[
styles.errorText,
warningMessage && styles.warningText,
!!warningMessage && styles.warningText,
]}>
{choosenMessage}
</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,8 @@ export default StyleSheet.create({
passwordInput: {
marginTop: 28,
},
plugLogoContainer: {
plugLogo: {
width: 70,
height: 33,
},
plugLogo: {
flex: 1,
width: null,
height: null,
resizeMode: 'contain',
},
});
Loading

0 comments on commit 987de48

Please sign in to comment.