diff --git a/.talismanrc b/.talismanrc index e69de29b..1bceb538 100644 --- a/.talismanrc +++ b/.talismanrc @@ -0,0 +1,29 @@ +fileignoreconfig: +- filename: package.json + checksum: 30e3a548809705ba38385a1c286b312629ac5dd7dea0d6e26ffb9daf8def312d +- filename: package-lock.json + checksum: 4d595248dfa13967eef07ffee65f86809672a0d145d74b9df55b296bdbe29f78 +- filename: components/PasscodeVerify.tsx + checksum: 14654c0f038979fcd0d260170a45894a072f81e0767ca9a0e66935d33b5cc703 +- filename: i18n.ts + checksum: 75dd5536038ba198aa7b12eb6d2c2e7042c9ce292e5a0d5c90883ae5b2312b1e +- filename: screens/BiometricScreenController.ts + checksum: b3d0184fb894f4a9ffa1a4d277d2975495dbc47771593895bf1999deabafeb94 +- filename: screens/Home/MyVcs/IdInputModal.tsx + checksum: ec48ebeaf46b8fbc756f19ef8ffe8901ce0528aef164f3c7ffdeec36fb53ffc6 +- filename: components/Passcode.tsx + checksum: db4a18001be8c63bf7ffb389359861401fa1d22261b10ad729a76fd431c019a7 +- filename: screens/PasscodeScreen.tsx + checksum: 0cc5b91350e491a058ee8a1878a496c16b65f14969e989bdb1c354f6e9b8c03c +- filename: locales/spa.json + checksum: 981103ff872d6f54610468c7ead65873d9294a11092649b105c552f770f0214b +- filename: screens/AuthScreen.tsx + checksum: 2c1183b2ad8ec27adf8f389a2511805493f229fdda674064e2579d2032119d1c +- filename: screens/BiometricScreen.tsx + checksum: 7a730731aaa7540eec9d05d73de277a665dc06425666280842e0f9ba6e5b8514 +- filename: screens/AuthScreenController.ts + checksum: 18af825821bc95e1056050623b804a5a8e7435b9e3383916a5d63024eeba9553 +- filename: screens/WelcomeScreenController.ts + checksum: d8fe74404c80bf435459f4d20427a661fb622f0ee9f754345616abd346b98d14 +- filename: shared/telemetry/TelemetryUtils.js + checksum: 9a61cd59a3718adf1f14faf3024fec66a3295ef373878a878a28e5cb1287afaa diff --git a/machines/store.ts b/machines/store.ts index c627e6da..7ca566ba 100644 --- a/machines/store.ts +++ b/machines/store.ts @@ -25,6 +25,7 @@ import { isCustomSecureKeystore, } from '../shared/cryptoutil/cryptoUtil'; import {VCMetadata} from '../shared/VCMetadata'; +import FileStorage, {getFilePath} from '../shared/fileStorage'; export const keyinvalidatedString = 'Key Invalidated due to biometric enrollment'; @@ -173,7 +174,7 @@ export const storeMachine = }, }, ready: { - entry: 'notifyParent', + entry: ['notifyParent', 'cacheVCFilesData'], invoke: { src: 'store', id: '_store', @@ -259,6 +260,18 @@ export const storeMachine = setEncryptionKey: model.assign({ encryptionKey: (_, event) => event.key, }), + + cacheVCFilesData: context => { + getItem(MY_VCS_STORE_KEY, [], context.encryptionKey).then(vcList => { + if (vcList) { + vcList?.forEach((vcMetadataStr: string) => { + const vcKey = + VCMetadata.fromVcMetadataString(vcMetadataStr).getVcKey(); + FileStorage.readAndCacheFile(getFilePath(vcKey)); + }); + } + }); + }, }, services: { @@ -289,6 +302,7 @@ export const storeMachine = ); } }, + checkStorageInitialisedOrNot: () => async callback => { const isDirectoryExist = await Storage.isVCStorageInitialised(); if (!isDirectoryExist) { diff --git a/package-lock.json b/package-lock.json index 1ca6f9ca..1e7e40ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -84,7 +84,7 @@ "react-native-vector-icons": "^10.0.0", "short-unique-id": "^4.4.4", "simple-pem2jwk": "^0.2.4", - "telemetry-sdk": "git://github.com/mosip/sunbird-telemetry-sdk.git#f762be5732ee552c0c70bdd540aa4e2701554c71", + "telemetry-sdk": "git://github.com/mosip/sunbird-telemetry-sdk.git#develop", "xstate": "^4.35.0" }, "devDependencies": { @@ -53475,7 +53475,7 @@ "telemetry-sdk": { "version": "git+ssh://git@github.com/mosip/sunbird-telemetry-sdk.git#f762be5732ee552c0c70bdd540aa4e2701554c71", "integrity": "sha512-aeA7uO77JzNQVSuUpxzUXK3I+BtYiOzDhcmYbD6R3pAETun4toP1/GR5PBfT9/iE3N5MdGJg70sQArwCIL1XaQ==", - "from": "telemetry-sdk@git://github.com/mosip/sunbird-telemetry-sdk.git#f762be5732ee552c0c70bdd540aa4e2701554c71", + "from": "telemetry-sdk@git://github.com/mosip/sunbird-telemetry-sdk.git#develop", "requires": { "axios": "^1.4.0", "grunt-karma": "^0.12.2", diff --git a/shared/fileStorage.ts b/shared/fileStorage.ts new file mode 100644 index 00000000..3863e365 --- /dev/null +++ b/shared/fileStorage.ts @@ -0,0 +1,87 @@ +import { + DocumentDirectoryPath, + exists, + mkdir, + readFile, + stat, + unlink, + writeFile, +} from 'react-native-fs'; + +interface CacheData { + data?: any; + count?: number; +} + +interface Cache { + [key: string]: CacheData; +} + +class FileStorage { + cache: Cache = {}; + + async readFile(path: string) { + return await readFile(path, 'utf8'); + } + + async readFromCacheFile(path: string) { + if (this.cache[path]?.data) { + const count = this.cache[path]?.count ?? 0; + const data = this.cache[path]?.data; + + if (count != undefined && count <= 1) { + this.cache[path] = {}; + } else { + this.cache[path].count = count - 1; + } + + return data; + } + + return this.readFile(path); + } + + async readAndCacheFile(path: string, useCount: number = 1) { + const data = await this.readFile(path); + + this.cache[path] = { + data, + count: useCount, + }; + + return data; + } + + async writeFile(path: string, data: string) { + return await writeFile(path, data, 'utf8'); + } + + async createDirectory(path: string) { + return await mkdir(path); + } + + async exists(path: string) { + return await exists(path); + } + + async removeItem(path: string) { + return await unlink(path); + } + + async getInfo(path: string) { + return await stat(path); + } +} + +export default new FileStorage(); + +/** + * iOS: /var/mobile/Containers/Data/Application/196A05AD-6B11-403D-BA2D-6DC1F30075E1/Documents/inji/VC/ + * android: /data/user/0/io.mosip.residentapp/files/inji/VC/ + * These paths are coming from DocumentDirectoryPath in react-native-fs. + */ +export const getFilePath = (key: string) => { + return `${vcDirectoryPath}/${key}.txt`; +}; + +export const vcDirectoryPath = `${DocumentDirectoryPath}/inji/VC`; diff --git a/shared/storage.ts b/shared/storage.ts index a4cd4fc0..07ddfe16 100644 --- a/shared/storage.ts +++ b/shared/storage.ts @@ -1,14 +1,5 @@ import {MMKVLoader} from 'react-native-mmkv-storage'; import CryptoJS from 'crypto-js'; -import { - DocumentDirectoryPath, - exists, - mkdir, - readFile, - stat, - unlink, - writeFile, -} from 'react-native-fs'; import getAllConfigurations from './commonprops/commonProps'; import {Platform} from 'react-native'; import { @@ -25,9 +16,9 @@ import { import {VCMetadata} from './VCMetadata'; import {ENOENT, getItem} from '../machines/store'; import {MY_VCS_STORE_KEY, RECEIVED_VCS_STORE_KEY} from './constants'; +import FileStorage, {getFilePath, vcDirectoryPath} from './fileStorage'; export const MMKV = new MMKVLoader().initialize(); -const vcDirectoryPath = `${DocumentDirectoryPath}/inji/VC`; export const API_CACHED_STORAGE_KEYS = { fetchIssuers: 'CACHE_FETCH_ISSUERS', @@ -48,7 +39,7 @@ async function generateHmac( class Storage { static isVCStorageInitialised = async (): Promise => { try { - const res = await stat(vcDirectoryPath); + const res = await FileStorage.getInfo(vcDirectoryPath); return res.isDirectory(); } catch (_) { return false; @@ -148,7 +139,7 @@ class Storage { } private static async readHmacForVC(key: string, encryptionKey: string) { - const encryptedHMACofCurrentVC = await MMKV.getItem(getVCKeyName(key)); + const encryptedHMACofCurrentVC = await MMKV.getItem(key); if (encryptedHMACofCurrentVC) { return decryptJson(encryptionKey, encryptedHMACofCurrentVC); } @@ -156,14 +147,13 @@ class Storage { } private static async readVCFromFile(key: string) { - const path = getFilePath(key); - return await readFile(path, 'utf8'); + return await FileStorage.readFromCacheFile(getFilePath(key)); } private static async storeVC(key: string, data: string) { - await mkdir(vcDirectoryPath); + await FileStorage.createDirectory(vcDirectoryPath); const path = getFilePath(key); - return await writeFile(path, data, 'utf8'); + return await FileStorage.writeFile(path, data); } private static async storeVcHmac( @@ -174,15 +164,15 @@ class Storage { const HMACofVC = await generateHmac(encryptionKey, data); console.log('[Inji-406]: Updating hmac of the vc: ', HMACofVC); const encryptedHMACofVC = await encryptJson(encryptionKey, HMACofVC); - await MMKV.setItem(getVCKeyName(key), encryptedHMACofVC); + await MMKV.setItem(key, encryptedHMACofVC); } static removeItem = async (key: string) => { if (VCMetadata.isVCKey(key)) { const path = getFilePath(key); - const isFileExists = await exists(path); + const isFileExists = await FileStorage.exists(path); if (isFileExists) { - return await unlink(path); + return await FileStorage.removeItem(path); } else { console.log('file not exist`s'); } @@ -192,8 +182,8 @@ class Storage { static clear = async () => { try { - (await exists(`${vcDirectoryPath}`)) && - (await unlink(`${vcDirectoryPath}`)); + (await FileStorage.exists(`${vcDirectoryPath}`)) && + (await FileStorage.removeItem(`${vcDirectoryPath}`)); MMKV.clearStore(); } catch (e) { console.log('Error Occurred while Clearing Storage.', e); @@ -218,35 +208,4 @@ class Storage { }; } -/** - * The VC file name will not have the pinned / unpinned state, we will splice the state as this will change. - * replace ':' with '_' in the key to get the file name as ':' are not allowed in filenames - * eg: "vc:UIN:6732935275:e7426576-112f-466a-961a-1ed9635db628" is changed to "vc_UIN_6732935275_e7426576-112f-466a-961a-1ed9635db628" - */ -const getFileName = (key: string) => { - return key.split(':').splice(0, 4).join('_'); -}; - -/** - * iOS: /var/mobile/Containers/Data/Application/196A05AD-6B11-403D-BA2D-6DC1F30075E1/Documents/inji/VC/ - * android: /data/user/0/io.mosip.residentapp/files/inji/VC/ - * These paths are coming from DocumentDirectoryPath in react-native-fs. - */ -const getFilePath = (key: string) => { - return `${vcDirectoryPath}/${key}.txt`; -}; - -/** - * The VC key will not have the pinned / unpinned state, we will splice the state as this will change. - * eg: "vc:UIN:6732935275:e7426576-112f-466a-961a-1ed9635db628:true" is changed to "vc:UIN:6732935275:e7426576-112f-466a-961a-1ed9635db628" - */ -const getVCKeyName = (key: string) => { - return key; -}; - -// To print the MMKV data cal this function in getItem -const getMMKVData = async () => { - return await MMKV.indexer.getKeys(); -}; - export default Storage;