Skip to content

Commit

Permalink
Bug/3464 fix login bug (#3484)
Browse files Browse the repository at this point in the history
* Fix switch navigator replacement logic

* Update unit tests

* Fix unit tests. Commit changes from yarn setup

* Fix login bug. Temporarily control splash animation.

* Fix login bug

* Wait for login event

* Properly handle biometrics button. Conditionally handle initial auth logic on Login screen.

* Clean up biometrics logic

Co-authored-by: sethkfman <10342624+sethkfman@users.noreply.github.com>
Co-authored-by: Curtis <Curtis.David7@gmail.com>
  • Loading branch information
3 people authored Dec 8, 2021
1 parent 283a75e commit c2a294a
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 44 deletions.
11 changes: 10 additions & 1 deletion app/actions/user/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,17 @@ export function logOut() {
};
}

export function checkedAuth() {
/**
* Temporary action to control auth flow
*
* @param {string} initialScreen - "login" or "onboarding"
* @returns - void
*/
export function checkedAuth(initialScreen) {
return {
type: 'CHECKED_AUTH',
payload: {
initialScreen,
},
};
}
2 changes: 1 addition & 1 deletion app/components/Nav/App/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ const App = ({ userLoggedIn }) => {

const isAuthChecked = useSelector((state) => state.user.isAuthChecked);
const dispatch = useDispatch();
const triggerCheckedAuth = () => dispatch(checkedAuth());
const triggerCheckedAuth = () => dispatch(checkedAuth('onboarding'));

const handleDeeplink = useCallback(({ error, params, uri }) => {
if (error) {
Expand Down
81 changes: 42 additions & 39 deletions app/components/Views/Login/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,9 @@ class Login extends PureComponent {
*/
setOnboardingWizardStep: PropTypes.func,
/**
* Boolean flag that determines if password has been set
* Temporary string that controls if componentDidMount should handle initial auth logic on mount
*/
passwordSet: PropTypes.bool,
initialScreen: PropTypes.string,
/**
* A string representing the selected address => account
*/
Expand Down Expand Up @@ -239,49 +239,40 @@ class Login extends PureComponent {
fieldRef = React.createRef();

async componentDidMount() {
const { initialScreen } = this.props;
const { KeyringController } = Engine.context;
const shouldHandleInitialAuth = initialScreen !== 'onboarding';
BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);

// Lock keyring just in case
if (KeyringController.isUnlocked()) {
await KeyringController.setLocked();
}

if (!this.props.passwordSet) {
try {
await KeyringController.submitPassword('');
await SecureKeychain.resetGenericPassword();
this.props.navigation.navigate('HomeNav');
} catch (e) {
//
}
} else {
const biometryType = await SecureKeychain.getSupportedBiometryType();
if (biometryType) {
let enabled = true;
const previouslyDisabled = await AsyncStorage.getItem(BIOMETRY_CHOICE_DISABLED);
if (previouslyDisabled && previouslyDisabled === TRUE) {
enabled = false;
}
const biometryType = await SecureKeychain.getSupportedBiometryType();
if (biometryType) {
const previouslyDisabled = await AsyncStorage.getItem(BIOMETRY_CHOICE_DISABLED);
const enabled = !(previouslyDisabled && previouslyDisabled === TRUE);

this.setState({
biometryType: Device.isAndroid() ? 'biometrics' : biometryType,
biometryChoice: enabled,
biometryPreviouslyDisabled: !!previouslyDisabled,
});
this.setState({
biometryType: Device.isAndroid() ? 'biometrics' : biometryType,
biometryChoice: enabled,
biometryPreviouslyDisabled: !!previouslyDisabled,
});
if (shouldHandleInitialAuth) {
try {
if (enabled && !previouslyDisabled) {
const hasBiometricCredentials = await this.tryBiometric();
this.setState({ hasBiometricCredentials });
await this.tryBiometric();
}
} catch (e) {
console.warn(e);
}
if (!enabled) {
await this.checkIfRememberMeEnabled();
}
} else {
await this.checkIfRememberMeEnabled();
}
} else {
shouldHandleInitialAuth && (await this.checkIfRememberMeEnabled());
}

this.props.checkedAuth();
Expand Down Expand Up @@ -318,13 +309,15 @@ class Login extends PureComponent {
this.props.setOnboardingWizardStep(1);
}

// Only way to land back on Login is to log out, which clears credentials (meaning we should not show biometric button)
this.setState({ hasBiometricCredentials: false });
delete credentials.password;
this.props.logIn();
this.props.navigation.navigate('HomeNav');
}
};

onLogin = async () => {
onLogin = async (hasCredentials = false) => {
const { password } = this.state;
const { current: field } = this.fieldRef;
const locked = !passwordRequirementsMet(password);
Expand All @@ -342,7 +335,7 @@ class Login extends PureComponent {
await AsyncStorage.setItem(ENCRYPTION_LIB, ORIGINAL);
}
// If the tryBiometric has been called and they password was retrived don't set it again
if (!this.state.hasBiometricCredentials) {
if (!hasCredentials) {
if (this.state.biometryChoice && this.state.biometryType) {
await SecureKeychain.setGenericPassword(this.state.password, SecureKeychain.TYPES.BIOMETRICS);
} else if (this.state.rememberMe) {
Expand All @@ -362,7 +355,8 @@ class Login extends PureComponent {
this.props.setOnboardingWizardStep(1);
this.props.navigation.navigate('HomeNav');
}
this.setState({ loading: false, password: '' });
// Only way to land back on Login is to log out, which clears credentials (meaning we should not show biometric button)
this.setState({ loading: false, password: '', hasBiometricCredentials: false });
field.setValue('');
} catch (e) {
// Should we force people to enable passcode / biometrics?
Expand Down Expand Up @@ -394,6 +388,10 @@ class Login extends PureComponent {
}
};

triggerLogIn = () => {
this.onLogin();
};

delete = async () => {
const { KeyringController } = Engine.context;
try {
Expand Down Expand Up @@ -448,8 +446,6 @@ class Login extends PureComponent {
updateBiometryChoice = async (biometryChoice) => {
if (!biometryChoice) {
await AsyncStorage.setItem(BIOMETRY_CHOICE_DISABLED, TRUE);
// This line will disable biometrics the next time SecureKeychain.getGenericPassword is called
await SecureKeychain.resetGenericPassword();
} else {
await AsyncStorage.removeItem(BIOMETRY_CHOICE_DISABLED);
}
Expand Down Expand Up @@ -501,17 +497,24 @@ class Login extends PureComponent {
field.blur();
try {
const credentials = await SecureKeychain.getGenericPassword();
if (!credentials) return false;
if (!credentials) {
this.setState({ hasBiometricCredentials: false });
return;
}
field.blur();
this.setState({ password: credentials.password });
field.setValue(credentials.password);
field.blur();
this.onLogin();
await this.onLogin(true);
} catch (error) {
const errObj = new Error(error);
const canceledBiometrics = errObj.message === 'Error: User canceled the operation.';
if (canceledBiometrics) {
this.setState({ hasBiometricCredentials: true });
}
Logger.log(error);
}
field.blur();
return true;
};

render = () => (
Expand Down Expand Up @@ -601,7 +604,7 @@ class Login extends PureComponent {
value={this.state.password}
baseColor={colors.grey500}
tintColor={colors.blue}
onSubmitEditing={this.onLogin}
onSubmitEditing={this.triggerLogIn}
renderRightAccessory={() => (
<BiometryButton
onPress={this.tryBiometric}
Expand All @@ -627,7 +630,7 @@ class Login extends PureComponent {
)}

<View style={styles.ctaWrapper} testID={'log-in-button'}>
<StyledButton type={'confirm'} onPress={this.onLogin}>
<StyledButton type={'confirm'} onPress={this.triggerLogIn}>
{this.state.loading ? (
<ActivityIndicator size="small" color="white" />
) : (
Expand Down Expand Up @@ -655,15 +658,15 @@ class Login extends PureComponent {
}

const mapStateToProps = (state) => ({
passwordSet: state.user.passwordSet,
selectedAddress: state.engine.backgroundState.PreferencesController?.selectedAddress,
initialScreen: state.user.initialScreen,
});

const mapDispatchToProps = (dispatch) => ({
setOnboardingWizardStep: (step) => dispatch(setOnboardingWizardStep(step)),
logIn: () => dispatch(logIn()),
logOut: () => dispatch(logOut()),
checkedAuth: () => dispatch(checkedAuth()),
checkedAuth: () => dispatch(checkedAuth('login')),
});

export default connect(mapStateToProps, mapDispatchToProps)(Login);
2 changes: 2 additions & 0 deletions app/reducers/user/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const initialState = {
gasEducationCarouselSeen: false,
userLoggedIn: false,
isAuthChecked: false,
initialScreen: '',
};

const userReducer = (state = initialState, action) => {
Expand All @@ -16,6 +17,7 @@ const userReducer = (state = initialState, action) => {
return {
...state,
isAuthChecked: true,
initialScreen: action.payload.initialScreen,
};
case 'LOGIN':
return {
Expand Down
2 changes: 1 addition & 1 deletion app/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const persistTransform = createTransform(

const persistUserTransform = createTransform(
(inboundState) => {
const { isAuthChecked, ...state } = inboundState;
const { initialScreen, isAuthChecked, ...state } = inboundState;
// Reconstruct data to persist
return state;
},
Expand Down
4 changes: 2 additions & 2 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ SPEC CHECKSUMS:
Branch: 6a281514287f99d707615ac62c2cca69e0213df0
BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DoubleConversion: cde416483dac037923206447da6e1454df403714
DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662
FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e
FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e
Flipper: 1bd2db48dcc31e4b167b9a33ec1df01c2ded4893
Expand All @@ -683,7 +683,7 @@ SPEC CHECKSUMS:
Flipper-RSocket: 127954abe8b162fcaf68d2134d34dc2bd7076154
FlipperKit: 651f50a42eb95c01b3e89a60996dd6aded529eeb
Folly: b73c3869541e86821df3c387eb0af5f65addfab4
glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3
glog: 5337263514dd6f09803962437687240c5dc39aa4
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
lottie-ios: a50d5c0160425cd4b01b852bb9578963e6d92d31
lottie-react-native: 7ca15c46249b61e3f9ffcf114cb4123e907a2156
Expand Down

0 comments on commit c2a294a

Please sign in to comment.