mirror of
https://github.com/mosip/inji-wallet.git
synced 2026-01-09 13:38:01 -05:00
[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:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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]'
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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]'
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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 ?? '',
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -14,6 +14,7 @@ export const TelemetryConstants = {
|
||||
fetchData: 'Fetch Data',
|
||||
dataBackup: 'Data Backup',
|
||||
dataRestore: 'Data Restore',
|
||||
decryption: 'Decryption',
|
||||
dataBackupAndRestoreSetup: 'Data Backup & Restore Setup',
|
||||
}),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user