Skip to content

Commit

Permalink
[FEAT] biometric for sending
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrielbazan7 committed Jul 19, 2022
1 parent 15e821c commit 29a0891
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 9 deletions.
9 changes: 8 additions & 1 deletion src/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ export default () => {
);
const introCompleted = useAppSelector(({APP}) => APP.introCompleted);
const appIsLoading = useAppSelector(({APP}) => APP.appIsLoading);
const checkingBiometricForSending = useAppSelector(
({APP}) => APP.checkingBiometricForSending,
);
const appColorScheme = useAppSelector(({APP}) => APP.colorScheme);
const currentRoute = useAppSelector(({APP}) => APP.currentRoute);
const appLanguage = useAppSelector(({APP}) => APP.defaultLanguage);
Expand Down Expand Up @@ -255,7 +258,10 @@ export default () => {
};

if (onboardingCompleted) {
if (status === 'active' && !appIsLoading) {
if (status === 'active' && checkingBiometricForSending) {
dispatch(AppActions.checkingBiometricForSending(false));
dispatch(AppActions.showBlur(false));
} else if (status === 'active' && !appIsLoading) {
if (lockAuthorizedUntil) {
const now = Math.floor(Date.now() / 1000);
const totalSecs = lockAuthorizedUntil - now;
Expand Down Expand Up @@ -286,6 +292,7 @@ export default () => {
pinLockActive,
lockAuthorizedUntil,
biometricLockActive,
checkingBiometricForSending,
appIsLoading,
failedAppInit,
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,9 @@ const ChangellyCheckout: React.FC = () => {
break;
case 'password canceled':
break;
case 'biometric check failed':
setResetSwipeButton(true);
break;
default:
logger.error(JSON.stringify(err));
const msg = t('Uh oh, something went wrong. Please try again later');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ const WalletConnectConfirm = () => {
break;
case 'password canceled':
break;
case 'biometric check failed':
setResetSwipeButton(true);
break;
default:
await showErrorMessage(
CustomErrorMessage({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ const WalletConnectRequestDetails = () => {
switch (err) {
case 'invalid password':
case 'password canceled':
case 'biometric check failed':
await sleep(800);
setApproveButtonState('loading');
await sleep(200);
Expand Down
3 changes: 3 additions & 0 deletions src/navigation/wallet/screens/TransactionProposalDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,9 @@ const TransactionProposalDetails = () => {
break;
case 'password canceled':
break;
case 'biometric check failed':
setResetSwipeButton(true);
break;
default:
await showErrorMessage(
CustomErrorMessage({
Expand Down
3 changes: 3 additions & 0 deletions src/navigation/wallet/screens/send/confirm/Confirm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,9 @@ const Confirm = () => {
break;
case 'password canceled':
break;
case 'biometric check failed':
setResetSwipeButton(true);
break;
default:
await showErrorMessage(
CustomErrorMessage({
Expand Down
7 changes: 7 additions & 0 deletions src/store/app/app.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,3 +275,10 @@ export const activeModalUpdated = (id: ModalId | null): AppActionType => ({
type: AppActionTypes.ACTIVE_MODAL_UPDATED,
payload: id,
});

export const checkingBiometricForSending = (
payload: boolean,
): AppActionType => ({
type: AppActionTypes.CHECKING_BIOMETRIC_FOR_SENDING,
payload,
});
8 changes: 8 additions & 0 deletions src/store/app/app.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export interface AppState {
keyMigrationFailureModalHasBeenShown: boolean;
activeModalId: ModalId | null;
failedAppInit: boolean;
checkingBiometricForSending: boolean;
}

const initialState: AppState = {
Expand Down Expand Up @@ -142,6 +143,7 @@ const initialState: AppState = {
keyMigrationFailureModalHasBeenShown: false,
activeModalId: null,
failedAppInit: false,
checkingBiometricForSending: false,
};

export const appReducer = (
Expand Down Expand Up @@ -477,6 +479,12 @@ export const appReducer = (
failedAppInit: action.payload,
};

case AppActionTypes.CHECKING_BIOMETRIC_FOR_SENDING:
return {
...state,
checkingBiometricForSending: action.payload,
};

default:
return state;
}
Expand Down
9 changes: 8 additions & 1 deletion src/store/app/app.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export enum AppActionTypes {
SET_SHOW_KEY_MIGRATION_FAILURE_MODAL = 'APP/SET_SHOW_KEY_MIGRATION_FAILURE_MODAL',
SET_KEY_MIGRATION_FAILURE_MODAL_HAS_BEEN_SHOWN = 'APP/SET_KEY_MIGRATION_FAILURE_MODAL_HAS_BEEN_SHOWN',
ACTIVE_MODAL_UPDATED = 'APP/ACTIVE_MODAL_UPDATED',
CHECKING_BIOMETRIC_FOR_SENDING = 'APP/CHECKING_BIOMETRIC_FOR_SENDING',
}

interface NetworkChanged {
Expand Down Expand Up @@ -294,6 +295,11 @@ interface ActiveModalUpdated {
payload: ModalId | null;
}

interface checkingBiometricForSending {
type: typeof AppActionTypes.CHECKING_BIOMETRIC_FOR_SENDING;
payload: boolean;
}

export type AppActionType =
| NetworkChanged
| SuccessAppInit
Expand Down Expand Up @@ -343,4 +349,5 @@ export type AppActionType =
| SetShowKeyMigrationFailureModal
| SetKeyMigrationFailureModalHasBeenShown
| SetDefaultAltCurrency
| ActiveModalUpdated;
| ActiveModalUpdated
| checkingBiometricForSending;
10 changes: 10 additions & 0 deletions src/store/wallet-connect/wallet-connect.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {checkEncryptPassword} from '../wallet/utils/wallet';
import {WrongPasswordError} from '../../navigation/wallet/components/ErrorMessages';
import {LogActions} from '../log';
import {t} from 'i18next';
import {checkBiometricForSending} from '../wallet/effects/send/send';

const BWC = BwcProvider.getInstance();

Expand Down Expand Up @@ -354,10 +355,19 @@ const getPrivKey =
return new Promise(async (resolve, reject) => {
try {
const {keys} = getState().WALLET;
const {biometricLockActive} = getState().APP;
const key: Key = keys[keyId];

let password: string | undefined;

if (biometricLockActive) {
try {
await dispatch(checkBiometricForSending());
} catch (error) {
return reject(error);
}
}

if (key.isPrivKeyEncrypted) {
password = await new Promise<string>((_resolve, _reject) => {
dispatch(
Expand Down
68 changes: 61 additions & 7 deletions src/store/wallet/effects/send/send.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {BWCErrorMessage, getErrorName} from '../../../../constants/BWCError';
import {Invoice} from '../../../shop/shop.models';
import {GetPayProDetails, HandlePayPro, PayProOptions} from '../paypro/paypro';
import {
checkingBiometricForSending,
dismissBottomNotificationModal,
dismissDecryptPasswordModal,
dismissOnGoingProcessModal,
Expand All @@ -49,6 +50,14 @@ import {t} from 'i18next';
import {startOnGoingProcessModal} from '../../../app/app.effects';
import {OnGoingProcessMessages} from '../../../../components/modal/ongoing-process/OngoingProcess';
import {LogActions} from '../../../log';
import TouchID from 'react-native-touch-id';
import {
authOptionalConfigObject,
BiometricErrorNotification,
isSupportedOptionalConfigObject,
TO_HANDLE_ERRORS,
} from '../../../../constants/BiometricError';
import {Platform} from 'react-native';

export const createProposalAndBuildTxDetails =
(
Expand Down Expand Up @@ -654,11 +663,6 @@ export const startSendPayment =
);
return resolve(broadcastedTx);
} catch (e) {
try {
await removeTxp(wallet, proposal);
} catch (removeTxpErr) {
console.log('Could not delete payment proposal');
}
return reject(e);
}
},
Expand All @@ -679,14 +683,26 @@ export const publishAndSign =
recipient,
password,
}: {
txp: Partial<TransactionProposal>;
txp: TransactionProposal;
key: Key;
wallet: Wallet;
recipient?: Recipient;
password?: string; // when signing multiple proposals from a wallet we ask for decrypt password before
}): Effect<Promise<Partial<TransactionProposal> | void>> =>
async (dispatch, getState) => {
return new Promise(async (resolve, reject) => {
const {
APP: {biometricLockActive},
} = getState();

// TODO android
if (biometricLockActive && Platform.OS === 'ios') {
try {
await dispatch(checkBiometricForSending());
} catch (error) {
return reject(error);
}
}
if (key.isPrivKeyEncrypted && !password) {
try {
password = await new Promise<string>((_resolve, _reject) => {
Expand Down Expand Up @@ -763,7 +779,15 @@ export const publishAndSign =

resolve(broadcastedTx);
} catch (err) {
console.log(err);
// if broadcast fails, remove transaction proposal
try {
await removeTxp(wallet, txp);
} catch (removeTxpErr: any) {
console.log(
'Could not delete payment proposal',
removeTxpErr?.message,
);
}
reject(err);
}
});
Expand Down Expand Up @@ -1214,3 +1238,33 @@ export const showNoWalletsModal =
}),
);
};

export const checkBiometricForSending =
(): Effect<Promise<any>> => async dispatch => {
// preventing for asking biometric again when the app goes to background ( ios only )
if (Platform.OS === 'ios') {
dispatch(checkingBiometricForSending(true));
}
await TouchID.isSupported(isSupportedOptionalConfigObject)
.then(biometryType => {
if (biometryType === 'FaceID') {
console.log('FaceID is supported.');
} else {
console.log('TouchID is supported.');
}
return TouchID.authenticate(
'Authentication Check',
authOptionalConfigObject,
);
})
.catch(error => {
if (error.code && TO_HANDLE_ERRORS[error.code]) {
const err = TO_HANDLE_ERRORS[error.code];
dispatch(
showBottomNotificationModal(BiometricErrorNotification(err)),
);
}
return Promise.reject('biometric check failed');
});
return Promise.resolve();
};

0 comments on commit 29a0891

Please sign in to comment.