Files
inji-wallet/screens/BiometricScreenController.ts
Alka Prasad 9b07e63383 [Inji 434 & INJI 441]: Add events in receiver VC sharing flow and cancel button handle (#990)
* refactor(INJI-434): rename some variables and functions to meaning names

Signed-off-by: Alka <prasadalka1998@gmail.com>

* feat(INJI-434): add telemetry events in the VC share flow on verifier end

Signed-off-by: Alka <prasadalka1998@gmail.com>

* fix(INJI-434): handle cancel button press during vc share

Signed-off-by: Alka <prasadalka1998@gmail.com>

* fix(INJI-441): handle cancel button press during vc share

Signed-off-by: Alka <prasadalka1998@gmail.com>

* refactor(INJI-434): extracts telemetry constants to a seperate file

Signed-off-by: Alka <prasadalka1998@gmail.com>

* refactor(INJI-434): remove unused imports

Signed-off-by: Alka <prasadalka1998@gmail.com>

* fix(INJI-441): update the CANCEL event on press of cancel button

Signed-off-by: Alka <prasadalka1998@gmail.com>

* refactor(INJI-434): update the method name

Signed-off-by: Alka <prasadalka1998@gmail.com>

---------

Signed-off-by: Alka <prasadalka1998@gmail.com>
Signed-off-by: Alka Prasad <Alka1703@users.noreply.github.com>
2023-11-07 10:43:39 +05:30

197 lines
5.2 KiB
TypeScript

import {useMachine, useSelector} from '@xstate/react';
import {useContext, useEffect, useState} from 'react';
import {Platform} from 'react-native';
import RNFingerprintChange from 'react-native-biometrics-changed';
import {
AuthEvents,
selectAuthorized,
selectPasscode,
selectPasscodeSalt,
} from '../machines/auth';
import {
biometricsMachine,
selectError,
selectErrorResponse,
selectIsAvailable,
selectIsSuccess,
selectIsUnenrolled,
selectIsUnvailable,
} from '../machines/biometrics';
import {RootRouteProps} from '../routes';
import {GlobalContext} from '../shared/GlobalContext';
import {
getStartEventData,
getEndEventData,
getInteractEventData,
sendEndEvent,
sendInteractEvent,
sendStartEvent,
resetRetryCount,
} from '../shared/telemetry/TelemetryUtils';
import {TelemetryConstants} from '../shared/telemetry/TelemetryConstants';
import {isAndroid} from '../shared/constants';
export function useBiometricScreen(props: RootRouteProps) {
const {appService} = useContext(GlobalContext);
const authService = appService.children.get('auth');
const [error, setError] = useState('');
const [isReEnabling, setReEnabling] = useState(false);
const [initAuthBio, updateInitAuthBio] = useState(true);
const [, bioSend, bioService] = useMachine(biometricsMachine);
const isAuthorized = useSelector(authService, selectAuthorized);
const isAvailable = useSelector(bioService, selectIsAvailable);
const isUnavailable = useSelector(bioService, selectIsUnvailable);
const isSuccessBio = useSelector(bioService, selectIsSuccess);
const isUnenrolled = useSelector(bioService, selectIsUnenrolled);
const errorMsgBio = useSelector(bioService, selectError);
const errorResponse = useSelector(bioService, selectErrorResponse);
const passcodeSalt = useSelector(authService, selectPasscodeSalt);
useEffect(() => {
if (isAvailable) {
sendStartEvent(getStartEventData(TelemetryConstants.FlowType.appLogin));
sendInteractEvent(
getInteractEventData(
TelemetryConstants.FlowType.appLogin,
TelemetryConstants.InteractEventSubtype.click,
'Unlock with Biometrics button',
),
);
}
}, [isAvailable]);
useEffect(() => {
if (isAuthorized) {
sendEndEvent(
getEndEventData(
TelemetryConstants.FlowType.appLogin,
TelemetryConstants.EndEventStatus.success,
),
);
props.navigation.reset({
index: 0,
routes: [{name: 'Main'}],
});
return;
}
if (initAuthBio && isAvailable) {
checkBiometricsChange();
// so we only init authentication of biometrics just once
updateInitAuthBio(false);
}
// if biometic state is success then lets send auth service BIOMETRICS
if (isSuccessBio) {
authService.send(AuthEvents.LOGIN());
return;
}
if (errorMsgBio && !isReEnabling) {
sendEndEvent(
getEndEventData(
TelemetryConstants.FlowType.appLogin,
TelemetryConstants.EndEventStatus.failure,
{
errorId: errorResponse.res.error,
errorMessage: errorResponse.res.warning,
stackTrace: errorResponse.stacktrace,
},
),
);
}
if (isUnavailable || isUnenrolled) {
props.navigation.reset({
index: 0,
routes: [{name: 'Passcode'}],
});
sendStartEvent(getStartEventData(TelemetryConstants.FlowType.appLogin));
sendInteractEvent(
getInteractEventData(
TelemetryConstants.FlowType.appLogin,
TelemetryConstants.InteractEventSubtype.click,
'Unlock application button',
),
);
}
}, [
isAuthorized,
isAvailable,
isUnenrolled,
isUnavailable,
isSuccessBio,
errorMsgBio,
]);
const checkBiometricsChange = () => {
if (isAndroid()) {
RNFingerprintChange.hasFingerPrintChanged().then(
async (biometricsHasChanged: boolean) => {
//if new biometrics are added, re-enable Biometrics Authentication
if (biometricsHasChanged) {
setReEnabling(true);
} else {
bioSend({type: 'AUTHENTICATE'});
}
},
);
} else {
// TODO: solution for iOS
}
};
const useBiometrics = () => {
sendStartEvent(getStartEventData(TelemetryConstants.FlowType.appLogin));
sendInteractEvent(
getInteractEventData(
TelemetryConstants.FlowType.appLogin,
TelemetryConstants.InteractEventSubtype.click,
'Unlock with biometrics button',
),
);
bioSend({type: 'AUTHENTICATE'});
};
const onSuccess = () => {
resetRetryCount();
bioSend({type: 'AUTHENTICATE'});
setError('');
};
const onError = (value: string) => {
setError(value);
};
const onDismiss = () => {
sendEndEvent(
getEndEventData(
TelemetryConstants.FlowType.appLogin,
TelemetryConstants.EndEventStatus.failure,
{
errorId: 'user_cancel',
errorMessage: 'Authentication canceled',
},
),
);
setReEnabling(false);
};
return {
error,
isReEnabling,
isSuccessBio,
passcodeSalt,
storedPasscode: useSelector(authService, selectPasscode),
useBiometrics,
onSuccess,
onError,
onDismiss,
};
}