From ca8f5360e0855bc8a22791561e849df36759c828 Mon Sep 17 00:00:00 2001 From: Alka Prasad Date: Tue, 17 Dec 2024 23:09:36 +0530 Subject: [PATCH 1/5] [INJIMOB-2571]: refactor backed up data restoration method Signed-off-by: Alka Prasad --- machines/store.ts | 27 ++- shared/storage.ts | 443 +++++++++++++++++++++++++++------------------- 2 files changed, 272 insertions(+), 198 deletions(-) diff --git a/machines/store.ts b/machines/store.ts index 2b67f53332..40032f6151 100644 --- a/machines/store.ts +++ b/machines/store.ts @@ -276,16 +276,17 @@ export const storeMachine = BIOMETRIC_CANCELLED: { actions: [ send( - (_, event) => model.events.BIOMETRIC_CANCELLED(event.requester), + (_, event) => + model.events.BIOMETRIC_CANCELLED(event.requester), { to: (_, event) => event.requester, }, ), sendUpdate(), - sendParent('BIOMETRIC_CANCELLED') + sendParent('BIOMETRIC_CANCELLED'), ], target: 'checkFreshInstall', - } + }, }, }, }, @@ -303,10 +304,10 @@ export const storeMachine = }, BIOMETRIC_CANCELLED: { actions: [sendParent('BIOMETRIC_CANCELLED')], - target: 'checkFreshInstall' + target: 'checkFreshInstall', + }, }, }, - }, { actions: { notifyParent: sendParent(model.events.READY()), @@ -334,11 +335,10 @@ export const storeMachine = return; }, checkFreshInstall: () => async callback => { - try{ - return await getItem('auth', null, ''); - } - catch(e){ - if(e instanceof BiometricCancellationError){ + try { + return await getItem('auth', null, ''); + } catch (e) { + if (e instanceof BiometricCancellationError) { callback(model.events.BIOMETRIC_CANCELLED()); } else { callback(model.events.STORE_ERROR(e)); @@ -363,7 +363,7 @@ export const storeMachine = base64EncodedString, ); } catch (e) { - if(e instanceof BiometricCancellationError){ + if (e instanceof BiometricCancellationError) { callback(model.events.BIOMETRIC_CANCELLED(event.requester)); } sendErrorEvent(getErrorEventData('ENCRYPTION', '', e)); @@ -431,10 +431,7 @@ export const storeMachine = } case 'RESTORE_BACKUP': { // the backup data is in plain text - response = await loadBackupData( - event.data, - context.encryptionKey, - ); + await loadBackupData(event.data, context.encryptionKey); break; } case 'SET': { diff --git a/shared/storage.ts b/shared/storage.ts index 120268db88..f914ad0493 100644 --- a/shared/storage.ts +++ b/shared/storage.ts @@ -20,7 +20,6 @@ import { SETTINGS_STORE_KEY, ENOENT, API_CACHED_STORAGE_KEYS, - BASE_36, } from './constants'; import FileStorage, { getFilePath, @@ -58,6 +57,7 @@ class Storage { let dataFromDB: Record = {}; const allKeysInDB = await MMKV.indexer.strings.getKeys(); + const keysToBeExported = allKeysInDB.filter(key => key.includes('CACHE_FETCH_ISSUER_WELLKNOWN_CONFIG_'), ); @@ -116,47 +116,276 @@ class Storage { } }; - static loadBackupData = async (data, encryptionKey) => { + /** + * Load backup data with improved error handling and logging + * @param data Backup data to be loaded + * @param encryptionKey Key used for encryption/decryption + * @returns Promise resolving to loaded data or error + */ + static async loadBackupData( + data: string, + encryptionKey: string, + ): Promise { + const PREV_BACKUP_STATE_PATH = `${DocumentDirectoryPath}/.prev`; try { - // 0. check for previous backup states - const prevBkpState = `${DocumentDirectoryPath}/.prev`; - const previousBackupExists = await fileStorage.exists(prevBkpState); - let previousRestoreTimestamp: string = ''; - if (previousBackupExists) { - // 0. Remove partial restored files - previousRestoreTimestamp = await fileStorage.readFile(prevBkpState); - previousRestoreTimestamp = previousRestoreTimestamp.trim(); - this.unloadVCs(encryptionKey, parseInt(previousRestoreTimestamp)); - } - // 1. opening the file + await this.handlePreviousBackup(PREV_BACKUP_STATE_PATH, encryptionKey); const completeBackupData = JSON.parse(data); - // 2. Load and store VC_records & MMKV things const backupStartState = Date.now().toString(); - // record the state to help with cleanup activities post partial backup - await fileStorage.writeFile(prevBkpState, backupStartState); - const dataFromDB = await Storage.loadVCs( - completeBackupData, - encryptionKey, + await fileStorage.writeFile(PREV_BACKUP_STATE_PATH, backupStartState); + const dataFromDB = await this.loadVCs(completeBackupData, encryptionKey); + await this.updateWellKnownConfigs(dataFromDB, encryptionKey); + } catch (error) { + console.error('Error while loading backup data:', error); + } + } + + /** + * Handle cleanup of previous backup state + * @param prevBackupStatePath Path to previous backup state file + * @param encryptionKey Encryption key + * @returns Previous restore timestamp + */ + private static async handlePreviousBackup( + prevBackupStatePath: string, + encryptionKey: string, + ) { + const previousBackupExists = await fileStorage.exists(prevBackupStatePath); + if (previousBackupExists) { + const previousRestoreTimestamp = await fileStorage.readFile( + prevBackupStatePath, ); - // 3. Update the Well Known configs of the VCs - const allKeysFromDB = Object.keys(dataFromDB); - const cacheKeys = allKeysFromDB.filter(key => - key.includes('CACHE_FETCH_ISSUER_WELLKNOWN_CONFIG_'), + const timestampNum = parseInt(previousRestoreTimestamp.trim()); + await this.unloadVCs(encryptionKey, timestampNum); + } + } + + /** + * Unload Verifiable Credentials based on a cutoff timestamp + * @param encryptionKey Encryption key + * @param cutOffTimestamp Timestamp to use as cutoff + */ + private static async unloadVCs( + encryptionKey: string, + cutOffTimestamp: number, + ) { + try { + await this.removeOldVCFiles(cutOffTimestamp); + await this.removeVCMetadataFromDB(encryptionKey, cutOffTimestamp); + } catch (error) { + console.error('Error while unloading VCs:', error); + sendErrorEvent( + getErrorEventData( + TelemetryConstants.FlowType.dataRestore, + TelemetryConstants.ErrorId.failure, + error.message, + ), + ); + } + } + + /** + * Remove VC files created after the cutoff timestamp + * @param cutOffTimestamp Timestamp to use as cutoff + */ + private static async removeOldVCFiles(cutOffTimestamp: number) { + const vcDirectory = `${DocumentDirectoryPath}/inji/VC/`; + const files = await fileStorage.getAllFilesInDirectory(vcDirectory); + + const filesToRemove = files.filter(file => { + const fileName = file.name.split('.')[0]; + const fileTimestamp = parseInt(fileName.split('_')[1]); + return fileTimestamp >= cutOffTimestamp; + }); + + await Promise.all( + filesToRemove.map(file => fileStorage.removeItem(file.path)), + ); + } + + /** + * Update MMKV store to remove VCs after cutoff timestamp + * @param encryptionKey Encryption key + * @param cutOffTimestamp Timestamp to use as cutoff + */ + private static async removeVCMetadataFromDB( + encryptionKey: any, + cutOffTimestamp: number, + ) { + const myVCsEnc = await MMKV.getItem(MY_VCS_STORE_KEY, encryptionKey); + + if (myVCsEnc === null) return; + + const mmkvVCs = await decryptJson(encryptionKey, myVCsEnc); + const vcList: VCMetadata[] = JSON.parse(mmkvVCs); + const newVCList = vcList.filter( + vc => !vc.timestamp || parseInt(vc.timestamp) < cutOffTimestamp, + ); + const finalVC = await encryptJson(encryptionKey, JSON.stringify(newVCList)); + await MMKV.setItem(MY_VCS_STORE_KEY, finalVC); + } + + /** + * Handle cleanup of previous backup state + * @param completeBackupData Entire Backup data to be loaded + * @param encryptionKey Encryption key + * @returns Previous + */ + private static async loadVCs( + completeBackupData: Record, + encryptionKey: string, + ): Promise | undefined> { + try { + const {VC_Records: allVCs, dataFromDB: dataFromDB} = completeBackupData; + + await this.processAndStoreVCs(allVCs, dataFromDB, encryptionKey); + await this.updateMyVcList(dataFromDB, encryptionKey); + await fileStorage.removeItemIfExist(`${DocumentDirectoryPath}/.prev`); + return dataFromDB; + } catch (error) { + console.error('Error while loading VCs:', error); + sendErrorEvent( + getErrorEventData( + TelemetryConstants.FlowType.dataBackup, + TelemetryConstants.ErrorId.failure, + error.message, + ), + ); + } + } + + /** + * Process and store individual Verifiable Credentials + * @param allVCs All Verifiable Credentials from backup + * @param dataFromDB Database data containing VC metadata + * @param encryptionKey Encryption key + */ + private static async processAndStoreVCs( + allVCs: Record, + dataFromDB: Record, + encryptionKey: string, + ) { + const vcKeys = Object.keys(allVCs); + + await Promise.all( + vcKeys.map(async key => { + const vcData = allVCs[key]; + // Add randomness to timestamp to maintain uniqueness + const timestamp = + Date.now() + Math.random().toString().substring(2, 10); + const prevUnixTimeStamp = vcData.vcMetadata.timestamp; + + // Verify and update the credential + const isVerified = await this.verifyCredential( + vcData, + vcData.vcMetadata, + ); + vcData.vcMetadata.timestamp = timestamp; + vcData.vcMetadata.isVerified = isVerified; + + //update the vcMetadata + dataFromDB.myVCs.forEach(myVcMetadata => { + if ( + myVcMetadata.requestId === vcData.vcMetadata.requestId && + myVcMetadata.timestamp === prevUnixTimeStamp + ) { + myVcMetadata.timestamp = timestamp; + myVcMetadata.isVerified = isVerified; + } + }); + + // Encrypt and store the VC + const updatedVcKey = new VCMetadata(vcData.vcMetadata).getVcKey(); + const encryptedVC = await encryptJson( + encryptionKey, + JSON.stringify(vcData), + ); + await this.setItem(updatedVcKey, encryptedVC, encryptionKey); + }), + ); + } + + /** + * Verify the restored credential + * @param vcData Verifiable Credential from backup + * @param vcMetadata VC metadata + */ + private static async verifyCredential(vcData: any, vcMetadata: any) { + let isVerified = true; + const verifiableCredential = + vcData.verifiableCredential?.credential || vcData.verifiableCredential; + if ( + vcMetadata.format === VCFormat.mso_mdoc || + !isMockVC(vcMetadata.issuer) + ) { + const verificationResult = await verifyCredential( + verifiableCredential, + vcMetadata.format, ); - cacheKeys.forEach(async key => { + isVerified = verificationResult.isVerified; + } + return isVerified; + } + + /** + * Update MMKV store with new VC metadata + * @param dataFromDB Database data containing VC metadata + * @param encryptionKey Encryption key + */ + private static async updateMyVcList( + dataFromDB: Record, + encryptionKey: string, + ) { + const dataFromMyVCKey = dataFromDB[MY_VCS_STORE_KEY]; + const encryptedMyVCKeyFromMMKV = await MMKV.getItem(MY_VCS_STORE_KEY); + + let newDataForMyVCKey: VCMetadata[]; + + if (encryptedMyVCKeyFromMMKV != null) { + const myVCKeyFromMMKV = await decryptJson( + encryptionKey, + encryptedMyVCKeyFromMMKV, + ); + + newDataForMyVCKey = [...JSON.parse(myVCKeyFromMMKV), ...dataFromMyVCKey]; + } else { + newDataForMyVCKey = dataFromMyVCKey; + } + const encryptedDataForMyVCKey = await encryptJson( + encryptionKey, + JSON.stringify(newDataForMyVCKey), + ); + + await this.setItem( + MY_VCS_STORE_KEY, + encryptedDataForMyVCKey, + encryptionKey, + ); + } + + /** + * Update Well Known configs for cached issuers + * @param dataFromDB Database data + * @param encryptionKey Encryption key + */ + private static async updateWellKnownConfigs( + dataFromDB: Record, + encryptionKey: string, + ) { + const cacheKeys = Object.keys(dataFromDB).filter(key => + key.includes('CACHE_FETCH_ISSUER_WELLKNOWN_CONFIG_'), + ); + + await Promise.all( + cacheKeys.map(async key => { const value = dataFromDB[key]; const encryptedValue = await encryptJson( encryptionKey, JSON.stringify(value), ); await this.setItem(key, encryptedValue, encryptionKey); - return true; - }); - } catch (error) { - console.error('Error while loading backup data ', error); - return error; - } - }; + }), + ); + } static fetchAllWellknownConfig = async (encryptionKey: string) => { let wellknownConfigData: Record = {}; @@ -265,158 +494,6 @@ class Storage { } }; - /** - * unloadVCs will remove a set of VCs against a particular time range - * - * @param cutOffTimestamp the timestamp of the VC backup start time to current time - */ - private static async unloadVCs(encryptionKey: any, cutOffTimestamp: number) { - try { - // 1. Find the VCs in the inji directory which have the said timestamp - const file: ReadDirItem[] = await fileStorage.getAllFilesInDirectory( - `${DocumentDirectoryPath}/inji/VC/`, - ); - const isGreaterThanEq = function (fName: string, ts: number): boolean { - fName = fName.split('.')[0]; - const curr = fName.split('_')[1]; - return parseInt(curr) >= ts; - }; - for (let i = 0; i < file.length; i++) { - const f = file[i]; - if (isGreaterThanEq(f.name, cutOffTimestamp)) { - await fileStorage.removeItem(f.path); - } - } - // TODO: should this be done via the Store state machine to avoid popups? - // 3. Remove the keys from MMKV which have the same timestamp - let myVCsEnc = await MMKV.getItem(MY_VCS_STORE_KEY, encryptionKey); - if (myVCsEnc !== null) { - let mmkvVCs = await decryptJson(encryptionKey, myVCsEnc); - let vcList: VCMetadata[] = JSON.parse(mmkvVCs); - let newVCList: VCMetadata[] = []; - vcList.forEach(d => { - if (d.timestamp && parseInt(d.timestamp) < cutOffTimestamp) { - newVCList.push(d); - } - }); - const finalVC = await encryptJson( - encryptionKey, - JSON.stringify(newVCList), - ); - await MMKV.setItem(MY_VCS_STORE_KEY, finalVC); - } - } catch (e) { - console.error('error while unloadVcs:', e); - sendErrorEvent( - getErrorEventData( - TelemetryConstants.FlowType.dataRestore, - TelemetryConstants.ErrorId.failure, - e.message, - ), - ); - } - } - - private static async verifyCredential( - verifiableCredential: Credential, - format: string, - issuer: string, - ) { - let isVerified = true; - //TODO: Remove bypassing verification of mock VCs once mock VCs are verifiable - if (format === VCFormat.mso_mdoc || !isMockVC(issuer)) { - const verificationResult = await verifyCredential( - verifiableCredential, - format, - ); - isVerified = verificationResult.isVerified; - } - return isVerified; - } - - private static async loadVCs(completeBackupData: {}, encryptionKey: any) { - try { - const allVCs = completeBackupData['VC_Records']; - const allVCKeys = Object.keys(allVCs); - const dataFromDB = completeBackupData['dataFromDB']; - - // 0. Check for VC presense in the store - // 1. store the VCs and the HMAC - // 2. Verify the VC and update the result - - await Promise.all( - allVCKeys.map(async key => { - const vc = allVCs[key]; - const ts = - Date.now() + Math.random().toString(BASE_36).substring(2, 7); - const prevUnixTimeStamp = vc.vcMetadata.timestamp; - - const isVerified = await Storage.verifyCredential( - vc.verifiableCredential?.credential || vc.verifiableCredential, - vc.vcMetadata.format, - vc.vcMetadata.issuer, - ); - vc.vcMetadata.timestamp = ts; - vc.vcMetadata.isVerified = isVerified; - - dataFromDB.myVCs.map(async myVcMetadata => { - if ( - myVcMetadata.requestId === vc.vcMetadata.requestId && - myVcMetadata.timestamp === prevUnixTimeStamp - ) { - myVcMetadata.timestamp = ts; - } - myVcMetadata.isVerified = isVerified; - }); - const updatedVcKey = new VCMetadata(vc.vcMetadata).getVcKey(); - - const encryptedVC = await encryptJson( - encryptionKey, - JSON.stringify(vc), - ); - // Save the VC to disk - await this.setItem(updatedVcKey, encryptedVC, encryptionKey); - }), - ); - // 2. Update myVCsKey - const dataFromMyVCKey = dataFromDB[MY_VCS_STORE_KEY]; - const encryptedMyVCKeyFromMMKV = await MMKV.getItem(MY_VCS_STORE_KEY); - let newDataForMyVCKey: VCMetadata[] = []; - if (encryptedMyVCKeyFromMMKV != null) { - const myVCKeyFromMMKV = await decryptJson( - encryptionKey, - encryptedMyVCKeyFromMMKV, - ); - newDataForMyVCKey = [ - ...JSON.parse(myVCKeyFromMMKV), - ...dataFromMyVCKey, - ]; - } else { - newDataForMyVCKey = dataFromMyVCKey; - } - const encryptedDataForMyVCKey = await encryptJson( - encryptionKey, - JSON.stringify(newDataForMyVCKey), - ); - await this.setItem( - MY_VCS_STORE_KEY, - encryptedDataForMyVCKey, - encryptionKey, - ); - await fileStorage.removeItemIfExist(`${DocumentDirectoryPath}/.prev`); - return dataFromDB; - } catch (e) { - console.error('error while loading Vcs:', e); - sendErrorEvent( - getErrorEventData( - TelemetryConstants.FlowType.dataBackup, - TelemetryConstants.ErrorId.failure, - e.message, - ), - ); - } - } - private static async isVCAlreadyDownloaded( key: string, encryptionKey: string, From 7aeec523d654368ce56738749e84f217828a0a96 Mon Sep 17 00:00:00 2001 From: Alka Prasad Date: Wed, 18 Dec 2024 04:57:28 +0530 Subject: [PATCH 2/5] [INJIMOB-2571]: refactor the storage class to make it more readable and for seperation of concerns Signed-off-by: Alka Prasad --- machines/backupAndRestore/backupRestore.ts | 4 +- machines/bleShare/request/requestMachine.ts | 6 +- machines/bleShare/scan/scanServices.ts | 6 +- machines/store.ts | 16 +- machines/store.typegen.ts | 142 +++--- screens/Home/HomeScreenMachine.ts | 4 +- shared/backupUtils/backupData.ts | 158 +++++++ shared/backupUtils/restoreData.ts | 275 +++++++++++ shared/fileStorage.ts | 9 + shared/storage.ts | 482 +++----------------- 10 files changed, 577 insertions(+), 525 deletions(-) create mode 100644 shared/backupUtils/backupData.ts create mode 100644 shared/backupUtils/restoreData.ts diff --git a/machines/backupAndRestore/backupRestore.ts b/machines/backupAndRestore/backupRestore.ts index c9cebe6865..e26e49efed 100644 --- a/machines/backupAndRestore/backupRestore.ts +++ b/machines/backupAndRestore/backupRestore.ts @@ -6,7 +6,7 @@ import fileStorage, { getBackupFilePath, unZipAndRemoveFile, } from '../../shared/fileStorage'; -import Storage from '../../shared/storage'; +import Storage, { isMinimumLimitReached } from '../../shared/storage'; import {StoreEvents} from '../store'; import Cloud from '../../shared/CloudBackupAndRestoreUtils'; import {TelemetryConstants} from '../../shared/telemetry/TelemetryConstants'; @@ -289,7 +289,7 @@ export const backupRestoreMachine = model.createMachine( checkInternet: async () => await NetInfo.fetch(), checkStorageAvailability: () => async () => { - return await Storage.isMinimumLimitReached('minStorageRequired'); + return await isMinimumLimitReached('minStorageRequired'); }, downloadLatestBackup: () => async () => { diff --git a/machines/bleShare/request/requestMachine.ts b/machines/bleShare/request/requestMachine.ts index 90eb99eaaf..6190a85afa 100644 --- a/machines/bleShare/request/requestMachine.ts +++ b/machines/bleShare/request/requestMachine.ts @@ -23,7 +23,7 @@ import {VcMetaEvents} from '../../VerifiableCredential/VCMetaMachine/VCMetaMachi import {subscribe} from '../../../shared/openIdBLE/verifierEventHandler'; import {VerifierDataEvent} from '../../../shared/tuvali/types/events'; import {BLEError} from '../types'; -import Storage from '../../../shared/storage'; +import Storage, { isMinimumLimitReached } from '../../../shared/storage'; import {VCMetadata} from '../../../shared/VCMetadata'; import { getEndEventData, @@ -885,9 +885,7 @@ export const requestMachine = }, checkStorageAvailability: () => async () => { - return Promise.resolve( - Storage.isMinimumLimitReached('minStorageRequired'), - ); + return Promise.resolve(isMinimumLimitReached('minStorageRequired')); }, }, diff --git a/machines/bleShare/scan/scanServices.ts b/machines/bleShare/scan/scanServices.ts index ba0bb3856f..86712f14a4 100644 --- a/machines/bleShare/scan/scanServices.ts +++ b/machines/bleShare/scan/scanServices.ts @@ -1,5 +1,5 @@ import {isLocationEnabled} from 'react-native-device-info'; -import Storage from '../../../shared/storage'; +import Storage, { isMinimumLimitReached } from '../../../shared/storage'; import BluetoothStateManager from 'react-native-bluetooth-state-manager'; import { check, @@ -188,9 +188,7 @@ export const ScanServices = (model: any) => { }, checkStorageAvailability: () => async () => { - return Promise.resolve( - Storage.isMinimumLimitReached('minStorageRequiredForAuditEntry'), - ); + return Promise.resolve(isMinimumLimitReached('minStorageRequiredForAuditEntry')); }, }; }; diff --git a/machines/store.ts b/machines/store.ts index 40032f6151..f10c69243a 100644 --- a/machines/store.ts +++ b/machines/store.ts @@ -1,5 +1,4 @@ import Storage, {MMKV} from '../shared/storage'; -import binaryToBase64 from 'react-native/Libraries/Utilities/binaryToBase64'; import { EventFrom, Receiver, @@ -36,6 +35,7 @@ import { } from '../shared/telemetry/TelemetryUtils'; import {Buffer} from 'buffer'; import {VC} from './VerifiableCredential/VCMetaMachine/vc'; +import { isVCStorageInitialised } from '../shared/fileStorage'; export const keyinvalidatedString = 'Key Invalidated due to biometric enrollment'; @@ -394,7 +394,7 @@ export const storeMachine = }, checkStorageInitialisedOrNot: () => async callback => { - const isDirectoryExist = await Storage.isVCStorageInitialised(); + const isDirectoryExist = await isVCStorageInitialised(); if (!isDirectoryExist) { callback(model.events.READY()); } else { @@ -422,7 +422,7 @@ export const storeMachine = break; } case 'EXPORT': { - response = await exportData(context.encryptionKey); + response = await backupAndExportData(context.encryptionKey); break; } case 'GET_VCS_DATA': { @@ -431,7 +431,7 @@ export const storeMachine = } case 'RESTORE_BACKUP': { // the backup data is in plain text - await loadBackupData(event.data, context.encryptionKey); + await restoreBackedUpData(event.data, context.encryptionKey); break; } case 'SET': { @@ -619,12 +619,12 @@ export async function setItem( } } -export async function exportData(encryptionKey: string) { - return Storage.exportData(encryptionKey); +export async function backupAndExportData(encryptionKey: string) { + return Storage.backupData(encryptionKey); } -export async function loadBackupData(data, encryptionKey) { - await Storage.loadBackupData(data, encryptionKey); +export async function restoreBackedUpData(data, encryptionKey) { + await Storage.restoreBackedUpData(data, encryptionKey); } export async function fetchAllWellknownConfig(encryptionKey: string) { diff --git a/machines/store.typegen.ts b/machines/store.typegen.ts index 1b326c7dea..6d6f0df048 100644 --- a/machines/store.typegen.ts +++ b/machines/store.typegen.ts @@ -1,90 +1,54 @@ -// 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.checkFreshInstall:invocation[0]': { - type: 'done.invoke.store.checkFreshInstall:invocation[0]'; - 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: { - checkFreshInstall: 'done.invoke.store.checkFreshInstall:invocation[0]'; - checkStorageInitialisedOrNot: 'done.invoke.store.checkStorageInitialisation:invocation[0]'; - clear: 'done.invoke.store.resettingStorage:invocation[0]'; - clearKeys: 'done.invoke.store.clearIosKeys:invocation[0]'; - generateEncryptionKey: 'done.invoke.store.generatingEncryptionKey:invocation[0]'; - getEncryptionKey: 'done.invoke.store.gettingEncryptionKey:invocation[0]'; - hasEncryptionKey: 'done.invoke.store.checkEncryptionKey:invocation[0]'; - store: 'done.invoke._store'; - }; - missingImplementations: { - actions: never; - delays: never; - guards: never; - services: never; - }; - eventsCausingActions: { - forwardStoreRequest: - | 'APPEND' - | 'CLEAR' - | 'EXPORT' - | 'FETCH_ALL_WELLKNOWN_CONFIG' - | 'GET' - | 'GET_VCS_DATA' - | 'PREPEND' - | 'REMOVE' - | 'REMOVE_ITEMS' - | 'REMOVE_VC_METADATA' - | 'RESTORE_BACKUP' - | 'SET' - | 'UPDATE'; - notifyParent: - | 'KEY_RECEIVED' - | 'READY' - | 'done.invoke.store.resettingStorage:invocation[0]'; - setEncryptionKey: 'KEY_RECEIVED'; - }; - eventsCausingDelays: {}; - eventsCausingGuards: { - hasData: 'done.invoke.store.checkFreshInstall:invocation[0]'; - isCustomSecureKeystore: 'KEY_RECEIVED'; - }; - eventsCausingServices: { - checkFreshInstall: 'xstate.init'; - checkStorageInitialisedOrNot: 'ERROR'; - clear: 'KEY_RECEIVED'; - clearKeys: 'done.invoke.store.checkFreshInstall:invocation[0]'; - generateEncryptionKey: 'ERROR' | 'IGNORE' | 'READY'; - getEncryptionKey: 'TRY_AGAIN'; - hasEncryptionKey: never; - store: - | 'KEY_RECEIVED' - | 'READY' - | 'done.invoke.store.resettingStorage:invocation[0]'; - }; - matchesStates: - | 'checkEncryptionKey' - | 'checkFreshInstall' - | 'checkStorageInitialisation' - | 'clearIosKeys' - | 'failedReadingKey' - | 'generatingEncryptionKey' - | 'gettingEncryptionKey' - | 'ready' - | 'resettingStorage'; - tags: never; -} + // 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.checkFreshInstall:invocation[0]": { type: "done.invoke.store.checkFreshInstall:invocation[0]"; 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: { + "checkFreshInstall": "done.invoke.store.checkFreshInstall:invocation[0]"; +"checkStorageInitialisedOrNot": "done.invoke.store.checkStorageInitialisation:invocation[0]"; +"clear": "done.invoke.store.resettingStorage:invocation[0]"; +"clearKeys": "done.invoke.store.clearIosKeys:invocation[0]"; +"generateEncryptionKey": "done.invoke.store.generatingEncryptionKey:invocation[0]"; +"getEncryptionKey": "done.invoke.store.gettingEncryptionKey:invocation[0]"; +"hasEncryptionKey": "done.invoke.store.checkEncryptionKey:invocation[0]"; +"store": "done.invoke._store"; + }; + missingImplementations: { + actions: never; + delays: never; + guards: never; + services: never; + }; + eventsCausingActions: { + "forwardStoreRequest": "APPEND" | "CLEAR" | "EXPORT" | "FETCH_ALL_WELLKNOWN_CONFIG" | "GET" | "GET_VCS_DATA" | "PREPEND" | "REMOVE" | "REMOVE_ITEMS" | "REMOVE_VC_METADATA" | "RESTORE_BACKUP" | "SET" | "UPDATE"; +"notifyParent": "KEY_RECEIVED" | "READY" | "done.invoke.store.resettingStorage:invocation[0]"; +"setEncryptionKey": "KEY_RECEIVED"; + }; + eventsCausingDelays: { + + }; + eventsCausingGuards: { + "hasData": "done.invoke.store.checkFreshInstall:invocation[0]"; +"isCustomSecureKeystore": "KEY_RECEIVED"; + }; + eventsCausingServices: { + "checkFreshInstall": "BIOMETRIC_CANCELLED" | "xstate.init"; +"checkStorageInitialisedOrNot": "ERROR"; +"clear": "KEY_RECEIVED"; +"clearKeys": "done.invoke.store.checkFreshInstall:invocation[0]"; +"generateEncryptionKey": "ERROR" | "IGNORE" | "READY"; +"getEncryptionKey": "TRY_AGAIN"; +"hasEncryptionKey": never; +"store": "KEY_RECEIVED" | "READY" | "done.invoke.store.resettingStorage:invocation[0]"; + }; + matchesStates: "checkEncryptionKey" | "checkFreshInstall" | "checkStorageInitialisation" | "clearIosKeys" | "failedReadingKey" | "generatingEncryptionKey" | "gettingEncryptionKey" | "ready" | "resettingStorage"; + tags: never; + } + \ No newline at end of file diff --git a/screens/Home/HomeScreenMachine.ts b/screens/Home/HomeScreenMachine.ts index bc53600fee..2f050b19d4 100644 --- a/screens/Home/HomeScreenMachine.ts +++ b/screens/Home/HomeScreenMachine.ts @@ -7,7 +7,7 @@ import { ReceivedVcsTabMachine, } from './ReceivedVcsTabMachine'; import {IssuersMachine} from '../../machines/Issuers/IssuersMachine'; -import Storage from '../../shared/storage'; +import Storage, { isMinimumLimitReached } from '../../shared/storage'; import {VCItemMachine} from '../../machines/VerifiableCredential/VCItemMachine/VCItemMachine'; const model = createModel( @@ -173,7 +173,7 @@ export const HomeScreenMachine = model.createMachine( services: { checkStorageAvailability: () => async () => { return Promise.resolve( - Storage.isMinimumLimitReached('minStorageRequired'), + isMinimumLimitReached('minStorageRequired'), ); }, }, diff --git a/shared/backupUtils/backupData.ts b/shared/backupUtils/backupData.ts new file mode 100644 index 0000000000..7d8d2406ad --- /dev/null +++ b/shared/backupUtils/backupData.ts @@ -0,0 +1,158 @@ +import { MY_VCS_STORE_KEY } from "../constants"; +import { decryptJson } from "../cryptoutil/cryptoUtil"; +import Storage, { MMKV } from "../storage"; +import { TelemetryConstants } from "../telemetry/TelemetryConstants"; +import { getErrorEventData, sendErrorEvent } from "../telemetry/TelemetryUtils"; +import { VCMetadata } from "../VCMetadata"; + + + +/** + * Main method to export data with clear, separated concerns + */ +export async function exportData(encryptionKey: string): Promise> { + try { + const allKeysInDB = await getAllDatabaseKeys(); + const dataFromDB = await extractConfigAndStoreData(allKeysInDB, encryptionKey); + const vcRecords = await extractVerifiableCredentials(allKeysInDB, encryptionKey, dataFromDB); + return { + VC_Records: vcRecords, + dataFromDB + }; + } catch (error) { + sendErrorEvent( + getErrorEventData( + TelemetryConstants.FlowType.dataBackup, + error.message, + error.stack, + ), + ); + console.error('exporting data is failed due to this error:', error); + throw error; + } +} + +/** + * Retrieve all keys from the database + */ +async function getAllDatabaseKeys(): Promise { + return await MMKV.indexer.strings.getKeys(); +} + +/** + * Extract configuration and store data + */ +async function extractConfigAndStoreData( + allKeysInDB: string[], + encryptionKey: string +): Promise> { + const keysToBeExported = [ + ...allKeysInDB.filter(key => key.includes('CACHE_FETCH_ISSUER_WELLKNOWN_CONFIG_')), + MY_VCS_STORE_KEY + ]; + + const dataFromDB: Record = await fetchAndDecryptData( + keysToBeExported, + encryptionKey + ); + + return processVCMetadata(dataFromDB); +} + +/** + * Fetch and decrypt data for given keys + */ +async function fetchAndDecryptData( + keys: string[], + encryptionKey: string +): Promise> { + const dataFromDB: Record = {}; + + // Fetch encrypted data concurrently + const encryptedDataList = await Promise.all( + keys.map(key => MMKV.getItem(key)) + ); + + // Decrypt each item + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + const encryptedData = encryptedDataList[i]; + + if (encryptedData) { + const decryptedData = await decryptJson(encryptionKey, encryptedData); + dataFromDB[key] = JSON.parse(decryptedData); + } + } + return dataFromDB; +} + +/** + * Process and modify VC metadata + */ +function processVCMetadata( + dataFromDB: Record +): Record { + if (dataFromDB[MY_VCS_STORE_KEY]) { + dataFromDB[MY_VCS_STORE_KEY] = dataFromDB[MY_VCS_STORE_KEY].map( + myVcMetadata => ({ ...myVcMetadata, isPinned: false }) + ); + } + return dataFromDB; +} + +/** + * Extract Verifiable Credentials + */ +async function extractVerifiableCredentials( + allKeysInDB: string[], + encryptionKey: string, + dataFromDB: Record +): Promise> { + const vcRecords: Record = {}; + const vcKeys = allKeysInDB.filter(key => key.startsWith('VC_')); + + // Process each VC key + for (const key of vcKeys) { + try { + const vc = await Storage.getItem(key, encryptionKey); + + if (vc) { + const decryptedVCData = await decryptJson(encryptionKey, vc); + const deactivatedVC = removeWalletBindingDataBeforeBackup(decryptedVCData); + vcRecords[key] = deactivatedVC; + } else { + removeNonExistentVCMetadata(dataFromDB, key); + } + } catch (error) { + throw error; + } + } + + return vcRecords; +} + +/** + * Remove metadata for non-existent VCs + */ +function removeNonExistentVCMetadata( + dataFromDB: Record, + key: string +) { + if (dataFromDB.myVCs) { + dataFromDB.myVCs = dataFromDB.myVCs.filter( + vcMetaData => + VCMetadata.fromVcMetadataString(vcMetaData).getVcKey() !== key + ); + } +} + +/** + * Remove wallet binding details from the VC + */ +function removeWalletBindingDataBeforeBackup(data: string) { + const vcData = JSON.parse(data); + vcData.walletBindingResponse = null; + vcData.publicKey = null; + vcData.privateKey = null; + return vcData; + } diff --git a/shared/backupUtils/restoreData.ts b/shared/backupUtils/restoreData.ts new file mode 100644 index 0000000000..71d4e7b6ca --- /dev/null +++ b/shared/backupUtils/restoreData.ts @@ -0,0 +1,275 @@ +import { DocumentDirectoryPath } from "react-native-fs"; +import fileStorage from "../fileStorage"; +import { getErrorEventData, sendErrorEvent } from "../telemetry/TelemetryUtils"; +import { TelemetryConstants } from "../telemetry/TelemetryConstants"; +import { decryptJson, encryptJson } from "../cryptoutil/cryptoUtil"; +import Storage, { MMKV } from "../storage"; +import { MY_VCS_STORE_KEY } from "../constants"; +import { VCMetadata } from "../VCMetadata"; +import { VCFormat } from "../VCFormat"; +import { isMockVC } from "../Utils"; + +export async function loadBackupData( + data: string, + encryptionKey: string, + ): Promise { + const PREV_BACKUP_STATE_PATH = `${DocumentDirectoryPath}/.prev`; + try { + await handlePreviousBackup(PREV_BACKUP_STATE_PATH, encryptionKey); + const completeBackupData = JSON.parse(data); + const backupStartState = Date.now().toString(); + await fileStorage.writeFile(PREV_BACKUP_STATE_PATH, backupStartState); + const dataFromDB = await loadVCs(completeBackupData, encryptionKey); + await updateWellKnownConfigs(dataFromDB, encryptionKey); + } catch (error) { + console.error('Error while loading backup data:', error); + } + } + +/** + * Handle cleanup of previous backup state + * @param prevBackupStatePath Path to previous backup state file + * @param encryptionKey Encryption key + * @returns Previous restore timestamp + */ +async function handlePreviousBackup( + prevBackupStatePath: string, + encryptionKey: string, + ) { + const previousBackupExists = await fileStorage.exists(prevBackupStatePath); + if (previousBackupExists) { + const previousRestoreTimestamp = await fileStorage.readFile( + prevBackupStatePath, + ); + const timestampNum = parseInt(previousRestoreTimestamp.trim()); + await unloadVCs(encryptionKey, timestampNum); + } + } + + /** + * Unload Verifiable Credentials based on a cutoff timestamp + * @param encryptionKey Encryption key + * @param cutOffTimestamp Timestamp to use as cutoff + */ + async function unloadVCs( + encryptionKey: string, + cutOffTimestamp: number, + ) { + try { + await removeOldVCFiles(cutOffTimestamp); + await removeVCMetadataFromDB(encryptionKey, cutOffTimestamp); + } catch (error) { + console.error('Error while unloading VCs:', error); + sendErrorEvent( + getErrorEventData( + TelemetryConstants.FlowType.dataRestore, + TelemetryConstants.ErrorId.failure, + error.message, + ), + ); + } + } + + /** + * Remove VC files created after the cutoff timestamp + * @param cutOffTimestamp Timestamp to use as cutoff + */ + async function removeOldVCFiles(cutOffTimestamp: number) { + const vcDirectory = `${DocumentDirectoryPath}/inji/VC/`; + const files = await fileStorage.getAllFilesInDirectory(vcDirectory); + + const filesToRemove = files.filter(file => { + const fileName = file.name.split('.')[0]; + const fileTimestamp = parseInt(fileName.split('_')[1]); + return fileTimestamp >= cutOffTimestamp; + }); + + await Promise.all( + filesToRemove.map(file => fileStorage.removeItem(file.path)), + ); + } + + /** + * Update MMKV store to remove VCs after cutoff timestamp + * @param encryptionKey Encryption key + * @param cutOffTimestamp Timestamp to use as cutoff + */ + async function removeVCMetadataFromDB( + encryptionKey: any, + cutOffTimestamp: number, + ) { + const myVCsEnc = await MMKV.getItem(MY_VCS_STORE_KEY, encryptionKey); + + if (myVCsEnc === null) return; + + const mmkvVCs = await decryptJson(encryptionKey, myVCsEnc); + const vcList: VCMetadata[] = JSON.parse(mmkvVCs); + const newVCList = vcList.filter( + vc => !vc.timestamp || parseInt(vc.timestamp) < cutOffTimestamp, + ); + const finalVC = await encryptJson(encryptionKey, JSON.stringify(newVCList)); + await MMKV.setItem(MY_VCS_STORE_KEY, finalVC); + } + + /** + * Handle cleanup of previous backup state + * @param completeBackupData Entire Backup data to be loaded + * @param encryptionKey Encryption key + * @returns Previous + */ + async function loadVCs( + completeBackupData: Record, + encryptionKey: string, + ): Promise | undefined> { + try { + const {VC_Records: allVCs, dataFromDB: dataFromDB} = completeBackupData; + + await processAndStoreVCs(allVCs, dataFromDB, encryptionKey); + await updateMyVcList(dataFromDB, encryptionKey); + await fileStorage.removeItemIfExist(`${DocumentDirectoryPath}/.prev`); + return dataFromDB; + } catch (error) { + console.error('Error while loading VCs:', error); + sendErrorEvent( + getErrorEventData( + TelemetryConstants.FlowType.dataBackup, + TelemetryConstants.ErrorId.failure, + error.message, + ), + ); + } + } + + /** + * Process and store individual Verifiable Credentials + * @param allVCs All Verifiable Credentials from backup + * @param dataFromDB Database data containing VC metadata + * @param encryptionKey Encryption key + */ + async function processAndStoreVCs( + allVCs: Record, + dataFromDB: Record, + encryptionKey: string, + ) { + const vcKeys = Object.keys(allVCs); + + await Promise.all( + vcKeys.map(async key => { + const vcData = allVCs[key]; + // Add randomness to timestamp to maintain uniqueness + const timestamp = + Date.now() + Math.random().toString().substring(2, 10); + const prevUnixTimeStamp = vcData.vcMetadata.timestamp; + + // Verify and update the credential + const isVerified = await verifyCredential( + vcData, + vcData.vcMetadata, + ); + vcData.vcMetadata.timestamp = timestamp; + vcData.vcMetadata.isVerified = isVerified; + + //update the vcMetadata + dataFromDB.myVCs.forEach(myVcMetadata => { + if ( + myVcMetadata.requestId === vcData.vcMetadata.requestId && + myVcMetadata.timestamp === prevUnixTimeStamp + ) { + myVcMetadata.timestamp = timestamp; + myVcMetadata.isVerified = isVerified; + } + }); + + // Encrypt and store the VC + const updatedVcKey = new VCMetadata(vcData.vcMetadata).getVcKey(); + const encryptedVC = await encryptJson( + encryptionKey, + JSON.stringify(vcData), + ); + await Storage.setItem(updatedVcKey, encryptedVC, encryptionKey); + }), + ); + } + + /** + * Verify the restored credential + * @param vcData Verifiable Credential from backup + * @param vcMetadata VC metadata + */ + async function verifyCredential(vcData: any, vcMetadata: any) { + let isVerified = true; + const verifiableCredential = + vcData.verifiableCredential?.credential || vcData.verifiableCredential; + if ( + vcMetadata.format === VCFormat.mso_mdoc || + !isMockVC(vcMetadata.issuer) + ) { + const verificationResult = await verifyCredential( + verifiableCredential, + vcMetadata.format, + ); + isVerified = verificationResult.isVerified; + } + return isVerified; + } + + /** + * Update MMKV store with new VC metadata + * @param dataFromDB Database data containing VC metadata + * @param encryptionKey Encryption key + */ + async function updateMyVcList( + dataFromDB: Record, + encryptionKey: string, + ) { + const dataFromMyVCKey = dataFromDB[MY_VCS_STORE_KEY]; + const encryptedMyVCKeyFromMMKV = await MMKV.getItem(MY_VCS_STORE_KEY); + + let newDataForMyVCKey: VCMetadata[]; + + if (encryptedMyVCKeyFromMMKV != null) { + const myVCKeyFromMMKV = await decryptJson( + encryptionKey, + encryptedMyVCKeyFromMMKV, + ); + + newDataForMyVCKey = [...JSON.parse(myVCKeyFromMMKV), ...dataFromMyVCKey]; + } else { + newDataForMyVCKey = dataFromMyVCKey; + } + const encryptedDataForMyVCKey = await encryptJson( + encryptionKey, + JSON.stringify(newDataForMyVCKey), + ); + + await Storage.setItem( + MY_VCS_STORE_KEY, + encryptedDataForMyVCKey, + encryptionKey, + ); + } + + /** + * Update Well Known configs for cached issuers + * @param dataFromDB Database data + * @param encryptionKey Encryption key + */ + async function updateWellKnownConfigs( + dataFromDB: Record, + encryptionKey: string, + ) { + const cacheKeys = Object.keys(dataFromDB).filter(key => + key.includes('CACHE_FETCH_ISSUER_WELLKNOWN_CONFIG_'), + ); + + await Promise.all( + cacheKeys.map(async key => { + const value = dataFromDB[key]; + const encryptedValue = await encryptJson( + encryptionKey, + JSON.stringify(value), + ); + await Storage.setItem(key, encryptedValue, encryptionKey); + }), + ); +} \ No newline at end of file diff --git a/shared/fileStorage.ts b/shared/fileStorage.ts index 7b57cf2f16..7a5798b18f 100644 --- a/shared/fileStorage.ts +++ b/shared/fileStorage.ts @@ -147,3 +147,12 @@ export async function writeToBackupFile(data: any): Promise { await writeFile(path, JSON.stringify(data)); return fileName; } + +export async function isVCStorageInitialised() : Promise { + try { + const res = await new FileStorage().getInfo(vcDirectoryPath); + return res.isDirectory(); + } catch (_) { + return false; + } +}; diff --git a/shared/storage.ts b/shared/storage.ts index f914ad0493..d9bb07d9cb 100644 --- a/shared/storage.ts +++ b/shared/storage.ts @@ -1,10 +1,20 @@ -import {MMKVLoader} from 'react-native-mmkv-storage'; -import getAllConfigurations from './api'; +import { NativeModules } from 'react-native'; import { getFreeDiskStorageOldSync, getFreeDiskStorageSync, } from 'react-native-device-info'; -import {NativeModules} from 'react-native'; +import { MMKVLoader } from 'react-native-mmkv-storage'; +import getAllConfigurations from './api'; +import { exportData as backupData } from './backupUtils/backupData'; +import { loadBackupData } from './backupUtils/restoreData'; +import { BYTES_IN_MEGABYTE } from './commonUtil'; +import { + androidVersion, + API_CACHED_STORAGE_KEYS, + ENOENT, + isAndroid, + SETTINGS_STORE_KEY +} from './constants'; import { decryptJson, encryptJson, @@ -12,30 +22,15 @@ import { hmacSHA, isHardwareKeystoreExists, } from './cryptoutil/cryptoUtil'; -import {VCMetadata} from './VCMetadata'; -import { - androidVersion, - isAndroid, - MY_VCS_STORE_KEY, - SETTINGS_STORE_KEY, - ENOENT, - API_CACHED_STORAGE_KEYS, -} from './constants'; import FileStorage, { - getFilePath, getDirectorySize, + getFilePath, vcDirectoryPath, } from './fileStorage'; -import {__AppId} from './GlobalVariables'; -import {getErrorEventData, sendErrorEvent} from './telemetry/TelemetryUtils'; -import {TelemetryConstants} from './telemetry/TelemetryConstants'; -import {BYTES_IN_MEGABYTE} from './commonUtil'; -import fileStorage from './fileStorage'; -import {DocumentDirectoryPath, ReadDirItem} from 'react-native-fs'; -import {verifyCredential} from './vcjs/verifyCredential'; -import {Credential} from '../machines/VerifiableCredential/VCMetaMachine/vc'; -import {VCFormat} from './VCFormat'; -import {isMockVC} from './Utils'; +import { __AppId } from './GlobalVariables'; +import { TelemetryConstants } from './telemetry/TelemetryConstants'; +import { getErrorEventData, sendErrorEvent } from './telemetry/TelemetryUtils'; +import { VCMetadata } from './VCMetadata'; export const MMKV = new MMKVLoader().initialize(); const {RNSecureKeystoreModule} = NativeModules; @@ -51,340 +46,13 @@ async function generateHmac( } class Storage { - static exportData = async (encryptionKey: string) => { - try { - const completeBackupData = {}; - let dataFromDB: Record = {}; - - const allKeysInDB = await MMKV.indexer.strings.getKeys(); - - const keysToBeExported = allKeysInDB.filter(key => - key.includes('CACHE_FETCH_ISSUER_WELLKNOWN_CONFIG_'), - ); - keysToBeExported?.push(MY_VCS_STORE_KEY); - - const encryptedDataPromises = keysToBeExported.map(key => - MMKV.getItem(key), - ); - const encryptedDataList = await Promise.all(encryptedDataPromises); - for (let index = 0; index < keysToBeExported.length; index++) { - const key = keysToBeExported[index]; - let encryptedData = encryptedDataList[index]; - if (encryptedData != null) { - const decryptedData = await decryptJson(encryptionKey, encryptedData); - dataFromDB[key] = JSON.parse(decryptedData); - } - } - - dataFromDB[MY_VCS_STORE_KEY].map(myVcMetadata => { - myVcMetadata.isPinned = false; - }); - - completeBackupData['VC_Records'] = {}; - - let vcKeys = allKeysInDB.filter(key => key.indexOf('VC_') === 0); - for (let ind in vcKeys) { - const key = vcKeys[ind]; - const vc = await this.getItem(key, encryptionKey); - - if (vc) { - const decryptedVCData = await decryptJson(encryptionKey, vc); - const deactivatedVC = - removeWalletBindingDataBeforeBackup(decryptedVCData); - completeBackupData['VC_Records'][key] = deactivatedVC; - } else { - dataFromDB.myVCs = dataFromDB.myVCs.filter(vcMetaData => { - return ( - VCMetadata.fromVcMetadataString(vcMetaData).getVcKey() !== key - ); - }); - } - } - completeBackupData['dataFromDB'] = dataFromDB; - return completeBackupData; - } catch (error) { - sendErrorEvent( - getErrorEventData( - TelemetryConstants.FlowType.dataBackup, - error.message, - error.stack, - ), - ); - console.error('exporting data is failed due to this error:', error); - throw error; - } + static backupData = async (encryptionKey: string) => { + return await backupData(encryptionKey) }; - - /** - * Load backup data with improved error handling and logging - * @param data Backup data to be loaded - * @param encryptionKey Key used for encryption/decryption - * @returns Promise resolving to loaded data or error - */ - static async loadBackupData( - data: string, - encryptionKey: string, - ): Promise { - const PREV_BACKUP_STATE_PATH = `${DocumentDirectoryPath}/.prev`; - try { - await this.handlePreviousBackup(PREV_BACKUP_STATE_PATH, encryptionKey); - const completeBackupData = JSON.parse(data); - const backupStartState = Date.now().toString(); - await fileStorage.writeFile(PREV_BACKUP_STATE_PATH, backupStartState); - const dataFromDB = await this.loadVCs(completeBackupData, encryptionKey); - await this.updateWellKnownConfigs(dataFromDB, encryptionKey); - } catch (error) { - console.error('Error while loading backup data:', error); - } - } - - /** - * Handle cleanup of previous backup state - * @param prevBackupStatePath Path to previous backup state file - * @param encryptionKey Encryption key - * @returns Previous restore timestamp - */ - private static async handlePreviousBackup( - prevBackupStatePath: string, - encryptionKey: string, - ) { - const previousBackupExists = await fileStorage.exists(prevBackupStatePath); - if (previousBackupExists) { - const previousRestoreTimestamp = await fileStorage.readFile( - prevBackupStatePath, - ); - const timestampNum = parseInt(previousRestoreTimestamp.trim()); - await this.unloadVCs(encryptionKey, timestampNum); - } - } - - /** - * Unload Verifiable Credentials based on a cutoff timestamp - * @param encryptionKey Encryption key - * @param cutOffTimestamp Timestamp to use as cutoff - */ - private static async unloadVCs( - encryptionKey: string, - cutOffTimestamp: number, - ) { - try { - await this.removeOldVCFiles(cutOffTimestamp); - await this.removeVCMetadataFromDB(encryptionKey, cutOffTimestamp); - } catch (error) { - console.error('Error while unloading VCs:', error); - sendErrorEvent( - getErrorEventData( - TelemetryConstants.FlowType.dataRestore, - TelemetryConstants.ErrorId.failure, - error.message, - ), - ); - } - } - - /** - * Remove VC files created after the cutoff timestamp - * @param cutOffTimestamp Timestamp to use as cutoff - */ - private static async removeOldVCFiles(cutOffTimestamp: number) { - const vcDirectory = `${DocumentDirectoryPath}/inji/VC/`; - const files = await fileStorage.getAllFilesInDirectory(vcDirectory); - - const filesToRemove = files.filter(file => { - const fileName = file.name.split('.')[0]; - const fileTimestamp = parseInt(fileName.split('_')[1]); - return fileTimestamp >= cutOffTimestamp; - }); - - await Promise.all( - filesToRemove.map(file => fileStorage.removeItem(file.path)), - ); - } - - /** - * Update MMKV store to remove VCs after cutoff timestamp - * @param encryptionKey Encryption key - * @param cutOffTimestamp Timestamp to use as cutoff - */ - private static async removeVCMetadataFromDB( - encryptionKey: any, - cutOffTimestamp: number, - ) { - const myVCsEnc = await MMKV.getItem(MY_VCS_STORE_KEY, encryptionKey); - - if (myVCsEnc === null) return; - - const mmkvVCs = await decryptJson(encryptionKey, myVCsEnc); - const vcList: VCMetadata[] = JSON.parse(mmkvVCs); - const newVCList = vcList.filter( - vc => !vc.timestamp || parseInt(vc.timestamp) < cutOffTimestamp, - ); - const finalVC = await encryptJson(encryptionKey, JSON.stringify(newVCList)); - await MMKV.setItem(MY_VCS_STORE_KEY, finalVC); - } - - /** - * Handle cleanup of previous backup state - * @param completeBackupData Entire Backup data to be loaded - * @param encryptionKey Encryption key - * @returns Previous - */ - private static async loadVCs( - completeBackupData: Record, - encryptionKey: string, - ): Promise | undefined> { - try { - const {VC_Records: allVCs, dataFromDB: dataFromDB} = completeBackupData; - - await this.processAndStoreVCs(allVCs, dataFromDB, encryptionKey); - await this.updateMyVcList(dataFromDB, encryptionKey); - await fileStorage.removeItemIfExist(`${DocumentDirectoryPath}/.prev`); - return dataFromDB; - } catch (error) { - console.error('Error while loading VCs:', error); - sendErrorEvent( - getErrorEventData( - TelemetryConstants.FlowType.dataBackup, - TelemetryConstants.ErrorId.failure, - error.message, - ), - ); - } - } - - /** - * Process and store individual Verifiable Credentials - * @param allVCs All Verifiable Credentials from backup - * @param dataFromDB Database data containing VC metadata - * @param encryptionKey Encryption key - */ - private static async processAndStoreVCs( - allVCs: Record, - dataFromDB: Record, - encryptionKey: string, - ) { - const vcKeys = Object.keys(allVCs); - - await Promise.all( - vcKeys.map(async key => { - const vcData = allVCs[key]; - // Add randomness to timestamp to maintain uniqueness - const timestamp = - Date.now() + Math.random().toString().substring(2, 10); - const prevUnixTimeStamp = vcData.vcMetadata.timestamp; - - // Verify and update the credential - const isVerified = await this.verifyCredential( - vcData, - vcData.vcMetadata, - ); - vcData.vcMetadata.timestamp = timestamp; - vcData.vcMetadata.isVerified = isVerified; - - //update the vcMetadata - dataFromDB.myVCs.forEach(myVcMetadata => { - if ( - myVcMetadata.requestId === vcData.vcMetadata.requestId && - myVcMetadata.timestamp === prevUnixTimeStamp - ) { - myVcMetadata.timestamp = timestamp; - myVcMetadata.isVerified = isVerified; - } - }); - - // Encrypt and store the VC - const updatedVcKey = new VCMetadata(vcData.vcMetadata).getVcKey(); - const encryptedVC = await encryptJson( - encryptionKey, - JSON.stringify(vcData), - ); - await this.setItem(updatedVcKey, encryptedVC, encryptionKey); - }), - ); - } - - /** - * Verify the restored credential - * @param vcData Verifiable Credential from backup - * @param vcMetadata VC metadata - */ - private static async verifyCredential(vcData: any, vcMetadata: any) { - let isVerified = true; - const verifiableCredential = - vcData.verifiableCredential?.credential || vcData.verifiableCredential; - if ( - vcMetadata.format === VCFormat.mso_mdoc || - !isMockVC(vcMetadata.issuer) - ) { - const verificationResult = await verifyCredential( - verifiableCredential, - vcMetadata.format, - ); - isVerified = verificationResult.isVerified; - } - return isVerified; - } - - /** - * Update MMKV store with new VC metadata - * @param dataFromDB Database data containing VC metadata - * @param encryptionKey Encryption key - */ - private static async updateMyVcList( - dataFromDB: Record, - encryptionKey: string, - ) { - const dataFromMyVCKey = dataFromDB[MY_VCS_STORE_KEY]; - const encryptedMyVCKeyFromMMKV = await MMKV.getItem(MY_VCS_STORE_KEY); - - let newDataForMyVCKey: VCMetadata[]; - - if (encryptedMyVCKeyFromMMKV != null) { - const myVCKeyFromMMKV = await decryptJson( - encryptionKey, - encryptedMyVCKeyFromMMKV, - ); - - newDataForMyVCKey = [...JSON.parse(myVCKeyFromMMKV), ...dataFromMyVCKey]; - } else { - newDataForMyVCKey = dataFromMyVCKey; - } - const encryptedDataForMyVCKey = await encryptJson( - encryptionKey, - JSON.stringify(newDataForMyVCKey), - ); - - await this.setItem( - MY_VCS_STORE_KEY, - encryptedDataForMyVCKey, - encryptionKey, - ); - } - - /** - * Update Well Known configs for cached issuers - * @param dataFromDB Database data - * @param encryptionKey Encryption key - */ - private static async updateWellKnownConfigs( - dataFromDB: Record, - encryptionKey: string, - ) { - const cacheKeys = Object.keys(dataFromDB).filter(key => - key.includes('CACHE_FETCH_ISSUER_WELLKNOWN_CONFIG_'), - ); - - await Promise.all( - cacheKeys.map(async key => { - const value = dataFromDB[key]; - const encryptedValue = await encryptJson( - encryptionKey, - JSON.stringify(value), - ); - await this.setItem(key, encryptedValue, encryptionKey); - }), - ); + + static async restoreBackedUpData(data: string, encryptionKey: string): Promise { + return await loadBackupData(data, encryptionKey) } static fetchAllWellknownConfig = async (encryptionKey: string) => { @@ -406,15 +74,6 @@ class Storage { return wellknownConfigData; }; - static isVCStorageInitialised = async (): Promise => { - try { - const res = await FileStorage.getInfo(vcDirectoryPath); - return res.isDirectory(); - } catch (_) { - return false; - } - }; - static setItem = async ( key: string, data: string, @@ -494,6 +153,33 @@ class Storage { } }; + static removeItem = async (key: string) => { + if (VCMetadata.isVCKey(key)) { + const path = getFilePath(key); + const isFileExists = await FileStorage.exists(path); + if (isFileExists) { + return await FileStorage.removeItem(path); + } else { + console.warn('file not exist`s'); + } + } + MMKV.removeItem(key); + }; + + static clear = async () => { + try { + (await FileStorage.exists(`${vcDirectoryPath}`)) && + (await FileStorage.removeItem(`${vcDirectoryPath}`)); + const settings = await MMKV.getItem(SETTINGS_STORE_KEY); + const appId = JSON.parse(settings).appId; + __AppId.setValue(appId); + MMKV.clearStore(); + await MMKV.setItem(SETTINGS_STORE_KEY, JSON.stringify({appId: appId})); + } catch (e) { + console.error('Error Occurred while Clearing Storage.', e); + } + }; + private static async isVCAlreadyDownloaded( key: string, encryptionKey: string, @@ -565,7 +251,6 @@ class Storage { return await FileStorage.writeFile(path, data); } - // TODO: INJI-612 refactor private static async storeVcHmac( encryptionKey: string, data: string, @@ -575,60 +260,10 @@ class Storage { const encryptedHMACofVC = await encryptJson(encryptionKey, HMACofVC); await MMKV.setItem(key, encryptedHMACofVC); } - - static removeItem = async (key: string) => { - if (VCMetadata.isVCKey(key)) { - const path = getFilePath(key); - const isFileExists = await FileStorage.exists(path); - if (isFileExists) { - return await FileStorage.removeItem(path); - } else { - console.warn('file not exist`s'); - } - } - MMKV.removeItem(key); - }; - - static clear = async () => { - try { - (await FileStorage.exists(`${vcDirectoryPath}`)) && - (await FileStorage.removeItem(`${vcDirectoryPath}`)); - const settings = await MMKV.getItem(SETTINGS_STORE_KEY); - const appId = JSON.parse(settings).appId; - __AppId.setValue(appId); - MMKV.clearStore(); - await MMKV.setItem(SETTINGS_STORE_KEY, JSON.stringify({appId: appId})); - } catch (e) { - console.error('Error Occurred while Clearing Storage.', e); - } - }; - - static isMinimumLimitReached = async (limitInMB: string) => { - const configurations = await getAllConfigurations(); - if (!configurations[limitInMB]) return false; - - const minimumStorageLimitInBytes = - configurations[limitInMB] * BYTES_IN_MEGABYTE; - - const freeDiskStorageInBytes = - isAndroid() && androidVersion < 29 - ? getFreeDiskStorageOldSync() - : getFreeDiskStorageSync(); - - return freeDiskStorageInBytes <= minimumStorageLimitInBytes; - }; } export default Storage; -function removeWalletBindingDataBeforeBackup(data: string) { - const vcData = JSON.parse(data); - vcData.walletBindingResponse = null; - vcData.publicKey = null; - vcData.privateKey = null; - return vcData; -} - export async function isMinimumLimitForBackupReached() { try { const directorySize = await getDirectorySize(vcDirectoryPath); @@ -650,5 +285,20 @@ export async function isMinimumLimitForBackupRestorationReached() { // APIs: // 1. CloudStorage.stat(file, context) // 2. getUncompressedSize() - return await Storage.isMinimumLimitReached('minStorageRequired'); + return await isMinimumLimitReached('minStorageRequired'); } + +export async function isMinimumLimitReached(limitInMB: string) { + const configurations = await getAllConfigurations(); + if (!configurations[limitInMB]) return false; + + const minimumStorageLimitInBytes = + configurations[limitInMB] * BYTES_IN_MEGABYTE; + + const freeDiskStorageInBytes = + isAndroid() && androidVersion < 29 + ? getFreeDiskStorageOldSync() + : getFreeDiskStorageSync(); + + return freeDiskStorageInBytes <= minimumStorageLimitInBytes; +}; From ab180d6fdcfcd349c6846e2fac4dae41c30e93d0 Mon Sep 17 00:00:00 2001 From: Alka Prasad Date: Wed, 18 Dec 2024 14:17:24 +0530 Subject: [PATCH 3/5] [INJIMOB-2571]: rename a few methods and throw the caught error along with logging it Signed-off-by: Alka Prasad --- .../backupAndRestore/restore/restoreService.ts | 4 ++-- machines/bleShare/request/requestMachine.ts | 4 ++-- machines/bleShare/scan/scanServices.ts | 4 ++-- machines/store.ts | 2 +- screens/Home/HomeScreenMachine.ts | 4 ++-- shared/backupUtils/restoreData.ts | 10 ++++++++-- shared/storage.ts | 16 ++++++++-------- 7 files changed, 25 insertions(+), 19 deletions(-) diff --git a/machines/backupAndRestore/restore/restoreService.ts b/machines/backupAndRestore/restore/restoreService.ts index f0576720bf..31a00f5986 100644 --- a/machines/backupAndRestore/restore/restoreService.ts +++ b/machines/backupAndRestore/restore/restoreService.ts @@ -1,6 +1,6 @@ import NetInfo from '@react-native-community/netinfo'; import Cloud from '../../../shared/CloudBackupAndRestoreUtils'; -import { isMinimumLimitReached } from '../../../shared/storage'; +import { isMinimumStorageLimitReached } from '../../../shared/storage'; import fileStorage, { getBackupFilePath, unZipAndRemoveFile, @@ -11,7 +11,7 @@ export const restoreService = model => { checkInternet: async () => await NetInfo.fetch(), checkStorageAvailability: () => async () => { - return await isMinimumLimitReached('minStorageRequired'); + return await isMinimumStorageLimitReached('minStorageRequired'); }, downloadLatestBackup: () => async () => { diff --git a/machines/bleShare/request/requestMachine.ts b/machines/bleShare/request/requestMachine.ts index 6190a85afa..5a5491f2ec 100644 --- a/machines/bleShare/request/requestMachine.ts +++ b/machines/bleShare/request/requestMachine.ts @@ -23,7 +23,7 @@ import {VcMetaEvents} from '../../VerifiableCredential/VCMetaMachine/VCMetaMachi import {subscribe} from '../../../shared/openIdBLE/verifierEventHandler'; import {VerifierDataEvent} from '../../../shared/tuvali/types/events'; import {BLEError} from '../types'; -import Storage, { isMinimumLimitReached } from '../../../shared/storage'; +import Storage, { isMinimumStorageLimitReached } from '../../../shared/storage'; import {VCMetadata} from '../../../shared/VCMetadata'; import { getEndEventData, @@ -885,7 +885,7 @@ export const requestMachine = }, checkStorageAvailability: () => async () => { - return Promise.resolve(isMinimumLimitReached('minStorageRequired')); + return Promise.resolve(isMinimumStorageLimitReached('minStorageRequired')); }, }, diff --git a/machines/bleShare/scan/scanServices.ts b/machines/bleShare/scan/scanServices.ts index 86712f14a4..3aa21665ae 100644 --- a/machines/bleShare/scan/scanServices.ts +++ b/machines/bleShare/scan/scanServices.ts @@ -1,5 +1,5 @@ import {isLocationEnabled} from 'react-native-device-info'; -import Storage, { isMinimumLimitReached } from '../../../shared/storage'; +import Storage, { isMinimumStorageLimitReached } from '../../../shared/storage'; import BluetoothStateManager from 'react-native-bluetooth-state-manager'; import { check, @@ -188,7 +188,7 @@ export const ScanServices = (model: any) => { }, checkStorageAvailability: () => async () => { - return Promise.resolve(isMinimumLimitReached('minStorageRequiredForAuditEntry')); + return Promise.resolve(isMinimumStorageLimitReached('minStorageRequiredForAuditEntry')); }, }; }; diff --git a/machines/store.ts b/machines/store.ts index f10c69243a..f967d2ec4f 100644 --- a/machines/store.ts +++ b/machines/store.ts @@ -624,7 +624,7 @@ export async function backupAndExportData(encryptionKey: string) { } export async function restoreBackedUpData(data, encryptionKey) { - await Storage.restoreBackedUpData(data, encryptionKey); + await Storage.restoreBackUpData(data, encryptionKey); } export async function fetchAllWellknownConfig(encryptionKey: string) { diff --git a/screens/Home/HomeScreenMachine.ts b/screens/Home/HomeScreenMachine.ts index 2f050b19d4..8371c4341d 100644 --- a/screens/Home/HomeScreenMachine.ts +++ b/screens/Home/HomeScreenMachine.ts @@ -7,7 +7,7 @@ import { ReceivedVcsTabMachine, } from './ReceivedVcsTabMachine'; import {IssuersMachine} from '../../machines/Issuers/IssuersMachine'; -import Storage, { isMinimumLimitReached } from '../../shared/storage'; +import Storage, { isMinimumStorageLimitReached } from '../../shared/storage'; import {VCItemMachine} from '../../machines/VerifiableCredential/VCItemMachine/VCItemMachine'; const model = createModel( @@ -173,7 +173,7 @@ export const HomeScreenMachine = model.createMachine( services: { checkStorageAvailability: () => async () => { return Promise.resolve( - isMinimumLimitReached('minStorageRequired'), + isMinimumStorageLimitReached('minStorageRequired'), ); }, }, diff --git a/shared/backupUtils/restoreData.ts b/shared/backupUtils/restoreData.ts index 71d4e7b6ca..3222d51df8 100644 --- a/shared/backupUtils/restoreData.ts +++ b/shared/backupUtils/restoreData.ts @@ -8,6 +8,9 @@ import { MY_VCS_STORE_KEY } from "../constants"; import { VCMetadata } from "../VCMetadata"; import { VCFormat } from "../VCFormat"; import { isMockVC } from "../Utils"; +import { + verifyCredential, +} from '../vcjs/verifyCredential' export async function loadBackupData( data: string, @@ -23,6 +26,7 @@ export async function loadBackupData( await updateWellKnownConfigs(dataFromDB, encryptionKey); } catch (error) { console.error('Error while loading backup data:', error); + throw error; } } @@ -67,6 +71,7 @@ async function handlePreviousBackup( error.message, ), ); + throw error; } } @@ -137,6 +142,7 @@ async function handlePreviousBackup( error.message, ), ); + throw error; } } @@ -162,7 +168,7 @@ async function handlePreviousBackup( const prevUnixTimeStamp = vcData.vcMetadata.timestamp; // Verify and update the credential - const isVerified = await verifyCredential( + const isVerified = await verifyCredentialData( vcData, vcData.vcMetadata, ); @@ -196,7 +202,7 @@ async function handlePreviousBackup( * @param vcData Verifiable Credential from backup * @param vcMetadata VC metadata */ - async function verifyCredential(vcData: any, vcMetadata: any) { + async function verifyCredentialData(vcData: any, vcMetadata: any) { let isVerified = true; const verifiableCredential = vcData.verifiableCredential?.credential || vcData.verifiableCredential; diff --git a/shared/storage.ts b/shared/storage.ts index d9bb07d9cb..800c7b6b25 100644 --- a/shared/storage.ts +++ b/shared/storage.ts @@ -5,7 +5,7 @@ import { } from 'react-native-device-info'; import { MMKVLoader } from 'react-native-mmkv-storage'; import getAllConfigurations from './api'; -import { exportData as backupData } from './backupUtils/backupData'; +import { exportData } from './backupUtils/backupData'; import { loadBackupData } from './backupUtils/restoreData'; import { BYTES_IN_MEGABYTE } from './commonUtil'; import { @@ -33,7 +33,7 @@ import { getErrorEventData, sendErrorEvent } from './telemetry/TelemetryUtils'; import { VCMetadata } from './VCMetadata'; export const MMKV = new MMKVLoader().initialize(); -const {RNSecureKeystoreModule} = NativeModules; +const { RNSecureKeystoreModule } = NativeModules; async function generateHmac( encryptionKey: string, @@ -48,10 +48,10 @@ async function generateHmac( class Storage { static backupData = async (encryptionKey: string) => { - return await backupData(encryptionKey) + return await exportData(encryptionKey) }; - - static async restoreBackedUpData(data: string, encryptionKey: string): Promise { + + static async restoreBackUpData(data: string, encryptionKey: string): Promise { return await loadBackupData(data, encryptionKey) } @@ -174,7 +174,7 @@ class Storage { const appId = JSON.parse(settings).appId; __AppId.setValue(appId); MMKV.clearStore(); - await MMKV.setItem(SETTINGS_STORE_KEY, JSON.stringify({appId: appId})); + await MMKV.setItem(SETTINGS_STORE_KEY, JSON.stringify({ appId: appId })); } catch (e) { console.error('Error Occurred while Clearing Storage.', e); } @@ -285,10 +285,10 @@ export async function isMinimumLimitForBackupRestorationReached() { // APIs: // 1. CloudStorage.stat(file, context) // 2. getUncompressedSize() - return await isMinimumLimitReached('minStorageRequired'); + return await isMinimumStorageLimitReached('minStorageRequired'); } -export async function isMinimumLimitReached(limitInMB: string) { +export async function isMinimumStorageLimitReached(limitInMB: string) { const configurations = await getAllConfigurations(); if (!configurations[limitInMB]) return false; From bf7fd538f4902d5aa471e80fd8de6ac2e9ae6a32 Mon Sep 17 00:00:00 2001 From: Alka Prasad Date: Wed, 18 Dec 2024 15:34:13 +0530 Subject: [PATCH 4/5] [INJIMOB-2571]: refactor verifyCredential method and its usages Signed-off-by: Alka Prasad --- machines/Issuers/IssuersService.ts | 25 +- .../VCItemMachine/VCItemMachine.typegen.ts | 629 ++++-------------- .../VCItemMachine/VCItemServices.ts | 28 +- shared/Utils.ts | 23 +- shared/backupUtils/restoreData.ts | 40 +- shared/vcjs/verifyCredential.ts | 153 +++-- 6 files changed, 271 insertions(+), 627 deletions(-) diff --git a/machines/Issuers/IssuersService.ts b/machines/Issuers/IssuersService.ts index cd890b3948..35bf26e35d 100644 --- a/machines/Issuers/IssuersService.ts +++ b/machines/Issuers/IssuersService.ts @@ -27,7 +27,7 @@ import { } from '../../shared/telemetry/TelemetryUtils'; import {TelemetryConstants} from '../../shared/telemetry/TelemetryConstants'; import {VciClient} from '../../shared/vciClient/VciClient'; -import {isMockVC} from '../../shared/Utils'; +import {isMockVC, verifyCredentialData} from '../../shared/Utils'; import {VCFormat} from '../../shared/VCFormat'; export const IssuersService = () => { @@ -151,26 +151,15 @@ export const IssuersService = () => { }, verifyCredential: async (context: any) => { - //TODO: Remove bypassing verification of mock VCs once mock VCs are verifiable - if ( - context.selectedCredentialType.format === VCFormat.mso_mdoc || - !isMockVC(context.selectedIssuerId) - ) { - const verificationResult = await verifyCredential( - context.verifiableCredential?.credential, - context.selectedCredentialType.format, - ); - if (!verificationResult.isVerified) { + const verificationResult = await verifyCredentialData( + context.verifiableCredential?.credential, + context.selectedCredentialType.format, + context.selectedIssuerId + ); + if(!verificationResult.isVerified) { throw new Error(verificationResult.verificationErrorCode); } return verificationResult; - } else { - return { - isVerified: true, - verificationMessage: VerificationErrorMessage.NO_ERROR, - verificationErrorCode: VerificationErrorType.NO_ERROR, - }; - } }, }; }; diff --git a/machines/VerifiableCredential/VCItemMachine/VCItemMachine.typegen.ts b/machines/VerifiableCredential/VCItemMachine/VCItemMachine.typegen.ts index c01016c68a..08e7beeb08 100644 --- a/machines/VerifiableCredential/VCItemMachine/VCItemMachine.typegen.ts +++ b/machines/VerifiableCredential/VCItemMachine/VCItemMachine.typegen.ts @@ -1,484 +1,147 @@ -// This file was automatically generated. Edits will be overwritten -export interface Typegen0 { - '@@xstate/typegen': true; - internalEvents: { - '': {type: ''}; - 'done.invoke.checkStatus': { - type: 'done.invoke.checkStatus'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.downloadCredential': { - type: 'done.invoke.downloadCredential'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.vc-item-machine.vcUtilitiesState.kebabPopUp.triggerAutoBackup:invocation[0]': { - type: 'done.invoke.vc-item-machine.vcUtilitiesState.kebabPopUp.triggerAutoBackup:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromContext.fetchWellknown:invocation[0]': { - type: 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromContext.fetchWellknown:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]': { - type: 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]': { - type: 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.vc-item-machine.vcUtilitiesState.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]': { - type: 'done.invoke.vc-item-machine.vcUtilitiesState.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]': { - type: 'done.invoke.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]': { - type: 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]': { - type: 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]': { - type: 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]': { - type: 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]': { - type: 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]': { - type: 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.vc-item-machine.verifyState.verifyingCredential:invocation[0]': { - type: 'done.invoke.vc-item-machine.verifyState.verifyingCredential:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'error.platform.checkStatus': { - type: 'error.platform.checkStatus'; - data: unknown; - }; - 'error.platform.downloadCredential': { - type: 'error.platform.downloadCredential'; - data: unknown; - }; - 'error.platform.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]': { - type: 'error.platform.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]'; - data: unknown; - }; - 'error.platform.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]': { - type: 'error.platform.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]'; - data: unknown; - }; - 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]': { - type: 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]'; - data: unknown; - }; - 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]': { - type: 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]'; - data: unknown; - }; - 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]': { - type: 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]'; - data: unknown; - }; - 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]': { - type: 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]'; - data: unknown; - }; - 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]': { - type: 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]'; - data: unknown; - }; - 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]': { - type: 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]'; - data: unknown; - }; - 'error.platform.vc-item-machine.verifyState.verifyingCredential:invocation[0]': { - type: 'error.platform.vc-item-machine.verifyState.verifyingCredential:invocation[0]'; - data: unknown; - }; - 'xstate.after(500)#vc-item-machine.verifyState.verifyingCredential': { - type: 'xstate.after(500)#vc-item-machine.verifyState.verifyingCredential'; - }; - 'xstate.init': {type: 'xstate.init'}; - 'xstate.stop': {type: 'xstate.stop'}; - }; - invokeSrcNameMap: { - addWalletBindingId: 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]'; - checkDownloadExpiryLimit: 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]'; - checkStatus: 'done.invoke.checkStatus'; - downloadCredential: 'done.invoke.downloadCredential'; - fetchIssuerWellknown: 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromContext.fetchWellknown:invocation[0]'; - fetchKeyPair: 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]'; - generateKeypairAndStore: 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]'; - isUserSignedAlready: - | 'done.invoke.vc-item-machine.vcUtilitiesState.kebabPopUp.triggerAutoBackup:invocation[0]' - | 'done.invoke.vc-item-machine.vcUtilitiesState.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]'; - loadDownloadLimitConfig: 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]'; - requestBindingOTP: - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]' - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]'; - updatePrivateKey: 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]'; - verifyCredential: - | 'done.invoke.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]' - | 'done.invoke.vc-item-machine.verifyState.verifyingCredential:invocation[0]'; - }; - missingImplementations: { - actions: - | 'addVcToInProgressDownloads' - | 'closeViewVcModal' - | 'incrementDownloadCounter' - | 'logDownloaded' - | 'logRemovedVc' - | 'logWalletBindingFailure' - | 'logWalletBindingSuccess' - | 'refreshAllVcs' - | 'removeVcFromInProgressDownloads' - | 'removeVcItem' - | 'removeVcMetaDataFromStorage' - | 'removeVcMetaDataFromVcMachineContext' - | 'removeVerificationStatusFromVcMeta' - | 'requestVcContext' - | 'resetIsMachineInKebabPopupState' - | 'resetIsVerified' - | 'resetPrivateKey' - | 'resetVerificationStatus' - | 'sendActivationStartEvent' - | 'sendActivationSuccessEvent' - | 'sendBackupEvent' - | 'sendDownloadLimitExpire' - | 'sendDownloadingFailedToVcMeta' - | 'sendTelemetryEvents' - | 'sendUserCancelledActivationFailedEndEvent' - | 'sendVerificationError' - | 'sendVerificationStatusToVcMeta' - | 'sendWalletBindingErrorEvent' - | 'sendWalletBindingSuccess' - | 'setCommunicationDetails' - | 'setContext' - | 'setDownloadInterval' - | 'setErrorAsVerificationError' - | 'setErrorAsWalletBindingError' - | 'setIsVerified' - | 'setMaxDownloadCount' - | 'setOTP' - | 'setPinCard' - | 'setPrivateKey' - | 'setPublicKey' - | 'setThumbprintForWalletBindingId' - | 'setVcKey' - | 'setVcMetadata' - | 'setVerificationStatus' - | 'setWalletBindingResponse' - | 'showVerificationBannerStatus' - | 'storeContext' - | 'storeVcInContext' - | 'unSetBindingTransactionId' - | 'unSetError' - | 'unSetOTP' - | 'updateVcMetadata' - | 'updateWellknownResponse'; - delays: never; - guards: - | 'hasCredential' - | 'hasCredentialAndWellknown' - | 'hasKeyPair' - | 'isCustomSecureKeystore' - | 'isDownloadAllowed' - | 'isSignedIn' - | 'isVerificationPendingBecauseOfNetworkIssue'; - services: - | 'addWalletBindingId' - | 'checkDownloadExpiryLimit' - | 'checkStatus' - | 'downloadCredential' - | 'fetchIssuerWellknown' - | 'fetchKeyPair' - | 'generateKeypairAndStore' - | 'isUserSignedAlready' - | 'loadDownloadLimitConfig' - | 'requestBindingOTP' - | 'updatePrivateKey' - | 'verifyCredential'; - }; - eventsCausingActions: { - addVcToInProgressDownloads: 'GET_VC_RESPONSE'; - closeViewVcModal: 'CLOSE_VC_MODAL' | 'STORE_RESPONSE'; - incrementDownloadCounter: - | 'POLL' - | 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]'; - logDownloaded: 'STORE_RESPONSE'; - logRemovedVc: 'STORE_RESPONSE'; - logWalletBindingFailure: - | 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]' - | 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]' - | 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]' - | 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]' - | 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]'; - logWalletBindingSuccess: - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]' - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]'; - refreshAllVcs: - | 'STORE_RESPONSE' - | 'done.invoke.vc-item-machine.vcUtilitiesState.kebabPopUp.triggerAutoBackup:invocation[0]'; - removeVcFromInProgressDownloads: - | 'STORE_RESPONSE' - | 'error.platform.downloadCredential' - | 'error.platform.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]'; - removeVcItem: 'CONFIRM'; - removeVcMetaDataFromStorage: - | 'STORE_ERROR' - | 'error.platform.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]'; - removeVcMetaDataFromVcMachineContext: 'DISMISS'; - removeVerificationStatusFromVcMeta: 'RESET_VERIFICATION_STATUS'; - requestVcContext: 'DISMISS' | 'REFRESH' | 'STORE_ERROR' | 'xstate.init'; - resetIsMachineInKebabPopupState: - | '' - | 'ADD_WALLET_BINDING_ID' - | 'CANCEL' - | 'CLOSE_VC_MODAL' - | 'DISMISS' - | 'REFRESH' - | 'REMOVE' - | 'SHOW_ACTIVITY' - | 'done.invoke.vc-item-machine.vcUtilitiesState.kebabPopUp.triggerAutoBackup:invocation[0]' - | 'xstate.stop'; - resetIsVerified: - | 'error.platform.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]' - | 'error.platform.vc-item-machine.verifyState.verifyingCredential:invocation[0]'; - resetPrivateKey: - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]' - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]'; - resetVerificationStatus: - | 'REMOVE_VERIFICATION_STATUS_BANNER' - | 'RESET_VERIFICATION_STATUS'; - sendActivationStartEvent: 'CONFIRM'; - sendActivationSuccessEvent: - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]' - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]'; - sendBackupEvent: - | 'done.invoke.vc-item-machine.vcUtilitiesState.kebabPopUp.triggerAutoBackup:invocation[0]' - | 'done.invoke.vc-item-machine.vcUtilitiesState.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]'; - sendDownloadLimitExpire: - | 'FAILED' - | 'error.platform.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]'; - sendDownloadingFailedToVcMeta: 'error.platform.downloadCredential'; - sendTelemetryEvents: 'STORE_RESPONSE'; - sendUserCancelledActivationFailedEndEvent: 'DISMISS'; - sendVerificationError: 'STORE_RESPONSE'; - sendVerificationStatusToVcMeta: 'STORE_RESPONSE'; - sendWalletBindingErrorEvent: - | 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]' - | 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]' - | 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]' - | 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]' - | 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]' - | 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]'; - sendWalletBindingSuccess: 'SHOW_BINDING_STATUS'; - setCommunicationDetails: - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]' - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]'; - setContext: 'CREDENTIAL_DOWNLOADED' | 'GET_VC_RESPONSE'; - setDownloadInterval: 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]'; - setErrorAsVerificationError: 'error.platform.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]'; - setErrorAsWalletBindingError: - | 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]' - | 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]' - | 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]' - | 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]' - | 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]' - | 'error.platform.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]'; - setIsVerified: - | 'done.invoke.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]' - | 'done.invoke.vc-item-machine.verifyState.verifyingCredential:invocation[0]'; - setMaxDownloadCount: 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]'; - setOTP: 'INPUT_OTP'; - setPinCard: 'PIN_CARD'; - setPrivateKey: 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]'; - setPublicKey: - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]' - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]'; - setThumbprintForWalletBindingId: - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]' - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]'; - setVcKey: 'REMOVE'; - setVcMetadata: 'UPDATE_VC_METADATA'; - setVerificationStatus: - | 'SET_VERIFICATION_STATUS' - | 'SHOW_VERIFICATION_STATUS_BANNER' - | 'STORE_RESPONSE'; - setWalletBindingResponse: 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]'; - showVerificationBannerStatus: - | 'SHOW_VERIFICATION_STATUS_BANNER' - | 'STORE_RESPONSE' - | 'xstate.after(500)#vc-item-machine.verifyState.verifyingCredential'; - storeContext: - | 'done.invoke.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]' - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]' - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]' - | 'done.invoke.vc-item-machine.verifyState.verifyingCredential:invocation[0]' - | 'error.platform.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]' - | 'error.platform.vc-item-machine.verifyState.verifyingCredential:invocation[0]'; - storeVcInContext: - | 'STORE_RESPONSE' - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]' - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]'; - unSetBindingTransactionId: 'DISMISS'; - unSetError: - | 'CANCEL' - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]' - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]'; - unSetOTP: - | 'DISMISS' - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]'; - updateVcMetadata: 'PIN_CARD' | 'STORE_RESPONSE'; - updateWellknownResponse: 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromContext.fetchWellknown:invocation[0]'; - }; - eventsCausingDelays: {}; - eventsCausingGuards: { - hasCredential: 'GET_VC_RESPONSE'; - hasCredentialAndWellknown: 'GET_VC_RESPONSE'; - hasKeyPair: 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]'; - isCustomSecureKeystore: 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]'; - isDownloadAllowed: 'POLL'; - isSignedIn: - | 'done.invoke.vc-item-machine.vcUtilitiesState.kebabPopUp.triggerAutoBackup:invocation[0]' - | 'done.invoke.vc-item-machine.vcUtilitiesState.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]'; - isVerificationPendingBecauseOfNetworkIssue: - | 'error.platform.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]' - | 'error.platform.vc-item-machine.verifyState.verifyingCredential:invocation[0]'; - }; - eventsCausingServices: { - addWalletBindingId: - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]' - | 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]'; - checkDownloadExpiryLimit: - | 'POLL' - | 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]'; - checkStatus: 'done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]'; - downloadCredential: 'DOWNLOAD_READY'; - fetchIssuerWellknown: 'GET_VC_RESPONSE'; - fetchKeyPair: 'INPUT_OTP'; - generateKeypairAndStore: 'done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]'; - isUserSignedAlready: 'STORE_RESPONSE'; - loadDownloadLimitConfig: 'GET_VC_RESPONSE' | 'STORE_ERROR'; - requestBindingOTP: 'CONFIRM' | 'RESEND_OTP'; - updatePrivateKey: never; - verifyCredential: 'CREDENTIAL_DOWNLOADED' | 'VERIFY'; - }; - matchesStates: - | 'vcUtilitiesState' - | 'vcUtilitiesState.idle' - | 'vcUtilitiesState.kebabPopUp' - | 'vcUtilitiesState.kebabPopUp.idle' - | 'vcUtilitiesState.kebabPopUp.pinCard' - | 'vcUtilitiesState.kebabPopUp.removeWallet' - | 'vcUtilitiesState.kebabPopUp.removingVc' - | 'vcUtilitiesState.kebabPopUp.showActivities' - | 'vcUtilitiesState.kebabPopUp.triggerAutoBackup' - | 'vcUtilitiesState.loadVc' - | 'vcUtilitiesState.loadVc.loadVcFromContext' - | 'vcUtilitiesState.loadVc.loadVcFromContext.fetchWellknown' - | 'vcUtilitiesState.loadVc.loadVcFromContext.idle' - | 'vcUtilitiesState.loadVc.loadVcFromServer' - | 'vcUtilitiesState.loadVc.loadVcFromServer.checkingStatus' - | 'vcUtilitiesState.loadVc.loadVcFromServer.downloadingCredential' - | 'vcUtilitiesState.loadVc.loadVcFromServer.loadDownloadLimitConfig' - | 'vcUtilitiesState.loadVc.loadVcFromServer.savingFailed' - | 'vcUtilitiesState.loadVc.loadVcFromServer.savingFailed.idle' - | 'vcUtilitiesState.loadVc.loadVcFromServer.savingFailed.viewingVc' - | 'vcUtilitiesState.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry' - | 'vcUtilitiesState.verifyingCredential' - | 'vcUtilitiesState.verifyingCredential.handleVCVerificationFailure' - | 'vcUtilitiesState.verifyingCredential.idle' - | 'vcUtilitiesState.verifyingCredential.triggerAutoBackupForVcDownload' - | 'vcUtilitiesState.walletBinding' - | 'vcUtilitiesState.walletBinding.acceptingBindingOTP' - | 'vcUtilitiesState.walletBinding.acceptingBindingOTP.idle' - | 'vcUtilitiesState.walletBinding.acceptingBindingOTP.resendOTP' - | 'vcUtilitiesState.walletBinding.addKeyPair' - | 'vcUtilitiesState.walletBinding.addingWalletBindingId' - | 'vcUtilitiesState.walletBinding.generateKeyPair' - | 'vcUtilitiesState.walletBinding.requestingBindingOTP' - | 'vcUtilitiesState.walletBinding.showBindingWarning' - | 'vcUtilitiesState.walletBinding.showingWalletBindingError' - | 'vcUtilitiesState.walletBinding.updatingContextVariables' - | 'vcUtilitiesState.walletBinding.updatingPrivateKey' - | 'verifyState' - | 'verifyState.idle' - | 'verifyState.verificationCompleted' - | 'verifyState.verifyingCredential' - | { - vcUtilitiesState?: - | 'idle' - | 'kebabPopUp' - | 'loadVc' - | 'verifyingCredential' - | 'walletBinding' - | { - kebabPopUp?: - | 'idle' - | 'pinCard' - | 'removeWallet' - | 'removingVc' - | 'showActivities' - | 'triggerAutoBackup'; - loadVc?: - | 'loadVcFromContext' - | 'loadVcFromServer' - | { - loadVcFromContext?: 'fetchWellknown' | 'idle'; - loadVcFromServer?: - | 'checkingStatus' - | 'downloadingCredential' - | 'loadDownloadLimitConfig' - | 'savingFailed' - | 'verifyingDownloadLimitExpiry' - | {savingFailed?: 'idle' | 'viewingVc'}; - }; - verifyingCredential?: - | 'handleVCVerificationFailure' - | 'idle' - | 'triggerAutoBackupForVcDownload'; - walletBinding?: - | 'acceptingBindingOTP' - | 'addKeyPair' - | 'addingWalletBindingId' - | 'generateKeyPair' - | 'requestingBindingOTP' - | 'showBindingWarning' - | 'showingWalletBindingError' - | 'updatingContextVariables' - | 'updatingPrivateKey' - | {acceptingBindingOTP?: 'idle' | 'resendOTP'}; - }; - verifyState?: 'idle' | 'verificationCompleted' | 'verifyingCredential'; - }; - tags: never; -} + // This file was automatically generated. Edits will be overwritten + + export interface Typegen0 { + '@@xstate/typegen': true; + internalEvents: { + "": { type: "" }; +"done.invoke.checkStatus": { type: "done.invoke.checkStatus"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.downloadCredential": { type: "done.invoke.downloadCredential"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.vc-item-machine.vcUtilitiesState.kebabPopUp.triggerAutoBackup:invocation[0]": { type: "done.invoke.vc-item-machine.vcUtilitiesState.kebabPopUp.triggerAutoBackup:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromContext.fetchWellknown:invocation[0]": { type: "done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromContext.fetchWellknown:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]": { type: "done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]": { type: "done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.vc-item-machine.vcUtilitiesState.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]": { type: "done.invoke.vc-item-machine.vcUtilitiesState.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]": { type: "done.invoke.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]": { type: "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]": { type: "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]": { type: "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]": { type: "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]": { type: "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]": { type: "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.vc-item-machine.verifyState.verifyingCredential:invocation[0]": { type: "done.invoke.vc-item-machine.verifyState.verifyingCredential:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"error.platform.checkStatus": { type: "error.platform.checkStatus"; data: unknown }; +"error.platform.downloadCredential": { type: "error.platform.downloadCredential"; data: unknown }; +"error.platform.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]": { type: "error.platform.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]"; data: unknown }; +"error.platform.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]": { type: "error.platform.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]"; data: unknown }; +"error.platform.vc-item-machine.vcUtilitiesState.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]": { type: "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]"; data: unknown }; +"error.platform.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]": { type: "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]"; data: unknown }; +"error.platform.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]": { type: "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]"; data: unknown }; +"error.platform.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]": { type: "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]"; data: unknown }; +"error.platform.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]": { type: "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]"; data: unknown }; +"error.platform.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]": { type: "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]"; data: unknown }; +"error.platform.vc-item-machine.verifyState.verifyingCredential:invocation[0]": { type: "error.platform.vc-item-machine.verifyState.verifyingCredential:invocation[0]"; data: unknown }; +"xstate.after(500)#vc-item-machine.verifyState.verifyingCredential": { type: "xstate.after(500)#vc-item-machine.verifyState.verifyingCredential" }; +"xstate.init": { type: "xstate.init" }; +"xstate.stop": { type: "xstate.stop" }; + }; + invokeSrcNameMap: { + "addWalletBindingId": "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]"; +"checkDownloadExpiryLimit": "done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]"; +"checkStatus": "done.invoke.checkStatus"; +"downloadCredential": "done.invoke.downloadCredential"; +"fetchIssuerWellknown": "done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromContext.fetchWellknown:invocation[0]"; +"fetchKeyPair": "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]"; +"generateKeypairAndStore": "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]"; +"isUserSignedAlready": "done.invoke.vc-item-machine.vcUtilitiesState.kebabPopUp.triggerAutoBackup:invocation[0]" | "done.invoke.vc-item-machine.vcUtilitiesState.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]"; +"loadDownloadLimitConfig": "done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]"; +"requestBindingOTP": "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]" | "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]"; +"updatePrivateKey": "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]"; +"verifyCredential": "done.invoke.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]" | "done.invoke.vc-item-machine.verifyState.verifyingCredential:invocation[0]"; + }; + missingImplementations: { + actions: "addVcToInProgressDownloads" | "closeViewVcModal" | "incrementDownloadCounter" | "logDownloaded" | "logRemovedVc" | "logWalletBindingFailure" | "logWalletBindingSuccess" | "refreshAllVcs" | "removeVcFromInProgressDownloads" | "removeVcItem" | "removeVcMetaDataFromStorage" | "removeVcMetaDataFromVcMachineContext" | "removeVerificationStatusFromVcMeta" | "requestVcContext" | "resetIsMachineInKebabPopupState" | "resetIsVerified" | "resetPrivateKey" | "resetVerificationStatus" | "sendActivationStartEvent" | "sendActivationSuccessEvent" | "sendBackupEvent" | "sendDownloadLimitExpire" | "sendDownloadingFailedToVcMeta" | "sendTelemetryEvents" | "sendUserCancelledActivationFailedEndEvent" | "sendVerificationError" | "sendVerificationStatusToVcMeta" | "sendWalletBindingErrorEvent" | "sendWalletBindingSuccess" | "setCommunicationDetails" | "setContext" | "setDownloadInterval" | "setErrorAsVerificationError" | "setErrorAsWalletBindingError" | "setIsVerified" | "setMaxDownloadCount" | "setOTP" | "setPinCard" | "setPrivateKey" | "setPublicKey" | "setThumbprintForWalletBindingId" | "setVcKey" | "setVcMetadata" | "setVerificationStatus" | "setWalletBindingResponse" | "showVerificationBannerStatus" | "storeContext" | "storeVcInContext" | "unSetBindingTransactionId" | "unSetError" | "unSetOTP" | "updateVcMetadata" | "updateWellknownResponse"; + delays: never; + guards: "hasCredential" | "hasCredentialAndWellknown" | "hasKeyPair" | "isCustomSecureKeystore" | "isDownloadAllowed" | "isSignedIn" | "isVerificationPendingBecauseOfNetworkIssue"; + services: "addWalletBindingId" | "checkDownloadExpiryLimit" | "checkStatus" | "downloadCredential" | "fetchIssuerWellknown" | "fetchKeyPair" | "generateKeypairAndStore" | "isUserSignedAlready" | "loadDownloadLimitConfig" | "requestBindingOTP" | "updatePrivateKey" | "verifyCredential"; + }; + eventsCausingActions: { + "addVcToInProgressDownloads": "GET_VC_RESPONSE"; +"closeViewVcModal": "CLOSE_VC_MODAL" | "STORE_RESPONSE"; +"incrementDownloadCounter": "POLL" | "done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]"; +"logDownloaded": "STORE_RESPONSE"; +"logRemovedVc": "STORE_RESPONSE"; +"logWalletBindingFailure": "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]" | "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]" | "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]" | "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]" | "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]"; +"logWalletBindingSuccess": "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]" | "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]"; +"refreshAllVcs": "STORE_RESPONSE" | "done.invoke.vc-item-machine.vcUtilitiesState.kebabPopUp.triggerAutoBackup:invocation[0]"; +"removeVcFromInProgressDownloads": "STORE_RESPONSE" | "error.platform.downloadCredential" | "error.platform.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]"; +"removeVcItem": "CONFIRM"; +"removeVcMetaDataFromStorage": "STORE_ERROR" | "error.platform.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]"; +"removeVcMetaDataFromVcMachineContext": "DISMISS"; +"removeVerificationStatusFromVcMeta": "RESET_VERIFICATION_STATUS"; +"requestVcContext": "DISMISS" | "REFRESH" | "STORE_ERROR" | "xstate.init"; +"resetIsMachineInKebabPopupState": "" | "ADD_WALLET_BINDING_ID" | "CANCEL" | "CLOSE_VC_MODAL" | "DISMISS" | "REFRESH" | "REMOVE" | "SHOW_ACTIVITY" | "done.invoke.vc-item-machine.vcUtilitiesState.kebabPopUp.triggerAutoBackup:invocation[0]" | "xstate.stop"; +"resetIsVerified": "error.platform.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]" | "error.platform.vc-item-machine.verifyState.verifyingCredential:invocation[0]"; +"resetPrivateKey": "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]" | "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]"; +"resetVerificationStatus": "REMOVE_VERIFICATION_STATUS_BANNER" | "RESET_VERIFICATION_STATUS"; +"sendActivationStartEvent": "CONFIRM"; +"sendActivationSuccessEvent": "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]" | "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]"; +"sendBackupEvent": "done.invoke.vc-item-machine.vcUtilitiesState.kebabPopUp.triggerAutoBackup:invocation[0]" | "done.invoke.vc-item-machine.vcUtilitiesState.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]"; +"sendDownloadLimitExpire": "FAILED" | "error.platform.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]"; +"sendDownloadingFailedToVcMeta": "error.platform.downloadCredential"; +"sendTelemetryEvents": "STORE_RESPONSE"; +"sendUserCancelledActivationFailedEndEvent": "DISMISS"; +"sendVerificationError": "STORE_RESPONSE"; +"sendVerificationStatusToVcMeta": "STORE_RESPONSE"; +"sendWalletBindingErrorEvent": "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]" | "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]" | "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]" | "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]" | "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]" | "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]"; +"sendWalletBindingSuccess": "SHOW_BINDING_STATUS"; +"setCommunicationDetails": "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]" | "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]"; +"setContext": "CREDENTIAL_DOWNLOADED" | "GET_VC_RESPONSE"; +"setDownloadInterval": "done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]"; +"setErrorAsVerificationError": "error.platform.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]"; +"setErrorAsWalletBindingError": "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]" | "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]" | "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]" | "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]" | "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]" | "error.platform.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]"; +"setIsVerified": "done.invoke.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]" | "done.invoke.vc-item-machine.verifyState.verifyingCredential:invocation[0]"; +"setMaxDownloadCount": "done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]"; +"setOTP": "INPUT_OTP"; +"setPinCard": "PIN_CARD"; +"setPrivateKey": "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]"; +"setPublicKey": "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]" | "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]"; +"setThumbprintForWalletBindingId": "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]" | "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]"; +"setVcKey": "REMOVE"; +"setVcMetadata": "UPDATE_VC_METADATA"; +"setVerificationStatus": "SET_VERIFICATION_STATUS" | "SHOW_VERIFICATION_STATUS_BANNER" | "STORE_RESPONSE"; +"setWalletBindingResponse": "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]"; +"showVerificationBannerStatus": "SHOW_VERIFICATION_STATUS_BANNER" | "STORE_RESPONSE" | "xstate.after(500)#vc-item-machine.verifyState.verifyingCredential"; +"storeContext": "done.invoke.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]" | "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]" | "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]" | "done.invoke.vc-item-machine.verifyState.verifyingCredential:invocation[0]" | "error.platform.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]" | "error.platform.vc-item-machine.verifyState.verifyingCredential:invocation[0]"; +"storeVcInContext": "STORE_RESPONSE" | "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]" | "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]"; +"unSetBindingTransactionId": "DISMISS"; +"unSetError": "CANCEL" | "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]" | "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.updatingPrivateKey:invocation[0]"; +"unSetOTP": "DISMISS" | "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.requestingBindingOTP:invocation[0]"; +"updateVcMetadata": "PIN_CARD" | "STORE_RESPONSE"; +"updateWellknownResponse": "done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromContext.fetchWellknown:invocation[0]"; + }; + eventsCausingDelays: { + + }; + eventsCausingGuards: { + "hasCredential": "GET_VC_RESPONSE"; +"hasCredentialAndWellknown": "GET_VC_RESPONSE"; +"hasKeyPair": "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]"; +"isCustomSecureKeystore": "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addingWalletBindingId:invocation[0]"; +"isDownloadAllowed": "POLL"; +"isSignedIn": "done.invoke.vc-item-machine.vcUtilitiesState.kebabPopUp.triggerAutoBackup:invocation[0]" | "done.invoke.vc-item-machine.vcUtilitiesState.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]"; +"isVerificationPendingBecauseOfNetworkIssue": "error.platform.vc-item-machine.vcUtilitiesState.verifyingCredential:invocation[0]" | "error.platform.vc-item-machine.verifyState.verifyingCredential:invocation[0]"; + }; + eventsCausingServices: { + "addWalletBindingId": "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]" | "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.generateKeyPair:invocation[0]"; +"checkDownloadExpiryLimit": "POLL" | "done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]"; +"checkStatus": "done.invoke.vc-item-machine.vcUtilitiesState.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]"; +"downloadCredential": "DOWNLOAD_READY"; +"fetchIssuerWellknown": "GET_VC_RESPONSE"; +"fetchKeyPair": "INPUT_OTP"; +"generateKeypairAndStore": "done.invoke.vc-item-machine.vcUtilitiesState.walletBinding.addKeyPair:invocation[0]"; +"isUserSignedAlready": "STORE_RESPONSE"; +"loadDownloadLimitConfig": "GET_VC_RESPONSE" | "STORE_ERROR"; +"requestBindingOTP": "CONFIRM" | "RESEND_OTP"; +"updatePrivateKey": never; +"verifyCredential": "CREDENTIAL_DOWNLOADED" | "VERIFY"; + }; + matchesStates: "vcUtilitiesState" | "vcUtilitiesState.idle" | "vcUtilitiesState.kebabPopUp" | "vcUtilitiesState.kebabPopUp.idle" | "vcUtilitiesState.kebabPopUp.pinCard" | "vcUtilitiesState.kebabPopUp.removeWallet" | "vcUtilitiesState.kebabPopUp.removingVc" | "vcUtilitiesState.kebabPopUp.showActivities" | "vcUtilitiesState.kebabPopUp.triggerAutoBackup" | "vcUtilitiesState.loadVc" | "vcUtilitiesState.loadVc.loadVcFromContext" | "vcUtilitiesState.loadVc.loadVcFromContext.fetchWellknown" | "vcUtilitiesState.loadVc.loadVcFromContext.idle" | "vcUtilitiesState.loadVc.loadVcFromServer" | "vcUtilitiesState.loadVc.loadVcFromServer.checkingStatus" | "vcUtilitiesState.loadVc.loadVcFromServer.downloadingCredential" | "vcUtilitiesState.loadVc.loadVcFromServer.loadDownloadLimitConfig" | "vcUtilitiesState.loadVc.loadVcFromServer.savingFailed" | "vcUtilitiesState.loadVc.loadVcFromServer.savingFailed.idle" | "vcUtilitiesState.loadVc.loadVcFromServer.savingFailed.viewingVc" | "vcUtilitiesState.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry" | "vcUtilitiesState.verifyingCredential" | "vcUtilitiesState.verifyingCredential.handleVCVerificationFailure" | "vcUtilitiesState.verifyingCredential.idle" | "vcUtilitiesState.verifyingCredential.triggerAutoBackupForVcDownload" | "vcUtilitiesState.walletBinding" | "vcUtilitiesState.walletBinding.acceptingBindingOTP" | "vcUtilitiesState.walletBinding.acceptingBindingOTP.idle" | "vcUtilitiesState.walletBinding.acceptingBindingOTP.resendOTP" | "vcUtilitiesState.walletBinding.addKeyPair" | "vcUtilitiesState.walletBinding.addingWalletBindingId" | "vcUtilitiesState.walletBinding.generateKeyPair" | "vcUtilitiesState.walletBinding.requestingBindingOTP" | "vcUtilitiesState.walletBinding.showBindingWarning" | "vcUtilitiesState.walletBinding.showingWalletBindingError" | "vcUtilitiesState.walletBinding.updatingContextVariables" | "vcUtilitiesState.walletBinding.updatingPrivateKey" | "verifyState" | "verifyState.idle" | "verifyState.verificationCompleted" | "verifyState.verifyingCredential" | { "vcUtilitiesState"?: "idle" | "kebabPopUp" | "loadVc" | "verifyingCredential" | "walletBinding" | { "kebabPopUp"?: "idle" | "pinCard" | "removeWallet" | "removingVc" | "showActivities" | "triggerAutoBackup"; +"loadVc"?: "loadVcFromContext" | "loadVcFromServer" | { "loadVcFromContext"?: "fetchWellknown" | "idle"; +"loadVcFromServer"?: "checkingStatus" | "downloadingCredential" | "loadDownloadLimitConfig" | "savingFailed" | "verifyingDownloadLimitExpiry" | { "savingFailed"?: "idle" | "viewingVc"; }; }; +"verifyingCredential"?: "handleVCVerificationFailure" | "idle" | "triggerAutoBackupForVcDownload"; +"walletBinding"?: "acceptingBindingOTP" | "addKeyPair" | "addingWalletBindingId" | "generateKeyPair" | "requestingBindingOTP" | "showBindingWarning" | "showingWalletBindingError" | "updatingContextVariables" | "updatingPrivateKey" | { "acceptingBindingOTP"?: "idle" | "resendOTP"; }; }; +"verifyState"?: "idle" | "verificationCompleted" | "verifyingCredential"; }; + tags: never; + } + \ No newline at end of file diff --git a/machines/VerifiableCredential/VCItemMachine/VCItemServices.ts b/machines/VerifiableCredential/VCItemMachine/VCItemServices.ts index 63483fb808..a66bfe38c4 100644 --- a/machines/VerifiableCredential/VCItemMachine/VCItemServices.ts +++ b/machines/VerifiableCredential/VCItemMachine/VCItemServices.ts @@ -21,7 +21,7 @@ import {getMatchingCredentialIssuerMetadata} from '../../../shared/openId4VCI/Ut import {isIOS} from '../../../shared/constants'; import {VCMetadata} from '../../../shared/VCMetadata'; import {VCFormat} from '../../../shared/VCFormat'; -import {isMockVC} from '../../../shared/Utils'; +import {isMockVC, verifyCredentialData} from '../../../shared/Utils'; const {RNSecureKeystoreModule} = NativeModules; export const VCItemServices = model => { @@ -199,26 +199,16 @@ export const VCItemServices = model => { }, verifyCredential: async (context: any) => { - if (context.verifiableCredential) { - //TODO: Remove bypassing verification of mock VCs once mock VCs are verifiable - if ( - context.selectedCredentialType.format === VCFormat.mso_mdoc || - !isMockVC(context.selectedIssuerId) - ) { - const verificationResult = await verifyCredential( - getVerifiableCredential(context.verifiableCredential), - (context.vcMetadata as VCMetadata).format, - ); - if (!verificationResult.isVerified) { + if(context.verifiableCredential){ + const verificationResult = await verifyCredentialData( + getVerifiableCredential(context.verifiableCredential), + context.selectedCredentialType.format, + context.selectedIssuerId + ); + if(!verificationResult.isVerified) { throw new Error(verificationResult.verificationErrorCode); } - } else { - return { - isVerified: true, - verificationMessage: VerificationErrorMessage.NO_ERROR, - verificationErrorCode: VerificationErrorType.NO_ERROR, - }; - } + return verificationResult; } }, }; diff --git a/shared/Utils.ts b/shared/Utils.ts index b7abd0dbaa..a00ef89ccb 100644 --- a/shared/Utils.ts +++ b/shared/Utils.ts @@ -1,7 +1,10 @@ +import { VCFormat } from './VCFormat'; import {VCMetadata} from './VCMetadata'; +import { VerificationErrorMessage, VerificationErrorType, verifyCredential } from './vcjs/verifyCredential'; import {NETWORK_REQUEST_FAILED} from './constants'; import {groupBy} from './javascript'; import {Issuers} from './openId4VCI/Utils'; +import {Credential} from '../machines/VerifiableCredential/VCMetaMachine/vc'; export const getVCsOrderedByPinStatus = (vcMetadatas: VCMetadata[]) => { const [pinned, unpinned] = groupBy( @@ -53,4 +56,22 @@ export const parseJSON = (input: any) => { export const isNetworkError = (error: string) => { return error.includes(NETWORK_REQUEST_FAILED); -}; \ No newline at end of file +}; + +export async function verifyCredentialData( + credential: Credential, + credentialFormat: string, + issuerId: string +) { + + if (credentialFormat === VCFormat.mso_mdoc || !isMockVC(issuerId)) { + const verificationResult = await verifyCredential(credential, credentialFormat); + return verificationResult; + } else { + return { + isVerified: true, + verificationMessage: VerificationErrorMessage.NO_ERROR, + verificationErrorCode: VerificationErrorType.NO_ERROR, + }; + } +} \ No newline at end of file diff --git a/shared/backupUtils/restoreData.ts b/shared/backupUtils/restoreData.ts index 3222d51df8..5a6bb9df65 100644 --- a/shared/backupUtils/restoreData.ts +++ b/shared/backupUtils/restoreData.ts @@ -7,10 +7,7 @@ import Storage, { MMKV } from "../storage"; import { MY_VCS_STORE_KEY } from "../constants"; import { VCMetadata } from "../VCMetadata"; import { VCFormat } from "../VCFormat"; -import { isMockVC } from "../Utils"; -import { - verifyCredential, -} from '../vcjs/verifyCredential' +import { isMockVC, verifyCredentialData } from "../Utils"; export async function loadBackupData( data: string, @@ -163,15 +160,14 @@ async function handlePreviousBackup( vcKeys.map(async key => { const vcData = allVCs[key]; // Add randomness to timestamp to maintain uniqueness - const timestamp = - Date.now() + Math.random().toString().substring(2, 10); + const timestamp = Date.now() + Math.random().toString().substring(2, 10); const prevUnixTimeStamp = vcData.vcMetadata.timestamp; - // Verify and update the credential - const isVerified = await verifyCredentialData( - vcData, - vcData.vcMetadata, - ); + //verify the credential and update the metadata + const verifiableCredential = vcData.verifiableCredential?.credential || vcData.verifiableCredential; + const verificationResult = await verifyCredentialData(verifiableCredential, vcData.vcMetadata.format, vcData.vcMetadata.issuer) + const isVerified = verificationResult.isVerified; + vcData.vcMetadata.timestamp = timestamp; vcData.vcMetadata.isVerified = isVerified; @@ -197,28 +193,6 @@ async function handlePreviousBackup( ); } - /** - * Verify the restored credential - * @param vcData Verifiable Credential from backup - * @param vcMetadata VC metadata - */ - async function verifyCredentialData(vcData: any, vcMetadata: any) { - let isVerified = true; - const verifiableCredential = - vcData.verifiableCredential?.credential || vcData.verifiableCredential; - if ( - vcMetadata.format === VCFormat.mso_mdoc || - !isMockVC(vcMetadata.issuer) - ) { - const verificationResult = await verifyCredential( - verifiableCredential, - vcMetadata.format, - ); - isVerified = verificationResult.isVerified; - } - return isVerified; - } - /** * Update MMKV store with new VC metadata * @param dataFromDB Database data containing VC metadata diff --git a/shared/vcjs/verifyCredential.ts b/shared/vcjs/verifyCredential.ts index dc958c8bd4..db7937651d 100644 --- a/shared/vcjs/verifyCredential.ts +++ b/shared/vcjs/verifyCredential.ts @@ -32,82 +32,15 @@ const vcVerifier = NativeModules.VCVerifierModule; export async function verifyCredential( verifiableCredential: Credential, - credentialFormat: String, + credentialFormat: string ): Promise { try { - //ToDo - Have to remove else part once Vc Verifier Library is built for Swift if (isAndroid()) { - let vcVerifierResult = await vcVerifier.verifyCredentials( - typeof verifiableCredential === 'string' - ? verifiableCredential - : JSON.stringify(verifiableCredential), - credentialFormat, - ); - return handleVcVerifierResponse(vcVerifierResult, verifiableCredential); - } else { - //ToDo - Have to remove the condition once Vc Verifier Library is built for Swift to validate mso_mdoc - if (credentialFormat == VCFormat.mso_mdoc) { - return { - isVerified: true, - verificationMessage: VerificationErrorMessage.NO_ERROR, - verificationErrorCode: VerificationErrorType.NO_ERROR, - }; - } - let purpose: PublicKeyProofPurpose | AssertionProofPurpose; - const proof = verifiableCredential.proof; - - switch (proof.proofPurpose) { - case ProofPurpose.PublicKey: - purpose = new PublicKeyProofPurpose(); - break; - case ProofPurpose.Assertion: - purpose = new AssertionProofPurpose(); - break; - } - - let suite: Ed25519Signature2018 | RsaSignature2018; - const suiteOptions = { - verificationMethod: proof.verificationMethod, - date: proof.created, - }; - switch (proof.type) { - case ProofType.RSA: { - suite = new RsaSignature2018(suiteOptions); - break; - } - case ProofType.ED25519_2018: { - suite = new Ed25519Signature2018(suiteOptions); - break; - } - /* - Since Digital Bazaar library is not able to verify ProofType: "Ed25519Signature2020", - defaulting it to return true until VcVerifier is implemented for iOS. - */ - case ProofType.ED25519_2020: { - return { - isVerified: true, - verificationMessage: VerificationErrorMessage.NO_ERROR, - verificationErrorCode: VerificationErrorType.NO_ERROR, - }; - } - } - - const vcjsOptions = { - purpose, - suite, - credential: verifiableCredential, - documentLoader: jsonld.documentLoaders.xhr(), - }; - - //ToDo - Have to remove once range error is fixed during verification - const result = await vcjs.verifyCredential(vcjsOptions); - return handleResponse(result, verifiableCredential); + return await verifyCredentialForAndroid(verifiableCredential, credentialFormat); } + return await verifyCredentialForIos(verifiableCredential, credentialFormat); } catch (error) { - console.error( - 'Error occurred while verifying the VC using digital bazaar:', - error, - ); + console.error('Error occurred during credential verification:', error); return { isVerified: false, @@ -117,6 +50,73 @@ export async function verifyCredential( } } +async function verifyCredentialForAndroid( + verifiableCredential: Credential, + credentialFormat: string +): Promise { + const credentialString = typeof verifiableCredential === 'string' + ? verifiableCredential + : JSON.stringify(verifiableCredential); + + const vcVerifierResult = await vcVerifier.verifyCredentials(credentialString, credentialFormat); + return handleVcVerifierResponse(vcVerifierResult, verifiableCredential); +} + +async function verifyCredentialForIos( + verifiableCredential: Credential, + credentialFormat: string +): Promise { + if (credentialFormat === VCFormat.mso_mdoc) { + return createSuccessfulVerificationResult(); + } + /* + Since Digital Bazaar library is not able to verify ProofType: "Ed25519Signature2020", + defaulting it to return true until VcVerifier is implemented for iOS. + */ + if (verifiableCredential.proof.type === ProofType.ED25519_2020) { + return createSuccessfulVerificationResult(); + } + + const purpose = getPurposeFromProof(verifiableCredential.proof.proofPurpose); + const suite = selectVerificationSuite(verifiableCredential.proof); + const vcjsOptions = { + purpose, + suite, + credential: verifiableCredential, + documentLoader: jsonld.documentLoaders.xhr(), + }; + + const result = await vcjs.verifyCredential(vcjsOptions); + return handleResponse(result, verifiableCredential); +} + +function getPurposeFromProof(proofPurpose) { + switch (proofPurpose) { + case ProofPurpose.PublicKey: + return new vcjs.PublicKeyProofPurpose(); + case ProofPurpose.Assertion: + return new vcjs.AssertionProofPurpose(); + default: + throw new Error('Unsupported proof purpose'); + } +} + +function selectVerificationSuite(proof: any) { + const suiteOptions = { + verificationMethod: proof.verificationMethod, + date: proof.created, + }; + + switch (proof.type) { + case ProofType.RSA: + return new RsaSignature2018(suiteOptions); + case ProofType.ED25519_2018: + return new Ed25519Signature2018(suiteOptions); + default: + throw new Error('Unsupported proof type'); + } +} + function handleResponse( result: any, verifiableCredential: VerifiableCredential | Credential, @@ -159,8 +159,7 @@ function handleVcVerifierResponse( ): VerificationResult { try { if (!verificationResult.verificationStatus) { - verificationResult.verificationErrorCode = - verificationResult.verificationErrorCode === '' + verificationResult.verificationErrorCode = verificationResult.verificationErrorCode === '' ? VerificationErrorType.GENERIC_TECHNICAL_ERROR : verificationResult.verificationErrorCode; sendVerificationErrorEvent( @@ -187,6 +186,14 @@ function handleVcVerifierResponse( } } +function createSuccessfulVerificationResult(): VerificationResult { + return { + isVerified: true, + verificationMessage: VerificationErrorMessage.NO_ERROR, + verificationErrorCode: VerificationErrorType.NO_ERROR, + }; +} + function sendVerificationErrorEvent( errorMessage: string, verifiableCredential: any, From 32fb1d541da4a745f4172ddbef4109e44b6c9988 Mon Sep 17 00:00:00 2001 From: Alka Prasad Date: Thu, 19 Dec 2024 10:12:17 +0530 Subject: [PATCH 5/5] [INJIMOB-2571]: move verifyCredentialData method under OpenIdVCI Signed-off-by: Alka Prasad --- machines/Issuers/IssuersService.ts | 28 ++++----- .../VCItemMachine/VCItemServices.ts | 22 +++---- shared/Utils.ts | 29 ++------- shared/backupUtils/restoreData.ts | 11 ++-- shared/openId4VCI/Utils.ts | 63 ++++++++++++------- 5 files changed, 69 insertions(+), 84 deletions(-) diff --git a/machines/Issuers/IssuersService.ts b/machines/Issuers/IssuersService.ts index 35bf26e35d..5100172f1b 100644 --- a/machines/Issuers/IssuersService.ts +++ b/machines/Issuers/IssuersService.ts @@ -1,6 +1,12 @@ -import Cloud from '../../shared/CloudBackupAndRestoreUtils'; -import {CACHED_API} from '../../shared/api'; import NetInfo from '@react-native-community/netinfo'; +import { NativeModules } from 'react-native'; +import { authorize } from 'react-native-app-auth'; +import Cloud from '../../shared/CloudBackupAndRestoreUtils'; +import { CACHED_API } from '../../shared/api'; +import { + fetchKeyPair, + generateKeyPair, +} from '../../shared/cryptoutil/cryptoUtil'; import { constructAuthorizationConfiguration, constructIssuerMetaData, @@ -9,26 +15,14 @@ import { OIDCErrors, updateCredentialInformation, vcDownloadTimeout, + verifyCredentialData } from '../../shared/openId4VCI/Utils'; -import {authorize} from 'react-native-app-auth'; -import { - fetchKeyPair, - generateKeyPair, -} from '../../shared/cryptoutil/cryptoUtil'; -import {NativeModules} from 'react-native'; -import { - VerificationErrorMessage, - VerificationErrorType, - verifyCredential, -} from '../../shared/vcjs/verifyCredential'; +import { TelemetryConstants } from '../../shared/telemetry/TelemetryConstants'; import { getImpressionEventData, sendImpressionEvent, } from '../../shared/telemetry/TelemetryUtils'; -import {TelemetryConstants} from '../../shared/telemetry/TelemetryConstants'; -import {VciClient} from '../../shared/vciClient/VciClient'; -import {isMockVC, verifyCredentialData} from '../../shared/Utils'; -import {VCFormat} from '../../shared/VCFormat'; +import { VciClient } from '../../shared/vciClient/VciClient'; export const IssuersService = () => { return { diff --git a/machines/VerifiableCredential/VCItemMachine/VCItemServices.ts b/machines/VerifiableCredential/VCItemMachine/VCItemServices.ts index a66bfe38c4..962eb53565 100644 --- a/machines/VerifiableCredential/VCItemMachine/VCItemServices.ts +++ b/machines/VerifiableCredential/VCItemMachine/VCItemServices.ts @@ -1,27 +1,19 @@ -import {NativeModules} from 'react-native'; -import Cloud from '../../../shared/CloudBackupAndRestoreUtils'; +import { NativeModules } from 'react-native'; import getAllConfigurations, { API_URLS, CACHED_API, DownloadProps, } from '../../../shared/api'; +import Cloud from '../../../shared/CloudBackupAndRestoreUtils'; +import { isIOS } from '../../../shared/constants'; import { fetchKeyPair, generateKeyPair, } from '../../../shared/cryptoutil/cryptoUtil'; -import {CredentialDownloadResponse, request} from '../../../shared/request'; -import {WalletBindingResponse} from '../VCMetaMachine/vc'; -import { - VerificationErrorMessage, - VerificationErrorType, - verifyCredential, -} from '../../../shared/vcjs/verifyCredential'; -import {getVerifiableCredential} from './VCItemSelectors'; -import {getMatchingCredentialIssuerMetadata} from '../../../shared/openId4VCI/Utils'; -import {isIOS} from '../../../shared/constants'; -import {VCMetadata} from '../../../shared/VCMetadata'; -import {VCFormat} from '../../../shared/VCFormat'; -import {isMockVC, verifyCredentialData} from '../../../shared/Utils'; +import { getMatchingCredentialIssuerMetadata, verifyCredentialData } from '../../../shared/openId4VCI/Utils'; +import { CredentialDownloadResponse, request } from '../../../shared/request'; +import { WalletBindingResponse } from '../VCMetaMachine/vc'; +import { getVerifiableCredential } from './VCItemSelectors'; const {RNSecureKeystoreModule} = NativeModules; export const VCItemServices = model => { diff --git a/shared/Utils.ts b/shared/Utils.ts index a00ef89ccb..a83da8c373 100644 --- a/shared/Utils.ts +++ b/shared/Utils.ts @@ -1,10 +1,7 @@ -import { VCFormat } from './VCFormat'; -import {VCMetadata} from './VCMetadata'; -import { VerificationErrorMessage, VerificationErrorType, verifyCredential } from './vcjs/verifyCredential'; -import {NETWORK_REQUEST_FAILED} from './constants'; -import {groupBy} from './javascript'; -import {Issuers} from './openId4VCI/Utils'; -import {Credential} from '../machines/VerifiableCredential/VCMetaMachine/vc'; +import { VCMetadata } from './VCMetadata'; +import { NETWORK_REQUEST_FAILED } from './constants'; +import { groupBy } from './javascript'; +import { Issuers } from './openId4VCI/Utils'; export const getVCsOrderedByPinStatus = (vcMetadatas: VCMetadata[]) => { const [pinned, unpinned] = groupBy( @@ -57,21 +54,3 @@ export const parseJSON = (input: any) => { export const isNetworkError = (error: string) => { return error.includes(NETWORK_REQUEST_FAILED); }; - -export async function verifyCredentialData( - credential: Credential, - credentialFormat: string, - issuerId: string -) { - - if (credentialFormat === VCFormat.mso_mdoc || !isMockVC(issuerId)) { - const verificationResult = await verifyCredential(credential, credentialFormat); - return verificationResult; - } else { - return { - isVerified: true, - verificationMessage: VerificationErrorMessage.NO_ERROR, - verificationErrorCode: VerificationErrorType.NO_ERROR, - }; - } -} \ No newline at end of file diff --git a/shared/backupUtils/restoreData.ts b/shared/backupUtils/restoreData.ts index 5a6bb9df65..72c6f8af21 100644 --- a/shared/backupUtils/restoreData.ts +++ b/shared/backupUtils/restoreData.ts @@ -1,13 +1,12 @@ import { DocumentDirectoryPath } from "react-native-fs"; -import fileStorage from "../fileStorage"; -import { getErrorEventData, sendErrorEvent } from "../telemetry/TelemetryUtils"; -import { TelemetryConstants } from "../telemetry/TelemetryConstants"; +import { MY_VCS_STORE_KEY } from "../constants"; import { decryptJson, encryptJson } from "../cryptoutil/cryptoUtil"; +import fileStorage from "../fileStorage"; import Storage, { MMKV } from "../storage"; -import { MY_VCS_STORE_KEY } from "../constants"; +import { TelemetryConstants } from "../telemetry/TelemetryConstants"; +import { getErrorEventData, sendErrorEvent } from "../telemetry/TelemetryUtils"; import { VCMetadata } from "../VCMetadata"; -import { VCFormat } from "../VCFormat"; -import { isMockVC, verifyCredentialData } from "../Utils"; +import { verifyCredentialData } from "../openId4VCI/Utils"; export async function loadBackupData( data: string, diff --git a/shared/openId4VCI/Utils.ts b/shared/openId4VCI/Utils.ts index 4a12c73800..fab447a4ac 100644 --- a/shared/openId4VCI/Utils.ts +++ b/shared/openId4VCI/Utils.ts @@ -1,32 +1,35 @@ -import jwtDecode from 'jwt-decode'; -import jose from 'node-jose'; -import {isIOS} from '../constants'; -import {displayType, issuerType} from '../../machines/Issuers/IssuersMachine'; -import getAllConfigurations, {CACHED_API} from '../api'; import base64url from 'base64url'; import i18next from 'i18next'; -import {getJWT, replaceCharactersInB64} from '../cryptoutil/cryptoUtil'; +import jwtDecode from 'jwt-decode'; +import jose from 'node-jose'; +import { NativeModules } from 'react-native'; +import { vcVerificationBannerDetails } from '../../components/BannerNotificationContainer'; +import { VCProcessor } from '../../components/VC/common/VCProcessor'; +import { + BOTTOM_SECTION_FIELDS_WITH_DETAILED_ADDRESS_FIELDS, + DETAIL_VIEW_ADD_ON_FIELDS, + getCredentialTypeFromWellKnown, +} from '../../components/VC/common/VCUtils'; import i18n from '../../i18n'; +import { displayType, issuerType } from '../../machines/Issuers/IssuersMachine'; +import { getVerifiableCredential } from '../../machines/VerifiableCredential/VCItemMachine/VCItemSelectors'; import { + Credential, CredentialTypes, CredentialWrapper, VerifiableCredential, } from '../../machines/VerifiableCredential/VCMetaMachine/vc'; -import { - BOTTOM_SECTION_FIELDS_WITH_DETAILED_ADDRESS_FIELDS, - DETAIL_VIEW_ADD_ON_FIELDS, - getCredentialTypeFromWellKnown, -} from '../../components/VC/common/VCUtils'; -import {getVerifiableCredential} from '../../machines/VerifiableCredential/VCItemMachine/VCItemSelectors'; -import {vcVerificationBannerDetails} from '../../components/BannerNotificationContainer'; -import {getErrorEventData, sendErrorEvent} from '../telemetry/TelemetryUtils'; -import {TelemetryConstants} from '../telemetry/TelemetryConstants'; -import {NativeModules} from 'react-native'; -import {KeyTypes} from '../cryptoutil/KeyTypes'; -import {VCFormat} from '../VCFormat'; -import {UnsupportedVcFormat} from '../error/UnsupportedVCFormat'; -import {VCMetadata} from '../VCMetadata'; -import {VCProcessor} from '../../components/VC/common/VCProcessor'; +import getAllConfigurations, { CACHED_API } from '../api'; +import { isIOS } from '../constants'; +import { getJWT } from '../cryptoutil/cryptoUtil'; +import { KeyTypes } from '../cryptoutil/KeyTypes'; +import { UnsupportedVcFormat } from '../error/UnsupportedVCFormat'; +import { TelemetryConstants } from '../telemetry/TelemetryConstants'; +import { getErrorEventData, sendErrorEvent } from '../telemetry/TelemetryUtils'; +import { isMockVC } from '../Utils'; +import { VCFormat } from '../VCFormat'; +import { VerificationErrorMessage, VerificationErrorType, verifyCredential } from '../vcjs/verifyCredential'; +import { VCMetadata } from '../VCMetadata'; export const Protocols = { OpenId4VCI: 'OpenId4VCI', @@ -438,3 +441,21 @@ export function getMatchingCredentialIssuerMetadata( `Selected credential type - ${credentialConfigurationId} is not available in wellknown config supported credentials list`, ); } + +export async function verifyCredentialData( + credential: Credential, + credentialFormat: string, + issuerId: string +) { + + if (credentialFormat === VCFormat.mso_mdoc || !isMockVC(issuerId)) { + const verificationResult = await verifyCredential(credential, credentialFormat); + return verificationResult; + } else { + return { + isVerified: true, + verificationMessage: VerificationErrorMessage.NO_ERROR, + verificationErrorCode: VerificationErrorType.NO_ERROR, + }; + } +} \ No newline at end of file