Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix: Fix mobile sync & Security options #989

Merged
merged 12 commits into from
Aug 16, 2019
2 changes: 2 additions & 0 deletions app/components/Nav/App/__snapshots__/index.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ exports[`App should render correctly 1`] = `
"AdvancedSettings": null,
"ChoosePasswordSimple": null,
"CompanySettings": null,
"EnterPasswordSimple": null,
"ExperimentalSettings": null,
"GeneralSettings": null,
"NetworkSettings": null,
Expand Down Expand Up @@ -607,6 +608,7 @@ exports[`App should render correctly 1`] = `
"AdvancedSettings": null,
"ChoosePasswordSimple": null,
"CompanySettings": null,
"EnterPasswordSimple": null,
"ExperimentalSettings": null,
"GeneralSettings": null,
"NetworkSettings": null,
Expand Down
2 changes: 2 additions & 0 deletions app/components/Nav/Main/__snapshots__/index.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ exports[`Main should render correctly 1`] = `
"AdvancedSettings": null,
"ChoosePasswordSimple": null,
"CompanySettings": null,
"EnterPasswordSimple": null,
"ExperimentalSettings": null,
"GeneralSettings": null,
"NetworkSettings": null,
Expand Down Expand Up @@ -501,6 +502,7 @@ exports[`Main should render correctly 1`] = `
"AdvancedSettings": null,
"ChoosePasswordSimple": null,
"CompanySettings": null,
"EnterPasswordSimple": null,
"ExperimentalSettings": null,
"GeneralSettings": null,
"NetworkSettings": null,
Expand Down
4 changes: 4 additions & 0 deletions app/components/Nav/Main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import QrScanner from '../../Views/QRScanner';
import LockScreen from '../../Views/LockScreen';
import ProtectYourAccount from '../../Views/ProtectYourAccount';
import ChoosePasswordSimple from '../../Views/ChoosePasswordSimple';
import EnterPasswordSimple from '../../Views/EnterPasswordSimple';
import ChoosePassword from '../../Views/ChoosePassword';
import AccountBackupStep1 from '../../Views/AccountBackupStep1';
import AccountBackupStep2 from '../../Views/AccountBackupStep2';
Expand Down Expand Up @@ -208,6 +209,9 @@ const MainNavigator = createStackNavigator(
},
ChoosePasswordSimple: {
screen: ChoosePasswordSimple
},
EnterPasswordSimple: {
screen: EnterPasswordSimple
}
})
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`EnterPasswordSimple should render correctly 1`] = `
<_class
emulateUnlessSupported={true}
style={
Object {
"backgroundColor": "#FFFFFF",
"flex": 1,
}
}
>
<View
style={
Object {
"flex": 1,
"padding": 20,
}
}
testID="enter-password-screen"
>
<KeyboardAwareScrollViewMock
enableAutomaticScroll={true}
enableOnAndroid={false}
enableResetScrollToCoords={true}
extraHeight={75}
extraScrollHeight={0}
keyboardOpeningTime={250}
resetScrollToCoords={
Object {
"x": 0,
"y": 0,
}
}
style={
Object {
"flex": 1,
"padding": 20,
}
}
viewIsInsideTabBar={false}
>
<View
style={
Object {
"flex": 1,
}
}
>
<View>
<Text
style={
Object {
"marginBottom": 15,
}
}
>
Please enter your password in order to continue
</Text>
<TextInput
allowFontScaling={true}
onChangeText={[Function]}
onSubmitEditing={[Function]}
placeholder="Password"
rejectResponderTermination={true}
secureTextEntry={true}
style={
Object {
"borderColor": "#f2f3f4",
"borderRadius": 5,
"borderWidth": 2,
"padding": 10,
}
}
underlineColorAndroid="transparent"
/>
</View>
<View
style={
Object {
"marginTop": 20,
"paddingHorizontal": 10,
}
}
>
<StyledButton
disabled={false}
disabledContainerStyle={
Object {
"opacity": 0.6,
}
}
onPress={[Function]}
styleDisabled={
Object {
"opacity": 0.6,
}
}
testID="submit-button"
type="blue"
>
Confirm
</StyledButton>
</View>
</View>
</KeyboardAwareScrollViewMock>
</View>
</_class>
`;
117 changes: 117 additions & 0 deletions app/components/Views/EnterPasswordSimple/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { ActivityIndicator, Alert, Text, View, TextInput, SafeAreaView, StyleSheet } from 'react-native';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
import StyledButton from '../../UI/StyledButton';

import { colors, baseStyles } from '../../../styles/common';
import { strings } from '../../../../locales/i18n';
import { getNavigationOptionsTitle } from '../../UI/Navbar';

const styles = StyleSheet.create({
mainWrapper: {
backgroundColor: colors.white,
flex: 1
},
wrapper: {
flex: 1,
padding: 20
},
input: {
borderWidth: 2,
borderRadius: 5,
borderColor: colors.grey000,
padding: 10
},
ctaWrapper: {
marginTop: 20,
paddingHorizontal: 10
},
enterPassword: {
marginBottom: 15
}
});

/**
* View where users can re-enter their password
*/
export default class EnterPasswordSimple extends PureComponent {
static navigationOptions = ({ navigation }) =>
getNavigationOptionsTitle(strings('enter_password.title'), navigation);

static propTypes = {
/**
* The navigator object
*/
navigation: PropTypes.object
};

state = {
password: '',
loading: false,
error: null
};

mounted = true;

componentWillUnmount() {
this.mounted = false;
}

onPressConfirm = async () => {
if (this.state.loading) return;
let error = null;
if (this.state.password.length < 8) {
error = strings('choose_password.password_length_error');
}

if (error) {
Alert.alert('Error', error);
brunobar79 marked this conversation as resolved.
Show resolved Hide resolved
} else {
this.props.navigation.state.params.onPasswordSet(this.state.password);
this.props.navigation.pop();
return;
}
};

onPasswordChange = val => {
this.setState({ password: val });
};

render() {
return (
<SafeAreaView style={styles.mainWrapper}>
<View style={styles.wrapper} testID={'enter-password-screen'}>
<KeyboardAwareScrollView style={styles.wrapper} resetScrollToCoords={{ x: 0, y: 0 }}>
<View style={baseStyles.flexGrow}>
<View>
<Text style={styles.enterPassword}>{strings('enter_password.desc')}</Text>
<TextInput
style={styles.input}
placeholder={strings('enter_password.password')}
onChangeText={this.onPasswordChange}
secureTextEntry
onSubmitEditing={this.onPressConfirm}
/>
</View>
<View style={styles.ctaWrapper}>
<StyledButton
type={'blue'}
onPress={this.onPressConfirm}
testID={'submit-button'}
disabled={!(this.state.password !== '' || this.state.password.length < 8)}
>
{this.state.loading ? (
<ActivityIndicator size="small" color="white" />
) : (
strings('enter_password.confirm_button')
)}
</StyledButton>
</View>
</View>
</KeyboardAwareScrollView>
</View>
</SafeAreaView>
);
}
}
19 changes: 19 additions & 0 deletions app/components/Views/EnterPasswordSimple/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
jest.useFakeTimers();

import React from 'react';
import { shallow } from 'enzyme';
import EnterPasswordSimple from './';

describe('EnterPasswordSimple', () => {
it('should render correctly', () => {
const wrapper = shallow(
<EnterPasswordSimple
navigation={{
state: { params: {} }
}}
/>,
{}
);
expect(wrapper.dive()).toMatchSnapshot();
});
});
53 changes: 47 additions & 6 deletions app/components/Views/ImportWallet/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -258,16 +258,57 @@ class ImportWallet extends PureComponent {
this.setState({ biometryType, biometryChoice: true });
}

Alert.alert(
strings('sync_with_extension.allow_biometrics_title', { biometrics: biometryType }),
strings('sync_with_extension.allow_biometrics_desc', { biometrics: biometryType }),
[
{
text: strings('sync_with_extension.warning_cancel_button'),
onPress: async () => {
await AsyncStorage.removeItem('@MetaMask:biometryChoice');
await AsyncStorage.setItem('@MetaMask:biometryChoiceDisabled', 'true');
this.finishSync({ biometrics: false, password });
},
style: 'cancel'
},
{
text: strings('sync_with_extension.warning_ok_button'),
onPress: async () => {
await AsyncStorage.setItem('@MetaMask:biometryChoice', biometryType);
await AsyncStorage.removeItem('@MetaMask:biometryChoiceDisabled');
this.finishSync({ biometrics: true, biometryType, password });
}
}
],
{ cancelable: false }
);
} else {
this.finishSync({ biometrics: false, password });
}
}

finishSync = async opts => {
if (opts.biometrics) {
const authOptions = {
accessControl: this.state.biometryChoice
? SecureKeychain.ACCESS_CONTROL.BIOMETRY_CURRENT_SET_OR_DEVICE_PASSCODE
: SecureKeychain.ACCESS_CONTROL.DEVICE_PASSCODE
accessControl: SecureKeychain.ACCESS_CONTROL.BIOMETRY_CURRENT_SET_OR_DEVICE_PASSCODE
};
await SecureKeychain.setGenericPassword('metamask-user', password, authOptions);
await SecureKeychain.setGenericPassword('metamask-user', opts.password, authOptions);

// If the user enables biometrics, we're trying to read the password
// immediately so we get the permission prompt
try {
if (Platform.OS === 'ios') {
await SecureKeychain.getGenericPassword();
await AsyncStorage.setItem('@MetaMask:biometryChoice', opts.biometryType);
}
} catch (e) {
Logger.error('User cancelled biometrics permission', e);
await AsyncStorage.removeItem('@MetaMask:biometryChoice');
}
}

try {
await Engine.sync({ ...this.dataToSync, seed: this.seedWords, pass: password });
await Engine.sync({ ...this.dataToSync, seed: this.seedWords, pass: opts.password });
await AsyncStorage.setItem('@MetaMask:existingUser', 'true');
this.props.passwordHasBeenSet();
this.props.setLockTime(AppConstants.DEFAULT_LOCK_TIMEOUT);
Expand All @@ -281,7 +322,7 @@ class ImportWallet extends PureComponent {
this.setState({ loading: false });
this.props.navigation.goBack();
}
}
};

alertExistingUser = callback => {
Alert.alert(
Expand Down
6 changes: 3 additions & 3 deletions app/components/Views/Login/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,10 @@ class Login extends PureComponent {

async componentDidMount() {
const biometryType = await SecureKeychain.getSupportedBiometryType();
if (biometryType) {
const passcodeDisabled = await AsyncStorage.getItem('@MetaMask:passcodeDisabled');
if (passcodeDisabled !== 'true' && biometryType) {
let enabled = true;
const previouslyDisabled = await AsyncStorage.removeItem('@MetaMask:biometryChoiceDisabled');
const previouslyDisabled = await AsyncStorage.getItem('@MetaMask:biometryChoiceDisabled');
if (previouslyDisabled && previouslyDisabled === 'true') {
enabled = false;
}
Expand All @@ -169,7 +170,6 @@ class Login extends PureComponent {

// Restore vault with user entered password
await KeyringController.submitPassword(this.state.password);

if (this.state.biometryType) {
const authOptions = {
accessControl: this.state.biometryChoice
Expand Down
Loading