Skip to content

Commit

Permalink
FIX: Keychain clear attempt reset
Browse files Browse the repository at this point in the history
  • Loading branch information
marcosrdz authored and Overtorment committed Jul 21, 2020
1 parent 0792add commit 6de8d62
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 37 deletions.
1 change: 1 addition & 0 deletions BlueApp.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ async function startAndDecrypt(retry) {
return false;
}
} else {
unlockAttempt = 0;
// Return true because there was no wallet data in keychain. Proceed.
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion Navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ const LoadingScreenRoot = () => (
const UnlockWithScreenStack = createStackNavigator();
const UnlockWithScreenRoot = () => (
<UnlockWithScreenStack.Navigator name="UnlockWithScreenRoot" screenOptions={{ headerShown: false }}>
<UnlockWithScreenStack.Screen name="UnlockWithScreen" component={UnlockWith} />
<UnlockWithScreenStack.Screen name="UnlockWithScreen" component={UnlockWith} initialParams={{ unlockOnComponentMount: true }} />
</UnlockWithScreenStack.Navigator>
);

Expand Down
82 changes: 50 additions & 32 deletions UnlockWith.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React, { Component } from 'react';
import { View, Image, TouchableOpacity, StyleSheet, Appearance, StatusBar } from 'react-native';
import { View, Image, TouchableOpacity, StyleSheet, Appearance, StatusBar, ActivityIndicator } from 'react-native';
import { Icon } from 'react-native-elements';
import Biometric from './class/biometrics';
import { SafeAreaView } from 'react-native-safe-area-context';
import * as NavigationService from './NavigationService';
import { StackActions } from '@react-navigation/native';
import PropTypes from 'prop-types';

const EV = require('./blue_modules/events');
/** @type {AppStorage} */

Expand Down Expand Up @@ -58,9 +60,11 @@ export default class UnlockWith extends Component {
}
const isStorageEncrypted = await BlueApp.storageIsEncrypted();
this.setState({ biometricType, isStorageEncrypted }, async () => {
if (!biometricType || isStorageEncrypted) {
this.unlockWithKey();
} else if (typeof biometricType === 'string') this.unlockWithBiometrics();
if (this.props.route.params.unlockOnComponentMount) {
if (!biometricType || isStorageEncrypted) {
this.unlockWithKey();
} else if (typeof biometricType === 'string') this.unlockWithBiometrics();
}
});
}

Expand Down Expand Up @@ -104,12 +108,44 @@ export default class UnlockWith extends Component {
});
};

renderUnlockOptions = () => {
if (this.state.isAuthenticating) {
return <ActivityIndicator />;
} else {
const color = this.state.appearance === 'dark' ? '#FFFFFF' : '#000000';
if (
(this.state.biometricType === Biometric.TouchID || this.state.biometricType === Biometric.Biometrics) &&
!this.state.isStorageEncrypted
) {
return (
<TouchableOpacity disabled={this.state.isAuthenticating} onPress={this.unlockWithBiometrics}>
<Icon name="fingerprint" size={64} type="font-awesome5" color={color} />
</TouchableOpacity>
);
} else if (this.state.biometricType === Biometric.FaceID && !this.state.isStorageEncrypted) {
return (
<TouchableOpacity disabled={this.state.isAuthenticating} onPress={this.unlockWithBiometrics}>
<Image
source={this.state.appearance === 'dark' ? require('./img/faceid-default.png') : require('./img/faceid-dark.png')}
style={styles.icon}
/>
</TouchableOpacity>
);
} else if (this.state.isStorageEncrypted) {
return (
<TouchableOpacity disabled={this.state.isAuthenticating} onPress={this.unlockWithKey}>
<Icon name="lock" size={64} type="font-awesome5" color={color} />
</TouchableOpacity>
);
}
}
};

render() {
if (!this.state.biometricType && !this.state.isStorageEncrypted) {
return <View />;
}

const color = this.state.appearance === 'dark' ? '#FFFFFF' : '#000000';
return (
<SafeAreaView style={styles.root}>
<StatusBar barStyle="default" />
Expand All @@ -118,36 +154,18 @@ export default class UnlockWith extends Component {
<Image source={require('./img/qr-code.png')} style={styles.qrCodeImage} />
</View>
<View style={styles.biometric}>
<View style={styles.biometricRow}>
{(this.state.biometricType === Biometric.TouchID || this.state.biometricType === Biometric.Biometrics) &&
!this.state.isStorageEncrypted && (
<>
<TouchableOpacity disabled={this.state.isAuthenticating} onPress={this.unlockWithBiometrics}>
<Icon name="fingerprint" size={64} type="font-awesome5" color={color} />
</TouchableOpacity>
</>
)}
{this.state.biometricType === Biometric.FaceID && !this.state.isStorageEncrypted && (
<>
<TouchableOpacity disabled={this.state.isAuthenticating} onPress={this.unlockWithBiometrics}>
<Image
source={this.state.appearance === 'dark' ? require('./img/faceid-default.png') : require('./img/faceid-dark.png')}
style={styles.icon}
/>
</TouchableOpacity>
</>
)}
{this.state.isStorageEncrypted && (
<>
<TouchableOpacity disabled={this.state.isAuthenticating} onPress={this.unlockWithKey}>
<Icon name="lock" size={64} type="font-awesome5" color={color} />
</TouchableOpacity>
</>
)}
</View>
<View style={styles.biometricRow}>{this.renderUnlockOptions()}</View>
</View>
</View>
</SafeAreaView>
);
}
}

UnlockWith.propTypes = {
route: PropTypes.shape({
params: PropTypes.shape({
unlockOnComponentMount: PropTypes.bool,
}),
}),
};
12 changes: 8 additions & 4 deletions class/biometrics.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import Biometrics from 'react-native-biometrics';
import { Platform, Alert } from 'react-native';
import PasscodeAuth from 'react-native-passcode-auth';
import * as NavigationService from '../NavigationService';
import { StackActions } from '@react-navigation/native';
import { StackActions, CommonActions } from '@react-navigation/native';
import RNSecureKeyStore from 'react-native-secure-key-store';
import loc from '../loc';
const BlueApp = require('../BlueApp');
const loc = require('../loc');

export default class Biometric {
static STORAGEKEY = 'Biometrics';
Expand Down Expand Up @@ -69,6 +69,7 @@ export default class Biometric {
static async clearKeychain() {
await RNSecureKeyStore.remove('data');
await RNSecureKeyStore.remove('data_encrypted');
await RNSecureKeyStore.remove(Biometric.STORAGEKEY);
await BlueApp.setResetOnAppUninstallTo(true);
NavigationService.dispatch(StackActions.replace('WalletsRoot'));
}
Expand All @@ -84,7 +85,7 @@ export default class Biometric {
'Storage',
`All your wallets will be removed and your storage will be decrypted. Are you sure you want to proceed?`,
[
{ text: loc.send.details.cancel, style: 'cancel' },
{ text: loc._.cancel, style: 'cancel' },
{
text: loc._.ok,
onPress: () => Biometric.clearKeychain(),
Expand All @@ -108,7 +109,10 @@ export default class Biometric {
'Storage',
`You have attempted to enter your password 10 times. Would you like to reset your storage? This will remove all wallets and decrypt your storage.`,
[
{ text: loc.send.details.cancel, onPress: () => {}, style: 'cancel' },
{ text: loc._.cancel, onPress: () => {
NavigationService.dispatch(CommonActions.setParams({index: 0, routes: [
{ name: 'UnlockWithScreenRoot' }, { params: { unlockOnComponentMount: false }}]}));
}, style: 'cancel' },
{
text: loc._.ok,
onPress: () => Biometric.requestDevicePasscode(),
Expand Down

0 comments on commit 6de8d62

Please sign in to comment.