feat(INJI-238): handling errors when invalidate keys of biometric

This commit is contained in:
Dhivya
2023-08-14 11:41:49 +05:30
parent 4b7b6ecb48
commit 04e5498572
19 changed files with 192 additions and 50 deletions

14
App.tsx
View File

@@ -8,12 +8,14 @@ import { useSelector } from '@xstate/react';
import { useTranslation } from 'react-i18next';
import {
selectIsDecryptError,
selectIsKeyInvalidateError,
selectIsReadError,
selectIsReady,
} from './machines/app';
import { DualMessageOverlay } from './components/DualMessageOverlay';
import { useApp } from './screens/AppController';
import { Alert } from 'react-native';
import { ErrorMessageOverlay } from './components/MessageOverlay';
// kludge: this is a bad practice but has been done temporarily to surface
// an occurance of a bug with minimal residual code changes, this should
@@ -45,11 +47,23 @@ const AppLayoutWrapper: React.FC = () => {
const AppLoadingWrapper: React.FC = () => {
const { appService } = useContext(GlobalContext);
const isReadError = useSelector(appService, selectIsReadError);
const isKeyInvalidateError = useSelector(
appService,
selectIsKeyInvalidateError
);
const controller = useApp();
const { t } = useTranslation('WelcomeScreen');
return (
<>
<AppLoading />
<ErrorMessageOverlay
translationPath={'WelcomeScreen'}
isVisible={isKeyInvalidateError}
error={'errors.invalidateKeyError'}
onDismiss={controller.IGNORE}
/>
{isReadError ? (
<DualMessageOverlay
isVisible={isReadError}

View File

@@ -63,6 +63,10 @@ export const HelpScreen: React.FC<HelpScreenProps & MainRouteProps> = (
{t('howToViewActivity?')}
</Text>
<Text style={Theme.TextStyles.helpDetailes}>{t('detail-8')}</Text>
<Text margin="7" style={Theme.TextStyles.header}>
{t('whatCanDoBiometricsChanged?')}
</Text>
<Text style={Theme.TextStyles.helpDetailes}>{t('detail-9')}</Text>
</Column>
</ScrollView>
</Modal>

View File

@@ -322,7 +322,7 @@
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = io.mosip2.asdf.mobileid1221;
PRODUCT_BUNDLE_IDENTIFIER = io.mosip.inji.mobileid;
PRODUCT_NAME = Inji;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Inji/Inji-Bridging-Header.h";

View File

@@ -48,10 +48,6 @@
</dict>
</dict>
</dict>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Allow $(PRODUCT_NAME) to access your location</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Allow $(PRODUCT_NAME) to access your location</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Bluetooth is used to allow sharing VCs with another device</string>
<key>NSBluetoothPeripheralUsageDescription</key>
@@ -60,6 +56,10 @@
<string>Allow $(PRODUCT_NAME) to access your camera</string>
<key>NSFaceIDUsageDescription</key>
<string>Resident app can be unlocked using Face ID</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Allow $(PRODUCT_NAME) to access your location</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Allow $(PRODUCT_NAME) to access your location</string>
<key>NSMicrophoneUsageDescription</key>
<string>Allow $(PRODUCT_NAME) to access your microphone</string>
<key>UILaunchStoryboardName</key>

View File

@@ -167,7 +167,9 @@
"howToActivateCardForOnlineLogin?": "كيف يتم تفعيل البطاقة لتسجيل الدخول عبر الإنترنت؟",
"detail-7": "بعد إضافة بطاقة إلى المحفظة بنجاح ، انقر فوق 'تعليق التنشيط لتسجيل الدخول عبر الإنترنت' على البطاقة. عند النقر فوق 'تنشيط' ، ستكون البطاقة جاهزة للاستخدام لتسجيل الدخول عبر الإنترنت.",
"howToViewActivity?": "كيفية عرض سجلات النشاط؟",
"detail-8": "في الصفحة الرئيسية ، انقر فوق 'المحفوظات' لعرض تفاصيل نشاط المستخدم."
"detail-8": "في الصفحة الرئيسية ، انقر فوق 'المحفوظات' لعرض تفاصيل نشاط المستخدم.",
"whatCanDoBiometricsChanged?": "ماذا يحدث عندما يتم تغيير المقاييس الحيوية لمخزن مفاتيح ذكري المظهر؟",
"detail-9": "يحتوي ملف تخزين مفاتيح ذكري المظهر على معلومات مهمة مثل المفاتيح الخاصة لإثباتات الهوية. عندما تقوم بتغيير القياسات الحيوية الخاصة بك ، فإن المفاتيح القديمة لم تعد آمنة. للحفاظ على أمان الأشياء ، نقوم بإزالة إثبات الهوية الموقعة بواسطة تلك المفاتيح القديمة. يمكنك ببساطة تنزيل إثباتات هويتك مرة أخرى ، وسيتم توقيعها بأحدث المفاتيح وأكثرها أمانًا."
},
"AddVcModal": {
"requestingCredential": "جارٍ طلب بيانات الاعتماد...",
@@ -251,7 +253,7 @@
"title": "بيانات التطبيق غير كافية",
"message": "لا يمكنك إضافة أو استلام بطاقات لأن بيانات التطبيق ممتلئة. امسح بيانات التطبيق للمتابعة."
},
"vcIsTampered":{
"vcIsTampered": {
"title": "تم العبث ببيانات VC",
"message": "تتم إزالة VCs المتأثر من التطبيق"
},
@@ -520,7 +522,11 @@
"failedToReadKeys": "فشلت قراءة المفاتيح",
"retryRead": "هل تريد إعادة المحاولة؟",
"errors": {
"decryptionFailed": "فشل في فك تشفير البيانات"
"decryptionFailed": "فشل في فك تشفير البيانات",
"invalidateKeyError": {
"title": "تمت إزالة بعض البطاقات لدواعي أمنية.",
"message": "يرجى إعادة التنزيل."
}
},
"ignore": "يتجاهل"
},
@@ -551,4 +557,4 @@
"copied": "نسخ"
}
}
}
}

View File

@@ -167,7 +167,9 @@
"howToActivateCardForOnlineLogin?": "How to activate a card for online login?",
"detail-7": "After successfully adding a card to the wallet, click on 'Activation pending for Online login' on the card. On clicking on 'Activate', the card will be ready to be used for online login.",
"howToViewActivity?": "How to view activity logs?",
"detail-8": "On the Home page, click on 'History' to view the details of the user's activitie."
"detail-8": "On the Home page, click on 'History' to view the details of the user's activitie.",
"whatCanDoBiometricsChanged?": "What happens when Android keystore biometric is changed?",
"detail-9": "The Android keystore holds important information like private keys for identity proofs. When you change your biometrics, old keys are no longer safe. To keep things secure, we remove identity proofs signed by those old keys. You can simply download your identity proofs again, and they will be signed with the latest, safer keys."
},
"AddVcModal": {
"requestingCredential": "Requesting credential...",
@@ -521,7 +523,11 @@
"retryRead": "Want to retry?",
"ignore": "Ignore",
"errors": {
"decryptionFailed": "Failed to decrypt data"
"decryptionFailed": "Failed to decrypt data",
"invalidateKeyError": {
"title": "Some Card(s) removed due to security concerns.",
"message": "Please redownload."
}
}
},
"SetupLanguage": {

View File

@@ -167,7 +167,9 @@
"howToActivateCardForOnlineLogin?": "Paano i-activate ang isang card para sa online na pag-login?",
"detail-7": "Matapos matagumpay na magdagdag ng card sa wallet, mag-click sa 'Activation pending for Online login' sa card. Sa pag-click sa 'I-activate', ang card ay handa nang gamitin para sa online na pag-login.",
"howToViewActivity?": "Paano tingnan ang mga log ng aktibidad?",
"detail-8": "Sa Home page, mag-click sa 'Kasaysayan' upang tingnan ang mga detalye ng aktibidad ng user."
"detail-8": "Sa Home page, mag-click sa 'Kasaysayan' upang tingnan ang mga detalye ng aktibidad ng user.",
"whatCanDoBiometricsChanged?": "Ano ang mangyayari kapag binago ang biometric ng Android keystore?",
"detail-9": "Ang Android keystore ay nagtataglay ng mahalagang impormasyon tulad ng mga pribadong key para sa mga patunay ng pagkakakilanlan. Kapag binago mo ang iyong biometrics, hindi na ligtas ang mga lumang key. Upang panatilihing secure ang mga bagay, inaalis namin ang mga patunay ng pagkakakilanlan na nilagdaan ng mga lumang key na iyon. Maaari mo lamang i-download muli ang iyong mga patunay ng pagkakakilanlan, at lalagdaan ang mga ito gamit ang pinakabago, mas ligtas na mga susi."
},
"AddVcModal": {
"requestingCredential": "Humihiling ng kredensyal...",
@@ -523,8 +525,12 @@
"unlockApp": "Buksan ang aplikasyon",
"failedToReadKeys": "Nabigong basahin ang mga susi",
"retryRead": "Gustong subukang muli?",
"error": {
"decryptionFailed": "Nabigong i-decrypt ang data"
"errors": {
"decryptionFailed": "Nabigong i-decrypt ang data",
"invalidateKeyError": {
"title": "Ang ilang (mga) patunay ng Pagkakakilanlan ay tinanggal dahil sa mga alalahanin sa seguridad.",
"message": "Mangyaring i-download muli."
}
},
"ignore": "Huwag pansinin"
},
@@ -555,4 +561,4 @@
"copied": "Kinopya"
}
}
}
}

View File

@@ -164,7 +164,9 @@
"howToActivateCardForOnlineLogin?": "ऑनलाइन लॉगिन के लिए कार्ड कैसे सक्रिय करें?",
"detail-7": "वॉलेट में सफलतापूर्वक कार्ड जोड़ने के बाद, कार्ड पर 'ऑनलाइन लॉगिन के लिए सक्रियण लंबित' पर क्लिक करें। 'एक्टिवेट' पर क्लिक करने पर, कार्ड ऑनलाइन लॉगिन के लिए उपयोग के लिए तैयार हो जाएगा।",
"howToViewActivity?": "गतिविधि लॉग कैसे देखें?",
"detail-8": "होम पेज पर, उपयोगकर्ता की गतिविधि का विवरण देखने के लिए 'इतिहास' पर क्लिक करें।"
"detail-8": "होम पेज पर, उपयोगकर्ता की गतिविधि का विवरण देखने के लिए 'इतिहास' पर क्लिक करें।",
"whatCanDoBiometricsChanged?": "क्या होता है जब एंड्रॉइड कीस्टोर बायोमेट्रिक बदल दिया जाता है?",
"detail-9": "एंड्रॉइड कीस्टोर में पहचान प्रमाण के लिए निजी कुंजी जैसी महत्वपूर्ण जानकारी होती है। जब आप अपना बायोमेट्रिक्स बदलते हैं, तो पुरानी चाबियाँ सुरक्षित नहीं रह जाती हैं। चीजों को सुरक्षित रखने के लिए, हम उन पुरानी चाबियों द्वारा हस्ताक्षरित पहचान प्रमाण हटा देते हैं। आप बस अपने पहचान प्रमाण दोबारा डाउनलोड कर सकते हैं, और उन पर नवीनतम, सुरक्षित कुंजी के साथ हस्ताक्षर किए जाएंगे।"
},
"AddVcModal": {
"requestingCredential": "क्रेडेंशियल का अनुरोध कर रहा है...",
@@ -519,7 +521,11 @@
"failedToReadKeys": "कुंजियाँ पढ़ने में विफल",
"retryRead": "पुनः प्रयास करना चाहते हैं?",
"errors": {
"decryptionFailed": "डेटा डिक्रिप्ट करने में विफल"
"decryptionFailed": "डेटा डिक्रिप्ट करने में विफल",
"invalidateKeyError": {
"title": "सुरक्षा चिंताओं के कारण कुछ पहचान प्रमाण हटा दिए गए हैं।",
"message": "कृपया पुनः डाउनलोड करें."
}
},
"ignore": "अनदेखा करना"
},
@@ -548,4 +554,4 @@
"copied": "कॉपी किया गया"
}
}
}
}

View File

@@ -163,7 +163,9 @@
"howToActivateCardForOnlineLogin?": "ಆನ್‌ಲೈನ್ ಲಾಗಿನ್‌ಗಾಗಿ ಕಾರ್ಡ್ ಅನ್ನು ಹೇಗೆ ಸಕ್ರಿಯಗೊಳಿಸುವುದು?",
"detail-7": "ವ್ಯಾಲೆಟ್‌ಗೆ ಕಾರ್ಡ್ ಅನ್ನು ಯಶಸ್ವಿಯಾಗಿ ಸೇರಿಸಿದ ನಂತರ, ಕಾರ್ಡ್‌ನಲ್ಲಿರುವ 'ಆನ್‌ಲೈನ್ ಲಾಗಿನ್‌ಗಾಗಿ ಆಕ್ಟಿವೇಶನ್ ಪೆಂಡಿಂಗ್' ಅನ್ನು ಕ್ಲಿಕ್ ಮಾಡಿ. 'ಸಕ್ರಿಯಗೊಳಿಸು' ಕ್ಲಿಕ್ ಮಾಡಿದಾಗ, ಕಾರ್ಡ್ ಆನ್‌ಲೈನ್ ಲಾಗಿನ್‌ಗೆ ಬಳಸಲು ಸಿದ್ಧವಾಗುತ್ತದೆ.",
"howToViewActivity?": "ಚಟುವಟಿಕೆ ಲಾಗ್‌ಗಳನ್ನು ವೀಕ್ಷಿಸುವುದು ಹೇಗೆ?",
"detail-8": "ಮುಖಪುಟದಲ್ಲಿ, ಬಳಕೆದಾರರ ಚಟುವಟಿಕೆಯ ವಿವರಗಳನ್ನು ವೀಕ್ಷಿಸಲು 'ಇತಿಹಾಸ' ಕ್ಲಿಕ್ ಮಾಡಿ."
"detail-8": "ಮುಖಪುಟದಲ್ಲಿ, ಬಳಕೆದಾರರ ಚಟುವಟಿಕೆಯ ವಿವರಗಳನ್ನು ವೀಕ್ಷಿಸಲು 'ಇತಿಹಾಸ' ಕ್ಲಿಕ್ ಮಾಡಿ.",
"whatCanDoBiometricsChanged?": "ಆಂಡ್ರಾಯ್ಡ್ ಕೀಸ್ಟೋರ್ ಬಯೋಮೆಟ್ರಿಕ್ ಅನ್ನು ಬದಲಾಯಿಸಿದಾಗ ಏನಾಗುತ್ತದೆ?",
"detail-9": "ಆಂಡ್ರಾಯ್ಡ್ ಕೀಸ್ಟೋರ್ ಗುರುತಿನ ಪುರಾವೆಗಳಿಗಾಗಿ ಖಾಸಗಿ ಕೀಗಳಂತಹ ಪ್ರಮುಖ ಮಾಹಿತಿಯನ್ನು ಹೊಂದಿದೆ. ನಿಮ್ಮ ಬಯೋಮೆಟ್ರಿಕ್ಸ್ ಅನ್ನು ನೀವು ಬದಲಾಯಿಸಿದಾಗ, ಹಳೆಯ ಕೀಗಳು ಇನ್ನು ಮುಂದೆ ಸುರಕ್ಷಿತವಾಗಿರುವುದಿಲ್ಲ. ವಿಷಯಗಳನ್ನು ಸುರಕ್ಷಿತವಾಗಿರಿಸಲು, ಆ ಹಳೆಯ ಕೀಗಳಿಂದ ಸಹಿ ಮಾಡಿದ ಗುರುತಿನ ಪುರಾವೆಗಳನ್ನು ನಾವು ತೆಗೆದುಹಾಕುತ್ತೇವೆ. ನಿಮ್ಮ ಗುರುತಿನ ಪುರಾವೆಗಳನ್ನು ನೀವು ಸರಳವಾಗಿ ಡೌನ್‌ಲೋಡ್ ಮಾಡಬಹುದು ಮತ್ತು ಅವುಗಳನ್ನು ಇತ್ತೀಚಿನ, ಸುರಕ್ಷಿತ ಕೀಗಳೊಂದಿಗೆ ಸಹಿ ಮಾಡಲಾಗುತ್ತದೆ."
},
"AddVcModal": {
"requestingCredential": "ರುಜುವಾತುಗಳನ್ನು ವಿನಂತಿಸಲಾಗುತ್ತಿದೆ...",
@@ -247,7 +249,7 @@
"title": "ಸಾಕಷ್ಟಿಲ್ಲ ಅಪ್ಲಿಕೇಶನ್ ಡೇಟಾವನ್ನು",
"message": "ಅಪ್ಲಿಕೇಶನ್ ಡೇಟಾ ತುಂಬಿರುವುದರಿಂದ ನೀವು ಕಾರ್ಡ್‌ಗಳನ್ನು ಸೇರಿಸಲು ಅಥವಾ ಸ್ವೀಕರಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಮುಂದುವರೆಯಲು ಅಪ್ಲಿಕೇಶನ್ ಡೇಟಾವನ್ನು ತೆರವುಗೊಳಿಸಿ."
},
"vcIsTampered":{
"vcIsTampered": {
"title": "ವಿಸಿ ಡೇಟಾವನ್ನು ಹಾಳುಮಾಡಲಾಗಿದೆ",
"message": "ಪೀಡಿತ VC ಗಳನ್ನು ಅಪ್ಲಿಕೇಶನ್‌ನಿಂದ ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ."
},
@@ -517,7 +519,11 @@
"failedToReadKeys": "ಕೀಗಳನ್ನು ಓದಲು ವಿಫಲವಾಗಿದೆ",
"retryRead": "ಮರುಪ್ರಯತ್ನಿಸಲು ಬಯಸುವಿರಾ?",
"errors": {
"decryptionFailed": "ಡೇಟಾವನ್ನು ಡೀಕ್ರಿಪ್ಟ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ"
"decryptionFailed": "ಡೇಟಾವನ್ನು ಡೀಕ್ರಿಪ್ಟ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ",
"invalidateKeyError": {
"title": "ಭದ್ರತೆಯ ಕಾರಣದಿಂದ ಕೆಲವು ಗುರುತಿನ ಪುರಾವೆ(ಗಳನ್ನು) ಅಳಿಸಲಾಗಿದೆ.",
"message": "ದಯವಿಟ್ಟು ಮರುಡೌನ್‌ಲೋಡ್ ಮಾಡಿ."
}
},
"ignore": "ನಿರ್ಲಕ್ಷಿಸಿ"
},

View File

@@ -434,7 +434,13 @@
"WelcomeScreen": {
"title": "Solución de identidad de código abierto",
"getStarted": "Empezar",
"unlockApp": "Desbloquear aplicación"
"unlockApp": "Desbloquear aplicación",
"errors": {
"invalidateKeyError": {
"title": "Algunas pruebas de identidad se eliminan debido a problemas de seguridad.",
"message": "Vuelva a descargar."
}
}
},
"common": {
"cancel": "Cancelar",

View File

@@ -163,7 +163,9 @@
"howToActivateCardForOnlineLogin?": "ஆன்லைன் உள்நுழைவுக்கான அட்டையை எவ்வாறு செயல்படுத்துவது?",
"detail-7": "வாலட்டில் கார்டை வெற்றிகரமாகச் சேர்த்த பிறகு, கார்டில் உள்ள 'ஆன்லைன் உள்நுழைவுக்கான ஆக்டிவேஷன் பெண்டிங்' என்பதைக் கிளிக் செய்யவும். 'செயல்படுத்து' என்பதைக் கிளிக் செய்தால், ஆன்லைன் உள்நுழைவுக்கு கார்டு தயாராக இருக்கும்.",
"howToViewActivity?": "செயல்பாட்டுப் பதிவுகளை எவ்வாறு பார்ப்பது?",
"detail-8": "முகப்புப் பக்கத்தில், பயனரின் செயல்பாட்டின் விவரங்களைப் பார்க்க, 'வரலாறு' என்பதைக் கிளிக் செய்யவும்."
"detail-8": "முகப்புப் பக்கத்தில், பயனரின் செயல்பாட்டின் விவரங்களைப் பார்க்க, 'வரலாறு' என்பதைக் கிளிக் செய்யவும்.",
"whatCanDoBiometricsChanged?": "ஆண்ட்ராய்டு கீஸ்டோர் பயோமெட்ரிக் மாற்றப்பட்டால் என்ன நடக்கும்?",
"detail-9": "அடையாளச் சான்றுகளுக்கான தனிப்பட்ட விசைகள் போன்ற முக்கியமான தகவல்களை ஆண்ட்ராய்டு கீஸ்டோர் வைத்திருக்கிறது. உங்கள் பயோமெட்ரிக்ஸை மாற்றினால், பழைய விசைகள் இனி பாதுகாப்பாக இருக்காது. விஷயங்களைப் பாதுகாப்பாக வைத்திருக்க, அந்தப் பழைய சாவிகளால் கையொப்பமிடப்பட்ட அடையாளச் சான்றுகளை அகற்றுவோம். உங்கள் அடையாளச் சான்றுகளை மீண்டும் பதிவிறக்கம் செய்யலாம், மேலும் அவை சமீபத்திய, பாதுகாப்பான விசைகளுடன் கையொப்பமிடப்படும்."
},
"AddVcModal": {
"requestingCredential": "நற்சான்றிதழைக் கோருகிறது...",
@@ -517,7 +519,11 @@
"failedToReadKeys": "விசைகளைப் படிக்க முடியவில்லை",
"retryRead": "மீண்டும் முயற்சிக்க வேண்டுமா?",
"errors": {
"decryptionFailed": "தரவை மறைகுறியாக்க முடியவில்லை"
"decryptionFailed": "தரவை மறைகுறியாக்க முடியவில்லை",
"invalidateKeyError": {
"title": "பாதுகாப்புக் காரணங்களால் சில அடையாளச் சான்றுகள் நீக்கப்பட்டன.",
"message": "மீண்டும் பதிவிறக்கவும்."
}
},
"ignore": "புறக்கணிக்க"
},

View File

@@ -34,6 +34,7 @@ const model = createModel(
serviceRefs: {} as AppServices,
isReadError: true,
isDecryptError: false,
isKeyInvalidateError: false,
},
{
events: {
@@ -42,6 +43,7 @@ const model = createModel(
ERROR: () => ({}),
DECRYPT_ERROR: () => ({}),
DECRYPT_ERROR_DISMISS: () => ({}),
KEY_INVALIDATE_ERROR: () => ({}),
OFFLINE: () => ({}),
ONLINE: (networkType: NetInfoStateType) => ({ networkType }),
REQUEST_DEVICE_INFO: () => ({}),
@@ -72,6 +74,9 @@ export const appMachine = model.createMachine(
DECRYPT_ERROR_DISMISS: {
actions: ['unsetIsDecryptError'],
},
KEY_INVALIDATE_ERROR: {
actions: ['updateKeyInvalidateError'],
},
},
states: {
init: {
@@ -81,11 +86,15 @@ export const appMachine = model.createMachine(
entry: ['spawnStoreActor', 'logStoreEvents'],
on: {
READY: {
actions: ['unsetIsReadError', 'unsetIsDecryptError'],
actions: [
'unsetIsReadError',
'unsetIsDecryptError',
'resetKeyInvalidateError',
],
target: 'services',
},
ERROR: {
actions: 'setIsReadError',
actions: ['setIsReadError', 'updateKeyInvalidateError'],
},
},
},
@@ -198,6 +207,19 @@ export const appMachine = model.createMachine(
unsetIsReadError: assign({
isReadError: false,
}),
updateKeyInvalidateError: model.assign({
isKeyInvalidateError: (_, event) => {
if (event.type === 'KEY_INVALIDATE_ERROR') {
return true;
}
},
}),
resetKeyInvalidateError: model.assign({
isKeyInvalidateError: false,
}),
requestDeviceInfo: respond((context) => ({
type: 'RECEIVE_DEVICE_INFO',
info: {
@@ -445,3 +467,7 @@ export function selectIsReadError(state: State) {
export function selectIsDecryptError(state: State) {
return state.context.isDecryptError;
}
export function selectIsKeyInvalidateError(state: State) {
return state.context.isKeyInvalidateError;
}

View File

@@ -24,6 +24,7 @@ export interface Typegen0 {
logServiceEvents: 'READY';
logStoreEvents: 'xstate.init';
requestDeviceInfo: 'REQUEST_DEVICE_INFO';
resetKeyInvalidateError: 'READY';
setAppInfo: 'APP_INFO_RECEIVED';
setBackendInfo: 'BACKEND_INFO_RECEIVED';
setIsDecryptError: 'DECRYPT_ERROR';
@@ -32,6 +33,7 @@ export interface Typegen0 {
spawnStoreActor: 'xstate.init';
unsetIsDecryptError: 'DECRYPT_ERROR_DISMISS' | 'READY';
unsetIsReadError: 'READY';
updateKeyInvalidateError: 'ERROR' | 'KEY_INVALIDATE_ERROR';
};
'eventsCausingDelays': {};
'eventsCausingGuards': {};

View File

@@ -41,7 +41,9 @@ export interface Typegen0 {
checkNearByDevicesPermission: 'done.invoke.scan.checkNearbyDevicesPermission.checking:invocation[0]';
checkStorageAvailability: 'done.invoke.scan.checkStorage:invocation[0]';
createVp: 'done.invoke.scan.reviewing.creatingVp:invocation[0]';
disconnect: 'done.invoke.scan.clearingConnection:invocation[0]';
disconnect:
| 'done.invoke.scan.clearingConnection:invocation[0]'
| 'done.invoke.scan.disconnectDevice:invocation[0]';
monitorConnection: 'done.invoke.scan:invocation[0]';
requestBluetooth: 'done.invoke.scan.checkBluetoothState.requesting:invocation[0]';
requestNearByDevicesPermission: 'done.invoke.scan.checkNearbyDevicesPermission.requesting:invocation[0]';
@@ -60,6 +62,7 @@ export interface Typegen0 {
| 'BLE_ERROR'
| 'DISCONNECT'
| 'DISMISS'
| 'RESET'
| 'SCREEN_BLUR'
| 'SCREEN_FOCUS'
| 'xstate.stop';
@@ -68,6 +71,7 @@ export interface Typegen0 {
| 'BLE_ERROR'
| 'DISCONNECT'
| 'DISMISS'
| 'RESET'
| 'SCREEN_BLUR'
| 'SCREEN_FOCUS'
| 'xstate.stop';
@@ -138,10 +142,10 @@ export interface Typegen0 {
checkLocationPermission: 'APP_ACTIVE' | 'LOCATION_ENABLED';
checkLocationStatus: '';
checkNearByDevicesPermission: 'APP_ACTIVE' | 'START_PERMISSION_CHECK';
checkStorageAvailability: 'SCREEN_FOCUS';
checkStorageAvailability: 'RESET' | 'SCREEN_FOCUS';
createVp: never;
disconnect: '' | 'DISMISS' | 'LOCATION_ENABLED';
monitorConnection: 'xstate.init';
disconnect: '' | 'DISMISS' | 'LOCATION_ENABLED' | 'SCREEN_BLUR';
monitorConnection: 'SCREEN_BLUR' | 'xstate.init';
requestBluetooth: 'BLUETOOTH_STATE_DISABLED';
requestNearByDevicesPermission: 'NEARBY_DISABLED';
sendVc:
@@ -175,6 +179,7 @@ export interface Typegen0 {
| 'connecting'
| 'connecting.inProgress'
| 'connecting.timeout'
| 'disconnectDevice'
| 'disconnected'
| 'findingConnection'
| 'handlingBleError'

View File

@@ -1,6 +1,6 @@
import * as Keychain from 'react-native-keychain';
import CryptoJS from 'crypto-js';
import Storage from '../shared/storage';
import Storage, { HMAC_ALIAS } from '../shared/storage';
import binaryToBase64 from 'react-native/Libraries/Utilities/binaryToBase64';
import {
EventFrom,
@@ -13,17 +13,14 @@ import {
import { createModel } from 'xstate/lib/model';
import { generateSecureRandom } from 'react-native-securerandom';
import { log } from 'xstate/lib/actions';
import {
VC_ITEM_STORE_KEY_REGEX,
MY_VCS_STORE_KEY,
isIOS,
} from '../shared/constants';
import { VC_ITEM_STORE_KEY_REGEX, MY_VCS_STORE_KEY } from '../shared/constants';
import SecureKeystore from 'react-native-secure-keystore';
import { isCustomSecureKeystore } from '../shared/cryptoutil/cryptoUtil';
import { AUTH_TIMEOUT } from '../shared/cryptoutil/cryptoUtil';
export const ENCRYPTION_ID = 'c7c22a6c-9759-4605-ac88-46f4041d863d';
const vcKeyRegExp = new RegExp(VC_ITEM_STORE_KEY_REGEX);
export const keyinvalidatedString = 'User not authenticated';
const model = createModel(
{
@@ -38,6 +35,7 @@ const model = createModel(
IGNORE: () => ({}),
GET: (key: string) => ({ key }),
DECRYPT_ERROR: () => ({}),
KEY_INVALIDATE_ERROR: () => ({}),
SET: (key: string, value: unknown) => ({ key, value }),
APPEND: (key: string, value: unknown) => ({ key, value }),
PREPEND: (key: string, value: unknown) => ({ key, value }),
@@ -139,7 +137,7 @@ export const storeMachine =
KEY_RECEIVED: [
{
cond: 'isCustomSecureKeystore',
target: 'ready',
target: ['ready'],
},
{
actions: 'setEncryptionKey',
@@ -229,6 +227,9 @@ export const storeMachine =
RESET_IS_TAMPERED: {
actions: ['resetIsTamperedVc'],
},
KEY_INVALIDATE_ERROR: {
actions: sendParent('KEY_INVALIDATE_ERROR'),
},
},
},
},
@@ -370,7 +371,11 @@ export const storeMachine =
}
callback(model.events.STORE_RESPONSE(response, event.requester));
} catch (e) {
if (e.message === 'Data is tampered') {
if (e.message.includes(keyinvalidatedString)) {
await clear();
callback(model.events.KEY_INVALIDATE_ERROR());
sendUpdate();
} else if (e.message === 'Data is tampered') {
callback(model.events.TAMPERED_VC());
} else if (
e.message.includes('JSON') ||
@@ -419,6 +424,7 @@ export const storeMachine =
}
} else {
await SecureKeystore.generateKey(ENCRYPTION_ID, true, AUTH_TIMEOUT);
SecureKeystore.generateHmacshaKey(HMAC_ALIAS);
callback(model.events.KEY_RECEIVED(''));
}
},
@@ -465,7 +471,10 @@ export async function getItem(
return defaultValue;
}
} catch (e) {
if (e.message.includes('Data is tampered')) {
if (
e.message.includes('Data is tampered') ||
e.message.includes(keyinvalidatedString)
) {
throw e;
}
console.error('Exception in getting item: ' + e);
@@ -613,7 +622,10 @@ export async function clear() {
}
}
export function encryptJson(encryptionKey: string, data: string): Promise<string> {
export function encryptJson(
encryptionKey: string,
data: string
): Promise<string> {
if (!isCustomSecureKeystore()) {
return CryptoJS.AES.encrypt(data, encryptionKey).toString();
}

32
package-lock.json generated
View File

@@ -71,6 +71,7 @@
"react-native-safe-area-context": "3.3.2",
"react-native-screens": "~3.10.1",
"react-native-secure-key-store": "^2.0.10",
"react-native-secure-keystore": "file:.yalc/react-native-secure-keystore",
"react-native-securerandom": "^1.0.0",
"react-native-simple-markdown": "^1.1.0",
"react-native-svg": "12.1.1",
@@ -99,6 +100,22 @@
"typescript": "~4.3.5"
}
},
".yalc/react-native-secure-keystore": {
"version": "0.1.0",
"license": "MIT",
"dependencies": {
"react-native-secure-keystore": "file:.yalc/react-native-secure-keystore"
},
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
".yalc/react-native-secure-keystore/.yalc/react-native-secure-keystore": {},
".yalc/react-native-secure-keystore/node_modules/react-native-secure-keystore": {
"resolved": ".yalc/react-native-secure-keystore/.yalc/react-native-secure-keystore",
"link": true
},
"node_modules/@ampproject/remapping": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz",
@@ -21758,6 +21775,10 @@
"resolved": "https://registry.npmjs.org/react-native-secure-key-store/-/react-native-secure-key-store-2.0.10.tgz",
"integrity": "sha512-K7aVlIGxyklnjhCidVexVgZF3LsgUD9GIxMy2NB/xkQsS9E2SJWkD/fJ56e25L2I6a9Mp1zuJrKnCtfBs1CvAw=="
},
"node_modules/react-native-secure-keystore": {
"resolved": ".yalc/react-native-secure-keystore",
"link": true
},
"node_modules/react-native-securerandom": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/react-native-securerandom/-/react-native-securerandom-1.0.1.tgz",
@@ -45594,6 +45615,17 @@
"resolved": "https://registry.npmjs.org/react-native-secure-key-store/-/react-native-secure-key-store-2.0.10.tgz",
"integrity": "sha512-K7aVlIGxyklnjhCidVexVgZF3LsgUD9GIxMy2NB/xkQsS9E2SJWkD/fJ56e25L2I6a9Mp1zuJrKnCtfBs1CvAw=="
},
"react-native-secure-keystore": {
"version": "file:.yalc/react-native-secure-keystore",
"requires": {
"react-native-secure-keystore": "file:.yalc/react-native-secure-keystore"
},
"dependencies": {
"react-native-secure-keystore": {
"version": "file:.yalc/react-native-secure-keystore/.yalc/react-native-secure-keystore"
}
}
},
"react-native-securerandom": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/react-native-securerandom/-/react-native-securerandom-1.0.1.tgz",

View File

@@ -76,7 +76,7 @@
"react-native-safe-area-context": "3.3.2",
"react-native-screens": "~3.10.1",
"react-native-secure-key-store": "^2.0.10",
"react-native-secure-keystore": "github:mosip/secure-keystore#223887ea21a70c1ea0ebe7ad33b34a33e546aabf",
"react-native-secure-keystore": "file:.yalc/react-native-secure-keystore",
"react-native-securerandom": "^1.0.0",
"react-native-simple-markdown": "^1.1.0",
"react-native-svg": "12.1.1",

View File

@@ -8,16 +8,16 @@ export interface Typegen0 {
'invokeSrcNameMap': {};
'missingImplementations': {
actions: never;
services: never;
guards: never;
delays: never;
guards: never;
services: never;
};
'eventsCausingActions': {
viewVcFromParent: 'VIEW_VC';
};
'eventsCausingServices': {};
'eventsCausingGuards': {};
'eventsCausingDelays': {};
'eventsCausingGuards': {};
'eventsCausingServices': {};
'matchesStates': 'idle' | 'viewingVc';
'tags': never;
}

View File

@@ -1,5 +1,5 @@
import { MMKVLoader } from 'react-native-mmkv-storage';
import { isIOS, VC_ITEM_STORE_KEY_REGEX } from './constants';
import { VC_ITEM_STORE_KEY_REGEX } from './constants';
import CryptoJS from 'crypto-js';
import {
DocumentDirectoryPath,
@@ -23,12 +23,17 @@ import { isCustomSecureKeystore } from './cryptoutil/cryptoUtil';
const MMKV = new MMKVLoader().initialize();
const vcKeyRegExp = new RegExp(VC_ITEM_STORE_KEY_REGEX);
const vcDirectoryPath = `${DocumentDirectoryPath}/inji/VC`;
export const HMAC_ALIAS = 'Hmacalias';
function generateHmac(encryptionKey: string, data: string) {
async function generateHmac(
encryptionKey: string,
data: string
): Promise<string> {
if (!isCustomSecureKeystore()) {
return CryptoJS.HmacSHA256(encryptionKey, data).toString();
}
return SecureKeystore.generateHmacSha(ENCRYPTION_ID, data);
const hmacSHA256 = await SecureKeystore.generateHmacSha(hmacalias, data);
return hmacSHA256;
}
class Storage {
@@ -84,7 +89,7 @@ class Storage {
data: string
) {
const storedHMACofCurrentVC = await this.readHmacForVC(key, encryptionKey);
const HMACofVC = generateHmac(encryptionKey, data);
const HMACofVC = await generateHmac(encryptionKey, data);
return HMACofVC !== storedHMACofCurrentVC;
}
@@ -109,7 +114,7 @@ class Storage {
data: string,
key: string
) {
const HMACofVC = generateHmac(encryptionKey, data);
const HMACofVC = await generateHmac(encryptionKey, data);
const encryptedHMACofVC = await encryptJson(encryptionKey, HMACofVC);
await MMKV.setItem(getVCKeyName(key), encryptedHMACofVC);
}