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

fix: #893 fix immediate lock timer #6653

Merged
merged 70 commits into from
Jul 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
81116cf
Stage saga changes
Cal-L Jun 20, 2023
ad41e16
Create action creators for authentication state machine
Cal-L Jun 21, 2023
13ce165
Remove unused code
Cal-L Jun 21, 2023
b70630a
Start and end state machine
Cal-L Jun 21, 2023
3e6c5ec
Clean up LockScreen
Cal-L Jun 21, 2023
a63859c
Clean up LockManager
Cal-L Jun 21, 2023
98e4087
Remove unused code
Cal-L Jun 21, 2023
b0971dc
Notify auth state machine from Authentication service
Cal-L Jun 21, 2023
afcbc08
Organize auth state machine in sagas
Cal-L Jun 21, 2023
628144b
Change sagas to TS
Cal-L Jun 21, 2023
541ab43
Remove unused changes
Cal-L Jun 21, 2023
fb540cb
Add type to navigation in NavigationService
Cal-L Jun 21, 2023
cf57eb9
Clean up sagas
Cal-L Jun 22, 2023
8057344
Remove console log
Cal-L Jun 22, 2023
19fa1d2
Add tests for sagas
Cal-L Jun 22, 2023
2fd86bb
Remove password set
Cal-L Jun 22, 2023
87de4fc
Fix saga lint issues
Cal-L Jun 22, 2023
ef48e39
Fix missing deps
Cal-L Jun 22, 2023
5193308
Fix merge conflicts
Cal-L Jun 22, 2023
eaa4648
Fix merge conflicts with package.json
Cal-L Jun 22, 2023
9f784ad
Merge branch 'main' into fix/893-biometrics-timer
Cal-L Jun 22, 2023
9df304b
Merge branch 'main' into fix/893-biometrics-timer
Cal-L Jun 23, 2023
47f06fe
Merge branch 'main' into fix/893-biometrics-timer
tommasini Jul 10, 2023
5094be5
Remove ts ignore from sagas
Cal-L Jul 11, 2023
ea732ca
Merge branch 'main' into fix/893-biometrics-timer
Cal-L Jul 11, 2023
e974c52
Merge branch 'main' into fix/893-biometrics-timer
Cal-L Jul 11, 2023
a5dc6da
Fix conflicts
Cal-L Jul 11, 2023
ffff913
Clarify navigation action
Cal-L Jul 11, 2023
1c76c8b
Remove commented logger
Cal-L Jul 11, 2023
f2e9ba4
Create LOCK_SCREEN route const
Cal-L Jul 11, 2023
d42228c
Provide comments to sagas
Cal-L Jul 11, 2023
cff808f
Merge branch 'main' into fix/893-biometrics-timer
Cal-L Jul 12, 2023
28a4b41
Rename biometrics listener
Cal-L Jul 12, 2023
548eb0d
Merge branch 'main' into fix/893-biometrics-timer
Cal-L Jul 12, 2023
d08e0ec
set timer immediately v2
tommasini Jul 15, 2023
0bda327
Add biometricsStateMachineId to auth code
Cal-L Jul 19, 2023
74f695a
Remove unused user actions
Cal-L Jul 19, 2023
856f753
Clean up LockManager logic to work with Android and iOS
Cal-L Jul 19, 2023
010b3ee
Better handle authentication sagas
Cal-L Jul 19, 2023
5f59e33
Fix saga export error
Cal-L Jul 19, 2023
97c22ba
Fix saga unit tests
Cal-L Jul 19, 2023
598264f
Merge from main
Cal-L Jul 19, 2023
d804972
Bump version for test
Cal-L Jul 19, 2023
3468308
Refine logout state when using biometrics
Cal-L Jul 20, 2023
8c5d786
Bump version
Cal-L Jul 20, 2023
5ce6368
Remove retry logic for lock screen
Cal-L Jul 20, 2023
622ee92
Cancel biometrics state machine when logging out
Cal-L Jul 20, 2023
97a5052
Clean up lock screen
Cal-L Jul 20, 2023
c6c0760
Reset isAuthenticating when biometrics fail in SecureKeychain.js
Cal-L Jul 20, 2023
d736a17
Move LockScreen to top nav level
Cal-L Jul 21, 2023
debd9ed
Persist app state when LockManager shows.
Cal-L Jul 21, 2023
9c2faa1
Fix saga tests
Cal-L Jul 21, 2023
cebface
Move LockManager initialization
Cal-L Jul 21, 2023
0837f66
Use existing login and logout actions for biometric state machine
Cal-L Jul 21, 2023
252ea61
Bump versions
Cal-L Jul 21, 2023
03a0d06
Use replace when logging out
Cal-L Jul 21, 2023
57f2450
Merge from main
Cal-L Jul 21, 2023
d15bd1c
Update LockScreen snapshoit
Cal-L Jul 22, 2023
eea90fa
Comment bioStateMachineId
Cal-L Jul 24, 2023
45ce8d9
Remove LockManager to LockManagerService
Cal-L Jul 24, 2023
9fc0ed8
Add comments to Authentication service
Cal-L Jul 24, 2023
c223c6e
Convert LockManagerService to Typescript
Cal-L Jul 25, 2023
6ad8c36
Fix typo
Cal-L Jul 26, 2023
d5a999a
Update LockManagerService visibility modifiers
Cal-L Jul 26, 2023
61867e9
Fix lint issues
Cal-L Jul 26, 2023
6ae39b0
Merge branch 'main' into fix/893-biometrics-timer
Cal-L Jul 26, 2023
ca47c1a
Merge with main
Cal-L Jul 26, 2023
fe25e73
Merge branch 'main' into fix/893-biometrics-timer
Cal-L Jul 27, 2023
8f24029
Fix merge conflicts with main
Cal-L Jul 27, 2023
2c6b5f3
Fix merge conflicts
Cal-L Jul 28, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 36 additions & 2 deletions app/actions/user/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,37 @@
// Constants
export const LOCKED_APP = 'LOCKED_APP';
export const AUTH_SUCCESS = 'AUTH_SUCCESS';
export const AUTH_ERROR = 'AUTH_ERROR';
export const INTERRUPT_BIOMETRICS = 'INTERRUPT_BIOMETRICS';
export const LOGIN = 'LOGIN';
export const LOGOUT = 'LOGOUT';

export function interruptBiometrics() {
return {
type: INTERRUPT_BIOMETRICS,
};
}

export function lockApp() {
return {
type: LOCKED_APP,
};
}

export function authSuccess(bioStateMachineId) {
return {
type: AUTH_SUCCESS,
payload: { bioStateMachineId },
};
}

export function authError(bioStateMachineId) {
return {
type: AUTH_ERROR,
payload: { bioStateMachineId },
};
}

export function passwordSet() {
return {
type: 'PASSWORD_SET',
Expand Down Expand Up @@ -73,13 +107,13 @@ export function setNftDetectionDismissed() {

export function logIn() {
return {
type: 'LOGIN',
type: LOGIN,
};
}

export function logOut() {
return {
type: 'LOGOUT',
type: LOGOUT,
};
}

Expand Down
10 changes: 9 additions & 1 deletion app/components/Nav/App/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ import EditAccountName from '../../Views/EditAccountName/EditAccountName';
import WC2Manager, {
isWC2Enabled,
} from '../../../../app/core/WalletConnect/WalletConnectV2';
import NavigationService from '../../../core/NavigationService';
import LockScreen from '../../Views/LockScreen';

const clearStackNavigatorOptions = {
headerShown: false,
Expand Down Expand Up @@ -240,7 +242,7 @@ const App = ({ userLoggedIn }) => {
const existingUser = await AsyncStorage.getItem(EXISTING_USER);
try {
if (existingUser && selectedAddress) {
await Authentication.appTriggeredAuth(selectedAddress);
await Authentication.appTriggeredAuth({ selectedAddress });
// we need to reset the navigator here so that the user cannot go back to the login screen
navigator.reset({ routes: [{ name: Routes.ONBOARDING.HOME_NAV }] });
}
Expand Down Expand Up @@ -410,6 +412,7 @@ const App = ({ userLoggedIn }) => {
const setNavigatorRef = (ref) => {
if (!prevNavigator.current) {
setNavigator(ref);
NavigationService.setNavigationRef(ref);
}
};

Expand Down Expand Up @@ -646,6 +649,11 @@ const App = ({ userLoggedIn }) => {
component={AddNetworkFlow}
options={{ animationEnabled: true }}
/>
<Stack.Screen
name={Routes.LOCK_SCREEN}
component={LockScreen}
options={{ gestureEnabled: false }}
/>
</Stack.Navigator>
</NavigationContainer>
{renderSplash()}
Expand Down
2 changes: 0 additions & 2 deletions app/components/Nav/Main/MainNavigator.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import { RevealPrivateCredential } from '../../Views/RevealPrivateCredential';
import WalletConnectSessions from '../../Views/WalletConnectSessions';
import OfflineMode from '../../Views/OfflineMode';
import QrScanner from '../../Views/QRScanner';
import LockScreen from '../../Views/LockScreen';
import EnterPasswordSimple from '../../Views/EnterPasswordSimple';
import ChoosePassword from '../../Views/ChoosePassword';
import ResetPassword from '../../Views/ResetPassword';
Expand Down Expand Up @@ -652,7 +651,6 @@ const MainNavigator = () => (
<Stack.Screen name="AddBookmarkView" component={AddBookmarkView} />
<Stack.Screen name="OfflineModeView" component={OfflineModeView} />
<Stack.Screen name={Routes.QR_SCANNER} component={QrScanner} />
<Stack.Screen name="LockScreen" component={LockScreen} />
<Stack.Screen name="PaymentRequestView" component={PaymentRequestView} />
<Stack.Screen
name={Routes.FIAT_ON_RAMP_AGGREGATOR.ID}
Expand Down
15 changes: 0 additions & 15 deletions app/components/Nav/Main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import Engine from '../../../core/Engine';
import AppConstants from '../../../core/AppConstants';
import PushNotification from 'react-native-push-notification';
import I18n, { strings } from '../../../../locales/i18n';
import LockManager from '../../../core/LockManager';
import FadeOutOverlay from '../../UI/FadeOutOverlay';
import Device from '../../../util/device';
import BackupAlert from '../../UI/BackupAlert';
Expand Down Expand Up @@ -51,7 +50,6 @@ import { createStackNavigator } from '@react-navigation/stack';
import ReviewModal from '../../UI/ReviewModal';
import { useTheme } from '../../../util/theme';
import RootRPCMethodsUI from './RootRPCMethodsUI';
import usePrevious from '../../hooks/usePrevious';
import { colors as importedColors } from '../../../styles/common';
import {
getNetworkImageSource,
Expand Down Expand Up @@ -99,13 +97,10 @@ const Main = (props) => {

const backgroundMode = useRef(false);
const locale = useRef(I18n.locale);
const lockManager = useRef();
const removeConnectionStatusListener = useRef();

const removeNotVisibleNotifications = props.removeNotVisibleNotifications;

const prevLockTime = usePrevious(props.lockTime);

useEnableAutomaticSecurityChecks();
useMinimumVersions();

Expand Down Expand Up @@ -261,9 +256,6 @@ const Main = (props) => {
initForceReload();
return;
}
if (prevLockTime !== props.lockTime) {
lockManager.current && lockManager.current.updateLockTime(props.lockTime);
}
});

// Remove all notifications that aren't visible
Expand All @@ -276,7 +268,6 @@ const Main = (props) => {
'change',
handleAppStateChange,
);
lockManager.current = new LockManager(props.navigation, props.lockTime);
PushNotification.configure({
requestPermissions: false,
onNotification: (notification) => {
Expand Down Expand Up @@ -318,7 +309,6 @@ const Main = (props) => {

return function cleanup() {
appStateListener.remove();
lockManager.current.stopListening();
removeConnectionStatusListener.current &&
removeConnectionStatusListener.current();
};
Expand Down Expand Up @@ -400,10 +390,6 @@ Main.propTypes = {
* Object that represents the navigator
*/
navigation: PropTypes.object,
/**
* Time to auto-lock the app after it goes in background mode
*/
lockTime: PropTypes.number,
/**
* Dispatch showing a transaction notification
*/
Expand Down Expand Up @@ -444,7 +430,6 @@ Main.propTypes = {
};

const mapStateToProps = (state) => ({
lockTime: state.settings.lockTime,
thirdPartyApiMode: state.privacy.thirdPartyApiMode,
providerType: selectProviderType(state),
});
Expand Down
4 changes: 2 additions & 2 deletions app/components/UI/DrawerView/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ class DrawerView extends PureComponent {
'ManualBackupStep2',
'ManualBackupStep3',
'Webview',
'LockScreen',
Routes.LOCK_SCREEN,
].includes(route)
) {
this.state.showProtectWalletModal &&
Expand Down Expand Up @@ -581,7 +581,7 @@ class DrawerView extends PureComponent {
if (
pendingDeeplink &&
KeyringController.isUnlocked() &&
route !== 'LockScreen'
route !== Routes.LOCK_SCREEN
) {
DeeplinkManager.expireDeeplink();
DeeplinkManager.parse(pendingDeeplink, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ exports[`LockScreen should render correctly 1`] = `
}
}
>
<Component />
<LockScreenFCWrapper />
</ContextProvider>
`;
98 changes: 50 additions & 48 deletions app/components/Views/LockScreen/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,93 +75,73 @@ class LockScreen extends PureComponent {
* The navigator object
*/
navigation: PropTypes.object,
/**
* Boolean flag that determines if password has been set
*/
passwordSet: PropTypes.bool,
selectedAddress: PropTypes.string,
appTheme: PropTypes.string,
/**
* ID associated with each biometric session.
* This is used by the biometric sagas to handle actions with the matching ID.
*/
bioStateMachineId: PropTypes.string,
Cal-L marked this conversation as resolved.
Show resolved Hide resolved
};

state = {
ready: false,
};

appState = 'active';
locked = true;
timedOut = false;
firstAnimation = React.createRef();
secondAnimation = React.createRef();
animationName = React.createRef();
opacity = new Animated.Value(1);
unlockAttempts = 0;
appStateListener;

componentDidMount() {
// Check if is the app is launching or it went to background mode
this.appState = 'background';
this.appStateListener = AppState.addEventListener(
'change',
this.handleAppStateChange,
);
this.mounted = true;
}

handleAppStateChange = async (nextAppState) => {
// Try to unlock when coming from the background
if (
this.locked &&
this.appState !== 'active' &&
nextAppState === 'active'
) {
// Trigger biometrics
if (nextAppState === 'active') {
this.firstAnimation?.play();
this.appState = nextAppState;
// Avoid trying to unlock with the app in background
this.unlockKeychain();
this.appStateListener?.remove();
}
};

componentWillUnmount() {
this.mounted = false;
this.appStateListener?.remove();
}

lock = async () => {
await Authentication.lockApp(false);
this.props.navigation.navigate(Routes.ONBOARDING.LOGIN);
lock = () => {
// Replace action reverts the nav state back to original state prior to logging in.
// Replace is used intentionally. Do not use navigate.
this.props.navigation.replace(Routes.ONBOARDING.LOGIN);
// Do not need to await since it's the last action.
Authentication.lockApp(false);
};

async unlockKeychain() {
this.unlockAttempts++;
const { bioStateMachineId } = this.props;
try {
// Retreive the credentials
Logger.log('Lockscreen::unlockKeychain - getting credentials');
await Authentication.appTriggeredAuth(this.props.selectedAddress);
this.locked = false;
await Authentication.appTriggeredAuth({
selectedAddress: this.props.selectedAddress,
bioStateMachineId,
disableAutoLogout: true,
});
this.setState({ ready: true });
Logger.log('Lockscreen::unlockKeychain - state: ready');
this.secondAnimation?.play();
this.animationName?.play();
Logger.log('Lockscreen::unlockKeychain - playing animations');

if (!this.props.passwordSet) {
this.props.navigation.navigate('OnboardingRootNav', {
screen: Routes.ONBOARDING.NAV,
params: { screen: 'Onboarding' },
});
}
this.props.navigation.navigate(Routes.ONBOARDING.HOME_NAV);
} catch (error) {
if (this.unlockAttempts <= 3) {
this.unlockKeychain();
} else {
trackErrorAsAnalytics(
'Lockscreen: Max Attempts Reached',
error?.message,
`Unlock attempts: ${this.unlockAttempts}`,
);
this.lock();
}
this.lock();
trackErrorAsAnalytics(
'Lockscreen: Authentication failed',
error?.message,
);
}
}

Expand All @@ -173,7 +153,9 @@ class LockScreen extends PureComponent {
useNativeDriver: true,
isInteraction: false,
}).start(() => {
this.props.navigation.goBack();
this.props.navigation.navigate(Routes.ONBOARDING.HOME_NAV, {
screen: Routes.WALLET_VIEW,
});
});
}, 100);
};
Expand Down Expand Up @@ -246,11 +228,31 @@ class LockScreen extends PureComponent {
}

const mapStateToProps = (state) => ({
passwordSet: state.user.passwordSet,
selectedAddress: selectSelectedAddress(state),
appTheme: state.user.appTheme,
});

LockScreen.contextType = ThemeContext;

export default connect(mapStateToProps)(LockScreen);
const ConnectedLockScreen = connect(mapStateToProps)(LockScreen);

// Wrapper that forces LockScreen to re-render when bioStateMachineId changes.
const LockScreenFCWrapper = (props) => {
const { bioStateMachineId } = props.route.params;
return (
<ConnectedLockScreen
key={bioStateMachineId}
bioStateMachineId={bioStateMachineId}
{...props}
/>
);
};

LockScreenFCWrapper.propTypes = {
/**
* Navigation object that holds params including bioStateMachineId.
*/
route: PropTypes.object,
};

export default LockScreenFCWrapper;
4 changes: 3 additions & 1 deletion app/components/Views/Login/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,9 @@ class Login extends PureComponent {
const { current: field } = this.fieldRef;
field?.blur();
try {
await Authentication.appTriggeredAuth(this.props.selectedAddress);
await Authentication.appTriggeredAuth({
selectedAddress: this.props.selectedAddress,
});
const onboardingWizard = await DefaultPreference.get(ONBOARDING_WIZARD);
if (!onboardingWizard) this.props.setOnboardingWizardStep(1);
this.props.navigation.replace(Routes.ONBOARDING.HOME_NAV);
Expand Down
2 changes: 1 addition & 1 deletion app/components/Views/RestoreWallet/WalletRestored.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const WalletRestored = () => {

const finishWalletRestore = useCallback(async (): Promise<void> => {
try {
await Authentication.appTriggeredAuth(selectedAddress);
await Authentication.appTriggeredAuth({ selectedAddress });
navigation.replace(Routes.ONBOARDING.HOME_NAV);
} catch (e) {
// we were not able to log in automatically so we will go back to login
Expand Down
Loading
Loading