diff --git a/.env b/.env
index d055ca21fc..6ff684b9d5 100644
--- a/.env
+++ b/.env
@@ -21,4 +21,4 @@ DEBUG_MODE=false
APPLICATION_LANGUAGE=en
#Toggle for openID for VC
-ENABLE_OPENID_FOR_VC=false
+ENABLE_OPENID_FOR_VC=true
diff --git a/machines/activityLog.typegen.ts b/machines/activityLog.typegen.ts
index 686854d097..a21e978730 100644
--- a/machines/activityLog.typegen.ts
+++ b/machines/activityLog.typegen.ts
@@ -2,31 +2,31 @@
export interface Typegen0 {
'@@xstate/typegen': true;
- 'internalEvents': {
- 'xstate.init': { type: 'xstate.init' };
+ internalEvents: {
+ 'xstate.init': {type: 'xstate.init'};
};
- 'invokeSrcNameMap': {};
- 'missingImplementations': {
+ invokeSrcNameMap: {};
+ missingImplementations: {
actions: never;
delays: never;
guards: never;
services: never;
};
- 'eventsCausingActions': {
+ eventsCausingActions: {
loadActivities: 'REFRESH' | 'xstate.init';
prependActivity: 'STORE_RESPONSE';
setActivities: 'STORE_RESPONSE';
storeActivity: 'LOG_ACTIVITY';
};
- 'eventsCausingDelays': {};
- 'eventsCausingGuards': {};
- 'eventsCausingServices': {};
- 'matchesStates':
+ eventsCausingDelays: {};
+ eventsCausingGuards: {};
+ eventsCausingServices: {};
+ matchesStates:
| 'init'
| 'ready'
| 'ready.idle'
| 'ready.logging'
| 'ready.refreshing'
- | { ready?: 'idle' | 'logging' | 'refreshing' };
- 'tags': never;
+ | {ready?: 'idle' | 'logging' | 'refreshing'};
+ tags: never;
}
diff --git a/machines/auth.typegen.ts b/machines/auth.typegen.ts
index 3843a6d7cb..71a4e6dc39 100644
--- a/machines/auth.typegen.ts
+++ b/machines/auth.typegen.ts
@@ -2,8 +2,8 @@
export interface Typegen0 {
'@@xstate/typegen': true;
- 'internalEvents': {
- '': { type: '' };
+ internalEvents: {
+ '': {type: ''};
'done.invoke.auth.authorized:invocation[0]': {
type: 'done.invoke.auth.authorized:invocation[0]';
data: unknown;
@@ -14,19 +14,19 @@ export interface Typegen0 {
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
- 'xstate.init': { type: 'xstate.init' };
+ 'xstate.init': {type: 'xstate.init'};
};
- 'invokeSrcNameMap': {
+ invokeSrcNameMap: {
downloadFaceSdkModel: 'done.invoke.auth.authorized:invocation[0]';
generatePasscodeSalt: 'done.invoke.auth.introSlider:invocation[0]';
};
- 'missingImplementations': {
+ missingImplementations: {
actions: never;
delays: never;
guards: never;
services: never;
};
- 'eventsCausingActions': {
+ eventsCausingActions: {
requestStoredContext: 'xstate.init';
setBiometrics: 'SETUP_BIOMETRICS';
setContext: 'STORE_RESPONSE';
@@ -40,18 +40,18 @@ export interface Typegen0 {
| 'done.invoke.auth.authorized:invocation[0]'
| 'done.invoke.auth.introSlider:invocation[0]';
};
- 'eventsCausingDelays': {};
- 'eventsCausingGuards': {
+ eventsCausingDelays: {};
+ eventsCausingGuards: {
hasBiometricSet: '';
hasData: 'STORE_RESPONSE';
hasLanguageset: '';
hasPasscodeSet: '';
};
- 'eventsCausingServices': {
+ eventsCausingServices: {
downloadFaceSdkModel: 'LOGIN' | 'SETUP_PASSCODE';
generatePasscodeSalt: 'SELECT';
};
- 'matchesStates':
+ matchesStates:
| 'authorized'
| 'checkingAuth'
| 'init'
@@ -60,5 +60,5 @@ export interface Typegen0 {
| 'savingDefaults'
| 'settingUp'
| 'unauthorized';
- 'tags': never;
+ tags: never;
}
diff --git a/machines/bleShare/request/requestMachine.typegen.ts b/machines/bleShare/request/requestMachine.typegen.ts
index 3ed41328a8..4a8b103887 100644
--- a/machines/bleShare/request/requestMachine.typegen.ts
+++ b/machines/bleShare/request/requestMachine.typegen.ts
@@ -66,11 +66,11 @@ export interface Typegen0 {
prependReceivedVc: 'VC_RESPONSE';
registerLoggers:
| 'DISCONNECT'
- | 'DISMISS'
+ | 'RESET'
| 'xstate.after(DESTROY_TIMEOUT)#request.clearingConnection';
removeLoggers:
| 'DISCONNECT'
- | 'DISMISS'
+ | 'RESET'
| 'SCREEN_BLUR'
| 'xstate.after(DESTROY_TIMEOUT)#request.clearingConnection'
| 'xstate.init';
@@ -105,7 +105,7 @@ export interface Typegen0 {
eventsCausingServices: {
advertiseDevice:
| 'DISCONNECT'
- | 'DISMISS'
+ | 'RESET'
| 'xstate.after(DESTROY_TIMEOUT)#request.clearingConnection';
checkBluetoothService: 'NEARBY_ENABLED';
checkNearByDevicesPermission:
diff --git a/machines/issuersMachine.ts b/machines/issuersMachine.ts
index 1ddf71b164..876535a308 100644
--- a/machines/issuersMachine.ts
+++ b/machines/issuersMachine.ts
@@ -2,9 +2,9 @@ import {authorize, AuthorizeResult} from 'react-native-app-auth';
import {assign, EventFrom, send, sendParent, StateFrom} from 'xstate';
import {createModel} from 'xstate/lib/model';
import {MY_VCS_STORE_KEY} from '../shared/constants';
-import {request} from '../shared/request';
import {StoreEvents} from './store';
import {AppServices} from '../shared/GlobalContext';
+import NetInfo from '@react-native-community/netinfo';
import {
generateKeys,
isCustomSecureKeystore,
@@ -14,18 +14,27 @@ import {KeyPair} from 'react-native-rsa-native';
import {ActivityLogEvents} from './activityLog';
import {log} from 'xstate/lib/actions';
import {verifyCredential} from '../shared/vcjs/verifyCredential';
-import {getBody, getIdentifier} from '../shared/openId4VCI/Utils';
+import {
+ getBody,
+ getIdentifier,
+ vcDownloadTimeout,
+ OIDCErrors,
+ ErrorMessage,
+} from '../shared/openId4VCI/Utils';
+import {NETWORK_REQUEST_FAILED, REQUEST_TIMEOUT} from '../shared/constants';
import {VCMetadata} from '../shared/VCMetadata';
import {
CredentialWrapper,
VerifiableCredential,
} from '../types/VC/EsignetMosipVC/vc';
import {CACHED_API} from '../shared/api';
+import {request} from '../shared/request';
const model = createModel(
{
issuers: [] as issuerType[],
- selectedIssuer: [] as issuerType[],
+ selectedIssuerId: '' as string,
+ selectedIssuer: {} as issuerType,
tokenResponse: {} as AuthorizeResult,
errorMessage: '' as string,
loadingReason: 'displayIssuers' as string,
@@ -56,7 +65,7 @@ export const Issuer_Tab_Ref_Id = 'issuersMachine';
export const Issuers_Key_Ref = 'OpenId4VCI';
export const IssuersMachine = model.createMachine(
{
- /** @xstate-layout N4IgpgJg5mDOIC5QEtawK5gE6wLIEMBjAC2QDswA6AG1QBcBJNTHAYggHsLLY786qqDNjxFS3WrybCcAbQAMAXUSgADh1jI6yLipAAPRAEYA7PMomj8gJwAWeSYAcTgMy2TJgDQgAnsZPWlLYArC5GAEzWEfKRtka2AL4J3kIsoiTkVLBg1GCE2mRQ0iysACIA8gDqAHIAMuUAgqUA+gBqDA3NDKUKykgg6prauv2GCMHuFo7W8sET8i4x1uHefgimJpTWoRHWJrYuc9YAbEkpzCIEGdzZufnkRRdYrADKAKK1bwDCACpvLQwXi8AKpvABKvT0gy0OjIejGE02Thmc3si0iK18iEcRiC1nxJxR22OjhcZxAqUuYkyPByeQKjxkZUBuEBL0h-Whwzho0QiKmKPm6OWq0Q4X2QXkx3C0uCOKM0pcJnJlJwV3EWTp+WK2HYXCyfAElFV6Q1tLujCeHLUGhhI1AY2mx0oRmCxyMjgcJMi8VF6xM4Uo4QWRjc2xMcqVp2SFKepppqmwADMOFgALYNdB0Yip5AAL34sNYDWBPwAEuUwQwAFr-a0DW3c+HGBaOILHeSOWwkj3hYIKv34rYmY4TUeOZzSxzR84yePcRNYFPpzPZ3MF7msMHfN4MVr-Zo-coAaTe1XrXNhzfW4VvlEW3YVMRcexlfo2Wx2kX2h2C20SMYmuqNIwHQXxYJAYBkNo+DUAAYlgHBpjqzycDchqCHGwHcKB4GQdByCwQhSEoRejZXry6zuG2yy9scSq0bY75WEGMpytM+wONsZLkmQHAQHAehAdSFBQuR9oGIgAC0xx+jJKpYSJghkFoYlDBRDqIMctiUB2EyOPpMzhM4mJrH2gTLHs8jxI44T2K6ClzthVCSJac5qXaPKaQgtimWK1lBJExwzF24QuMGtgAbOaTOea9IPChHlNpRLi2ZQ-Zur5o7PlEslYggwa4r5JwBFlLijvsjkxUpcXak8SUaZJCARi4Lq2F28izGEna2e+dgugExwmKl7hmFKVVUtcVCLsuGZZjmWD5oWEmXhJYxWCxtkxGiRjLJYjh+oVgUlXYMrlcElWAYpU2ULhEECQRRGIch9WcuJXlNfECqBR6MTOHYZgHflwZtkNVkxGdrbhBNao1cgEC5A1a2IC1bUdV1VgTn5BV7JQWOksENhyk4RhJEkQA */
+ /** @xstate-layout N4IgpgJg5mDOIC5QEtawK5gE6wLIEMBjAC2QDswA6CVABwBt8BPASTUxwGIIB7Cy8gDceAayqoM2PEVL8asBszaScCIT0L4ALsj4BtAAwBdQ0cShaPWMh19zIAB6IALAEYAnJWfuAzM4BsAKwAHN7BwQDsfgA0IEyIAEw+Ea6UBgkRwT7uEekGrhHOAL5FsRIc0iTkVPKKrOxSnNhYPFiUiloAZq0AtgINOARVcnSM9SqwamTCmrZkpqb2ltZz9k4Izgme3n5Boe7hUc6x8QgJ3gZpgT6BgRH+yYWBJWUDlbJUza2cACoASgBNAD6AEEAOIglgAOUWSBAyxsujIaxcWy8vgCITCkRicUSIQSlGyCQMETu7n84QKLxA5SkQw+lC+WF+gNBEOhelcZjhCNWcPWrgSJ0QQppdMGMmqTKwLRZ-2B4MhMISPIsVkRdgFooMvjS-jc9wezl1ARFZwiCUClFcN3czmcKWuPnFbwZ0uZnD+AFEAMren5A71-P4AeT+sPVKyRKIQrgMwX8lASCWCgVcgW8lt15oyEU8CSCloz6WcN38rom7v4sDA9DAhB0ZCgyg4nAAIqGAOpQgAyoZB7aBLHbkfhGv5oHWPgMBmclEigQM-lTVpyc9z+R8yfzriyPhTS4zlYq1aotfrjfILYGnH9ve9AGEft6hyxfb6AKrBsd8mPahBAmFPEEB8VwhS8XVkgKA5dXcE96SlOQeAAdzIegeHwCBW2wR8+E6ZAoG4PhxGmURxDdJCalQ9DMOwgY8LIAioCmGZtCRBZjCWCd-ynUVgNOMVSlpSjhmotCMKwnCsEY5imllVp2kYLpen6KsqOoGjJPolRZMI1iNHY-RjF-HitT4jYUwXZwgMpFMfHCGcIlze15zuFdghyA5UweBDJTEygSAbEQWDILRsAoLRiP4dQxEC4hgtC8KsEi0zo3MxxRVuQlLUCdxdUzbIhX8c14w8Iky1ucI1zTYI-PeaUgsIEKwoisAot4GKyLipqWuS1LuW49LkQA4I0SFdxwOXO1-HSUrbUuLZSX8XwMn8Vwy3qs94sS1qUva+S5SU7RuiwPpeqStqtDSzURos4IIMpB5i1moCHPNSbgi8QIDXcPLcltDIto0i69simU5QSVlFQ5GEuN5My7syuNkiTfJJvyDwiyCUrZ2tPwbimoDMhuYGAtobBTp6EF0C0YhWmQAAvIyyGi0jhDiiUGv4CmsCpmm6YZ5m5gM2YOJM+Go1u2NbJtFbJoyN7U3cc0V2tbxXH8FdHSPe0ycZXn+dp+msCZlnDsUjoqbU08NMN3oBZNs2RfUMXjJMSXx2GmXNbl9wFbJJJlfNB6bUiLYbiW-KIgifXpXts7HaF83mWOlSzptxDycph3jeTl2yLd+YTMGhHvYA64k01-2hUDg9PNK5J52CAwZ3TQpwNj4Sue23qAGkwCYAAFfBkBZR8AAknz7oE++9YEh8hCNPb-DLBTnKuPD+h15cKc0qptDaMcibxnm70TGX7weR7HzhJ+n2f56BReWAjUupcnZH4x8Tf-czAJ-Z7xAskS4YFiQeXOJ5F0591IBRgBQLA2gwAD2HqPFknV2bkUzv5Rk8DsBIJQTfLAosWacTVF7aWAECjZEoPlTy6Z1o5HOOaPwqRqoOQyGNTMKY478DwYg8KhC0FswEN1CisDcFgAQQQ6+aCSFzAWO-Chn9BRRE8HQv6msPCWmOCBFMhI0xBH8DHMkOQyS8PErRLCj4sCQCkTofA9BYAiNiuI22AVeASTojYuxYVkCOMmK7UhEtyGryRusGyER9SWgpIVCkYFAi5j3EmG4CZW4OSbsUGB7jGSeKsRAHxEB7H+KcRbNoVtVI9w0nk7ShTikBPkeLD2oTEaxkidErYQQyzxIzLmThlBKSrQzJsKkFjNJeOsbYopfiAl3xBFCR83pew3RUS4R0HTYndIeL0kCe4ogVSyB4ByMcNpjMENgZAnQmDXjqTM+gLixHYO5lQc5psrk3KmfU+gjT3YrN4l-eMnguF3HOAkDMDlEl6ITFXYxDosjnCONA14EjpSvMudc5styHH3NThUjOVSApoveZiz5dyfnF2aUNShFkppAqtCCzY4K0x9IMNafMDCDgPBJAeMZyAID1jvqGXAQ8HwvlHCvVpVC1ZeG5VsVMUQ9l9JNAM5wY0W6pnjJEXl-KwBzIWUsv5a9RTSs2K3OVOJFV6NtKkG4eVUytx+jymkZAeBFPgHCAlHwqWrIQAAWh-uaX1ZIw6WnuJVKIK0EhjNqGMaS7qP7-PWJaXMP0okmhTPmGOFJ4wVmyVnRkzJvWJsQC3IFOQNqJkKPmG4uZMiXF1JSTYhZ0i7DGReBsTYbwqCLUauMu4iRUh+pmIUG0km2gGQURMqNNibTzTg6UNS6LST0lAHt4TEDGJcoWWhI6xreACGSXNyKcmNQSs1S6+0tBrtjGGgZU6XqsqSMEc0ZJtwFRNAUHeGYz7Hvzae3a-V2oQ1aAka9VCwVROhS3PKfhlwFA+mNZMjxcgORskkI9IkUU8xzonPOpthb-LCW0gSoofB+C8GNFaLd4zLhjmMq+qCx5gYsoehcMcbi7g2imVW5H0yqrGjcPwlo6pzueZQfhMjGNYGY1-PwhISQFGeoJlILCwJeHWhmBVFahK-vnchCZBTSXYvjco4tCAch9LU7Va48ZHSUjORc4lUAsUlJk+sQZyYqrrgNFrZ9VrKR3uMR5TWZGf5tq0AzZsbnSO+0NNkNwbhHKQsEv7bcar8pgW8FsUI2r6zRZRhmNIMdVy5Dyuqyz84AhPXsqqlI0aSL5ZgjawdXSR26NOCmX2WxHS6k-Xxs+JQgA */
predictableActionArguments: true,
preserveActionOrder: true,
id: Issuer_Tab_Ref_Id,
@@ -73,10 +82,11 @@ export const IssuersMachine = model.createMachine(
invoke: {
src: 'downloadIssuersList',
onDone: {
- actions: ['setIssuers'],
+ actions: ['setIssuers', 'resetLoadingReason'],
target: 'selectingIssuer',
},
onError: {
+ //loadingReason is not reset here so that we go to previous(Home) screen on back button press of error screen
actions: ['setError'],
target: 'error',
},
@@ -85,13 +95,27 @@ export const IssuersMachine = model.createMachine(
error: {
description: 'reaches here when any error happens',
on: {
- TRY_AGAIN: {
- actions: 'resetError',
- target: 'displayIssuers',
- },
+ TRY_AGAIN: [
+ {
+ description: 'not fetched issuers config yet',
+ cond: 'shouldFetchIssuersAgain',
+ actions: ['setLoadingReasonAsDisplayIssuers', 'resetError'],
+ target: 'displayIssuers',
+ },
+ {
+ cond: 'canSelectIssuerAgain',
+ actions: 'resetError',
+ target: 'selectingIssuer',
+ },
+ {
+ description: 'not fetched issuers config yet',
+ actions: ['setLoadingReasonAsDisplayIssuers', 'resetError'],
+ target: 'downloadIssuerConfig',
+ },
+ ],
RESET_ERROR: {
actions: 'resetError',
- target: 'idle',
+ target: 'selectingIssuer',
},
},
},
@@ -102,6 +126,7 @@ export const IssuersMachine = model.createMachine(
actions: sendParent('DOWNLOAD_ID'),
},
SELECTED_ISSUER: {
+ actions: 'setSelectedIssuerId',
target: 'downloadIssuerConfig',
},
},
@@ -112,7 +137,32 @@ export const IssuersMachine = model.createMachine(
src: 'downloadIssuerConfig',
onDone: {
actions: 'setSelectedIssuers',
- target: 'performAuthorization',
+ target: 'checkInternet',
+ },
+ onError: {
+ actions: ['setError', 'resetLoadingReason'],
+ target: 'error',
+ },
+ },
+ },
+ checkInternet: {
+ description: 'checks internet before opening the web view',
+ invoke: {
+ src: 'checkInternet',
+ id: 'checkInternet',
+ onDone: [
+ {
+ cond: 'isInternetConnected',
+ target: 'performAuthorization',
+ },
+ {
+ actions: ['setNoInternet', 'resetLoadingReason'],
+ target: 'error',
+ },
+ ],
+ onError: {
+ actions: () => console.log('checkInternet error caught'),
+ target: 'error',
},
},
},
@@ -122,13 +172,34 @@ export const IssuersMachine = model.createMachine(
invoke: {
src: 'invokeAuthorization',
onDone: {
- actions: ['setTokenResponse', 'getKeyPairFromStore', 'loadKeyPair'],
+ actions: [
+ 'setTokenResponse',
+ 'setLoadingReasonAsSettingUp',
+ 'getKeyPairFromStore',
+ 'loadKeyPair',
+ ],
target: 'checkKeyPair',
},
- onError: {
- actions: [() => console.log('error in invokeAuth - ', event.data)],
- target: 'downloadCredentials',
- },
+ onError: [
+ {
+ cond: 'isOIDCflowCancelled',
+ actions: ['resetError', 'resetLoadingReason'],
+ target: 'selectingIssuer',
+ },
+ {
+ cond: 'isOIDCConfigError',
+ actions: ['setOIDCConfigError'],
+ target: 'error',
+ },
+ {
+ actions: [
+ 'setError',
+ 'resetLoadingReason',
+ (_, event) => console.log('error in invokeAuth - ', event.data),
+ ],
+ target: 'error',
+ },
+ ],
},
},
checkKeyPair: {
@@ -153,11 +224,20 @@ export const IssuersMachine = model.createMachine(
src: 'generateKeyPair',
onDone: [
{
- actions: ['setPublicKey', 'setPrivateKey', 'storeKeyPair'],
+ actions: [
+ 'setPublicKey',
+ 'setLoadingReasonAsDownloadingCredentials',
+ 'setPrivateKey',
+ 'storeKeyPair',
+ ],
target: 'downloadCredentials',
},
{
- actions: ['setPublicKey', 'storeKeyPair'],
+ actions: [
+ 'setPublicKey',
+ 'setLoadingReasonAsDownloadingCredentials',
+ 'storeKeyPair',
+ ],
cond: 'isCustomSecureKeystore',
target: 'downloadCredentials',
},
@@ -172,10 +252,12 @@ export const IssuersMachine = model.createMachine(
actions: ['setVerifiableCredential', 'setCredentialWrapper'],
target: 'verifyingCredential',
},
- onError: {
- actions: event =>
- console.log(' error occured in downloadCredential', event),
- },
+ onError: [
+ {
+ actions: ['setError', 'resetLoadingReason'],
+ target: 'error',
+ },
+ ],
},
on: {
CANCEL: {
@@ -232,19 +314,39 @@ export const IssuersMachine = model.createMachine(
actions: {
setIssuers: model.assign({
issuers: (_, event) => event.data,
+ }),
+ setNoInternet: model.assign({
+ errorMessage: () => ErrorMessage.NO_INTERNET,
+ }),
+ setLoadingReasonAsDisplayIssuers: model.assign({
+ loadingReason: 'displayIssuers',
+ }),
+ setLoadingReasonAsDownloadingCredentials: model.assign({
+ loadingReason: 'downloadingCredentials',
+ }),
+ setLoadingReasonAsSettingUp: model.assign({
+ loadingReason: 'settingUp',
+ }),
+ resetLoadingReason: model.assign({
loadingReason: null,
}),
-
setError: model.assign({
errorMessage: (_, event) => {
- console.log('Error while fetching issuers ', event.data.message);
- return event.data.message === 'Network request failed'
- ? 'noInternetConnection'
- : 'generic';
+ console.log('Error occured ', event.data.message);
+ const error = event.data.message;
+ switch (error) {
+ case NETWORK_REQUEST_FAILED:
+ return ErrorMessage.NO_INTERNET;
+ case REQUEST_TIMEOUT:
+ return ErrorMessage.REQUEST_TIMEDOUT;
+ default:
+ return ErrorMessage.GENERIC;
+ }
},
- loadingReason: null,
}),
-
+ setOIDCConfigError: model.assign({
+ errorMessage: (_, event) => event.data.toString(),
+ }),
resetError: model.assign({
errorMessage: '',
}),
@@ -268,7 +370,6 @@ export const IssuersMachine = model.createMachine(
to: context => context.serviceRefs.store,
},
),
-
storeVerifiableCredentialMeta: send(
context =>
StoreEvents.PREPEND(MY_VCS_STORE_KEY, getVCMetadata(context)),
@@ -316,9 +417,11 @@ export const IssuersMachine = model.createMachine(
setSelectedIssuers: model.assign({
selectedIssuer: (_, event) => event.data,
}),
+ setSelectedIssuerId: model.assign({
+ selectedIssuerId: (_, event) => event.id,
+ }),
setTokenResponse: model.assign({
tokenResponse: (_, event) => event.data,
- loadingReason: 'settingUp',
}),
setVerifiableCredential: model.assign({
verifiableCredential: (_, event) => {
@@ -331,17 +434,16 @@ export const IssuersMachine = model.createMachine(
},
}),
setPublicKey: assign({
- publicKey: (context, event) => {
+ publicKey: (_, event) => {
if (!isCustomSecureKeystore()) {
return (event.data as KeyPair).public;
}
return event.data as string;
},
- loadingReason: 'downloadingCredentials',
}),
setPrivateKey: assign({
- privateKey: (context, event) => (event.data as KeyPair).private,
+ privateKey: (_, event) => (event.data as KeyPair).private,
}),
logDownloaded: send(
@@ -363,31 +465,30 @@ export const IssuersMachine = model.createMachine(
downloadIssuersList: async () => {
return await CACHED_API.fetchIssuers();
},
-
- downloadIssuerConfig: async (_, event) => {
- return await CACHED_API.fetchIssuerConfig(event.id);
+ checkInternet: async () => await NetInfo.fetch(),
+ downloadIssuerConfig: async (context, _) => {
+ return await CACHED_API.fetchIssuerConfig(context.selectedIssuerId);
},
-
downloadCredential: async context => {
const body = await getBody(context);
- const response = await fetch(
+ const downloadTimeout = await vcDownloadTimeout();
+ const response = await request(
+ 'POST',
context.selectedIssuer.serviceConfiguration.credentialEndpoint,
+ body,
+ '',
{
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- Authorization: 'Bearer ' + context.tokenResponse?.accessToken,
- },
- body: JSON.stringify(body),
+ 'Content-Type': 'application/json',
+ Authorization: 'Bearer ' + context.tokenResponse?.accessToken,
},
+ downloadTimeout,
);
let credential = await response.json();
credential = updateCredentialInformation(context, credential);
return credential;
},
invokeAuthorization: async context => {
- const response = await authorize(context.selectedIssuer);
- return response;
+ return await authorize(context.selectedIssuer);
},
generateKeyPair: async context => {
if (!isCustomSecureKeystore()) {
@@ -408,6 +509,33 @@ export const IssuersMachine = model.createMachine(
hasKeyPair: context => {
return context.publicKey != null;
},
+ isInternetConnected: (_, event) => !!event.data.isConnected,
+ isOIDCflowCancelled: (_, event) => {
+ // iOS & Android have different error strings for user cancelled flow
+ const err = [
+ OIDCErrors.OIDC_FLOW_CANCELLED_ANDROID,
+ OIDCErrors.OIDC_FLOW_CANCELLED_IOS,
+ ];
+ return (
+ !!event.data &&
+ typeof event.data.toString === 'function' &&
+ err.some(e => event.data.toString().includes(e))
+ );
+ },
+ isOIDCConfigError: (_, event) => {
+ return (
+ !!event.data &&
+ typeof event.data.toString === 'function' &&
+ event.data.toString().includes(OIDCErrors.OIDC_CONFIG_ERROR_PREFIX)
+ );
+ },
+ canSelectIssuerAgain: (context, _) => {
+ return (
+ context.errorMessage.includes(OIDCErrors.OIDC_CONFIG_ERROR_PREFIX) ||
+ context.errorMessage.includes(ErrorMessage.REQUEST_TIMEDOUT)
+ );
+ },
+ shouldFetchIssuersAgain: context => context.issuers.length === 0,
isCustomSecureKeystore: () => isCustomSecureKeystore(),
},
},
@@ -419,8 +547,11 @@ export function selectIssuers(state: State) {
return state.context.issuers;
}
-export function selectErrorMessage(state: State) {
- return state.context.errorMessage;
+export function selectErrorMessageType(state: State) {
+ return state.context.errorMessage === '' ||
+ state.context.errorMessage === ErrorMessage.NO_INTERNET
+ ? state.context.errorMessage
+ : ErrorMessage.GENERIC;
}
export function selectLoadingReason(state: State) {
diff --git a/machines/issuersMachine.typegen.ts b/machines/issuersMachine.typegen.ts
index b07dc261d3..9d9bb364e6 100644
--- a/machines/issuersMachine.typegen.ts
+++ b/machines/issuersMachine.typegen.ts
@@ -3,6 +3,11 @@
export interface Typegen0 {
'@@xstate/typegen': true;
internalEvents: {
+ 'done.invoke.checkInternet': {
+ type: 'done.invoke.checkInternet';
+ data: unknown;
+ __tip: 'See the XState TS docs to learn how to strongly type this.';
+ };
'done.invoke.issuersMachine.displayIssuers:invocation[0]': {
type: 'done.invoke.issuersMachine.displayIssuers:invocation[0]';
data: unknown;
@@ -33,10 +38,22 @@ export interface Typegen0 {
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
+ 'error.platform.checkInternet': {
+ type: 'error.platform.checkInternet';
+ data: unknown;
+ };
'error.platform.issuersMachine.displayIssuers:invocation[0]': {
type: 'error.platform.issuersMachine.displayIssuers:invocation[0]';
data: unknown;
};
+ 'error.platform.issuersMachine.downloadCredentials:invocation[0]': {
+ type: 'error.platform.issuersMachine.downloadCredentials:invocation[0]';
+ data: unknown;
+ };
+ 'error.platform.issuersMachine.downloadIssuerConfig:invocation[0]': {
+ type: 'error.platform.issuersMachine.downloadIssuerConfig:invocation[0]';
+ data: unknown;
+ };
'error.platform.issuersMachine.performAuthorization:invocation[0]': {
type: 'error.platform.issuersMachine.performAuthorization:invocation[0]';
data: unknown;
@@ -44,6 +61,7 @@ export interface Typegen0 {
'xstate.init': {type: 'xstate.init'};
};
invokeSrcNameMap: {
+ checkInternet: 'done.invoke.checkInternet';
downloadCredential: 'done.invoke.issuersMachine.downloadCredentials:invocation[0]';
downloadIssuerConfig: 'done.invoke.issuersMachine.downloadIssuerConfig:invocation[0]';
downloadIssuersList: 'done.invoke.issuersMachine.displayIssuers:invocation[0]';
@@ -61,12 +79,31 @@ export interface Typegen0 {
getKeyPairFromStore: 'done.invoke.issuersMachine.performAuthorization:invocation[0]';
loadKeyPair: 'done.invoke.issuersMachine.performAuthorization:invocation[0]';
logDownloaded: 'done.invoke.issuersMachine.verifyingCredential:invocation[0]';
- resetError: 'RESET_ERROR' | 'TRY_AGAIN';
+ resetError:
+ | 'RESET_ERROR'
+ | 'TRY_AGAIN'
+ | 'error.platform.issuersMachine.performAuthorization:invocation[0]';
+ resetLoadingReason:
+ | 'done.invoke.checkInternet'
+ | 'done.invoke.issuersMachine.displayIssuers:invocation[0]'
+ | 'error.platform.issuersMachine.downloadCredentials:invocation[0]'
+ | 'error.platform.issuersMachine.downloadIssuerConfig:invocation[0]'
+ | 'error.platform.issuersMachine.performAuthorization:invocation[0]';
setCredentialWrapper: 'done.invoke.issuersMachine.downloadCredentials:invocation[0]';
- setError: 'error.platform.issuersMachine.displayIssuers:invocation[0]';
+ setError:
+ | 'error.platform.issuersMachine.displayIssuers:invocation[0]'
+ | 'error.platform.issuersMachine.downloadCredentials:invocation[0]'
+ | 'error.platform.issuersMachine.downloadIssuerConfig:invocation[0]'
+ | 'error.platform.issuersMachine.performAuthorization:invocation[0]';
setIssuers: 'done.invoke.issuersMachine.displayIssuers:invocation[0]';
+ setLoadingReasonAsDisplayIssuers: 'TRY_AGAIN';
+ setLoadingReasonAsDownloadingCredentials: 'done.invoke.issuersMachine.generateKeyPair:invocation[0]';
+ setLoadingReasonAsSettingUp: 'done.invoke.issuersMachine.performAuthorization:invocation[0]';
+ setNoInternet: 'done.invoke.checkInternet';
+ setOIDCConfigError: 'error.platform.issuersMachine.performAuthorization:invocation[0]';
setPrivateKey: 'done.invoke.issuersMachine.generateKeyPair:invocation[0]';
setPublicKey: 'done.invoke.issuersMachine.generateKeyPair:invocation[0]';
+ setSelectedIssuerId: 'SELECTED_ISSUER';
setSelectedIssuers: 'done.invoke.issuersMachine.downloadIssuerConfig:invocation[0]';
setTokenResponse: 'done.invoke.issuersMachine.performAuthorization:invocation[0]';
setVerifiableCredential: 'done.invoke.issuersMachine.downloadCredentials:invocation[0]';
@@ -78,21 +115,27 @@ export interface Typegen0 {
};
eventsCausingDelays: {};
eventsCausingGuards: {
+ canSelectIssuerAgain: 'TRY_AGAIN';
hasKeyPair: 'CHECK_KEY_PAIR';
isCustomSecureKeystore: 'done.invoke.issuersMachine.generateKeyPair:invocation[0]';
+ isInternetConnected: 'done.invoke.checkInternet';
+ isOIDCConfigError: 'error.platform.issuersMachine.performAuthorization:invocation[0]';
+ isOIDCflowCancelled: 'error.platform.issuersMachine.performAuthorization:invocation[0]';
+ shouldFetchIssuersAgain: 'TRY_AGAIN';
};
eventsCausingServices: {
+ checkInternet: 'done.invoke.issuersMachine.downloadIssuerConfig:invocation[0]';
downloadCredential:
| 'CHECK_KEY_PAIR'
- | 'done.invoke.issuersMachine.generateKeyPair:invocation[0]'
- | 'error.platform.issuersMachine.performAuthorization:invocation[0]';
- downloadIssuerConfig: 'SELECTED_ISSUER';
+ | 'done.invoke.issuersMachine.generateKeyPair:invocation[0]';
+ downloadIssuerConfig: 'SELECTED_ISSUER' | 'TRY_AGAIN';
downloadIssuersList: 'TRY_AGAIN' | 'xstate.init';
generateKeyPair: 'CHECK_KEY_PAIR';
- invokeAuthorization: 'done.invoke.issuersMachine.downloadIssuerConfig:invocation[0]';
+ invokeAuthorization: 'done.invoke.checkInternet';
verifyCredential: 'done.invoke.issuersMachine.downloadCredentials:invocation[0]';
};
matchesStates:
+ | 'checkInternet'
| 'checkKeyPair'
| 'displayIssuers'
| 'done'
diff --git a/machines/settings.typegen.ts b/machines/settings.typegen.ts
index e616d17f17..31ee28ed65 100644
--- a/machines/settings.typegen.ts
+++ b/machines/settings.typegen.ts
@@ -32,12 +32,13 @@ export interface Typegen0 {
| 'done.invoke.settings.resetInjiProps:invocation[0]'
| 'error.platform.settings.resetInjiProps:invocation[0]';
requestStoredContext: 'xstate.init';
- resetCredentialRegistry: 'CANCEL' | 'UPDATE_CREDENTIAL_REGISTRY';
+ resetCredentialRegistry: 'CANCEL' | 'UPDATE_MIMOTO_HOST';
setContext: 'STORE_RESPONSE';
storeContext:
| 'ACCEPT_HARDWARE_SUPPORT_NOT_EXISTS'
| 'STORE_RESPONSE'
| 'TOGGLE_BIOMETRIC_UNLOCK'
+ | 'UPDATE_ESIGNET_HOST'
| 'UPDATE_NAME'
| 'UPDATE_VC_LABEL'
| 'done.invoke.settings.resetInjiProps:invocation[0]';
@@ -46,6 +47,7 @@ export interface Typegen0 {
updateCredentialRegistryResponse: 'error.platform.settings.resetInjiProps:invocation[0]';
updateCredentialRegistrySuccess: 'done.invoke.settings.resetInjiProps:invocation[0]';
updateDefaults: 'STORE_RESPONSE';
+ updateEsignetHostUrl: 'UPDATE_ESIGNET_HOST';
updateName: 'UPDATE_NAME';
updatePartialDefaults: 'STORE_RESPONSE';
updateUserShownWithHardwareKeystoreNotExists: 'ACCEPT_HARDWARE_SUPPORT_NOT_EXISTS';
@@ -57,7 +59,7 @@ export interface Typegen0 {
hasPartialData: 'STORE_RESPONSE';
};
eventsCausingServices: {
- resetInjiProps: 'UPDATE_CREDENTIAL_REGISTRY';
+ resetInjiProps: 'UPDATE_MIMOTO_HOST';
};
matchesStates:
| 'idle'
diff --git a/machines/store.typegen.ts b/machines/store.typegen.ts
index c689d514de..804f958af5 100644
--- a/machines/store.typegen.ts
+++ b/machines/store.typegen.ts
@@ -1,8 +1,57 @@
-// This file was automatically generated. Edits will be overwritten
+<<<<<<< HEAD
+ // This file was automatically generated. Edits will be overwritten
+
+ export interface Typegen0 {
+ '@@xstate/typegen': true;
+ internalEvents: {
+ "done.invoke._store": { type: "done.invoke._store"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
+"done.invoke.store.resettingStorage:invocation[0]": { type: "done.invoke.store.resettingStorage:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
+"error.platform._store": { type: "error.platform._store"; data: unknown };
+"xstate.init": { type: "xstate.init" };
+ };
+ invokeSrcNameMap: {
+ "checkStorageInitialisedOrNot": "done.invoke.store.checkStorageInitialisation:invocation[0]";
+"clear": "done.invoke.store.resettingStorage:invocation[0]";
+"generateEncryptionKey": "done.invoke.store.generatingEncryptionKey:invocation[0]";
+"getEncryptionKey": "done.invoke.store.gettingEncryptionKey:invocation[0]";
+"hasAndroidEncryptionKey": "done.invoke.store.checkEncryptionKey:invocation[0]";
+"store": "done.invoke._store";
+ };
+ missingImplementations: {
+ actions: "logKey";
+ delays: never;
+ guards: never;
+ services: never;
+ };
+ eventsCausingActions: {
+ "forwardStoreRequest": "APPEND" | "CLEAR" | "GET" | "PREPEND" | "REMOVE" | "REMOVE_ITEMS" | "REMOVE_VC_METADATA" | "SET" | "UPDATE";
+"logKey": "KEY_RECEIVED";
+"notifyParent": "KEY_RECEIVED" | "READY" | "done.invoke.store.resettingStorage:invocation[0]";
+"setEncryptionKey": "KEY_RECEIVED";
+ };
+ eventsCausingDelays: {
+
+ };
+ eventsCausingGuards: {
+ "isCustomSecureKeystore": "KEY_RECEIVED";
+ };
+ eventsCausingServices: {
+ "checkStorageInitialisedOrNot": "ERROR";
+"clear": "KEY_RECEIVED";
+"generateEncryptionKey": "ERROR" | "IGNORE" | "READY";
+"getEncryptionKey": "TRY_AGAIN";
+"hasAndroidEncryptionKey": never;
+"store": "KEY_RECEIVED" | "READY" | "done.invoke.store.resettingStorage:invocation[0]";
+ };
+ matchesStates: "checkEncryptionKey" | "checkStorageInitialisation" | "failedReadingKey" | "generatingEncryptionKey" | "gettingEncryptionKey" | "ready" | "resettingStorage";
+ tags: never;
+ }
+
+=======
export interface Typegen0 {
'@@xstate/typegen': true;
- 'internalEvents': {
+ internalEvents: {
'done.invoke._store': {
type: 'done.invoke._store';
data: unknown;
@@ -13,10 +62,10 @@ export interface Typegen0 {
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
- 'error.platform._store': { type: 'error.platform._store'; data: unknown };
- 'xstate.init': { type: 'xstate.init' };
+ 'error.platform._store': {type: 'error.platform._store'; data: unknown};
+ 'xstate.init': {type: 'xstate.init'};
};
- 'invokeSrcNameMap': {
+ invokeSrcNameMap: {
checkStorageInitialisedOrNot: 'done.invoke.store.checkStorageInitialisation:invocation[0]';
clear: 'done.invoke.store.resettingStorage:invocation[0]';
generateEncryptionKey: 'done.invoke.store.generatingEncryptionKey:invocation[0]';
@@ -24,13 +73,13 @@ export interface Typegen0 {
hasAndroidEncryptionKey: 'done.invoke.store.checkEncryptionKey:invocation[0]';
store: 'done.invoke._store';
};
- 'missingImplementations': {
+ missingImplementations: {
actions: 'logKey';
delays: never;
guards: never;
services: never;
};
- 'eventsCausingActions': {
+ eventsCausingActions: {
forwardStoreRequest:
| 'APPEND'
| 'CLEAR'
@@ -50,11 +99,11 @@ export interface Typegen0 {
setEncryptionKey: 'KEY_RECEIVED';
setIsTamperedVc: 'TAMPERED_VC';
};
- 'eventsCausingDelays': {};
- 'eventsCausingGuards': {
+ eventsCausingDelays: {};
+ eventsCausingGuards: {
isCustomSecureKeystore: 'KEY_RECEIVED';
};
- 'eventsCausingServices': {
+ eventsCausingServices: {
checkStorageInitialisedOrNot: 'ERROR';
clear: 'KEY_RECEIVED';
generateEncryptionKey: 'ERROR' | 'IGNORE' | 'READY';
@@ -65,7 +114,7 @@ export interface Typegen0 {
| 'READY'
| 'done.invoke.store.resettingStorage:invocation[0]';
};
- 'matchesStates':
+ matchesStates:
| 'checkEncryptionKey'
| 'checkStorageInitialisation'
| 'failedReadingKey'
@@ -73,5 +122,6 @@ export interface Typegen0 {
| 'gettingEncryptionKey'
| 'ready'
| 'resettingStorage';
- 'tags': never;
+ tags: never;
}
+>>>>>>> 5b53b069 (refactor(INJI-205): Check Internet before OIDC AuthZ)
diff --git a/screens/Issuers/IssuerScreenController.tsx b/screens/Issuers/IssuerScreenController.tsx
index 63f10d4ec9..a22129f4af 100644
--- a/screens/Issuers/IssuerScreenController.tsx
+++ b/screens/Issuers/IssuerScreenController.tsx
@@ -2,7 +2,7 @@ import {useSelector} from '@xstate/react';
import {
IssuerScreenTabEvents,
IssuersMachine,
- selectErrorMessage,
+ selectErrorMessageType,
selectIsDone,
selectIsDownloadCredentials,
selectIsIdle,
@@ -18,7 +18,7 @@ export function useIssuerScreenController({route, navigation}) {
return {
issuers: useSelector(service, selectIssuers),
- errorMessage: useSelector(service, selectErrorMessage),
+ errorMessageType: useSelector(service, selectErrorMessageType),
isDownloadingCredentials: useSelector(service, selectIsDownloadCredentials),
isDone: useSelector(service, selectIsDone),
isIdle: useSelector(service, selectIsIdle),
diff --git a/screens/Issuers/IssuersScreen.tsx b/screens/Issuers/IssuersScreen.tsx
index 3e969cb250..398cb31998 100644
--- a/screens/Issuers/IssuersScreen.tsx
+++ b/screens/Issuers/IssuersScreen.tsx
@@ -11,6 +11,7 @@ import {HomeRouteProps} from '../../routes/main';
import {useIssuerScreenController} from './IssuerScreenController';
import {Loader} from '../../components/ui/Loader';
import testIDProps, {removeWhiteSpace} from '../../shared/commonUtil';
+import {ErrorMessage} from '../../shared/openId4VCI/Utils';
export const IssuersScreen: React.FC<
HomeRouteProps | RootRouteProps
@@ -19,7 +20,7 @@ export const IssuersScreen: React.FC<
const {t} = useTranslation('IssuersScreen');
useLayoutEffect(() => {
- if (controller.loadingReason || controller.errorMessage) {
+ if (controller.loadingReason || controller.errorMessageType) {
props.navigation.setOptions({
headerShown: false,
});
@@ -39,7 +40,11 @@ export const IssuersScreen: React.FC<
if (controller.isStoring) {
props.navigation.goBack();
}
- }, [controller.loadingReason, controller.errorMessage, controller.isStoring]);
+ }, [
+ controller.loadingReason,
+ controller.errorMessageType,
+ controller.isStoring,
+ ]);
const onPressHandler = (id: string) => {
if (id !== 'UIN, VID, AID') {
@@ -50,14 +55,18 @@ export const IssuersScreen: React.FC<
};
const isGenericError = () => {
- return controller.errorMessage === 'generic';
+ return controller.errorMessageType === ErrorMessage.GENERIC;
};
const goBack = () => {
- controller.RESET_ERROR();
- setTimeout(() => {
+ if (
+ controller.errorMessageType &&
+ controller.loadingReason === 'displayIssuers'
+ ) {
props.navigation.goBack();
- }, 0);
+ } else {
+ controller.RESET_ERROR();
+ }
};
const getImage = () => {
@@ -78,6 +87,20 @@ export const IssuersScreen: React.FC<
);
};
+ if (controller.errorMessageType) {
+ return (
+
+ );
+ }
+
if (controller.loadingReason) {
return (
)}
- {controller.errorMessage && (
-
- )}
);
};
diff --git a/shared/GlobalContext.ts b/shared/GlobalContext.ts
index d93dca3afc..43be0f4aaa 100644
--- a/shared/GlobalContext.ts
+++ b/shared/GlobalContext.ts
@@ -1,14 +1,14 @@
-import { createContext } from 'react';
-import { ActorRefFrom, InterpreterFrom } from 'xstate';
-import { activityLogMachine } from '../machines/activityLog';
-import { appMachine } from '../machines/app';
-import { authMachine } from '../machines/auth';
-import { requestMachine } from '../machines/bleShare/request/requestMachine';
-import { scanMachine } from '../machines/bleShare/scan/scanMachine';
-import { settingsMachine } from '../machines/settings';
-import { storeMachine } from '../machines/store';
-import { vcMachine } from '../machines/vc';
-import { revokeVidsMachine } from '../machines/revoke';
+import {createContext} from 'react';
+import {ActorRefFrom, InterpreterFrom} from 'xstate';
+import {activityLogMachine} from '../machines/activityLog';
+import {appMachine} from '../machines/app';
+import {authMachine} from '../machines/auth';
+import {requestMachine} from '../machines/bleShare/request/requestMachine';
+import {scanMachine} from '../machines/bleShare/scan/scanMachine';
+import {settingsMachine} from '../machines/settings';
+import {storeMachine} from '../machines/store';
+import {vcMachine} from '../machines/vc';
+import {revokeVidsMachine} from '../machines/revoke';
export const GlobalContext = createContext({} as GlobalServices);
diff --git a/shared/InitialConfig.ts b/shared/InitialConfig.ts
index 44b37075d9..3f0b65c4d8 100644
--- a/shared/InitialConfig.ts
+++ b/shared/InitialConfig.ts
@@ -17,5 +17,6 @@ export const INITIAL_CONFIG = {
warningDomainName: '',
aboutInjiUrl: 'https://docs.mosip.io/inji',
faceSdkModelUrl: '',
+ openId4VCIDownloadVCTimeout: '30000',
},
};
diff --git a/shared/constants.ts b/shared/constants.ts
index c194a6c77f..cce9377d04 100644
--- a/shared/constants.ts
+++ b/shared/constants.ts
@@ -68,3 +68,6 @@ export const argon2iConfigForUinVid: Argon2iConfig = {
export const argon2iSalt =
'1234567891011121314151617181920212223242526272829303132333435363';
+
+export const NETWORK_REQUEST_FAILED = 'Network request failed';
+export const REQUEST_TIMEOUT = 'request timedout';
diff --git a/shared/openId4VCI/Utils.ts b/shared/openId4VCI/Utils.ts
index 5d9e290e96..30c46017bb 100644
--- a/shared/openId4VCI/Utils.ts
+++ b/shared/openId4VCI/Utils.ts
@@ -5,6 +5,7 @@ import {isIOS} from '../constants';
import pem2jwk from 'simple-pem2jwk';
import {Issuers_Key_Ref} from '../../machines/issuersMachine';
import {ENABLE_OPENID_FOR_VC} from 'react-native-dotenv';
+import getAllConfigurations from '../commonprops/commonProps';
export const OpenId4VCIProtocol = 'OpenId4VCIProtocol';
export const isOpenId4VCIEnabled = () => {
@@ -92,3 +93,24 @@ export const getJWT = async context => {
throw e;
}
};
+
+export const vcDownloadTimeout = async (): Promise => {
+ const response = await getAllConfigurations();
+
+ return Number(response['openId4VCIDownloadVCTimeout']) || 30000;
+};
+
+// OIDCErrors is a collection of external errors from the OpenID library or the issuer
+export enum OIDCErrors {
+ OIDC_FLOW_CANCELLED_ANDROID = 'User cancelled flow',
+ OIDC_FLOW_CANCELLED_IOS = 'org.openid.appauth.general error -3',
+
+ INVALID_TOKEN_SPECIFIED = 'Invalid token specified',
+ OIDC_CONFIG_ERROR_PREFIX = 'Config error',
+}
+// ErrorMessage is the type of error message shown in the UI
+export enum ErrorMessage {
+ NO_INTERNET = 'noInternetConnection',
+ GENERIC = 'generic',
+ REQUEST_TIMEDOUT = 'requestTimedOut',
+}
diff --git a/shared/request.ts b/shared/request.ts
index 16a0837c30..5ea47bfd66 100644
--- a/shared/request.ts
+++ b/shared/request.ts
@@ -3,7 +3,7 @@ import {
VerifiableCredential,
} from '../types/VC/ExistingMosipVC/vc';
import {__AppId} from './GlobalVariables';
-import {HOST, MIMOTO_BASE_URL} from './constants';
+import {MIMOTO_BASE_URL, REQUEST_TIMEOUT} from './constants';
export type HTTP_METHOD = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
@@ -19,18 +19,43 @@ export async function request(
path: `/${string}`,
body?: Record,
host = MIMOTO_BASE_URL,
-) {
- const headers = {
+ headers: Record = {
'Content-Type': 'application/json',
- };
+ },
+ timeoutMillis?: undefined | number,
+) {
if (path.includes('residentmobileapp'))
headers['X-AppId'] = __AppId.getValue();
-
- const response = await fetch(host + path, {
- method,
- headers,
- body: JSON.stringify(body),
- });
+ let response;
+ if (timeoutMillis === undefined) {
+ response = await fetch(host + path, {
+ method,
+ headers,
+ body: body ? JSON.stringify(body) : undefined,
+ });
+ } else {
+ console.log(`making a web request to ${host + path}`);
+ let controller = new AbortController();
+ setTimeout(() => {
+ controller.abort();
+ }, timeoutMillis);
+ try {
+ response = await fetch(host + path, {
+ method,
+ headers,
+ body: body ? JSON.stringify(body) : undefined,
+ signal: controller.signal,
+ });
+ } catch (error) {
+ console.log(
+ `Error occurred while making request: ${host + path}: ${error}`,
+ );
+ if (error.name === 'AbortError') {
+ throw new Error(REQUEST_TIMEOUT);
+ }
+ throw error;
+ }
+ }
const jsonResponse = await response.json();
@@ -38,10 +63,7 @@ export async function request(
let backendUrl = host + path;
let errorMessage = jsonResponse.message || jsonResponse.error;
console.error(
- 'The backend API ' +
- backendUrl +
- ' returned error code 400 with message --> ' +
- errorMessage,
+ `The backend API ${backendUrl} returned error code ${response.status} with message --> ${errorMessage}`,
);
throw new Error(errorMessage);
}