fix(INJI-552): handle biometric reject on vc download (#1003)

* refactor(INJI-552): store and read generated keypair to avoid multiple write

In issuersMachine, when user is downloading VC via issuer for the forst time, the keypair is generated and stored for further usage. Since we were checking for keypair availability in storage before the read keypair action is sending result event, keypair is generated for every download. This issue is fixed here thus making the 2+nth downloads faster than 1st download.

Signed-off-by: Kiruthika Jeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>

* fix(INJI-552): show error when user cancel biometric on download via issuer

actions in error screen after biometric cancellation
RETRY -> ask for biometric and resume downloading from there itself if biometric given
BACK -> Go back to add new card screen

Signed-off-by: Kiruthika Jeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>

* fix(INJI-552): Handle biometric cancel on vc download via issuer

Signed-off-by: Kiruthika Jeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>

* refactor(INJI-552): change let to const

Signed-off-by: Kiruthika Jeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>

---------

Signed-off-by: Kiruthika Jeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>
This commit is contained in:
KiruthikaJeyashankar
2023-11-16 09:51:01 +05:30
committed by GitHub
parent 2152c982df
commit 76122977e8
18 changed files with 238 additions and 58 deletions

View File

@@ -26,7 +26,11 @@ fileignoreconfig:
- filename: screens/Home/IntroSlidersScreen.tsx
checksum: 9ff212530850e9f921f91d406c01f67ea5dd2a44e9cdb5e63d977749c7a7c5bd
- filename: machines/store.ts
checksum: fda6511ab88566820cf6b7324178b4646f495fae5168af73a0fb1c3bb52e5b8d
checksum: fda6511ab88566820cf6b7324178b4646f495fae5168af73a0fb1c3bb52e5b8d
- filename: machines/issuersMachine.ts
checksum: 742b8ff561dca61be08ab0b9aef3997ad5d043df298a84c17349dc0206ddcee6
- filename: machines/issuersMachine.typegen.ts
checksum: b17d8cc03347af59098fa4fc439d40cc436998b0d148a2ac922acc2e0288e09c
- filename: screens/Home/MyVcs/IdInputModal.tsx
checksum: 6f21b2caf20ee1821b69e178a69e755e0b1094275e4a9f9cb4ae5ab515ce5d23
- filename: screens/WelcomeScreenController.ts

View File

@@ -176,6 +176,10 @@
"title": "لا يوجد اتصال بالإنترنت",
"message": "الرجاء التحقق من اتصالك وإعادة المحاولة"
},
"biometricsCancelled": {
"title": "هل تريد إلغاء التنزيل؟",
"message": "مطلوب تأكيد البيومترية لمواصلة تنزيل البطاقة."
},
"generic": {
"title": "هناك خطأ ما!",
"message":"نواجه بعض المشاكل مع طلبك. حاول مرة اخرى."

View File

@@ -177,6 +177,10 @@
"title": "No internet connection",
"message": "Please check your connection and retry"
},
"biometricsCancelled": {
"title": "Do you want to cancel download?",
"message": "Biometric confirmation is required to continue downloading the card."
},
"generic": {
"title": "Something went wrong!",
"message": "We are having some trouble with your request. Please try again."
@@ -307,7 +311,7 @@
"title": "No internet connection",
"message": "Please check your connection and retry"
},
"downloadLimitExpires":{
"downloadLimitExpires": {
"title": "Download Error",
"message": "There was an issue downloading following cards. Please try again"
}
@@ -613,4 +617,4 @@
"description": "Please use fingerprint to unlock the app"
}
}
}
}

View File

@@ -175,6 +175,10 @@
"title": "Pakisuri ang iyong koneksyon at subukang muli",
"message": "Mangyaring kumonekta sa internet at subukang muli."
},
"biometricsCancelled": {
"title": "Gusto mo bang kanselahin ang pag-download?",
"message": "Kinakailangan ang biometric confirmation para magpatuloy sa pag-download ng card."
},
"generic": {
"title": "may nangyaring mali!",
"message": "Nagkakaproblema kami sa iyong kahilingan. Pakisubukang muli."

View File

@@ -173,6 +173,10 @@
"title": "कोई इंटरनेट कनेक्शन नहीं",
"message": "कृपया अपना कनेक्शन जांचें और पुनः प्रयास करें"
},
"biometricsCancelled": {
"title": "क्या आप डाउनलोड रद्द करना चाहते हैं?",
"message": "कार्ड डाउनलोड करना जारी रखने के लिए बायोमेट्रिक पुष्टिकरण आवश्यक है।"
},
"generic": {
"title": "कुछ गलत हो गया!",
"message": "आपके अनुरोध से हमें कुछ परेशानी हो रही है. कृपया पुन: प्रयास करें।"

View File

@@ -172,6 +172,10 @@
"title": "ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವಿಲ್ಲ",
"message": "ದಯವಿಟ್ಟು ನಿಮ್ಮ ಸಂಪರ್ಕವನ್ನು ಪರಿಶೀಲಿಸಿ ಮತ್ತು ಮರುಪ್ರಯತ್ನಿಸಿ"
},
"biometricsCancelled": {
"title": "ನೀವು ಡೌನ್‌ಲೋಡ್ ರದ್ದುಗೊಳಿಸಲು ಬಯಸುವಿರಾ?",
"message": "ಕಾರ್ಡ್ ಡೌನ್‌ಲೋಡ್ ಮಾಡುವುದನ್ನು ಮುಂದುವರಿಸಲು ಬಯೋಮೆಟ್ರಿಕ್ ದೃಢೀಕರಣದ ಅಗತ್ಯವಿದೆ."
},
"generic": {
"title": "ಏನೋ ತಪ್ಪಾಗಿದೆ!",
"message": "ನಿಮ್ಮ ವಿನಂತಿಯೊಂದಿಗೆ ನಮಗೆ ಸ್ವಲ್ಪ ತೊಂದರೆ ಇದೆ. ದಯವಿಟ್ಟು ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."

View File

@@ -291,6 +291,10 @@
"title": "Sin conexión a Internet",
"message": "Por favor verifique su conexión y vuelva a intentarlo"
},
"biometricsCancelled": {
"title": "Quieres cancelar la descarga?",
"message": "Se requiere confirmación biométrica para continuar descargando la tarjeta."
},
"generic": {
"title": "¡Algo salió mal!",
"message": "Estamos teniendo algunos problemas con su solicitud. Inténtalo de nuevo."

View File

@@ -172,6 +172,10 @@
"title": "இணைய இணைப்பு இல்லை",
"message": "உங்கள் இணைப்பைச் சரிபார்த்து மீண்டும் முயற்சிக்கவும்"
},
"biometricsCancelled": {
"title": "பதிவிறக்கத்தை ரத்து செய்ய வேண்டுமா?",
"message": "கார்டை தொடர்ந்து பதிவிறக்க பயோமெட்ரிக் உறுதிப்படுத்தல் தேவை."
},
"generic": {
"title": "ஏதோ தவறு நடந்துவிட்டது!",
"message": "உங்கள் கோரிக்கையில் எங்களுக்கு சில சிக்கல்கள் உள்ளன. தயவு செய்து மீண்டும் முயற்சிக்கவும்."

View File

@@ -20,7 +20,6 @@ import {log} from 'xstate/lib/actions';
import {verifyCredential} from '../shared/vcjs/verifyCredential';
import {
getBody,
getIdentifier,
vcDownloadTimeout,
OIDCErrors,
ErrorMessage,
@@ -29,7 +28,6 @@ import {
getVCMetadata,
Issuers_Key_Ref,
} from '../shared/openId4VCI/Utils';
import {VCMetadata} from '../shared/VCMetadata';
import {
getEndEventData,
getImpressionEventData,
@@ -44,6 +42,7 @@ import {
} from '../types/VC/EsignetMosipVC/vc';
import {CACHED_API} from '../shared/api';
import {request} from '../shared/request';
import {BiometricCancellationError} from '../shared/error/BiometricCancellationError';
const model = createModel(
{
@@ -62,14 +61,16 @@ const model = createModel(
},
{
events: {
DISMISS: () => ({}),
SELECTED_ISSUER: (id: string) => ({id}),
DOWNLOAD_ID: () => ({}),
BIOMETRIC_CANCELLED: (requester?: string) => ({requester}),
COMPLETED: () => ({}),
TRY_AGAIN: () => ({}),
RESET_ERROR: () => ({}),
CHECK_KEY_PAIR: () => ({}),
CANCEL: () => ({}),
STORE_RESPONSE: (response?: unknown) => ({response}),
STORE_ERROR: (error: Error, requester?: string) => ({error, requester}),
},
},
);
@@ -115,7 +116,7 @@ export const IssuersMachine = model.createMachine(
on: {
TRY_AGAIN: [
{
description: 'not fetched issuers config yet',
description: 'not fetched issuers yet',
cond: 'shouldFetchIssuersAgain',
actions: ['setLoadingReasonAsDisplayIssuers', 'resetError'],
target: 'displayIssuers',
@@ -195,9 +196,7 @@ export const IssuersMachine = model.createMachine(
'setTokenResponse',
'setLoadingReasonAsSettingUp',
'getKeyPairFromStore',
'loadKeyPair',
],
target: 'checkKeyPair',
},
onError: [
{
@@ -224,10 +223,44 @@ export const IssuersMachine = model.createMachine(
},
],
},
initial: 'idle',
states: {
idle: {
on: {
STORE_RESPONSE: {
actions: 'loadKeyPair',
target: '#issuersMachine.checkKeyPair',
},
BIOMETRIC_CANCELLED: {
target: 'userCancelledBiometric',
},
STORE_ERROR: {
target: '#issuersMachine.checkKeyPair',
},
},
},
userCancelledBiometric: {
on: {
TRY_AGAIN: [
{
actions: ['getKeyPairFromStore'],
target: 'idle',
},
],
RESET_ERROR: {
actions: 'resetLoadingReason',
target: '#issuersMachine.selectingIssuer',
},
},
},
},
},
checkKeyPair: {
description: 'checks whether key pair is generated',
entry: ['setLoadingReasonAsSettingUp', send('CHECK_KEY_PAIR')],
entry: [
'setLoadingReasonAsDownloadingCredentials',
send('CHECK_KEY_PAIR'),
],
on: {
CHECK_KEY_PAIR: [
{
@@ -250,18 +283,18 @@ export const IssuersMachine = model.createMachine(
actions: [
'setPublicKey',
'setLoadingReasonAsDownloadingCredentials',
'setPrivateKey',
'storeKeyPair',
],
cond: 'isCustomSecureKeystore',
target: 'downloadCredentials',
},
{
actions: [
'setPublicKey',
'setLoadingReasonAsDownloadingCredentials',
'setPrivateKey',
'storeKeyPair',
],
cond: 'isCustomSecureKeystore',
target: 'downloadCredentials',
},
],
@@ -276,6 +309,10 @@ export const IssuersMachine = model.createMachine(
target: 'verifyingCredential',
},
onError: [
{
cond: 'hasUserCancelledBiometric',
target: '.userCancelledBiometric',
},
{
actions: ['setError', 'resetLoadingReason'],
target: 'error',
@@ -287,6 +324,24 @@ export const IssuersMachine = model.createMachine(
target: 'selectingIssuer',
},
},
initial: 'idle',
states: {
idle: {},
userCancelledBiometric: {
on: {
TRY_AGAIN: [
{
actions: ['setLoadingReasonAsDownloadingCredentials'],
target: '#issuersMachine.downloadCredentials',
},
],
RESET_ERROR: {
actions: 'resetLoadingReason',
target: '#issuersMachine.selectingIssuer',
},
},
},
},
},
verifyingCredential: {
description:
@@ -379,18 +434,20 @@ export const IssuersMachine = model.createMachine(
}),
loadKeyPair: assign({
publicKey: (_, event) => event.publicKey,
publicKey: (_, event) => event.response?.publicKey,
privateKey: (context, event) =>
event.privateKey ? event.privateKey : context.privateKey,
event.response?.privateKey
? event.response.privateKey
: context.privateKey,
}),
getKeyPairFromStore: send(StoreEvents.GET(Issuers_Key_Ref), {
to: context => context.serviceRefs.store,
}),
storeKeyPair: send(
(_, event) => {
context => {
return StoreEvents.SET(Issuers_Key_Ref, {
publicKey: (event.data as KeyPair).public + ``,
privateKey: (event.data as KeyPair).private + ``,
publicKey: context.publicKey,
privateKey: context.privateKey,
});
},
{
@@ -569,9 +626,7 @@ export const IssuersMachine = model.createMachine(
},
},
guards: {
hasKeyPair: context => {
return context.publicKey != null;
},
hasKeyPair: context => !!context.publicKey,
isInternetConnected: (_, event) => !!event.data.isConnected,
isOIDCflowCancelled: (_, event) => {
// iOS & Android have different error strings for user cancelled flow
@@ -600,6 +655,8 @@ export const IssuersMachine = model.createMachine(
},
shouldFetchIssuersAgain: context => context.issuers.length === 0,
isCustomSecureKeystore: () => isHardwareKeystoreExists,
hasUserCancelledBiometric: (_, event) =>
event.data instanceof BiometricCancellationError,
},
},
);
@@ -611,8 +668,8 @@ export function selectIssuers(state: State) {
}
export function selectErrorMessageType(state: State) {
return state.context.errorMessage === '' ||
state.context.errorMessage === ErrorMessage.NO_INTERNET
const nonGenericErrors = ['', ErrorMessage.NO_INTERNET];
return nonGenericErrors.includes(state.context.errorMessage)
? state.context.errorMessage
: ErrorMessage.GENERIC;
}
@@ -625,6 +682,13 @@ export function selectIsDownloadCredentials(state: State) {
return state.matches('downloadCredentials');
}
export function selectIsBiometricCancelled(state: State) {
return (
state.matches('downloadCredentials.userCancelledBiometric') ||
state.matches('performAuthorization.userCancelledBiometric')
);
}
export function selectIsDone(state: State) {
return state.matches('done');
}

View File

@@ -80,14 +80,17 @@ export interface Typegen0 {
services: never;
};
eventsCausingActions: {
getKeyPairFromStore: 'done.invoke.issuersMachine.performAuthorization:invocation[0]';
loadKeyPair: 'done.invoke.issuersMachine.performAuthorization:invocation[0]';
getKeyPairFromStore:
| 'TRY_AGAIN'
| 'done.invoke.issuersMachine.performAuthorization:invocation[0]';
loadKeyPair: 'STORE_RESPONSE';
logDownloaded: 'done.invoke.issuersMachine.verifyingCredential:invocation[0]';
resetError:
| 'RESET_ERROR'
| 'TRY_AGAIN'
| 'error.platform.issuersMachine.performAuthorization:invocation[0]';
resetLoadingReason:
| 'RESET_ERROR'
| 'done.invoke.checkInternet'
| 'done.invoke.issuersMachine.displayIssuers:invocation[0]'
| 'error.platform.issuersMachine.downloadCredentials:invocation[0]'
@@ -104,7 +107,11 @@ export interface Typegen0 {
| 'error.platform.issuersMachine.performAuthorization:invocation[0]';
setIssuers: 'done.invoke.issuersMachine.displayIssuers:invocation[0]';
setLoadingReasonAsDisplayIssuers: 'TRY_AGAIN';
setLoadingReasonAsDownloadingCredentials: 'done.invoke.issuersMachine.generateKeyPair:invocation[0]';
setLoadingReasonAsDownloadingCredentials:
| 'STORE_ERROR'
| 'STORE_RESPONSE'
| 'TRY_AGAIN'
| 'done.invoke.issuersMachine.generateKeyPair:invocation[0]';
setLoadingReasonAsSettingUp:
| 'SELECTED_ISSUER'
| 'TRY_AGAIN'
@@ -127,6 +134,7 @@ export interface Typegen0 {
eventsCausingGuards: {
canSelectIssuerAgain: 'TRY_AGAIN';
hasKeyPair: 'CHECK_KEY_PAIR';
hasUserCancelledBiometric: 'error.platform.issuersMachine.downloadCredentials:invocation[0]';
isCustomSecureKeystore: 'done.invoke.issuersMachine.generateKeyPair:invocation[0]';
isInternetConnected: 'done.invoke.checkInternet';
isOIDCConfigError: 'error.platform.issuersMachine.performAuthorization:invocation[0]';
@@ -150,13 +158,21 @@ export interface Typegen0 {
| 'displayIssuers'
| 'done'
| 'downloadCredentials'
| 'downloadCredentials.idle'
| 'downloadCredentials.userCancelledBiometric'
| 'downloadIssuerConfig'
| 'error'
| 'generateKeyPair'
| 'idle'
| 'performAuthorization'
| 'performAuthorization.idle'
| 'performAuthorization.userCancelledBiometric'
| 'selectingIssuer'
| 'storing'
| 'verifyingCredential';
| 'verifyingCredential'
| {
downloadCredentials?: 'idle' | 'userCancelledBiometric';
performAuthorization?: 'idle' | 'userCancelledBiometric';
};
tags: never;
}

View File

@@ -24,6 +24,7 @@ import {
isHardwareKeystoreExists,
} from '../shared/cryptoutil/cryptoUtil';
import {VCMetadata} from '../shared/VCMetadata';
import {BiometricCancellationError} from '../shared/error/BiometricCancellationError';
export const keyinvalidatedString =
'Key Invalidated due to biometric enrollment';
@@ -43,6 +44,7 @@ const model = createModel(
GET: (key: string) => ({key}),
DECRYPT_ERROR: () => ({}),
KEY_INVALIDATE_ERROR: () => ({}),
BIOMETRIC_CANCELLED: (requester?: string) => ({requester}),
SET: (key: string, value: unknown) => ({key, value}),
APPEND: (key: string, value: unknown) => ({key, value}),
PREPEND: (key: string, value: unknown) => ({key, value}),
@@ -241,6 +243,17 @@ export const storeMachine =
KEY_INVALIDATE_ERROR: {
actions: sendParent('KEY_INVALIDATE_ERROR'),
},
BIOMETRIC_CANCELLED: {
actions: [
send(
(_, event) => model.events.BIOMETRIC_CANCELLED(event.requester),
{
to: (_, event) => event.requester,
},
),
sendUpdate(),
],
},
},
},
{
@@ -403,6 +416,9 @@ export const storeMachine =
) {
callback(model.events.DECRYPT_ERROR());
sendUpdate();
} else if (e instanceof BiometricCancellationError) {
callback(model.events.BIOMETRIC_CANCELLED(event.requester));
sendUpdate();
} else {
console.error(e);
callback(model.events.STORE_ERROR(e, event.requester));
@@ -525,6 +541,7 @@ export async function getItem(
e.message.includes(tamperedErrorMessageString) ||
e.message.includes(keyinvalidatedString) ||
e.message === ENOENT ||
e instanceof BiometricCancellationError ||
e.message.includes('Key not found') // this error happens when previous get Item calls failed due to key invalidation and data and keys are deleted
) {
throw e;

View File

@@ -31,10 +31,6 @@ export interface Typegen0 {
services: never;
};
eventsCausingActions: {
cacheVCFilesData:
| 'KEY_RECEIVED'
| 'READY'
| 'done.invoke.store.resettingStorage:invocation[0]';
forwardStoreRequest:
| 'APPEND'
| 'CLEAR'

View File

@@ -3,6 +3,7 @@ import {
IssuerScreenTabEvents,
IssuersMachine,
selectErrorMessageType,
selectIsBiometricCancelled,
selectIsDone,
selectIsDownloadCredentials,
selectIsIdle,
@@ -12,14 +13,17 @@ import {
} from '../../machines/issuersMachine';
import {ActorRefFrom} from 'xstate';
import {BOTTOM_TAB_ROUTES} from '../../routes/routesConstants';
import {logState} from '../../shared/commonUtil';
export function useIssuerScreenController({route, navigation}) {
const service = route.params.service;
service.subscribe(logState);
return {
issuers: useSelector(service, selectIssuers),
errorMessageType: useSelector(service, selectErrorMessageType),
isDownloadingCredentials: useSelector(service, selectIsDownloadCredentials),
isBiometricsCancelled: useSelector(service, selectIsBiometricCancelled),
isDone: useSelector(service, selectIsDone),
isIdle: useSelector(service, selectIsIdle),
loadingReason: useSelector(service, selectLoadingReason),
@@ -28,7 +32,6 @@ export function useIssuerScreenController({route, navigation}) {
CANCEL: () => service.send(IssuerScreenTabEvents.CANCEL()),
SELECTED_ISSUER: id =>
service.send(IssuerScreenTabEvents.SELECTED_ISSUER(id)),
DISMISS: () => service.send(IssuerScreenTabEvents.DISMISS()),
TRY_AGAIN: () => service.send(IssuerScreenTabEvents.TRY_AGAIN()),
RESET_ERROR: () => service.send(IssuerScreenTabEvents.RESET_ERROR()),
DOWNLOAD_ID: () => {

View File

@@ -4,7 +4,7 @@ import {FlatList, Image, View, TextInput, ScrollView} from 'react-native';
import {Issuer} from '../../components/openId4VCI/Issuer';
import {Error} from '../../components/ui/Error';
import {Header} from '../../components/ui/Header';
import {Column, Row, Text} from '../../components/ui';
import {Button, Column, Row, Text} from '../../components/ui';
import {Theme} from '../../components/ui/styleUtils';
import {RootRouteProps} from '../../routes';
import {HomeRouteProps} from '../../routes/main';
@@ -24,6 +24,7 @@ import {
} from '../../shared/telemetry/TelemetryUtils';
import {TelemetryConstants} from '../../shared/telemetry/TelemetryConstants';
import {Icon} from 'react-native-elements';
import {MessageOverlay} from '../../components/MessageOverlay';
export const IssuersScreen: React.FC<
HomeRouteProps | RootRouteProps
@@ -111,6 +112,46 @@ export const IssuersScreen: React.FC<
);
};
const filterIssuers = (searchText: string) => {
const filteredData = issuers.filter(item => {
if (
getDisplayObjectForCurrentLanguage(item.display)
?.name.toLowerCase()
.includes(searchText.toLowerCase())
) {
return getDisplayObjectForCurrentLanguage(item.display);
}
});
setFilteredSearchData(filteredData);
setSearch(searchText);
};
if (controller.isBiometricsCancelled) {
return (
<MessageOverlay
isVisible={controller.isBiometricsCancelled}
customHeight={'auto'}
title={t('errors.biometricsCancelled.title')}
message={t('errors.biometricsCancelled.message')}
onBackdropPress={controller.RESET_ERROR}>
<Row>
<Button
fill
type="clear"
title={t('common:cancel')}
onPress={controller.RESET_ERROR}
margin={[0, 8, 0, 0]}
/>
<Button
fill
title={t('common:tryAgain')}
onPress={controller.TRY_AGAIN}
/>
</Row>
</MessageOverlay>
);
}
if (controller.errorMessageType) {
return (
<Error
@@ -136,20 +177,6 @@ export const IssuersScreen: React.FC<
);
}
const filterIssuers = (searchText: string) => {
let filterdData = issuers.filter(item => {
if (
getDisplayObjectForCurrentLanguage(item.display)
?.name.toLowerCase()
.includes(searchText.toLowerCase())
) {
return getDisplayObjectForCurrentLanguage(item.display);
}
});
setFilteredSearchData(filterdData);
setSearch(searchText);
};
return (
<React.Fragment>
{controller.issuers.length > 0 && (

View File

@@ -68,5 +68,7 @@ export type IndividualId = {
id: string;
idType: VcIdType;
};
export const NETWORK_REQUEST_FAILED = 'Network request failed';
export const REQUEST_TIMEOUT = 'request timedout';
export const BIOMETRIC_CANCELLED = 'User has cancelled biometric';

View File

@@ -1,8 +1,9 @@
import {KeyPair, RSA} from 'react-native-rsa-native';
import forge from 'node-forge';
import {DEBUG_MODE_ENABLED, isIOS} from '../constants';
import {BIOMETRIC_CANCELLED, DEBUG_MODE_ENABLED, isIOS} from '../constants';
import SecureKeystore from 'react-native-secure-keystore';
import CryptoJS from 'crypto-js';
import {BiometricCancellationError} from '../error/BiometricCancellationError';
// 5min
export const AUTH_TIMEOUT = 5 * 60;
@@ -38,7 +39,7 @@ export async function getJWT(
);
return header64 + '.' + payLoad64 + '.' + signature64;
} catch (e) {
console.log('Exception Occured While Constructing JWT ', e);
console.log('Exception Occurred While Constructing JWT ', e);
throw e;
}
}
@@ -60,9 +61,12 @@ export async function createSignature(
} else {
try {
signature64 = await SecureKeystore.sign(individualId, preHash);
} catch (e) {
console.error('Error in creating signature:', e);
throw e;
} catch (error) {
console.error('Error in creating signature:', error);
if (error.toString().includes(BIOMETRIC_CANCELLED)) {
throw new BiometricCancellationError(error.toString());
}
throw error;
}
return replaceCharactersInB64(signature64);
@@ -99,15 +103,23 @@ export async function encryptJson(
encryptionKey: string,
data: string,
): Promise<string> {
// Disable Encryption in debug mode
if (DEBUG_MODE_ENABLED && __DEV__) {
return JSON.stringify(data);
}
try {
// Disable Encryption in debug mode
if (DEBUG_MODE_ENABLED && __DEV__) {
return JSON.stringify(data);
}
if (!isHardwareKeystoreExists) {
return CryptoJS.AES.encrypt(data, encryptionKey).toString();
if (!isHardwareKeystoreExists) {
return CryptoJS.AES.encrypt(data, encryptionKey).toString();
}
return await SecureKeystore.encryptData(ENCRYPTION_ID, data);
} catch (error) {
console.error('error while encrypting:', error);
if (error.toString().includes(BIOMETRIC_CANCELLED)) {
throw new BiometricCancellationError(error.toString());
}
throw error;
}
return await SecureKeystore.encryptData(ENCRYPTION_ID, data);
}
export async function decryptJson(
@@ -133,6 +145,10 @@ export async function decryptJson(
return await SecureKeystore.decryptData(ENCRYPTION_ID, encryptedData);
} catch (e) {
console.error('error decryptJson:', e);
if (e.toString().includes(BIOMETRIC_CANCELLED)) {
throw new BiometricCancellationError(e.toString());
}
throw e;
}
}

View File

@@ -0,0 +1,6 @@
export class BiometricCancellationError extends Error {
constructor(message: string) {
super(message);
this.name = 'BiometricCancellationError';
}
}

View File

@@ -155,4 +155,5 @@ export enum ErrorMessage {
NO_INTERNET = 'noInternetConnection',
GENERIC = 'generic',
REQUEST_TIMEDOUT = 'requestTimedOut',
BIOMETRIC_CANCELLED = 'biometricCancelled',
}