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

TW-346: Fix unlock after minimize #731

Merged
merged 8 commits into from
Jan 30, 2023
1 change: 1 addition & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ dependencies {

//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+" // From node_modules
implementation project(':react-native-keychain')

implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
implementation "androidx.core:core-splashscreen:1.0.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import com.facebook.react.ReactPackage;
import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.soloader.SoLoader;
import com.oblador.keychain.KeychainPackage;
import com.oblador.keychain.KeychainModuleBuilder;
import com.templewallet.newarchitecture.MainApplicationReactNativeHost;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
Expand All @@ -28,6 +30,11 @@ public boolean getUseDeveloperSupport() {
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
packages.add(
new KeychainPackage(
new KeychainModuleBuilder().withoutWarmUp()
)
);
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
return packages;
Expand Down
4 changes: 4 additions & 0 deletions android/settings.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
rootProject.name = 'TempleWallet'
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app'

include ':react-native-keychain'
project(':react-native-keychain').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keychain/android')

includeBuild('../node_modules/react-native-gradle-plugin')

if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
Expand Down
9 changes: 8 additions & 1 deletion react-native.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
module.exports = {
assets: ['./src/assets/fonts/']
assets: ['./src/assets/fonts/'],
dependencies: {
'react-native-keychain': {
platforms: {
android: null
}
}
}
};
13 changes: 9 additions & 4 deletions src/app/app.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AnalyticsProvider } from '@segment/analytics-react-native';
import React from 'react';
import React, { useEffect, useState } from 'react';
import { LogBox } from 'react-native';
import { hide } from 'react-native-bootsplash';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
Expand All @@ -11,7 +11,6 @@ import { PersistGate } from 'redux-persist/integration/react';
import { BiometryAvailabilityProvider } from '../biometry/biometry-availability.provider';
import { HIDE_SPLASH_SCREEN_TIMEOUT } from '../config/animation';
import { HideBalanceProvider } from '../hooks/hide-balance/hide-balance.provider';
import { useDelayedEffect } from '../hooks/use-delayed-effect.hook';
import { RootStackScreen } from '../navigator/root-stack';
import { AppLockContextProvider } from '../shelter/app-lock/app-lock';
import { persistor, store } from '../store/store';
Expand All @@ -25,7 +24,13 @@ enableScreens();
LogBox.ignoreAllLogs();

export const App = () => {
useDelayedEffect(HIDE_SPLASH_SCREEN_TIMEOUT, () => void hide({ fade: true }), []);
const [atBootsplash, setAtBootsplash] = useState(true);
useEffect(() => {
(async () => {
await hide({ fade: true });
setTimeout(() => void setAtBootsplash(false), HIDE_SPLASH_SCREEN_TIMEOUT);
})();
}, []);
unixvb marked this conversation as resolved.
Show resolved Hide resolved

return (
<GestureHandlerRootView style={AppStyles.root}>
Expand All @@ -36,7 +41,7 @@ export const App = () => {
<HideBalanceProvider>
<AppLockContextProvider>
<SafeAreaProvider>
<RootStackScreen />
<RootStackScreen atBootsplash={atBootsplash} />
<ToastProvider />
</SafeAreaProvider>
</AppLockContextProvider>
Expand Down
9 changes: 0 additions & 9 deletions src/hooks/use-delayed-effect.hook.ts

This file was deleted.

8 changes: 6 additions & 2 deletions src/navigator/root-stack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ type RootStackParamList = { MainStack: undefined } & ModalsParamList;

const RootStack = createStackNavigator<RootStackParamList>();

export const RootStackScreen = () => {
interface Props {
atBootsplash: boolean;
}

export const RootStackScreen = ({ atBootsplash }: Props) => {
const { isLocked } = useAppLock();
const isShowLoader = useIsShowLoaderSelector();
const isAuthorised = useIsAuthorisedSelector();
Expand Down Expand Up @@ -159,7 +163,7 @@ export const RootStackScreen = () => {
</PortalProvider>

{isSplash && <SplashModal />}
{isAuthorised && isLocked && <EnterPassword />}
{isAuthorised && isLocked && <EnterPassword atBootsplash={atBootsplash} />}
{!isPasscode && <PassCode />}
{isForceUpdateNeeded && <ForceUpdate />}
{isAppCheckFailed && <AppCheckWarning />}
Expand Down
17 changes: 10 additions & 7 deletions src/screens/enter-password/enter-password.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Formik } from 'formik';
import React from 'react';
import React, { useEffect } from 'react';
import { Text, View } from 'react-native';

import { useBiometryAvailability } from '../../biometry/use-biometry-availability.hook';
Expand All @@ -13,10 +13,8 @@ import { InsetSubstitute } from '../../components/inset-substitute/inset-substit
import { Label } from '../../components/label/label';
import { Quote } from '../../components/quote/quote';
import { ScreenContainer } from '../../components/screen-container/screen-container';
import { HIDE_SPLASH_SCREEN_TIMEOUT } from '../../config/animation';
import { MAX_PASSWORD_ATTEMPTS } from '../../config/security';
import { FormPasswordInput } from '../../form/form-password-input';
import { useDelayedEffect } from '../../hooks/use-delayed-effect.hook';
import { usePasswordLock } from '../../hooks/use-password-lock.hook';
import { useResetDataHandler } from '../../hooks/use-reset-data-handler.hook';
import { OverlayEnum } from '../../navigator/enums/overlay.enum';
Expand All @@ -33,7 +31,11 @@ import {
} from './enter-password.form';
import { useEnterPasswordStyles } from './enter-password.styles';

export const EnterPassword = () => {
interface Props {
atBootsplash: boolean;
}

export const EnterPassword = ({ atBootsplash }: Props) => {
const styles = useEnterPasswordStyles();

const { unlock, unlockWithBiometry } = useAppLock();
Expand All @@ -51,9 +53,10 @@ export const EnterPassword = () => {

usePageAnalytic(OverlayEnum.EnterPassword);

useDelayedEffect(HIDE_SPLASH_SCREEN_TIMEOUT, () => void (isBiometryAvailable && unlockWithBiometry()), [
isBiometryAvailable
]);
useEffect(
() => void (!atBootsplash && isBiometryAvailable && unlockWithBiometry()),
[isBiometryAvailable, atBootsplash]
);

return (
<ScreenContainer style={styles.root} keyboardBehavior="padding" isFullScreenMode={true}>
Expand Down
2 changes: 1 addition & 1 deletion src/shelter/app-lock/app-lock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const AppLockContextProvider: FC = ({ children }) => {

return undefined;
})
.catch(() => undefined);
.catch(error => void console.error(error));

isDefined(password) && unlock(password);
}, [unlock]);
Expand Down
2 changes: 1 addition & 1 deletion src/shelter/shelter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ export class Shelter {

static disableBiometryPassword$ = () => from(Keychain.resetGenericPassword(getKeychainOptions(PASSWORD_STORAGE_KEY)));

static getBiometryPassword = () => Keychain.getGenericPassword(biometryKeychainOptions);
static getBiometryPassword = async () => Keychain.getGenericPassword(biometryKeychainOptions);

static isPasswordCorrect$ = (password: string) =>
hashPassword$(password).pipe(map(passwordHash => passwordHash === Shelter._passwordHash$.getValue()));
Expand Down