diff --git a/.env b/.env index ec478f88..b1bc3370 100644 --- a/.env +++ b/.env @@ -2,9 +2,9 @@ # eg . npm build android:newlogic --reset-cache #MIMOTO_HOST=http://mock.mimoto.newlogic.dev -MIMOTO_HOST=https://api.qa-inji.mosip.net +MIMOTO_HOST=https://api.peru-pilot2.mosip.net -ESIGNET_HOST=https://esignet.qa-inji.mosip.net +ESIGNET_HOST=https://esignet.peru-pilot2.mosip.net OBSRV_HOST = https://dataset-api.telemetry.mosip.net diff --git a/.github/scripts/set-google-clientid.sh b/.github/scripts/set-google-clientid.sh index a5d6fb4c..679e9c67 100755 --- a/.github/scripts/set-google-clientid.sh +++ b/.github/scripts/set-google-clientid.sh @@ -12,6 +12,8 @@ elif [[ "$flavor" == "inji" ]]; then echo "CLIENT_ID=INJI_ORG_KEY" >> $GITHUB_OUTPUT elif [[ "$flavor" == "mec" ]]; then echo "CLIENT_ID=MEC_ORG_KEY" >> $GITHUB_OUTPUT +elif [[ "$flavor" == "reniec" ]]; then + echo "CLIENT_ID=RENIEC_ORG_KEY" >> $GITHUB_OUTPUT else echo "Error: Invalid flavor '$flavor'" exit 1 diff --git a/.github/workflows/internal-build.yml b/.github/workflows/internal-build.yml index baf3c6f4..54df5977 100644 --- a/.github/workflows/internal-build.yml +++ b/.github/workflows/internal-build.yml @@ -47,6 +47,7 @@ on: - collab - synergy - mec + - reniec internal-testers: description: 'Internal Testers Group' required: true @@ -200,4 +201,4 @@ jobs: # secrets: # SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} # SONAR_ORGANIZATION: ${{ secrets.ORG_KEY }} - # SLACK_WEBHOOK_URL: '${{ secrets.SLACK_WEBHOOK_INJI_TEAM }}' \ No newline at end of file + # SLACK_WEBHOOK_URL: '${{ secrets.SLACK_WEBHOOK_INJI_TEAM }}' diff --git a/.talismanrc b/.talismanrc index 23d77564..55f38ae5 100644 --- a/.talismanrc +++ b/.talismanrc @@ -200,7 +200,7 @@ fileignoreconfig: - filename: screens/Home/IntroSlidersScreen.tsx checksum: 9880724461b194db7651737576ad2fd2db9cf3b4e732747f59be422a7ff4e4a1 - filename: .env - checksum: ac76b852842c44ff5dac96c1fa5061e569bea4f54b3080d869a9dc25abd17991 + checksum: f8375c44b0e70e691f942ea3323a0bf12cb0e2a7653a5551b34e2403a47119a8 - filename: machines/VCItemMachine/VCItemMachine.typegen.ts checksum: 850b5d02636bef9e286fc0fbc4ffffbd38068f332c319302a906496f4bc1c8a1 - filename: machines/VerifiableCredential/VCItemMachine/VCItemModel.ts @@ -258,7 +258,7 @@ fileignoreconfig: - filename: machines/Issuers/IssuersMachine.ts checksum: 1eb1e912ea76c88a8d477cce9742da59b5bb41a2a39cc1dc67c5bca240c1553b - filename: .github/scripts/set-google-clientid.sh - checksum: 013ef3b43f50ba05e18c9c83e89cc366c3f0d8ed4d931ce7daa19a757880419b + checksum: 04de37335d2efb014107db49c751ba04e5993ffa868ea5a4e3bca57a64b00fe6 - filename: screens/Issuers/CredentialTypeSelectionScreen.tsx checksum: 144bbf59e86a89bf580ac7931645ca3eaed69a9409de36f6ce9f88a14091a9d3 - filename: components/QrCodeOverlay.tsx @@ -268,11 +268,11 @@ fileignoreconfig: - filename: machines/Issuers/IssuersGuards.ts checksum: 21783a057207ad04facdb4c71884f49b0230490def04158419d730e0cc60eb83 - filename: machines/Issuers/IssuersActions.ts - checksum: 4414aa10588d2305293b1902982c5969895c858355e4b91d01dfaa8601c2dd62 + checksum: 7a7918df36cc41a9ebc5af763fe7c9e355be50223caf267315b12822000918cb - filename: injitest/automation_trigger.sh checksum: f2f34839c99cb1b871dde17aed8508a071345d22738796e005ff709d2dab8644 - filename: machines/Issuers/IssuersService.ts - checksum: e3832dff27687abc28609d2b281e570b4b0017995b7cfb56627a6b96949c469a + checksum: e33a75d4ea92db6e843900c9e57411f48bbe3d2fd43b78335f9cc6662cdfa85a - filename: screens/Home/ViewVcModal.tsx checksum: cfb25d562185488432b76287c4ef93359c1c64d8e29f5755d4c0a726c1485442 - filename: injitest/src/main/resources/TestData.json @@ -310,7 +310,7 @@ fileignoreconfig: - filename: machines/store.ts checksum: 3fd2db0c41f8bd5f30ef922b856549cb5423997b2123c5364e643e47e5efd3cf - filename: components/BannerNotificationContainer.tsx - checksum: 9e5b4a61b87e86666f0bee550d410df2b8576dfe5ec374de0ab139a468a234f7 + checksum: 15bfe7b05ae7faa2a00f80a7efe35f7285b2178731908e80ac358cc5b3c740d0 - filename: injitest/src/test/java/iosTestCases/PinVcTest.java checksum: 55098750062a199fdf1e33078acc50080dea12a885f934a7aa88411c06899cb7 - filename: injitest/src/test/java/androidTestCases/VcBackupAndRestoreTest.java @@ -396,4 +396,6 @@ fileignoreconfig: checksum: 9f29c9b0b91eba7fd7f5f4d1f78f9b6f96ef2c850c1346d712058a438d01036a - filename: assets/InjiHomeLogo.svg checksum: 6600a3d75033af4d702dd8c9663e12ad7c2c096a529bac2771bb856cc75a5ed0 + - filename: locales/es.json + checksum: a03fae655b13342afb45ab2b79998f3e06afcb02346c2ddf6aaacacf3b027209 version: "" diff --git a/android/app/build.gradle b/android/app/build.gradle index 47d31d5c..7c457407 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -229,6 +229,12 @@ android { dimension "inji" resValue "string", "app_name", "Inji Wallet Mec" } + reniec { + applicationId "io.mosip.inji.reniec" + versionName defaultConfig.versionName + dimension "inji" + resValue "string", "app_name", "Inji Wallet RENIEC" + } } android.applicationVariants.all { variant -> diff --git a/android/fastlane/Fastfile b/android/fastlane/Fastfile index d4c360d0..b5ed19bc 100644 --- a/android/fastlane/Fastfile +++ b/android/fastlane/Fastfile @@ -26,6 +26,8 @@ def generate_app_bundle_id() return "io.mosip.inji.synergy" when "mec" return "io.mosip.inji.mec" + when "reniec" + return "io.mosip.inji.reniec" end end @@ -42,6 +44,8 @@ def generate_app_name() return "Inji Wallet Synergy" when "mec" return "Inji Wallet Mec" + when "reniec" + return "Inji Wallet RENIEC" end end diff --git a/components/BannerNotificationContainer.tsx b/components/BannerNotificationContainer.tsx index 5d18e6f9..70312cec 100644 --- a/components/BannerNotificationContainer.tsx +++ b/components/BannerNotificationContainer.tsx @@ -23,6 +23,8 @@ export const BannerNotificationContainer: React.FC< const bannerNotificationController = UseBannerNotification(); const WalletBindingSuccess = bannerNotificationController.isBindingSuccess; + const autoWalletBindingSuccess = + bannerNotificationController.isAutoWalletBindingSuccess; const {t} = useTranslation('BannerNotification'); const rt = useTranslation('RequestScreen').t; const verificationStatus = bannerNotificationController.verificationStatus; @@ -55,19 +57,20 @@ export const BannerNotificationContainer: React.FC< )} - {WalletBindingSuccess && ( - - - - )} + {WalletBindingSuccess || + (!autoWalletBindingSuccess && ( + + + + ))} {showQuickShareSuccessBanner && ( diff --git a/components/BannerNotificationController.tsx b/components/BannerNotificationController.tsx index cf5db6a4..decf8a96 100644 --- a/components/BannerNotificationController.tsx +++ b/components/BannerNotificationController.tsx @@ -8,6 +8,7 @@ import {useContext} from 'react'; import {GlobalContext} from '../shared/GlobalContext'; import {VcMetaEvents} from '../machines/VerifiableCredential/VCMetaMachine/VCMetaMachine'; import { + selectAutoWalletBindingSuccess, selectIsDownloadingFailed, selectIsDownloadingSuccess, selectWalletBindingSuccess, @@ -21,11 +22,18 @@ export const UseBannerNotification = () => { return { isBindingSuccess: useSelector(vcMetaService, selectWalletBindingSuccess), + isAutoWalletBindingSuccess: useSelector( + vcMetaService, + selectAutoWalletBindingSuccess, + ), verificationStatus: useSelector(vcMetaService, selectVerificationStatus), isPasscodeUnlock: useSelector(settingsService, selectIsPasscodeUnlock), isBiometricUnlock: useSelector(settingsService, selectIsBiometricUnlock), - isDownloadingSuccess: useSelector(vcMetaService, selectIsDownloadingSuccess), + isDownloadingSuccess: useSelector( + vcMetaService, + selectIsDownloadingSuccess, + ), isDownloadingFailed: useSelector(vcMetaService, selectIsDownloadingFailed), DISMISS: () => { settingsService.send(SettingsEvents.DISMISS()); diff --git a/components/HelpScreen.tsx b/components/HelpScreen.tsx index bf2719f6..314bd43d 100644 --- a/components/HelpScreen.tsx +++ b/components/HelpScreen.tsx @@ -189,21 +189,6 @@ export const HelpScreen: React.FC = props => { {getTextField(t('answers.inji.eight'))} ), }, - { - title: t('questions.inji.nine'), - data: ( - - {getTextField( - t('answers.inji.nine'), - getLinkedText( - injiHelpUrl + - '/functional-overview/end-user-guide#activating-a-vc', - t('here'), - ), - )} - - ), - }, { title: t('questions.inji.ten'), data: ( @@ -220,14 +205,6 @@ export const HelpScreen: React.FC = props => { ), }, - { - title: t('questions.inji.eleven'), - data: ( - - {getTextField(t('answers.inji.eleven'))} - - ), - }, { title: t('questions.inji.twelve'), data: ( diff --git a/components/VC/Views/VCCardViewContent.tsx b/components/VC/Views/VCCardViewContent.tsx index e330ed1e..d7fd4070 100644 --- a/components/VC/Views/VCCardViewContent.tsx +++ b/components/VC/Views/VCCardViewContent.tsx @@ -18,6 +18,7 @@ import {RemoveVcWarningOverlay} from '../../../screens/Home/MyVcs/RemoveVcWarnin import {HistoryTab} from '../../../screens/Home/MyVcs/HistoryTab'; import {useCopilot} from 'react-native-copilot'; import {useTranslation} from 'react-i18next'; +import {addPngBase64Prefix} from '../../../shared/commonUtil'; export const VCCardViewContent: React.FC = props => { const wellknownDisplayProperty = new Display(props.wellknown); @@ -53,7 +54,7 @@ export const VCCardViewContent: React.FC = props => { /> )); const issuerLogo = props.verifiableCredentialData.issuerLogo; - const faceImage = props.verifiableCredentialData.face; + const faceImage = addPngBase64Prefix(props.verifiableCredentialData.face); const {start} = useCopilot(); const {t} = useTranslation(); diff --git a/components/VC/Views/VCDetailView.tsx b/components/VC/Views/VCDetailView.tsx index 38d02523..0b5d345e 100644 --- a/components/VC/Views/VCDetailView.tsx +++ b/components/VC/Views/VCDetailView.tsx @@ -21,9 +21,12 @@ import { } from '../common/VCUtils'; import {ProfileIcon} from '../../ProfileIcon'; import {VCFormat} from '../../../shared/VCFormat'; +import {VCItemField} from '../common/VCItemField'; +import {addPngBase64Prefix} from '../../../shared/commonUtil'; const getProfileImage = (face: any) => { if (face) { + face = addPngBase64Prefix(face); return ( ); diff --git a/components/VcItemContainerProfileImage.tsx b/components/VcItemContainerProfileImage.tsx index fc65104d..1b8478de 100644 --- a/components/VcItemContainerProfileImage.tsx +++ b/components/VcItemContainerProfileImage.tsx @@ -4,9 +4,10 @@ import {Theme} from './ui/styleUtils'; import React from 'react'; import {ProfileIcon} from './ProfileIcon'; import {SvgImage} from './ui/svg'; +import {addPngBase64Prefix} from '../shared/commonUtil'; export const VcItemContainerProfileImage = (props: VCItemContentProps) => { - const imageUri = props.verifiableCredentialData.face; + const imageUri = addPngBase64Prefix(props.verifiableCredentialData.face); return imageUri ? ( { @@ -347,6 +352,14 @@ export const IssuersActions = (model: any) => { verificationErrorMessage: () => '', }), + setAutoWalletBindingFailure: assign({ + isAutoWalletBindingFailed: () => true, + }), + + resetAutoWalletBindingFailure: model.assign({ + isAutoWalletBindingFailed: () => false, + }), + sendDownloadingFailedToVcMeta: send( (_: any) => ({ type: 'VC_DOWNLOADING_FAILED', @@ -355,5 +368,64 @@ export const IssuersActions = (model: any) => { to: context => context.serviceRefs.vcMeta, }, ), + unsetOTP: model.assign({OTP: () => ''}), + setOTP: model.assign({ + OTP: (_, event) => { + return DEFAULT_OTP; + }, + }), + setWalletBindingResponse: (context: any, event: any) => { + context.credentialWrapper = { + ...context.credentialWrapper, + walletBindingResponse: event.data as WalletBindingResponse, + }; + }, + sendActivationStartEvent: context => { + sendStartEvent( + getStartEventData( + context.isMachineInKebabPopupState + ? TelemetryConstants.FlowType.vcActivationFromKebab + : TelemetryConstants.FlowType.vcActivation, + ), + ); + }, + setThumbprintForWalletBindingId: send( + (context: any) => { + const {credentialWrapper} = context; + const walletBindingIdKey = getBindingCertificateConstant( + credentialWrapper.walletBindingResponse.walletBindingId, + ); + return StoreEvents.SET( + walletBindingIdKey, + credentialWrapper.walletBindingResponse.thumbprint, + ); + }, + { + to: context => context.serviceRefs.store, + }, + ), + resetPrivateKey: assign({ + privateKey: () => '', + }), + sendActivationSuccessEvent: context => + sendEndEvent( + getEndEventData( + context.isMachineInKebabPopupState + ? TelemetryConstants.FlowType.vcActivationFromKebab + : TelemetryConstants.FlowType.vcActivation, + TelemetryConstants.EndEventStatus.success, + {'Activation key': context.vcMetadata?.downloadKeyType}, + ), + ), + sendWalletBindingSuccess: send( + context => { + return { + type: 'AUTO_WALLET_BINDING_SUCCESS', + }; + }, + { + to: (context: any) => context.serviceRefs.vcMeta, + }, + ), }; }; diff --git a/machines/Issuers/IssuersEvents.ts b/machines/Issuers/IssuersEvents.ts index 3aa94d77..2092e280 100644 --- a/machines/Issuers/IssuersEvents.ts +++ b/machines/Issuers/IssuersEvents.ts @@ -11,6 +11,7 @@ export const IssuersEvents = { CANCEL: () => ({}), STORE_RESPONSE: (response?: unknown) => ({response}), STORE_ERROR: (error: Error, requester?: string) => ({error, requester}), - RESET_VERIFY_ERROR: () => ({}), + RESET_ERROR_SCREEN: () => ({}), SELECTED_CREDENTIAL_TYPE: (credType: CredentialTypes) => ({credType}), + SHOW_BINDING_STATUS: () => ({}), }; diff --git a/machines/Issuers/IssuersGuards.ts b/machines/Issuers/IssuersGuards.ts index 2cc8771b..383bec20 100644 --- a/machines/Issuers/IssuersGuards.ts +++ b/machines/Issuers/IssuersGuards.ts @@ -3,6 +3,7 @@ import {ErrorMessage, OIDCErrors} from '../../shared/openId4VCI/Utils'; import {isHardwareKeystoreExists} from '../../shared/cryptoutil/cryptoUtil'; import {BiometricCancellationError} from '../../shared/error/BiometricCancellationError'; import {VerificationErrorType} from '../../shared/vcjs/verifyCredential'; +import {DEFAULT_OTP} from '../../shared/constants'; export const IssuersGuards = () => { return { @@ -57,5 +58,7 @@ export const IssuersGuards = () => { const errorMessage = event.data.message; return errorMessage === ErrorMessage.GENERIC; }, + isAutoWalletBindingFlow: (context: any, event: any) => + context?.OTP === DEFAULT_OTP, }; }; diff --git a/machines/Issuers/IssuersMachine.ts b/machines/Issuers/IssuersMachine.ts index e46f7ce3..19bf9909 100644 --- a/machines/Issuers/IssuersMachine.ts +++ b/machines/Issuers/IssuersMachine.ts @@ -358,6 +358,16 @@ export const IssuersMachine = model.createMachine( cond: 'isCustomSecureKeystore', target: 'downloadCredentials', }, + { + cond: 'isAutoWalletBindingFlow', + actions: [ + 'setPublicKey', + 'setPrivateKey', + 'setLoadingReasonAsDownloadingCredentials', + 'storeKeyPair', + ], + target: 'addingWalletBindingId', + }, { actions: [ // to be decided @@ -369,6 +379,13 @@ export const IssuersMachine = model.createMachine( target: 'downloadCredentials', }, ], + onError: [ + { + cond: 'isAutoWalletBindingFlow', + actions: 'setAutoWalletBindingFailure', + target: 'handleVCAutoWalletBindingFailure', + }, + ], }, }, downloadCredentials: { @@ -432,8 +449,12 @@ export const IssuersMachine = model.createMachine( src: 'verifyCredential', onDone: [ { - actions: ['sendSuccessEndEvent', 'setVerificationResult'], - target: 'storing', + actions: [ + 'sendSuccessEndEvent', + 'setVerificationResult', + 'setVCMetadata', + ], + target: 'requestingBindingOTP', }, ], onError: [ @@ -454,14 +475,94 @@ export const IssuersMachine = model.createMachine( }, }, + requestingBindingOTP: { + entry: 'sendActivationStartEvent', + invoke: { + src: 'requestBindingOTP', + onDone: [ + { + target: 'addKeyPair', + actions: ['unsetOTP', 'setOTP'], + }, + ], + onError: [ + { + actions: 'setAutoWalletBindingFailure', + target: 'handleVCAutoWalletBindingFailure', + }, + ], + }, + }, + addKeyPair: { + invoke: { + src: 'fetchKeyPair', + onDone: [ + { + cond: 'hasKeyPair', + actions: ['setPublicKey'], + target: 'addingWalletBindingId', + }, + { + target: 'generateKeyPair', + }, + ], + onError: [ + { + actions: 'setAutoWalletBindingFailure', + target: 'handleVCAutoWalletBindingFailure', + }, + ], + }, + }, + addingWalletBindingId: { + invoke: { + src: 'addWalletBindingId', + onDone: [ + { + cond: 'isCustomSecureKeystore', + actions: ['setWalletBindingResponse'], + target: 'updatingContextVariables', + }, + ], + onError: [ + { + actions: 'setAutoWalletBindingFailure', + target: 'handleVCAutoWalletBindingFailure', + }, + ], + }, + }, + updatingContextVariables: { + entry: [ + 'setThumbprintForWalletBindingId', + 'resetPrivateKey', + send('SHOW_BINDING_STATUS'), + ], + on: { + SHOW_BINDING_STATUS: [ + { + actions: 'sendWalletBindingSuccess', + target: 'storing', + }, + ], + }, + }, handleVCVerificationFailure: { on: { - RESET_VERIFY_ERROR: { + RESET_ERROR_SCREEN: { actions: ['resetVerificationErrorMessage'], }, }, }, + handleVCAutoWalletBindingFailure: { + on: { + RESET_ERROR_SCREEN: { + actions: ['resetAutoWalletBindingFailure'], + }, + }, + }, + storing: { description: 'all the verified credential is stored.', entry: [ diff --git a/machines/Issuers/IssuersModel.ts b/machines/Issuers/IssuersModel.ts index e3f90f80..a5004c78 100644 --- a/machines/Issuers/IssuersModel.ts +++ b/machines/Issuers/IssuersModel.ts @@ -10,6 +10,7 @@ import {AppServices} from '../../shared/GlobalContext'; import {VCMetadata} from '../../shared/VCMetadata'; import {IssuersEvents} from './IssuersEvents'; import {issuerType} from './IssuersMachine'; +import {CommunicationDetails} from '../../shared/Utils'; export const IssuersModel = createModel( { @@ -31,6 +32,8 @@ export const IssuersModel = createModel( vcMetadata: {} as VCMetadata, keyType: 'RS256' as string, wellknownKeyTypes: [] as string[], + OTP: '', + isAutoWalletBindingFailed: false, }, { events: IssuersEvents, diff --git a/machines/Issuers/IssuersSelectors.ts b/machines/Issuers/IssuersSelectors.ts index 2c7b8b13..7983b785 100644 --- a/machines/Issuers/IssuersSelectors.ts +++ b/machines/Issuers/IssuersSelectors.ts @@ -58,6 +58,10 @@ export function selectVerificationErrorMessage(state: State) { return state.context.verificationErrorMessage; } +export function selectAutoWalletBindingFailure(state: State) { + return state.context.isAutoWalletBindingFailed; +} + export function selectSelectingCredentialType(state: State) { return state.matches('selectingCredentialType'); } diff --git a/machines/Issuers/IssuersService.ts b/machines/Issuers/IssuersService.ts index cd890b39..a47eaa8d 100644 --- a/machines/Issuers/IssuersService.ts +++ b/machines/Issuers/IssuersService.ts @@ -1,5 +1,5 @@ import Cloud from '../../shared/CloudBackupAndRestoreUtils'; -import {CACHED_API} from '../../shared/api'; +import {API_URLS, CACHED_API} from '../../shared/api'; import NetInfo from '@react-native-community/netinfo'; import { constructAuthorizationConfiguration, @@ -29,6 +29,8 @@ import {TelemetryConstants} from '../../shared/telemetry/TelemetryConstants'; import {VciClient} from '../../shared/vciClient/VciClient'; import {isMockVC} from '../../shared/Utils'; import {VCFormat} from '../../shared/VCFormat'; +import {request} from '../../shared/request'; +import {WalletBindingResponse} from '../VerifiableCredential/VCMetaMachine/vc'; export const IssuersService = () => { return { @@ -172,5 +174,62 @@ export const IssuersService = () => { }; } }, + + requestBindingOTP: async (context: any) => { + const response = await request( + API_URLS.bindingOtp.method, + API_URLS.bindingOtp.buildURL(), + { + requestTime: String(new Date().toISOString()), + request: { + individualId: + context.verifiableCredential.credential.credentialSubject.dni, + otpChannels: ['EMAIL', 'PHONE'], + }, + }, + ); + if (response.response == null) { + throw new Error('Could not process request'); + } + return response; + }, + + fetchKeyPair: async context => { + const keyType = context.vcMetadata?.downloadKeyType; + return await fetchKeyPair(keyType); + }, + + addWalletBindingId: async context => { + const response = await request( + API_URLS.walletBinding.method, + API_URLS.walletBinding.buildURL(), + { + requestTime: String(new Date().toISOString()), + request: { + authFactorType: 'WLA', + format: 'jwt', + individualId: + context.verifiableCredential.credential.credentialSubject.dni, + transactionId: context.bindingTransactionId, + publicKey: context.publicKey, + challengeList: [ + { + authFactorType: 'OTP', + challenge: context.OTP, + format: 'alpha-numeric', + }, + ], + }, + }, + ); + + const walletResponse: WalletBindingResponse = { + walletBindingId: response.response.encryptedWalletBindingId, + keyId: response.response.keyId, + thumbprint: response.response.thumbprint, + expireDateTime: response.response.expireDateTime, + }; + return walletResponse; + }, }; }; diff --git a/machines/VerifiableCredential/VCMetaMachine/VCMetaActions.ts b/machines/VerifiableCredential/VCMetaMachine/VCMetaActions.ts index 574395b9..0779c08c 100644 --- a/machines/VerifiableCredential/VCMetaMachine/VCMetaActions.ts +++ b/machines/VerifiableCredential/VCMetaMachine/VCMetaActions.ts @@ -218,6 +218,12 @@ export const VCMetaActions = (model: any) => { ...getUpdatedVCMetadatas(context.myVcsMetadata, event.vcMetadata), ], }), + setAutoWalletBindingSuccess: model.assign({ + autoWalletBindingSuccess: true, + }), + resetAutoWalletBindingSuccess: model.assign({ + autoWalletBindingSuccess: false, + }), setWalletBindingSuccess: model.assign({ walletBindingSuccess: true, diff --git a/machines/VerifiableCredential/VCMetaMachine/VCMetaEvents.ts b/machines/VerifiableCredential/VCMetaMachine/VCMetaEvents.ts index 8233bfa6..1d3e9955 100644 --- a/machines/VerifiableCredential/VCMetaMachine/VCMetaEvents.ts +++ b/machines/VerifiableCredential/VCMetaMachine/VCMetaEvents.ts @@ -18,6 +18,7 @@ export const VcMetaEvents = { REFRESH_MY_VCS_TWO: (vc: VC) => ({vc}), REFRESH_RECEIVED_VCS: () => ({}), WALLET_BINDING_SUCCESS: () => ({}), + AUTO_WALLET_BINDING_SUCCESS: () => ({}), RESET_WALLET_BINDING_SUCCESS: () => ({}), ADD_VC_TO_IN_PROGRESS_DOWNLOADS: (requestId: string) => ({requestId}), REMOVE_VC_FROM_IN_PROGRESS_DOWNLOADS: (vcMetadata: VCMetadata) => ({ @@ -31,7 +32,7 @@ export const VcMetaEvents = { errorMessage, vcMetadata, }), - RESET_VERIFY_ERROR: () => ({}), + RESET_ERROR_SCREEN: () => ({}), REFRESH_VCS_METADATA: () => ({}), SHOW_TAMPERED_POPUP: () => ({}), SET_VERIFICATION_STATUS: (verificationStatus: unknown) => ({ diff --git a/machines/VerifiableCredential/VCMetaMachine/VCMetaMachine.ts b/machines/VerifiableCredential/VCMetaMachine/VCMetaMachine.ts index 30f5b003..ec7c9206 100644 --- a/machines/VerifiableCredential/VCMetaMachine/VCMetaMachine.ts +++ b/machines/VerifiableCredential/VCMetaMachine/VCMetaMachine.ts @@ -25,8 +25,8 @@ export const vcMetaMachine = VC_DOWNLOADING_FAILED: { actions: 'setDownloadCreadentialsFailed', }, - RESET_DOWNLOADING_SUCCESS:{ - actions: 'resetDownloadCredentialsSuccess' + RESET_DOWNLOADING_SUCCESS: { + actions: 'resetDownloadCredentialsSuccess', }, RESET_DOWNLOADING_FAILED: { actions: 'resetDownloadCreadentialsFailed', @@ -105,6 +105,9 @@ export const vcMetaMachine = WALLET_BINDING_SUCCESS: { actions: 'setWalletBindingSuccess', }, + AUTO_WALLET_BINDING_SUCCESS: { + actions: 'setAutoWalletBindingSuccess', + }, GET_VC_ITEM: { actions: 'getVcItemResponse', }, @@ -118,7 +121,7 @@ export const vcMetaMachine = actions: ['updateMyVcsMetadata', 'setUpdatedVcMetadatas'], }, VC_DOWNLOADED: { - actions: ['setDownloadCredentialsSuccess','setDownloadedVc',] + actions: ['setDownloadCredentialsSuccess', 'setDownloadedVc'], }, ADD_VC_TO_IN_PROGRESS_DOWNLOADS: { actions: 'addVcToInProgressDownloads', @@ -151,7 +154,7 @@ export const vcMetaMachine = ], target: '#vcMeta.ready', }, - RESET_VERIFY_ERROR: { + RESET_ERROR_SCREEN: { actions: 'resetVerificationErrorMessage', }, SET_VERIFICATION_STATUS: { diff --git a/machines/VerifiableCredential/VCMetaMachine/VCMetaModel.ts b/machines/VerifiableCredential/VCMetaMachine/VCMetaModel.ts index 0e501b1f..83a4ff10 100644 --- a/machines/VerifiableCredential/VCMetaMachine/VCMetaModel.ts +++ b/machines/VerifiableCredential/VCMetaMachine/VCMetaModel.ts @@ -15,12 +15,13 @@ export const VCMetamodel = createModel( inProgressVcDownloads: new Set(), //VCDownloadInProgress areAllVcsDownloaded: false as boolean, walletBindingSuccess: false, + autoWalletBindingSuccess: true, tamperedVcs: [] as VCMetadata[], downloadingFailedVcs: [] as VCMetadata[], //VCDownloadFailed verificationErrorMessage: '' as string, verificationStatus: null as vcVerificationBannerDetails | null, DownloadingCredentialsFailed: false, - DownloadingCredentialsSuccess: false + DownloadingCredentialsSuccess: false, }, { events: VcMetaEvents, diff --git a/machines/VerifiableCredential/VCMetaMachine/VCMetaSelectors.ts b/machines/VerifiableCredential/VCMetaMachine/VCMetaSelectors.ts index 8fc9e2fc..0a8c7d49 100644 --- a/machines/VerifiableCredential/VCMetaMachine/VCMetaSelectors.ts +++ b/machines/VerifiableCredential/VCMetaMachine/VCMetaSelectors.ts @@ -68,6 +68,10 @@ export function selectWalletBindingSuccess(state: State) { return state.context.walletBindingSuccess; } +export function selectAutoWalletBindingSuccess(state: State) { + return state.context.autoWalletBindingSuccess; +} + export function selectIsTampered(state: State) { return state.matches('ready.tamperedVCs'); } diff --git a/machines/VerifiableCredential/VCMetaMachine/vc.d.ts b/machines/VerifiableCredential/VCMetaMachine/vc.d.ts index 0d1e1ef7..941bc219 100644 --- a/machines/VerifiableCredential/VCMetaMachine/vc.d.ts +++ b/machines/VerifiableCredential/VCMetaMachine/vc.d.ts @@ -43,22 +43,24 @@ export interface CredentialSubject { type VCContext = (string | Record)[]; -export type Credential = { - credentialConfigurationId: any; - '@context': VCContext; - credentialSubject: CredentialSubject; - id: string; - issuanceDate: string; - issuer: string; - proof: { - created: string; - jws: string; - proofPurpose: 'assertionMethod' | string; - type: 'RsaSignature2018' | string; - verificationMethod: string; - }; - type: string[]; -} | string +export type Credential = + | { + credentialConfigurationId: any; + '@context': VCContext; + credentialSubject: CredentialSubject; + id: string; + issuanceDate: string; + issuer: string; + proof: { + created: string; + jws: string; + proofPurpose: 'assertionMethod' | string; + type: 'RsaSignature2018' | string; + verificationMethod: string; + }; + type: string[]; + } + | string; export interface VerifiableCredential { issuerLogo: logoType; @@ -84,6 +86,7 @@ export interface CredentialWrapper { identifier: string; generatedOn: Date; vcMetadata: VCMetadata; + walletBindingResponse: WalletBindingResponse; } export interface CredentialTypes { diff --git a/screens/Home/MyVcsTab.tsx b/screens/Home/MyVcsTab.tsx index cc903783..2579cc1c 100644 --- a/screens/Home/MyVcsTab.tsx +++ b/screens/Home/MyVcsTab.tsx @@ -84,8 +84,8 @@ export const MyVcsTab: React.FC = props => { const credentialSubject = vc.verifiableCredential.credentialSubject || vc.verifiableCredential.credential.credentialSubject; - if(isStringAndContains(searchText,vc['vcMetadata'].credentialType)) - isVcFound=true + if (isStringAndContains(searchText, vc['vcMetadata'].credentialType)) + isVcFound = true; else if (credentialSubject) { isVcFound = searchNestedCredentialFields( searchTextLower, @@ -449,7 +449,7 @@ export const MyVcsTab: React.FC = props => { image={SvgImage.PermissionDenied()} showClose={false} primaryButtonText="goBack" - primaryButtonEvent={controller.RESET_VERIFY_ERROR} + primaryButtonEvent={controller.RESET_ERROR_SCREEN} primaryButtonTestID="goBack" customStyles={{marginTop: '30%'}} /> diff --git a/screens/Home/MyVcsTabController.ts b/screens/Home/MyVcsTabController.ts index 7473c49d..f892de80 100644 --- a/screens/Home/MyVcsTabController.ts +++ b/screens/Home/MyVcsTabController.ts @@ -107,8 +107,8 @@ export function useMyVcsTab(props: HomeScreenTabProps) { DELETE_VC: () => vcMetaService?.send(VcMetaEvents.DELETE_VC()), - RESET_VERIFY_ERROR: () => { - vcMetaService?.send(VcMetaEvents.RESET_VERIFY_ERROR()); + RESET_ERROR_SCREEN: () => { + vcMetaService?.send(VcMetaEvents.RESET_ERROR_SCREEN()); }, SET_TOUR_GUIDE: set => { authService?.send(AuthEvents.SET_TOUR_GUIDE(set)); diff --git a/screens/Issuers/IssuerScreenController.tsx b/screens/Issuers/IssuerScreenController.tsx index 4f582ec5..ec6d8e66 100644 --- a/screens/Issuers/IssuerScreenController.tsx +++ b/screens/Issuers/IssuerScreenController.tsx @@ -14,6 +14,7 @@ import { selectStoring, selectVerificationErrorMessage, selectIsNonGenericError, + selectAutoWalletBindingFailure, } from '../../machines/Issuers/IssuersSelectors'; import {ActorRefFrom} from 'xstate'; import {BOTTOM_TAB_ROUTES} from '../../routes/routesConstants'; @@ -52,6 +53,10 @@ export function useIssuerScreenController({route, navigation}) { service, selectVerificationErrorMessage, ), + isAutoWalletBindingFailed: useSelector( + service, + selectAutoWalletBindingFailure, + ), isError: useSelector(service, selectIsError), CANCEL: () => service.send(IssuerScreenTabEvents.CANCEL()), @@ -65,8 +70,8 @@ export function useIssuerScreenController({route, navigation}) { }, SELECTED_CREDENTIAL_TYPE: (credType: CredentialTypes) => service.send(IssuerScreenTabEvents.SELECTED_CREDENTIAL_TYPE(credType)), - RESET_VERIFY_ERROR: () => { - service.send(IssuerScreenTabEvents.RESET_VERIFY_ERROR()); + RESET_ERROR_SCREEN: () => { + service.send(IssuerScreenTabEvents.RESET_ERROR_SCREEN()); if (isAndroid()) { navigation.navigate(BOTTOM_TAB_ROUTES.home, {screen: 'HomeScreen'}); } else { diff --git a/screens/Issuers/IssuersScreen.tsx b/screens/Issuers/IssuersScreen.tsx index 8118c22b..98487b8c 100644 --- a/screens/Issuers/IssuersScreen.tsx +++ b/screens/Issuers/IssuersScreen.tsx @@ -51,6 +51,8 @@ export const IssuersScreen: React.FC< ? t(translationKey) : t(`errors.verificationFailed.ERR_GENERIC`); + const isAutoWalletBindingFailed = controller.isAutoWalletBindingFailed; + useLayoutEffect(() => { if (controller.loadingReason || showFullScreenError) { props.navigation.setOptions({ @@ -170,7 +172,26 @@ export const IssuersScreen: React.FC< image={SvgImage.PermissionDenied()} showClose={false} primaryButtonText="goBack" - primaryButtonEvent={controller.RESET_VERIFY_ERROR} + primaryButtonEvent={controller.RESET_ERROR_SCREEN} + primaryButtonTestID="goBack" + customStyles={{marginTop: '30%'}} + /> + ); + } + + if (isAutoWalletBindingFailed) { + return ( + diff --git a/shared/VCMetadata.ts b/shared/VCMetadata.ts index 1e3ae00b..5c2fdfee 100644 --- a/shared/VCMetadata.ts +++ b/shared/VCMetadata.ts @@ -9,7 +9,7 @@ import {Protocols} from './openId4VCI/Utils'; import {getMosipIdentifier} from './commonUtil'; import {VCFormat} from './VCFormat'; import {isMosipVC} from './Utils'; -import { getCredentialType } from '../components/VC/common/VCUtils'; +import {getCredentialType} from '../components/VC/common/VCUtils'; const VC_KEY_PREFIX = 'VC'; const VC_ITEM_STORE_KEY_REGEX = '^VC_[a-zA-Z0-9_-]+$'; @@ -57,7 +57,7 @@ export class VCMetadata { this.format = format; this.downloadKeyType = downloadKeyType; this.isExpired = isExpired; - this.credentialType = credentialType + this.credentialType = credentialType; } //TODO: Remove any typing and use appropriate typing @@ -79,7 +79,7 @@ export class VCMetadata { ? vc.vcMetadata.mosipIndividualId : getMosipIndividualId(vc.verifiableCredential, vc.issuer), downloadKeyType: vc.downloadKeyType, - credentialType: vc.credentialType + credentialType: vc.credentialType, }); } @@ -119,7 +119,11 @@ export function parseMetadatas(metadataStrings: object[]) { return metadataStrings.map(o => new VCMetadata(o)); } -export const getVCMetadata = (context: object, keyType: string, credType: CredentialTypes) => { +export const getVCMetadata = ( + context: object, + keyType: string, + credType: CredentialTypes, +) => { const [issuer, protocol, credentialId] = context.credentialWrapper?.identifier.split(':'); @@ -137,7 +141,7 @@ export const getVCMetadata = (context: object, keyType: string, credType: Creden ), format: context['credentialWrapper'].format, downloadKeyType: keyType, - credentialType: getCredentialType(context.selectedCredentialType) + credentialType: getCredentialType(context.selectedCredentialType), }); }; @@ -150,10 +154,7 @@ const getMosipIndividualId = ( ? verifiableCredential.credential : verifiableCredential; const credentialSubject = credential?.credentialSubject; - if (isMosipVC(issuer)) { - return credentialSubject ? getMosipIdentifier(credentialSubject) : ''; - } - return ''; + return credentialSubject ? getMosipIdentifier(credentialSubject) : ''; } catch (error) { console.error('Error getting the display ID:', error); return null; diff --git a/shared/commonUtil.ts b/shared/commonUtil.ts index b4af6775..ef5fb6be 100644 --- a/shared/commonUtil.ts +++ b/shared/commonUtil.ts @@ -63,6 +63,10 @@ export const removeWhiteSpace = (str: string) => { return str ? str.replace(/\s/g, '') : str; }; +export const addPngBase64Prefix = (faceImage: string) => { + return faceImage ? 'data:image/png;base64,' + faceImage : faceImage; +}; + export function logState(state: AnyState) { if (__DEV__) { const data = JSON.stringify( diff --git a/shared/constants.ts b/shared/constants.ts index 6cbcbf3f..09d937a3 100644 --- a/shared/constants.ts +++ b/shared/constants.ts @@ -70,7 +70,7 @@ export const API_CACHED_STORAGE_KEYS = { fetchIssuerWellknownConfig: (issuerId: string) => `CACHE_FETCH_ISSUER_WELLKNOWN_CONFIG_${issuerId}`, fetchIssuerAuthorizationServerMetadata: (authorizationServerUrl: string) => - `CACHE_FETCH_ISSUER_AUTHORIZATION_SERVER_METADATA_${authorizationServerUrl}`, + `CACHE_FETCH_ISSUER_AUTHORIZATION_SERVER_METADATA_${authorizationServerUrl}`, fetchTrustedVerifiers: 'CACHE_FETCH_TRUSTED_VERIFIERS', }; @@ -170,3 +170,5 @@ export const FACE_SDK_MODEL_CHECKSUM = export const EXPIRED_VC_ERROR_CODE = 'ERR_VC_EXPIRED'; export const BASE_36 = 36; + +export const DEFAULT_OTP = '111111';