Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
- Changed inputs of PinScreen to be secure.
- Fixed iOS only issue of keyboard hiding buttons.
  • Loading branch information
daniel-toth-leeder committed Jul 17, 2024
1 parent 04994e2 commit 982172a
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 123 deletions.
11 changes: 7 additions & 4 deletions src/components/InputField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ function InputField({
placeholder,
onChangeText,
keyboardType,
secureTextEntry,
}: {
placeholder: string;
onChangeText: (text: string) => void;
keyboardType?: KeyboardTypeOptions;
readonly placeholder: string;
readonly onChangeText: (text: string) => void;
readonly keyboardType?: KeyboardTypeOptions;
readonly secureTextEntry?: boolean;
}) {
const colorScheme = useColorScheme();
const styles = colorScheme === 'dark' ? darkStyle : lightStyle;
Expand All @@ -23,9 +25,10 @@ function InputField({
<TextInput
style={[styles.input, styles.inputField]}
autoCorrect={false}
keyboardType={keyboardType || 'default'}
keyboardType={keyboardType ?? 'default'}
onChangeText={onChangeText}
placeholder={placeholder}
secureTextEntry={secureTextEntry}
placeholderTextColor={placeholderTextColor}
/>
);
Expand Down
73 changes: 43 additions & 30 deletions src/screens/AuthCloudApiRegistrationScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,15 @@
*/

import { useCallback } from 'react';
import { BackHandler, ScrollView, Text, useColorScheme, View } from 'react-native';
import {
BackHandler,
KeyboardAvoidingView,
Platform,
ScrollView,
Text,
useColorScheme,
View,
} from 'react-native';

import { useFocusEffect } from '@react-navigation/native';
import { useTranslation } from 'react-i18next';
Expand Down Expand Up @@ -52,36 +60,41 @@ const AuthCloudApiRegistrationScreen = () => {
},
]}
>
<ScrollView
contentContainerStyle={styles.contentContainer}
keyboardShouldPersistTaps={'handled'}
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'height' : undefined}
style={styles.container}
>
<View style={styles.titleContainer}>
<Text style={[styles.textForeground, styles.textTitle]}>
{t('authCloudApiRegistration.title')}
</Text>
</View>
<View style={styles.middleContainer}>
<Text style={[styles.textForeground, styles.textNormal]}>
{t('authCloudApiRegistration.enrollResponse')}
</Text>
<InputField
placeholder={t('authCloudApiRegistration.enrollResponse')}
onChangeText={setEnrollResponse}
/>
<Text style={[styles.textForeground, styles.textNormal]}>
{t('authCloudApiRegistration.appLinkUri')}
</Text>
<InputField
placeholder={t('authCloudApiRegistration.appLinkUri')}
onChangeText={setAppLinkUri}
/>
</View>
<View style={styles.bottomContainer}>
<OutlinedButton text={t('confirmButtonTitle')} onPress={confirm} />
<OutlinedButton text={t('cancelButtonTitle')} onPress={onCancel} />
</View>
</ScrollView>
<ScrollView
contentContainerStyle={styles.contentContainer}
keyboardShouldPersistTaps={'handled'}
>
<View style={styles.titleContainer}>
<Text style={[styles.textForeground, styles.textTitle]}>
{t('authCloudApiRegistration.title')}
</Text>
</View>
<View style={styles.middleContainer}>
<Text style={[styles.textForeground, styles.textNormal]}>
{t('authCloudApiRegistration.enrollResponse')}
</Text>
<InputField
placeholder={t('authCloudApiRegistration.enrollResponse')}
onChangeText={setEnrollResponse}
/>
<Text style={[styles.textForeground, styles.textNormal]}>
{t('authCloudApiRegistration.appLinkUri')}
</Text>
<InputField
placeholder={t('authCloudApiRegistration.appLinkUri')}
onChangeText={setAppLinkUri}
/>
</View>
<View style={styles.bottomContainer}>
<OutlinedButton text={t('confirmButtonTitle')} onPress={confirm} />
<OutlinedButton text={t('cancelButtonTitle')} onPress={onCancel} />
</View>
</ScrollView>
</KeyboardAvoidingView>
</View>
);
};
Expand Down
59 changes: 36 additions & 23 deletions src/screens/DeviceInformationChangeScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,15 @@
*/

import { useCallback } from 'react';
import { BackHandler, ScrollView, Text, useColorScheme, View } from 'react-native';
import {
BackHandler,
KeyboardAvoidingView,
Platform,
ScrollView,
Text,
useColorScheme,
View,
} from 'react-native';

import { useFocusEffect } from '@react-navigation/native';
import { type NativeStackScreenProps } from '@react-navigation/native-stack';
Expand Down Expand Up @@ -55,29 +63,34 @@ const DeviceInformationChangeScreen = ({ route }: Props) => {
},
]}
>
<ScrollView
contentContainerStyle={styles.contentContainer}
keyboardShouldPersistTaps={'handled'}
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'height' : undefined}
style={styles.container}
>
<View style={styles.titleContainer}>
<Text style={[styles.textForeground, styles.textTitle]}>
{t('deviceInformationChange.title')}
</Text>
</View>
<View style={styles.middleContainer}>
<Text style={[styles.textForeground, styles.textNormal]}>
{route.params.name}
</Text>
<InputField
placeholder={t('deviceInformationChange.newName')}
onChangeText={setDeviceName}
/>
</View>
<View style={styles.bottomContainer}>
<OutlinedButton text={t('confirmButtonTitle')} onPress={confirm} />
<OutlinedButton text={t('cancelButtonTitle')} onPress={onCancel} />
</View>
</ScrollView>
<ScrollView
contentContainerStyle={styles.contentContainer}
keyboardShouldPersistTaps={'handled'}
>
<View style={styles.titleContainer}>
<Text style={[styles.textForeground, styles.textTitle]}>
{t('deviceInformationChange.title')}
</Text>
</View>
<View style={styles.middleContainer}>
<Text style={[styles.textForeground, styles.textNormal]}>
{route.params.name}
</Text>
<InputField
placeholder={t('deviceInformationChange.newName')}
onChangeText={setDeviceName}
/>
</View>
<View style={styles.bottomContainer}>
<OutlinedButton text={t('confirmButtonTitle')} onPress={confirm} />
<OutlinedButton text={t('cancelButtonTitle')} onPress={onCancel} />
</View>
</ScrollView>
</KeyboardAvoidingView>
</View>
);
};
Expand Down
101 changes: 65 additions & 36 deletions src/screens/PinScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,22 @@
*/

import { useCallback } from 'react';
import { BackHandler, ScrollView, Text, useColorScheme, View } from 'react-native';
import {
BackHandler,
KeyboardAvoidingView,
Platform,
ScrollView,
Text,
useColorScheme,
View,
} from 'react-native';

import {
PinAuthenticatorProtectionStatus,
PinProtectionStatusLastAttemptFailed,
PinProtectionStatusLockedOut,
PinProtectionStatusUnlocked,
RecoverableError,
} from '@nevis-security/nevis-mobile-authentication-sdk-react';
import { useFocusEffect } from '@react-navigation/native';
import { type NativeStackScreenProps } from '@react-navigation/native-stack';
Expand Down Expand Up @@ -68,6 +77,15 @@ const PinScreen = ({ route }: Props) => {
}
}

function errorText(recoverableError: RecoverableError): string {
let text = recoverableError.description;
if (recoverableError.cause) {
text += ` ${recoverableError.cause}`;
}

return text;
}

function authenticatorProtectionText(status?: PinAuthenticatorProtectionStatus): string {
if (status instanceof PinProtectionStatusLastAttemptFailed) {
const remainingRetries = status.remainingRetries;
Expand Down Expand Up @@ -106,48 +124,59 @@ const PinScreen = ({ route }: Props) => {
},
]}
>
<ScrollView
contentContainerStyle={styles.contentContainer}
keyboardShouldPersistTaps={'handled'}
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'height' : undefined}
style={styles.container}
>
<View style={styles.titleContainer}>
<Text style={[styles.textForeground, styles.textTitle]}>
{title(route.params.mode)}
</Text>
</View>
<View style={styles.middleContainer}>
<Text style={[styles.textForeground, styles.textNormal]}>
{description(route.params.mode)}
</Text>
{isChange && (
<ScrollView
contentContainerStyle={styles.contentContainer}
keyboardShouldPersistTaps={'handled'}
>
<View style={styles.titleContainer}>
<Text style={[styles.textForeground, styles.textTitle]}>
{title(route.params.mode)}
</Text>
</View>
<View style={styles.middleContainer}>
<Text style={[styles.textForeground, styles.textNormal]}>
{description(route.params.mode)}
</Text>
{isChange && (
<InputField
placeholder={t('pin.placeholder.oldPin')}
onChangeText={setOldPin}
keyboardType={'numeric'}
secureTextEntry={true}
/>
)}
<InputField
placeholder={t('pin.placeholder.oldPin')}
onChangeText={setOldPin}
placeholder={t('pin.placeholder.pin')}
onChangeText={setPin}
keyboardType={'numeric'}
secureTextEntry={route.params.mode !== PinMode.enrollment}
/>
)}
<InputField
placeholder={t('pin.placeholder.pin')}
onChangeText={setPin}
keyboardType={'numeric'}
/>
{lastRecoverableError && (
<Text style={[styles.textError, styles.textNormal, styles.textCenter]}>
{lastRecoverableError.description}
</Text>
)}
{authenticatorProtectionStatus &&
!(authenticatorProtectionStatus instanceof PinProtectionStatusUnlocked) && (
{lastRecoverableError && (
<Text style={[styles.textError, styles.textNormal, styles.textCenter]}>
{authenticatorProtectionText(authenticatorProtectionStatus)}
{errorText(lastRecoverableError)}
</Text>
)}
</View>
<View style={styles.bottomContainer}>
<OutlinedButton text={t('confirmButtonTitle')} onPress={onConfirm} />
<OutlinedButton text={t('cancelButtonTitle')} onPress={onCancel} />
</View>
</ScrollView>
{authenticatorProtectionStatus &&
!(
authenticatorProtectionStatus instanceof PinProtectionStatusUnlocked
) && (
<Text
style={[styles.textError, styles.textNormal, styles.textCenter]}
>
{authenticatorProtectionText(authenticatorProtectionStatus)}
</Text>
)}
</View>
<View style={styles.bottomContainer}>
<OutlinedButton text={t('confirmButtonTitle')} onPress={onConfirm} />
<OutlinedButton text={t('cancelButtonTitle')} onPress={onCancel} />
</View>
</ScrollView>
</KeyboardAvoidingView>
</View>
);
};
Expand Down
Loading

0 comments on commit 982172a

Please sign in to comment.