[INJIMOB-799] append timestamp to the restored vc vckey to make it unique (#1230)

* [INJIMOB-799] append timestamp to the restored vc vckey to make it unique

Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-799] set isPinned status to false for all VCs before generating backup file

Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-799] add timestamp to the vcMetadata and add it to the restored vc vckey to make it unique

Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-799] send error event when exporting data is failed and refactor the way of setting timestamp in metadata

Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-799] call getVcKey method on vcMetadata class instance not directly on vc metadata

Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-799] update vc item machine typegen files

Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

---------

Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
Signed-off-by: Swati Goel <meet2swati@gmail.com>
Co-authored-by: Swati Goel <meet2swati@gmail.com>
This commit is contained in:
PuBHARGAVI
2024-02-09 12:11:31 +05:30
committed by GitHub
parent 43395d179a
commit f7a68c7419
12 changed files with 83 additions and 43 deletions

View File

@@ -140,7 +140,7 @@ fileignoreconfig:
- filename: ios/fastlane/Fastfile
checksum: a4e3772dc67a07ecbcfc58be0d6d4f7fa799cec7ac25bd269ac29459c8669ca4
- filename: shared/storage.ts
checksum: 5700dbefff3da97dc85be1d171bd80a3e72d6f488e77db4044a14520cbc1642a
checksum: 5b503c02ccb57b7576fb2b038a3e9a59f425a67311d624169bb4bd69721542e4
- filename: injitest/src/test/java/iosTestCases/CredentialRegistryTest.java
checksum: b0808e0c511412cde21fd169a9bbeaf3b77cb48f25418e12d341cc3ce1df5898
- filename: machines/backupAndRestore/backupAndRestore.ts

View File

@@ -588,7 +588,7 @@ export const EsignetMosipVCItemMachine = model.createMachine(
sendActivationFailedEndEvent: (context, event, meta) => {
const [errorId, errorMessage] =
event.data.message === 'Could not store private key in keystore'
event.data?.message === 'Could not store private key in keystore'
? [
TelemetryConstants.ErrorId.updatePrivateKey,
TelemetryConstants.ErrorMessage.privateKeyUpdationFailed,

View File

@@ -78,7 +78,6 @@ export interface Typegen0 {
removedVc: 'STORE_RESPONSE';
requestStoredContext: 'GET_VC_RESPONSE' | 'REFRESH';
requestVcContext: 'DISMISS' | 'xstate.init';
resetWalletBindingSuccess: 'DISMISS';
sendActivationFailedEndEvent:
| 'DISMISS'
| 'error.platform.vc-item-openid4vci.updatingPrivateKey:invocation[0]';
@@ -114,7 +113,6 @@ export interface Typegen0 {
setWalletBindingId:
| 'done.invoke.vc-item-openid4vci.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item-openid4vci.updatingPrivateKey:invocation[0]';
setWalletBindingSuccess: 'SHOW_BINDING_STATUS';
storeContext:
| 'PIN_CARD'
| 'done.invoke.vc-item-openid4vci.addingWalletBindingId:invocation[0]'

View File

@@ -843,7 +843,7 @@ export const ExistingMosipVCItemMachine =
sendActivationFailedEndEvent: (context, event, meta) => {
const [errorId, errorMessage] =
event.data.message === 'Could not store private key in keystore'
event.data?.message === 'Could not store private key in keystore'
? [
TelemetryConstants.ErrorId.updatePrivateKey,
TelemetryConstants.ErrorMessage.privateKeyUpdationFailed,

View File

@@ -180,7 +180,6 @@ export interface Typegen0 {
removeVcMetaDataFromVcMachine: 'DISMISS';
requestStoredContext: 'GET_VC_RESPONSE' | 'REFRESH';
requestVcContext: 'DISMISS' | 'xstate.init';
resetWalletBindingSuccess: 'DISMISS';
revokeVID: 'done.invoke.vc-item.requestingRevoke:invocation[0]';
sendActivationFailedEndEvent:
| 'DISMISS'
@@ -235,7 +234,6 @@ export interface Typegen0 {
setWalletBindingId:
| 'done.invoke.vc-item.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item.updatingPrivateKey:invocation[0]';
setWalletBindingSuccess: 'SHOW_BINDING_STATUS';
storeContext:
| 'CREDENTIAL_DOWNLOADED'
| 'done.invoke.vc-item.addingWalletBindingId:invocation[0]'

View File

@@ -246,7 +246,8 @@ export const vcMachine =
})),
getVcItemResponse: respond((context, event) => {
const vc = context.vcs[event.vcMetadata?.getVcKey()];
const vc =
context.vcs[VCMetadata.fromVC(event.vcMetadata)?.getVcKey()];
if (event.protocol === Protocols.OpenId4VCI) {
return EsignetMosipVCItemEvents.GET_VC_RESPONSE(vc);
}

View File

@@ -466,10 +466,10 @@ export const IssuersMachine = model.createMachine(
storeVerifiableCredentialData: send(
context =>
StoreEvents.SET(
getVCMetadata(context).getVcKey(),
context.credentialWrapper,
),
StoreEvents.SET(getVCMetadata(context).getVcKey(), {
...context.credentialWrapper,
vcMetadata: getVCMetadata(context),
}),
{
to: context => context.serviceRefs.store,
},

View File

@@ -12,6 +12,7 @@ export class VCMetadata {
issuer?: string = '';
protocol?: string = '';
timestamp?: string = '';
static vcKeyRegExp = new RegExp(VC_ITEM_STORE_KEY_REGEX);
constructor({
@@ -21,6 +22,7 @@ export class VCMetadata {
id = '',
issuer = '',
protocol = '',
timestamp = '',
} = {}) {
this.idType = idType;
this.requestId = requestId;
@@ -28,6 +30,7 @@ export class VCMetadata {
this.id = id;
this.protocol = protocol;
this.issuer = issuer;
this.timestamp = timestamp;
}
//TODO: Remove any typing and use appropriate typing
@@ -39,6 +42,7 @@ export class VCMetadata {
id: vc.id,
protocol: vc.protocol,
issuer: vc.issuer,
timestamp: vc.timestamp,
});
}
@@ -64,7 +68,9 @@ export class VCMetadata {
// Used for mmkv storage purposes and as a key for components and vc maps
// Update VC_ITEM_STORE_KEY_REGEX in case of changes in vckey
getVcKey(): string {
return `${VC_KEY_PREFIX}_${this.requestId}`;
return this.timestamp !== ''
? `${VC_KEY_PREFIX}_${this.timestamp}_${this.requestId}`
: `${VC_KEY_PREFIX}_${this.requestId}`;
}
equals(other: VCMetadata): boolean {

View File

@@ -4,6 +4,8 @@ import {BIOMETRIC_CANCELLED, DEBUG_MODE_ENABLED, isIOS} from '../constants';
import SecureKeystore from '@mosip/secure-keystore';
import {BiometricCancellationError} from '../error/BiometricCancellationError';
import {EncryptedOutput} from './encryptedOutput';
import {getErrorEventData, sendErrorEvent} from '../telemetry/TelemetryUtils';
import {TelemetryConstants} from '../telemetry/TelemetryConstants';
// 5min
export const AUTH_TIMEOUT = 5 * 60;
@@ -142,6 +144,13 @@ export async function decryptJson(
return await SecureKeystore.decryptData(ENCRYPTION_ID, encryptedData);
} catch (e) {
sendErrorEvent(
getErrorEventData(
TelemetryConstants.FlowType.decryption,
e.message,
e.stack,
),
);
console.error('error decryptJson:', e);
if (e.toString().includes(BIOMETRIC_CANCELLED)) {

View File

@@ -125,6 +125,7 @@ export const getVCMetadata = context => {
id: context.verifiableCredential?.credential.credentialSubject.UIN
? context.verifiableCredential?.credential.credentialSubject.UIN
: context.verifiableCredential?.credential.credentialSubject.VID,
timestamp: context.timestamp ?? '',
});
};

View File

@@ -52,42 +52,56 @@ async function generateHmac(
class Storage {
static exportData = async (encryptionKey: string) => {
const completeBackupData = {};
const dataFromDB: Record<string, any> = {};
try {
const completeBackupData = {};
let dataFromDB: Record<string, any> = {};
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 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),
);
Promise.all(encryptedDataPromises).then(encryptedDataList => {
keysToBeExported.forEach(async (key, index) => {
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['dataFromDB'] = dataFromDB;
completeBackupData['VC_Records'] = {};
completeBackupData['dataFromDB'] = dataFromDB;
completeBackupData['VC_Records'] = {};
let vcKeys = allKeysInDB.filter(key => key.indexOf('VC_') === 0);
for (let ind in vcKeys) {
const key = vcKeys[ind];
const vc = await Storage.readVCFromFile(key);
const decryptedVCData = await decryptJson(encryptionKey, vc);
const deactivatedVC =
removeWalletBindingDataBeforeBackup(decryptedVCData);
completeBackupData['VC_Records'][key] = deactivatedVC;
let vcKeys = allKeysInDB.filter(key => key.indexOf('VC_') === 0);
for (let ind in vcKeys) {
const key = vcKeys[ind];
const vc = await Storage.readVCFromFile(key);
const decryptedVCData = await decryptJson(encryptionKey, vc);
const deactivatedVC =
removeWalletBindingDataBeforeBackup(decryptedVCData);
completeBackupData['VC_Records'][key] = deactivatedVC;
}
return completeBackupData;
} catch (error) {
sendErrorEvent(
getErrorEventData(
TelemetryConstants.FlowType.dataBackup,
error.message,
error.stack,
),
);
console.error('exporting data is failed due to this error:', error);
}
return completeBackupData;
};
static loadBackupData = async (data, encryptionKey) => {
@@ -208,13 +222,25 @@ class Storage {
private static async loadVCs(completeBackupData: any, encryptionKey: any) {
const allVCs = completeBackupData['VC_Records'];
const allVCKeys = Object.keys(allVCs);
allVCKeys.forEach(async key => {
const vc = allVCs[key];
const encryptedVC = await encryptJson(encryptionKey, JSON.stringify(vc));
await this.setItem(key, encryptedVC, encryptionKey);
});
const dataFromDB = completeBackupData['dataFromDB'];
allVCKeys.forEach(async key => {
let vc = allVCs[key];
const currentUnixTimeStamp = Date.now();
const prevUnixTimeStamp = vc.vcMetadata.timestamp;
vc.vcMetadata.timestamp = currentUnixTimeStamp;
dataFromDB.myVCs.forEach(myVcMetadata => {
if (
myVcMetadata.requestId === vc.vcMetadata.requestId &&
myVcMetadata.timestamp === prevUnixTimeStamp
) {
myVcMetadata.timestamp = currentUnixTimeStamp;
}
});
const updatedVcKey = new VCMetadata(vc.vcMetadata).getVcKey();
const encryptedVC = await encryptJson(encryptionKey, JSON.stringify(vc));
await this.setItem(updatedVcKey, encryptedVC, encryptionKey);
});
const dataFromMyVCKey = dataFromDB[MY_VCS_STORE_KEY];
const encryptedMyVCKeyFromMMKV = await MMKV.getItem(MY_VCS_STORE_KEY);
let newDataForMyVCKey;

View File

@@ -14,6 +14,7 @@ export const TelemetryConstants = {
fetchData: 'Fetch Data',
dataBackup: 'Data Backup',
dataRestore: 'Data Restore',
decryption: 'Decryption',
dataBackupAndRestoreSetup: 'Data Backup & Restore Setup',
}),