2019-09-25 05:42:21 +02:00
|
|
|
import React, { Component } from 'react';
|
2020-07-21 00:14:02 +02:00
|
|
|
import { View, Image, TouchableOpacity, StyleSheet, Appearance, StatusBar, ActivityIndicator } from 'react-native';
|
2019-09-25 05:42:21 +02:00
|
|
|
import { Icon } from 'react-native-elements';
|
|
|
|
import Biometric from './class/biometrics';
|
2020-05-27 13:12:17 +02:00
|
|
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
2020-06-20 06:18:17 +02:00
|
|
|
import * as NavigationService from './NavigationService';
|
|
|
|
import { StackActions } from '@react-navigation/native';
|
2020-07-21 00:14:02 +02:00
|
|
|
import PropTypes from 'prop-types';
|
2020-10-24 19:20:59 +02:00
|
|
|
import { BlueStorageContext } from './blue_modules/storage-context';
|
2019-09-25 05:42:21 +02:00
|
|
|
/** @type {AppStorage} */
|
|
|
|
|
2020-05-30 10:16:03 +02:00
|
|
|
const styles = StyleSheet.create({
|
|
|
|
root: {
|
|
|
|
flex: 1,
|
|
|
|
},
|
|
|
|
container: {
|
|
|
|
flex: 2,
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
alignItems: 'center',
|
|
|
|
},
|
|
|
|
qrCode: {
|
|
|
|
flex: 1,
|
|
|
|
justifyContent: 'center',
|
|
|
|
alignItems: 'center',
|
|
|
|
},
|
|
|
|
qrCodeImage: {
|
|
|
|
width: 120,
|
|
|
|
height: 120,
|
|
|
|
},
|
|
|
|
biometric: {
|
|
|
|
flex: 0.2,
|
|
|
|
justifyContent: 'flex-end',
|
|
|
|
marginBottom: 58,
|
|
|
|
},
|
|
|
|
biometricRow: {
|
|
|
|
justifyContent: 'center',
|
|
|
|
flexDirection: 'row',
|
|
|
|
},
|
|
|
|
icon: {
|
|
|
|
width: 64,
|
|
|
|
height: 64,
|
|
|
|
},
|
|
|
|
encrypted: {
|
|
|
|
width: 0.5,
|
|
|
|
height: 20,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2019-09-25 05:42:21 +02:00
|
|
|
export default class UnlockWith extends Component {
|
2020-07-15 19:32:59 +02:00
|
|
|
state = { biometricType: false, isStorageEncrypted: false, isAuthenticating: false, appearance: Appearance.getColorScheme() };
|
2020-10-24 19:20:59 +02:00
|
|
|
static contextType = BlueStorageContext;
|
2019-09-25 05:42:21 +02:00
|
|
|
|
|
|
|
async componentDidMount() {
|
2020-07-15 19:32:59 +02:00
|
|
|
Appearance.addChangeListener(this.appearanceChanged);
|
2019-09-25 05:42:21 +02:00
|
|
|
let biometricType = false;
|
2019-10-06 13:40:21 +02:00
|
|
|
if (await Biometric.isBiometricUseCapableAndEnabled()) {
|
2019-09-25 05:42:21 +02:00
|
|
|
biometricType = await Biometric.biometricType();
|
|
|
|
}
|
2020-10-24 19:20:59 +02:00
|
|
|
const storageIsEncrypted = await this.context.isStorageEncrypted();
|
|
|
|
this.setState({ biometricType, isStorageEncrypted: storageIsEncrypted }, async () => {
|
2020-07-21 00:14:02 +02:00
|
|
|
if (this.props.route.params.unlockOnComponentMount) {
|
2020-10-24 19:20:59 +02:00
|
|
|
if (!biometricType || storageIsEncrypted) {
|
2020-07-21 00:14:02 +02:00
|
|
|
this.unlockWithKey();
|
|
|
|
} else if (typeof biometricType === 'string') this.unlockWithBiometrics();
|
|
|
|
}
|
2019-09-25 05:42:21 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-07-15 19:32:59 +02:00
|
|
|
componentWillUnmount() {
|
|
|
|
Appearance.removeChangeListener();
|
|
|
|
}
|
|
|
|
|
|
|
|
appearanceChanged = () => {
|
|
|
|
const appearance = Appearance.getColorScheme();
|
|
|
|
if (appearance) {
|
|
|
|
this.setState({ appearance });
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-09-25 05:42:21 +02:00
|
|
|
successfullyAuthenticated = () => {
|
2020-10-24 19:20:59 +02:00
|
|
|
this.context.setWalletsInitialized(true);
|
2020-09-08 18:06:41 +02:00
|
|
|
NavigationService.dispatch(StackActions.replace('DrawerRoot'));
|
2019-09-25 05:42:21 +02:00
|
|
|
};
|
|
|
|
|
2019-10-17 03:33:00 +02:00
|
|
|
unlockWithBiometrics = async () => {
|
2020-10-24 19:20:59 +02:00
|
|
|
if (await this.context.isStorageEncrypted()) {
|
2019-10-17 03:33:00 +02:00
|
|
|
this.unlockWithKey();
|
|
|
|
}
|
2019-09-25 05:42:21 +02:00
|
|
|
this.setState({ isAuthenticating: true }, async () => {
|
|
|
|
if (await Biometric.unlockWithBiometrics()) {
|
2019-12-28 20:42:59 +01:00
|
|
|
this.setState({ isAuthenticating: false });
|
2020-10-24 19:20:59 +02:00
|
|
|
await this.context.startAndDecrypt();
|
2020-06-20 06:18:17 +02:00
|
|
|
return this.successfullyAuthenticated();
|
2019-09-25 05:42:21 +02:00
|
|
|
}
|
|
|
|
this.setState({ isAuthenticating: false });
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2019-10-06 13:40:21 +02:00
|
|
|
unlockWithKey = () => {
|
|
|
|
this.setState({ isAuthenticating: true }, async () => {
|
2020-10-24 19:20:59 +02:00
|
|
|
if (await this.context.startAndDecrypt()) {
|
2020-07-20 16:58:35 +02:00
|
|
|
this.successfullyAuthenticated();
|
|
|
|
} else {
|
|
|
|
this.setState({ isAuthenticating: false });
|
|
|
|
}
|
2019-10-06 13:40:21 +02:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2020-07-21 00:14:02 +02:00
|
|
|
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>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-09-25 05:42:21 +02:00
|
|
|
render() {
|
|
|
|
if (!this.state.biometricType && !this.state.isStorageEncrypted) {
|
|
|
|
return <View />;
|
|
|
|
}
|
2020-06-25 03:57:30 +02:00
|
|
|
|
2019-09-25 05:42:21 +02:00
|
|
|
return (
|
2020-05-30 10:16:03 +02:00
|
|
|
<SafeAreaView style={styles.root}>
|
2020-07-15 19:32:59 +02:00
|
|
|
<StatusBar barStyle="default" />
|
2020-05-30 10:16:03 +02:00
|
|
|
<View style={styles.container}>
|
|
|
|
<View style={styles.qrCode}>
|
|
|
|
<Image source={require('./img/qr-code.png')} style={styles.qrCodeImage} />
|
2019-09-25 05:42:21 +02:00
|
|
|
</View>
|
2020-05-30 10:16:03 +02:00
|
|
|
<View style={styles.biometric}>
|
2020-07-21 00:14:02 +02:00
|
|
|
<View style={styles.biometricRow}>{this.renderUnlockOptions()}</View>
|
2019-09-25 05:42:21 +02:00
|
|
|
</View>
|
|
|
|
</View>
|
|
|
|
</SafeAreaView>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2020-07-21 00:14:02 +02:00
|
|
|
|
|
|
|
UnlockWith.propTypes = {
|
|
|
|
route: PropTypes.shape({
|
|
|
|
params: PropTypes.shape({
|
|
|
|
unlockOnComponentMount: PropTypes.bool,
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
};
|