[INJIMOB-878] : vc state machine refactoring (#1344)

* [INJI-631] add share and share with selfie options into kebab menu

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

* [INJI-631] change share vc component service attribute type to existingMosipVcItemMachine

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

* [INJI-631] change the kebab menu options name as per the wireframe

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

* [INJI-631] add missing otp screen confirmation dialog translations for kannada language

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

* [INJI-631] extract vcItemField name and value into two separate components for better usability

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

* [INJI-631] show mini card view of the loaded VC and change the styles as per the wireframe

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

* [INJI-631] do not show the activation status and kebab menu when sharing vc and while doing QR login

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

* [INJI-631] show mini card view usin shimmerPlaceholder component when card is in loading state

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

* [INJI-631] add svg images for wallet activated and unactivated icon

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

* [INJI-631] fix the postion of pin icon when there is no image displayed in VC

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

* [INJIMOB-631] show help icon and meat ball menu in vc detailed view

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

* [INJIMOB-631] add styles for detailed view profile icon and it's container

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

* [INJIMOB-721]: add help icon on top bar and remove setting button

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-721]: move settings to bottom tab bar

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-721]: add search bar ui for vc search

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-721]: add search filter for the vc search

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-721]: refactor filtered data to show message when vc not found

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-631] redirect to the home screen when user gives confirmation to delete the vc from the detailed view

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

* [INJIMOB-721]: add search svg for search bar and also style it

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-631] in existing vcitem machine close the kebab popup when an option is selected in kebab menu except for remove vc option

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

* [INJIMOB-631] change the remove vc confirm popup as per the wireframe

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

* [INJIMOB-631] add icons for the kebab menu options and show the number of cards available in home screen

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

* [INJIMOB-631] remove tooltip in detailed view and show remove vc kebab menu option in red color

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

* [INJIMOB-631] close the kebab menu when user clicks on cancel button in removal confirmation popup

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

* [INJIMON-631] show verification status for all the VCs in mini view and detailed view based on isVerified status

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

* [INJIMOB-631]: send vc data to scan machine while selecting share or share with selfie from meatball menu

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-721]: add styles to search bar

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-721]: add text msg when field searched in the vc search bar is not found

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-631]: implement sharing VC flow from mini card view

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-721]: refactor search bar component to show diff icon for vc search and issuers search

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-721]: remove unused code

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-631]: implement sharing VC with selfie flow from mini card view

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-631]: handle face auth failure scenario in VC sharing with selfie

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-631]: handle proper closing of kebab menu on VC share option click

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-721]: add styles to the search bar

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-631]: handle navigation to history page from success vc share page

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-721]: add background colour for home screen

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-631]: display proper label for QR login from meat ball menu

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-631]: handle QR login flow for mini view card

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-631] show count of cards available matching with search keyword

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

* [INJIMOB-631] show activated icon for the sunbird cards in the mini view

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

* [INJIMOB-631] hide share with selfie and qr login options in kebab menu if profile image is not available

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

* [INJIMOB-631]: updating logic to call isFromOpenId4VCI from an instance of VCMetadata

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-631]: update kebab menu list icons to outline with black color

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-631]: close kebab popup on selecting sharing option for esignet VCs

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-631]: clear connect for invalid identity and back button click face auth during share with selfie

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-631] fix the logic of showing how many cards available in the ui

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

* [INJIMOB-631] remove styles for kebab menu pin icon

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

* [INJIMOB-631]: updating logic to call isFromOpenId4VCI from an instance of VCMetadata

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-631]: reset the flowType and selectedVC variable in scan machine on any disconnect or success share of VC

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-631] in detail view show activation status popup everytime in the bottom

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

* [INJIMOB-631] replace activated icon with svg image in detailed view

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

* [INJIMOB-631]: remove unused files

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-631] don't show activation details in detailed view if VC image is not available

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

* [INJIMOB-631] show verification status as valid if credentials are available

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

* [INJIMOB-631] adjust the size of the image, qr code, magnifier and logo in detialed view

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

* [INJIMOB-631] increase the width of the activate button in the detialed view

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

* [INJIMOB-631] in detialed view increase the divider with and change it's styles to show it as per wireframe

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

* [INJIMOB-631] in detialed view  move email and all the address fields to the bottom view for all type of VCs

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

* [INJIMOB-631] filter the supported credentials of esignet wellknown config based on credential type of issuers config

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

* [INJIMOB-631] show the horizontal line in detailed view only if email or one of the address fields available in vc

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

* [INJIMOB-631] fix the spelling mistake of detailed view image styles

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

* [INJIMOB-631] remove unused event in existing mosip vc item machine

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

* [INJIMOB-631] change the name of the enum used for sharing flow from flow type to vc share flow type

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

* [INJIMOB-631] create a new enum type to use it for showing the activation status in vcitem container

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

* [INJIMOB-631] use logical and operator to decide whether to show horizontal line or not in detailed view and remove unnecessary logs

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

* [INJIMOB-631] add test id to the profile icon container and adjust the styles of pin icon

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

* [INJIMOB-631] move invalid identity message overlay to verify identity overlay component

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

* [INJIMOB-631] show credential registry in the bottom section of detial view if it's env variable is set to true

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

* [INJIMOB-631] add testId to detailed view qr code view and change settings tab title to settings

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

* [INJIMOB-631] make whole kebab menu option as pressable

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

* [INJIMOB-631]: hide kebab menu from the VC on SendVCScreen

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-631]: reset SelectedVc and flow type in scan machine for every kind of disconnect

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-631]: remove redundant check on qr login

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-631]: fix the prop value passed to the face scanner

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-631] add email & address back to default fields and write a logic to remove bottom section fields from wellknown config supported fields

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

* [INJIMOB-631] move detailed view bottom section fields list into vcUtils file

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

* [INJIMOB-631] remove unused action selectIsVerifiable in existing vc item machine

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

* [INJIMOB-631] pass the controller functions directly to verifyIdentityOverlay when calling it

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

* [INJIMOB-631] add todo comment in vcVerification file to handled vc verification pending status as part of another task

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

* [INJIMOB-631] render kebab menu options using flat list and make necessary changes related to menu options

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

* [INJIMOB-721]: refactor search Filter for normal otp flow VC

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-721]: refactor search Filter for sunbird and esignet vc

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-721]: refactor to add metadata to esignet and sunbird vc on download before saving

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-721]: show no of cards when search data is updated

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-631] add back history tab file

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

* INJIMOB-778 (#122)

* [INJIMOB-778]: add new localistaion for set and confirm passcode screen

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-778]: add authorization after the biometric unlock

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-778]: add check for biometric and password for the toggle

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-778]: add success toaster message when alternate unlock method is added

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-778]: remove toaster when the app is reopened

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-778]: add locales for succes toaster for biometric toggle

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-778]: refactor to check for the toggle from settings

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-778]: refactor function that handles biometric toggle

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-778]: refactor toggle_biometric_unlock event

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-778]: refactor banner notification to show success message

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* [INJIMOB-778]: add testID for new components

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

---------

Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>
Signed-off-by: PoojaBabusing <115976560+PoojaBabusing@users.noreply.github.com>
Co-authored-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>

* Injimob 784 (#124)

* [INJIMOB-784] add face verification consent overlay

Signed-off-by: adityankannan-tw <adityan410pm@gmail.com>

* [INJIMOB-784] add dismiss for backdrop press

Signed-off-by: adityankannan-tw <adityan410pm@gmail.com>

* [INJIMOB-784] add pop up for qrlogin flow also

Signed-off-by: adityankannan-tw <adityan410pm@gmail.com>

* [INJIMOB-864] disable backup button when restoring and vice versa (#1279)

Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>

* [INJIMOB-867] - remove all files including unsynced files and get latest file based on date (#1281)

Signed-off-by: Sreenadh S <32409698+sree96@users.noreply.github.com>

* [INJIMOB - 865,868] - Fix duplicate VC key for restored VC's and remove metadata if vc file not found (#1283)

* [INJIMOB-something] use incremental timestamp for restore and make unload take a flag start time

Signed-off-by: Harsh Vardhan <harsh59v@gmail.com>

* [INJIMOB-865,868] fix duplicate vckey value for restored vcs and remove vc metadata if file not found

Co-authored-by: adityankannan-tw <109274996+adityankannan-tw@users.noreply.github.com>
Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-869] remove unused method in store.ts machine

Co-authored-by: adityankannan-tw <109274996+adityankannan-tw@users.noreply.github.com>
Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-869] revert removing vc metadata if file not found

Co-authored-by: adityankannan-tw <109274996+adityankannan-tw@users.noreply.github.com>
Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-865] fix tamper vc removal

When a VC is tampered, we get the tampered vc popup. Once we press okay button in the popup, we will be refreshing the vc machine's myVcs & recievedVcs context. Due to calling of parallel states, we were having issue with refreshing of myVcs. It is fixed by targeting to init state to refresh

Co-authored-by: adityankannan-tw <109274996+adityankannan-tw@users.noreply.github.com>
Co-authored-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>

* [INJIMOB-865] remove vc metadata when file is not found

Co-authored-by: adityankannan-tw <109274996+adityankannan-tw@users.noreply.github.com>
Co-authored-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>
Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-869] add code comments & fix minor code issues

Signed-off-by: Harsh Vardhan <harsh59v@gmail.com>

---------

Signed-off-by: Harsh Vardhan <harsh59v@gmail.com>
Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>
Co-authored-by: Harsh Vardhan <harsh59v@gmail.com>
Co-authored-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
Co-authored-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>

* [INJIMOB-784] set context after getting the value from store

Signed-off-by: adityankannan-tw <adityan410pm@gmail.com>

* [INJIMOB-784] refactor the names and send isConsentGiven value properly to the scan machine event

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

* [INJIMOB-784] store & fetch the face auth consent value with proper types

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

* INJIMOB-604 VC Verification Failure Scenarios (#1228)

* [INJI-604]: Handle Verification VC Error Scenarios

Signed-off-by: BalachandarG <balachandar.g@thoughtworks.com>

* [INJIMOB-604] remove the card from UI when verify credential is failed and show error overlay

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

* [INJIMOB-604] remove unused actions in existingMosipVcItem and issuers machine

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

* INJIMOB-604 Replace Error message overlay with new error screen.

Signed-off-by: BalachandarG <balachandar.g@thoughtworks.com>

* [INJI-611]: New Error screen implemented

Signed-off-by: BalachandarG <balachandar.g@thoughtworks.com>

* [INJI-604]: Transation added for Verification error messages.

Signed-off-by: BalachandarG <balachandar.g@thoughtworks.com>

* [INJI-604] merge develop and resolve conflicts

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

* [INJI-604] remove unnecessary log in error screen

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

* [INJIMOB-604] remove removeVcFromMyVcs action from verify vc failed event and fix typegen warnings

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

* INJIMOB-604 : Removing logs and renaming functions

Signed-off-by: BalachandarG <balachandar.g@thoughtworks.com>

* [INJIMOB-604]: Removing unused method.

Signed-off-by: BalachandarG <balachandar.g@thoughtworks.com>

* [Inji-604]: Fixing the issue of recursive VC deletion during Go Back event in Verification Error screen.

Signed-off-by: BalachandarG <balachandar.g@thoughtworks.com>

* [Inji-604]: Fixing bugs post conflict resolve.

Signed-off-by: BalachandarG <balachandar.g@thoughtworks.com>

* [Inji-604]: Removing unused events and adding translations for Go Back button

* [Inji-604]: Removed angle brackets for Technical Error

* [Inji-604]: Added ToDo to handle backup

* [Inji-604]: Removing isVerified flag from the Existing VC Item Machine.

* [Inji-604] iOS crash fixed for Verification error Go Back Button

Signed-off-by: BalachandarG <balachandar.g@thoughtworks.com>

* [Inji-604]: Simplified condition for result in verify Credential call.

Signed-off-by: BalachandarG <balachandar.g@thoughtworks.com>

---------

Signed-off-by: BalachandarG <balachandar.g@thoughtworks.com>
Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
Co-authored-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* [INJIMOB-784] add styles for the popup

Signed-off-by: adityankannan-tw <adityan410pm@gmail.com>

* [INJIMOB-784] add locales changes in all languages

Signed-off-by: adityankannan-tw <adityan410pm@gmail.com>

* [INJIMOB-784] send consent data using event to qrlogin machine

Signed-off-by: adityankannan-tw <adityan410pm@gmail.com>

* [INJIMOB-784] refactor scan and qr  machines and remove logs

Signed-off-by: adityankannan-tw <adityan410pm@gmail.com>

* [INJIMOB-784] add testID for icons and buttons

Signed-off-by: adityankannan-tw <adityan410pm@gmail.com>

* [INJIMOB-784] add translations for help screen contents

Signed-off-by: adityankannan-tw <adityan410pm@gmail.com>

* [INJIMOB-784] add translations for help screen contents

Signed-off-by: adityankannan-tw <adityan410pm@gmail.com>

* [INJIMOB-784] change popup text and alter help screen msg order

Signed-off-by: adityankannan-tw <adityan410pm@gmail.com>

* Update SendVcScreenController.ts

* [INJIMOB-784] refactor actions for show face auth consent screen

Signed-off-by: adityankannan-tw <adityan410pm@gmail.com>

---------

Signed-off-by: adityankannan-tw <adityan410pm@gmail.com>
Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>
Signed-off-by: Sreenadh S <32409698+sree96@users.noreply.github.com>
Signed-off-by: Harsh Vardhan <harsh59v@gmail.com>
Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
Signed-off-by: BalachandarG <balachandar.g@thoughtworks.com>
Signed-off-by: adityankannan-tw <109274996+adityankannan-tw@users.noreply.github.com>
Co-authored-by: adityankannan-tw <adityan410pm@gmail.com>
Co-authored-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>
Co-authored-by: Sreenadh S <32409698+sree96@users.noreply.github.com>
Co-authored-by: Harsh Vardhan <harsh59v@gmail.com>
Co-authored-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
Co-authored-by: balachandarg-tw <115633327+balachandarg-tw@users.noreply.github.com>

* [INJIMOB-878]: VC State Machine Refactoring

Signed-off-by: Vijay <94220135+vijay151096@users.noreply.github.com>

* [INJIMOB-878]: removed unused component from the codebase

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-878]: remove any traces of existing and esignet item state machine from the code base

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-878]: extract out phone number and email id to a wrapper object

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-878]: optimize context variable declaration and usage in vc and vcItemStateMachine

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-878]: move all the selectors to VCItemMachine from a seperate file

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-878]: bring back code lost in code merge from develop

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-878]: remove unused imports and refactor the openId4VCI check from entire code base to a single point

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-878]: remove the entire vc or context sharing from the state machine to the component

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-878]: refactor controller to remove seperate declaration of variables

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-878]: extract events of VCItemMAchine into a seperate file

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-878]: removed some unused imports renamed VCItemSelectors file and refactored KebabPopUpController

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-878]: add issuer in OTP flow VC data as well

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-878]: remove VP implemetation and some unused components

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-878]: split VCItemMachine into multiple logical units

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-878]: correct a test id for activation flow

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-878]: fix issues dueto merge conflict

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

* [INJIMOB-878]: changed the folder structure for VCItemMAchine and related files

Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>

---------

Signed-off-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
Signed-off-by: Alka <prasadalka1998@gmail.com>
Signed-off-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>
Signed-off-by: Alka Prasad <prasadalka1998@gmail.com>
Signed-off-by: Alka Prasad <Alka1703@users.noreply.github.com>
Signed-off-by: PoojaBabusing <115976560+PoojaBabusing@users.noreply.github.com>
Signed-off-by: adityankannan-tw <adityan410pm@gmail.com>
Signed-off-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>
Signed-off-by: Sreenadh S <32409698+sree96@users.noreply.github.com>
Signed-off-by: Harsh Vardhan <harsh59v@gmail.com>
Signed-off-by: BalachandarG <balachandar.g@thoughtworks.com>
Signed-off-by: adityankannan-tw <109274996+adityankannan-tw@users.noreply.github.com>
Signed-off-by: Vijay <94220135+vijay151096@users.noreply.github.com>
Co-authored-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
Co-authored-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>
Co-authored-by: PoojaBabusing <115976560+PoojaBabusing@users.noreply.github.com>
Co-authored-by: adityankannan-tw <109274996+adityankannan-tw@users.noreply.github.com>
Co-authored-by: adityankannan-tw <adityan410pm@gmail.com>
Co-authored-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>
Co-authored-by: Sreenadh S <32409698+sree96@users.noreply.github.com>
Co-authored-by: Harsh Vardhan <harsh59v@gmail.com>
Co-authored-by: balachandarg-tw <115633327+balachandarg-tw@users.noreply.github.com>
Co-authored-by: Vijay <94220135+vijay151096@users.noreply.github.com>
This commit is contained in:
Alka Prasad
2024-04-01 11:24:33 +05:30
committed by GitHub
parent 1e75dc8391
commit 2cfd99d614
96 changed files with 2432 additions and 4562 deletions

4
.env
View File

@@ -2,9 +2,9 @@
# eg . npm build android:newlogic --reset-cache
#MIMOTO_HOST=http://mock.mimoto.newlogic.dev
MIMOTO_HOST=https://api.qa-inji1.mosip.net
MIMOTO_HOST=https://api.qa-inji.mosip.net
ESIGNET_HOST=https://api.qa-inji1.mosip.net
ESIGNET_HOST=https://api.qa-inji.mosip.net
OBSRV_HOST = https://dataset-api.obsrv.mosip.net

View File

@@ -47,14 +47,6 @@ fileignoreconfig:
checksum: 6d22bc5c77398316b943c512c208ce0846a9fff674c1ccac79e07f21962acd5f
- filename: shared/telemetry/TelemetryConstants.js
checksum: fd8dc3a69cdef68855dc5f0531d8e634bfa2621bb4dc22f85b8247512a349c4c
- filename: machines/VCItemMachine/EsignetMosipVCItem/EsignetMosipVCItemMachine.ts
checksum: cca7657da3a1a91b63e0a10605545d1e0d3d152b083a55f9dbb9eed893646e4b
- filename: machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine.ts
checksum: 1d06c737c0a59cdda6604eb2a6f384bcaf361a682c19f43ef9e8537e38c53db4
- filename: machines/VCItemMachine/EsignetMosipVCItem/EsignetMosipVCItemMachine.typegen.ts
checksum: 0de47337ba60b29c8e4d4231439c77028197d3d8d3139eb367c471138c40f93d
- filename: machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine.typegen.ts
checksum: 86ecb95b58456d42676247eb768a7fba980a3c0ef83d515f8b9ce0c44d8c6906
- filename: shared/telemetry/TelemetryUtils.js
checksum: a0686e9a5c006176fd720b84bc36ca947db1422caf65c90cd0c2d1102a9e96df
- filename: ios/fastlane/Fastfile
@@ -115,8 +107,6 @@ fileignoreconfig:
checksum: ac9c154060c7c1adb3392ac8c78a42cae5ca3faea3b4b0166dd00d4ca38b290d
- filename: machines/settings.typegen.ts
checksum: e4ae05822f1b1c23f3f70d03dd46fd8f29ba6b52d40f2f24c121f536fbb5f2c4
- filename: .env
checksum: 387e1fbafb92f58b152b751ec97e8e0e31a699c43e273c61bdedb67f8ee7e453
- filename: .github/workflows/ui-automation.yml
checksum: 0b26a5dcb7524ba15d6aaeaf04f2ef94be9d25ef702d9072d6628bcd58e50f36
- filename: injitest/src/test/java/androidTestCases/PinVcTest.java
@@ -211,5 +201,17 @@ fileignoreconfig:
checksum: 1a15e4327b358ffee8bddfe412a38873ad6d4414d2b1d6bffd3c1782f5ec852f
- filename: screens/Home/IntroSlidersScreen.tsx
checksum: 9880724461b194db7651737576ad2fd2db9cf3b4e732747f59be422a7ff4e4a1
- filename: .env
checksum: 9386b7d2d9bba27d8f15e6cb482451dc45b785b4caa31bc29718ef16967e6ed1
- filename: machines/VCItemMachine/VCItemMachine.typegen.ts
checksum: 850b5d02636bef9e286fc0fbc4ffffbd38068f332c319302a906496f4bc1c8a1
- filename: machines/VCItemMachine/VCItemEvents.ts
checksum: 04e5758d4fa8bc37e8b66f7f51627a9e71ccbca7a046aa64e914f5cf855aa48b
- filename: machines/VCItemMachine/VCItemGaurds.ts
checksum: 4f32814fc26a0edaa54a42dbc9f9e1d899144eb059ac8da211d1738887871829
- filename: machines/VCItemMachine/VCItemServices.ts
checksum: 51b4872a64abd76b124000358068c0b213d50fb131d735c122cd9a177cd8390c
- filename: machines/VCItemMachine/VCItemActions.ts
checksum: cda2ec61f0b884e537d05d018330d7b3c6febbf10ad4cd8cd87c715e6ad1dcf4
version: ""

View File

@@ -2,10 +2,11 @@
Inji Mobile Wallet is a mobile application specifically created to streamline all types of identification and credentials into one digital wallet.
It offers a secure, trustworthy, and dependable mobile Verifiable Credentials wallet designed to fulfil the following functions
- Download and store Verifiable Credentials
- Conduct offline face authentication
- Share Verifiable Credentials
- Enable users to log in to online portals
- Share Verifiable Credentials
- Enable users to log in to online portals
for more details refer [here](https://docs.mosip.io/inji)

View File

@@ -5,12 +5,12 @@ import {Column, Row, Text} from '../components/ui';
import {View} from 'react-native';
import {useKebabPopUp} from './KebabPopUpController';
import {ActorRefFrom} from 'xstate';
import {ExistingMosipVCItemMachine} from '../machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine';
import {useTranslation} from 'react-i18next';
import {FlatList} from 'react-native-gesture-handler';
import {VCMetadata} from '../shared/VCMetadata';
import testIDProps from '../shared/commonUtil';
import {getKebabMenuOptions} from './kebabMenuUtils';
import {VCItemMachine} from '../machines/VerifiableCredential/VCItemMachine/VCItemMachine';
export const KebabPopUp: React.FC<KebabPopUpProps> = props => {
const controller = useKebabPopUp(props);
@@ -83,7 +83,7 @@ export interface KebabPopUpProps {
vcMetadata: VCMetadata;
isVisible?: boolean;
onDismiss: () => void;
service: ActorRefFrom<typeof ExistingMosipVCItemMachine>;
service: ActorRefFrom<typeof VCItemMachine>;
iconColor?: any;
icon?: any;
vcHasImage: boolean;

View File

@@ -1,134 +1,86 @@
import {useSelector} from '@xstate/react';
import {ActorRefFrom} from 'xstate';
import {
selectAcceptingBindingOtp,
selectBindingAuthFailedError,
selectEmptyWalletBindingId,
selectBindingWarning,
selectIsCommunicationDetails,
selectIsPinned,
selectKebabPopUp,
selectAcceptingBindingOtp,
selectBindingWarning,
selectWalletBindingInProgress,
selectOtpError,
selectRemoveWalletWarning,
selectShowActivities,
selectWalletBindingResponse,
selectShowWalletBindingError,
selectWalletBindingError,
selectIsPhoneNumber,
selectIsEmail,
} from '../machines/VCItemMachine/commonSelectors';
import {
ExistingMosipVCItemEvents,
ExistingMosipVCItemMachine,
} from '../machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine';
import {
EsignetMosipVCItemEvents,
EsignetMosipVCItemMachine,
} from '../machines/VCItemMachine/EsignetMosipVCItem/EsignetMosipVCItemMachine';
selectWalletBindingInProgress,
} from '../machines/VerifiableCredential/VCItemMachine/VCItemSelectors';
import {selectActivities} from '../machines/activityLog';
import {GlobalContext} from '../shared/GlobalContext';
import {useContext, useState} from 'react';
import {useContext} from 'react';
import {VCMetadata} from '../shared/VCMetadata';
import {ScanEvents} from '../machines/bleShare/scan/scanMachine';
import {
BOTTOM_TAB_ROUTES,
SCAN_ROUTES,
ScanStackParamList,
} from '../routes/routesConstants';
import {BOTTOM_TAB_ROUTES, ScanStackParamList} from '../routes/routesConstants';
import {NavigationProp, useNavigation} from '@react-navigation/native';
import {MainBottomTabParamList} from '../routes/main';
import {selectIsScanning} from '../machines/bleShare/scan/selectors';
import {
VCItemEvents,
VCItemMachine,
} from '../machines/VerifiableCredential/VCItemMachine/VCItemMachine';
import {selectError} from '../machines/biometrics';
type ScanLayoutNavigation = NavigationProp<
ScanStackParamList & MainBottomTabParamList
>;
export function useKebabPopUp(props) {
const service = props.service as
| ActorRefFrom<typeof ExistingMosipVCItemMachine>
| ActorRefFrom<typeof EsignetMosipVCItemMachine>;
const service = props.service as ActorRefFrom<typeof VCItemMachine>;
const navigation = useNavigation<ScanLayoutNavigation>();
const vcEvents =
props.vcKey !== undefined && props.vcMetadata.isFromOpenId4VCI()
? EsignetMosipVCItemEvents
: ExistingMosipVCItemEvents;
const PIN_CARD = () => service.send(vcEvents.PIN_CARD());
const KEBAB_POPUP = () => service.send(vcEvents.KEBAB_POPUP());
const ADD_WALLET_BINDING_ID = () =>
service.send(vcEvents.ADD_WALLET_BINDING_ID());
const CONFIRM = () => service.send(vcEvents.CONFIRM());
const REMOVE = (vcMetadata: VCMetadata) =>
service.send(vcEvents.REMOVE(vcMetadata));
const DISMISS = () => service.send(vcEvents.DISMISS());
const CANCEL = () => service.send(vcEvents.CANCEL());
const SHOW_ACTIVITY = () => service.send(vcEvents.SHOW_ACTIVITY());
const INPUT_OTP = (otp: string) => service.send(vcEvents.INPUT_OTP(otp));
const RESEND_OTP = () => service.send(vcEvents.RESEND_OTP());
const isPinned = useSelector(service, selectIsPinned);
const isBindingWarning = useSelector(service, selectBindingWarning);
const isRemoveWalletWarning = useSelector(service, selectRemoveWalletWarning);
const isAcceptingOtpInput = useSelector(service, selectAcceptingBindingOtp);
const isWalletBindingError = useSelector(
service,
selectShowWalletBindingError,
);
const otpError = useSelector(service, selectOtpError);
const walletBindingError = useSelector(service, selectWalletBindingError);
const bindingAuthFailedError = useSelector(
service,
selectBindingAuthFailedError,
);
const WalletBindingInProgress = useSelector(
service,
selectWalletBindingInProgress,
);
const emptyWalletBindingId = useSelector(service, selectEmptyWalletBindingId);
const isKebabPopUp = useSelector(service, selectKebabPopUp);
const isShowActivities = useSelector(service, selectShowActivities);
const phoneNumber = useSelector(service, selectIsPhoneNumber);
const email = useSelector(service, selectIsEmail);
const {appService} = useContext(GlobalContext);
const activityLogService = appService.children.get('activityLog');
const scanService = appService.children.get('scan');
const isScanning = useSelector(scanService, selectIsScanning);
const GOTO_SCANSCREEN = () => {
navigation.navigate(BOTTOM_TAB_ROUTES.share);
};
const activityLogService = appService.children.get('activityLog')!!;
const scanService = appService.children.get('scan')!!;
return {
isPinned,
PIN_CARD,
KEBAB_POPUP,
ADD_WALLET_BINDING_ID,
CONFIRM,
GOTO_SCANSCREEN,
DISMISS,
REMOVE,
CANCEL,
INPUT_OTP,
RESEND_OTP,
SHOW_ACTIVITY,
service: props.service as ActorRefFrom<typeof VCItemMachine>,
navigation: useNavigation<ScanLayoutNavigation>(),
isScanning: useSelector(scanService, selectIsScanning),
activities: useSelector(activityLogService, selectActivities),
isPinned: useSelector(service, selectIsPinned),
isBindingWarning: useSelector(service, selectBindingWarning),
isRemoveWalletWarning: useSelector(service, selectRemoveWalletWarning),
isAcceptingOtpInput: useSelector(service, selectAcceptingBindingOtp),
isWalletBindingError: useSelector(service, selectShowWalletBindingError),
walletBindingResponse: useSelector(service, selectWalletBindingResponse),
otpError: useSelector(service, selectError),
walletBindingError: useSelector(service, selectError),
bindingAuthFailedError: useSelector(service, selectBindingAuthFailedError),
isKebabPopUp: useSelector(service, selectKebabPopUp),
isShowActivities: useSelector(service, selectShowActivities),
communicationDetails: useSelector(service, selectIsCommunicationDetails),
walletBindingInProgress: useSelector(
service,
selectWalletBindingInProgress,
),
PIN_CARD: () => service.send(VCItemEvents.PIN_CARD()),
KEBAB_POPUP: () => service.send(VCItemEvents.KEBAB_POPUP()),
ADD_WALLET_BINDING_ID: () =>
service.send(VCItemEvents.ADD_WALLET_BINDING_ID()),
CONFIRM: () => service.send(VCItemEvents.CONFIRM()),
REMOVE: (vcMetadata: VCMetadata) =>
service.send(VCItemEvents.REMOVE(vcMetadata)),
DISMISS: () => service.send(VCItemEvents.DISMISS()),
CANCEL: () => service.send(VCItemEvents.CANCEL()),
SHOW_ACTIVITY: () => service.send(VCItemEvents.SHOW_ACTIVITY()),
INPUT_OTP: (otp: string) => service.send(VCItemEvents.INPUT_OTP(otp)),
RESEND_OTP: () => service.send(VCItemEvents.RESEND_OTP()),
GOTO_SCANSCREEN: () => {
navigation.navigate(BOTTOM_TAB_ROUTES.share);
},
SELECT_VC_ITEM: (
vcRef: ActorRefFrom<typeof ExistingMosipVCItemMachine>,
vcRef: ActorRefFrom<typeof VCItemMachine>,
flowType: string,
) => {
const {serviceRefs, ...vcData} = vcRef.getSnapshot().context;
scanService.send(ScanEvents.SELECT_VC(vcData, flowType));
},
isScanning,
isBindingWarning,
isAcceptingOtpInput,
isWalletBindingError,
walletBindingError,
bindingAuthFailedError,
otpError,
WalletBindingInProgress,
emptyWalletBindingId,
isKebabPopUp,
isShowActivities,
isRemoveWalletWarning,
activities: useSelector(activityLogService, selectActivities),
phoneNumber,
email,
};
}

View File

@@ -0,0 +1,45 @@
import {useContext, useRef} from 'react';
import {GlobalContext} from '../../shared/GlobalContext';
import {
selectContext,
selectGeneratedOn,
selectKebabPopUp,
selectWalletBindingResponse,
selectCredential,
selectVerifiableCredentialData,
} from '../../machines/VerifiableCredential/VCItemMachine/VCItemSelectors';
import {useInterpret, useSelector} from '@xstate/react';
import {VCItemProps} from './Views/VCCardView';
import {
createVCItemMachine,
VCItemEvents,
} from '../../machines/VerifiableCredential/VCItemMachine/VCItemMachine';
import {selectIsSavingFailedInIdle} from '../../screens/Home/MyVcsTabMachine';
export function useVcItemController(props: VCItemProps) {
const {appService} = useContext(GlobalContext);
const machine = useRef(
createVCItemMachine(
appService.getSnapshot().context.serviceRefs,
props.vcMetadata,
),
);
const service = useInterpret(machine.current, {devTools: __DEV__});
return {
service,
context: useSelector(service, selectContext),
credential: useSelector(service, selectCredential),
verifiableCredentialData: useSelector(
service,
selectVerifiableCredentialData,
),
walletBindingResponse: useSelector(service, selectWalletBindingResponse),
isKebabPopUp: useSelector(service, selectKebabPopUp),
DISMISS: () => service.send(VCItemEvents.DISMISS()),
KEBAB_POPUP: () => service.send(VCItemEvents.KEBAB_POPUP()),
isSavingFailedInIdle: useSelector(service, selectIsSavingFailedInIdle),
storeErrorTranslationPath: 'errors.savingFailed',
generatedOn: useSelector(service, selectGeneratedOn),
};
}

View File

@@ -1,12 +1,6 @@
import React from 'react';
import {
EsignetVCItemDetailsProps,
ExistingVCItemDetailsProps,
VCDetailView,
} from './Views/VCDetailView';
import {VCDetailView, VCItemDetailsProps} from './Views/VCDetailView';
export const VcDetailsContainer: React.FC<
ExistingVCItemDetailsProps | EsignetVCItemDetailsProps
> = props => {
export const VcDetailsContainer: React.FC<VCItemDetailsProps> = props => {
return <VCDetailView {...props} />;
};

View File

@@ -1,12 +1,6 @@
import React from 'react';
import {
VCCardView,
EsignetVCItemProps,
ExistingVCItemProps,
} from './Views/VCCardView';
import {VCCardView, VCItemProps} from './Views/VCCardView';
export const VcItemContainer: React.FC<
ExistingVCItemProps | EsignetVCItemProps
> = props => {
export const VcItemContainer: React.FC<VCItemProps> = props => {
return <VCCardView {...props} />;
};

View File

@@ -1,67 +0,0 @@
import {useContext, useRef} from 'react';
import {GlobalContext} from '../../shared/GlobalContext';
import {
selectContext,
selectEmptyWalletBindingId,
selectGeneratedOn,
selectKebabPopUp,
selectVerifiableCredential,
} from '../../machines/VCItemMachine/commonSelectors';
import {
createExistingMosipVCItemMachine,
ExistingMosipVCItemEvents,
selectIsSavingFailedInIdle,
} from '../../machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine';
import {
createEsignetMosipVCItemMachine,
EsignetMosipVCItemEvents,
} from '../../machines/VCItemMachine/EsignetMosipVCItem/EsignetMosipVCItemMachine';
import {useInterpret, useSelector} from '@xstate/react';
import {EsignetVCItemProps, ExistingVCItemProps} from './Views/VCCardView';
import {VCMetadata} from '../../shared/VCMetadata';
export function useVcItemController(
props: ExistingVCItemProps | EsignetVCItemProps,
) {
const {appService} = useContext(GlobalContext);
const vcMetadata = VCMetadata.fromVC(props.vcMetadata);
const machine = useRef(
!vcMetadata.isFromOpenId4VCI()
? createExistingMosipVCItemMachine(
appService.getSnapshot().context.serviceRefs,
props.vcMetadata,
)
: createEsignetMosipVCItemMachine(
appService.getSnapshot().context.serviceRefs,
props.vcMetadata,
),
);
const service = useInterpret(machine.current, {devTools: __DEV__});
const context = useSelector(service, selectContext);
const verifiableCredential = useSelector(service, selectVerifiableCredential);
const emptyWalletBindingId = useSelector(service, selectEmptyWalletBindingId);
const isKebabPopUp = useSelector(service, selectKebabPopUp);
let DISMISS = () => service.send(ExistingMosipVCItemEvents.DISMISS());
let KEBAB_POPUP = () => service.send(ExistingMosipVCItemEvents.KEBAB_POPUP());
const isSavingFailedInIdle = useSelector(service, selectIsSavingFailedInIdle);
const storeErrorTranslationPath = 'errors.savingFailed';
const generatedOn = useSelector(service, selectGeneratedOn);
if (vcMetadata.isFromOpenId4VCI()) {
DISMISS = () => service.send(EsignetMosipVCItemEvents.DISMISS());
KEBAB_POPUP = () => service.send(EsignetMosipVCItemEvents.KEBAB_POPUP());
}
return {
service,
context,
verifiableCredential,
emptyWalletBindingId,
isKebabPopUp,
DISMISS,
KEBAB_POPUP,
isSavingFailedInIdle,
storeErrorTranslationPath,
generatedOn,
};
}

View File

@@ -1,30 +1,28 @@
import React, {useEffect, useState} from 'react';
import {Pressable, View} from 'react-native';
import {ActorRefFrom} from 'xstate';
import {
ExistingMosipVCItemEvents,
ExistingMosipVCItemMachine,
} from '../../../machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine';
import {ErrorMessageOverlay} from '../../MessageOverlay';
import {Theme} from '../../ui/styleUtils';
import {VCMetadata} from '../../../shared/VCMetadata';
import {format} from 'date-fns';
import {EsignetMosipVCItemMachine} from '../../../machines/VCItemMachine/EsignetMosipVCItem/EsignetMosipVCItemMachine';
import {VCCardSkeleton} from '../common/VCCardSkeleton';
import {VCCardViewContent} from './VCCardViewContent';
import {useVcItemController} from '../VcItemController';
import {useVcItemController} from '../VCItemController';
import {getCredentialIssuersWellKnownConfig} from '../../../shared/openId4VCI/Utils';
import {CARD_VIEW_DEFAULT_FIELDS, isVCLoaded} from '../common/VCUtils';
import {
VCItemEvents,
VCItemMachine,
} from '../../../machines/VerifiableCredential/VCItemMachine/VCItemMachine';
export const VCCardView: React.FC<
ExistingVCItemProps | EsignetVCItemProps
> = props => {
export const VCCardView: React.FC<VCItemProps> = props => {
let {
service,
context,
verifiableCredential,
emptyWalletBindingId,
credential,
verifiableCredentialData,
walletBindingResponse,
isKebabPopUp,
isSavingFailedInIdle,
storeErrorTranslationPath,
@@ -37,37 +35,27 @@ export const VCCardView: React.FC<
generatedOn && format(new Date(generatedOn), 'MM/dd/yyyy');
useEffect(() => {
service.send(
ExistingMosipVCItemEvents.UPDATE_VC_METADATA(props.vcMetadata),
);
service.send(VCItemEvents.UPDATE_VC_METADATA(props.vcMetadata));
}, [props.vcMetadata]);
const credential = props.isDownloading
? null
: new VCMetadata(props.vcMetadata).isFromOpenId4VCI()
? verifiableCredential?.credential
: verifiableCredential;
const vc = props.isDownloading ? null : credential;
const [fields, setFields] = useState([]);
const [wellknown, setWellknown] = useState(null);
useEffect(() => {
getCredentialIssuersWellKnownConfig(
props?.vcMetadata.issuer,
verifiableCredential?.wellKnown,
verifiableCredential?.credentialTypes,
verifiableCredentialData?.issuer,
verifiableCredentialData?.wellKnown,
verifiableCredentialData?.credentialTypes,
CARD_VIEW_DEFAULT_FIELDS,
).then(response => {
setWellknown(response.wellknown);
setFields(response.fields);
});
}, [verifiableCredential?.wellKnown]);
}, [verifiableCredentialData?.wellKnown]);
if (!isVCLoaded(verifiableCredential, fields) || wellknown === null) {
return (
<View style={Theme.Styles.closeCardBgContainer}>
<VCCardSkeleton />
</View>
);
if (!isVCLoaded(credential, fields)) {
return <VCCardSkeleton />;
}
return (
@@ -83,9 +71,9 @@ export const VCCardView: React.FC<
<VCCardViewContent
vcMetadata={props.vcMetadata}
context={context}
verifiableCredential={verifiableCredential}
emptyWalletBindingId={emptyWalletBindingId}
credential={credential}
walletBindingResponse={walletBindingResponse}
credential={vc}
verifiableCredentialData={verifiableCredentialData}
fields={fields}
wellknown={wellknown}
generatedOn={formattedDate}
@@ -99,7 +87,7 @@ export const VCCardView: React.FC<
isKebabPopUp={isKebabPopUp}
DISMISS={DISMISS}
KEBAB_POPUP={KEBAB_POPUP}
isVerified={verifiableCredential !== null}
isVerified={credential !== null}
/>
</Pressable>
<ErrorMessageOverlay
@@ -112,25 +100,13 @@ export const VCCardView: React.FC<
);
};
export interface ExistingVCItemProps {
export interface VCItemProps {
vcMetadata: VCMetadata;
margin?: string;
selectable?: boolean;
selected?: boolean;
onPress?: (vcRef?: ActorRefFrom<typeof ExistingMosipVCItemMachine>) => void;
onShow?: (vcRef?: ActorRefFrom<typeof ExistingMosipVCItemMachine>) => void;
isDownloading?: boolean;
isPinned?: boolean;
flow?: string;
}
export interface EsignetVCItemProps {
vcMetadata: VCMetadata;
margin?: string;
selectable?: boolean;
selected?: boolean;
onPress?: (vcRef?: ActorRefFrom<typeof EsignetMosipVCItemMachine>) => void;
onShow?: (vcRef?: ActorRefFrom<typeof EsignetMosipVCItemMachine>) => void;
onPress?: (vcRef?: ActorRefFrom<typeof VCItemMachine>) => void;
onShow?: (vcRef?: ActorRefFrom<typeof VCItemMachine>) => void;
isDownloading?: boolean;
isPinned?: boolean;
flow?: string;

View File

@@ -1,34 +1,25 @@
import React from 'react';
import {ImageBackground, Pressable} from 'react-native';
import {ImageBackground, Pressable, Image} from 'react-native';
import {getLocalizedField} from '../../../i18n';
import {VCMetadata} from '../../../shared/VCMetadata';
import {KebabPopUp} from '../../KebabPopUp';
import {VerifiableCredential} from '../../../types/VC/ExistingMosipVC/vc';
import {VerifiableCredential} from '../../../types/VC/vc';
import {Column, Row} from '../../ui';
import {Theme} from '../../ui/styleUtils';
import {CheckBox, Icon} from 'react-native-elements';
import {SvgImage} from '../../ui/svg';
import {faceImageSource} from '../../VcItemContainerProfileImage';
import {
getIssuerLogo,
isVCLoaded,
setBackgroundColour,
} from '../common/VCUtils';
import {setTextColor} from '../common/VCItemField';
import {VCItemFieldValue} from '../common/VCItemField';
import {VcItemContainerProfileImage} from '../../VcItemContainerProfileImage';
import {isVCLoaded, setBackgroundColour} from '../common/VCUtils';
import {setTextColor, VCItemFieldValue} from '../common/VCItemField';
import {WalletBinding} from '../../../screens/Home/MyVcs/WalletBinding';
import {VCVerification} from '../../VCVerification';
import {Issuers} from '../../../shared/openId4VCI/Utils';
import {VCItemContainerFlowType} from '../../../shared/Utils';
import {RemoveVcWarningOverlay} from '../../../screens/Home/MyVcs/RemoveVcWarningOverlay';
import {HistoryTab} from '../../../screens/Home/MyVcs/HistoryTab';
import {VcItemContainerProfileImage} from '../../VcItemContainerProfileImage';
export const VCCardViewContent: React.FC<
ExistingMosipVCItemContentProps | EsignetMosipVCItemContentProps
> = props => {
const selectableOrCheck = props.selectable && (
export const VCCardViewContent: React.FC<VCItemContentProps> = props => {
const isVCSelectable = props.selectable && (
<CheckBox
checked={props.selected}
checkedIcon={
@@ -43,15 +34,15 @@ export const VCCardViewContent: React.FC<
onPress={() => props.onPress()}
/>
);
const issuerLogo = props.verifiableCredentialData.issuerLogo;
const faceImage = props.verifiableCredentialData.face;
return (
<ImageBackground
source={!props.credential ? null : Theme.CloseCard}
source={Theme.CloseCard}
resizeMode="stretch"
style={[
!props.credential
? Theme.Styles.vertloadingContainer
: Theme.Styles.backgroundImageContainer,
Theme.Styles.backgroundImageContainer,
setBackgroundColour(props.wellknown),
]}>
<Column>
@@ -74,16 +65,20 @@ export const VCCardViewContent: React.FC<
</Row>
</Column>
{!isVCLoaded(props.credential, props.fields)
? null
: getIssuerLogo(
new VCMetadata(props.vcMetadata).isFromOpenId4VCI(),
props.verifiableCredential?.issuerLogo,
)}
{isVCLoaded(props.credential, props.fields) && (
<Image
src={issuerLogo?.url}
alt={issuerLogo?.alt_text}
style={Theme.Styles.issuerLogo}
resizeMethod="scale"
resizeMode="contain"
/>
)}
{!Object.values(VCItemContainerFlowType).includes(props.flow) && (
<>
{props.vcMetadata.issuer === Issuers.Sunbird ||
!props.emptyWalletBindingId
props.walletBindingResponse
? SvgImage.walletActivatedIcon()
: SvgImage.walletUnActivatedIcon()}
<Pressable
@@ -98,12 +93,12 @@ export const VCCardViewContent: React.FC<
isVisible={props.isKebabPopUp}
onDismiss={props.DISMISS}
service={props.service}
vcHasImage={faceImageSource(props) !== undefined}
vcHasImage={faceImage !== undefined}
/>
</Pressable>
</>
)}
{props.credential && selectableOrCheck}
{isVCSelectable}
</Row>
<WalletBinding service={props.service} vcMetadata={props.vcMetadata} />
@@ -120,10 +115,10 @@ export const VCCardViewContent: React.FC<
);
};
export interface ExistingMosipVCItemContentProps {
export interface VCItemContentProps {
context: any;
verifiableCredential: VerifiableCredential;
credential: VerifiableCredential;
verifiableCredentialData: any;
fields: [];
wellknown: {};
generatedOn: string;
@@ -134,29 +129,7 @@ export interface ExistingMosipVCItemContentProps {
onPress?: () => void;
isDownloading?: boolean;
flow?: string;
emptyWalletBindingId: boolean;
KEBAB_POPUP: () => {};
DISMISS: () => {};
isKebabPopUp: boolean;
vcMetadata: VCMetadata;
isVerified?: boolean;
}
export interface EsignetMosipVCItemContentProps {
context: any;
credential: VerifiableCredential;
fields: [];
wellknown: {};
generatedOn: string;
selectable: boolean;
selected: boolean;
isPinned?: boolean;
service: any;
onPress?: () => void;
isDownloading?: boolean;
flow?: string;
emptyWalletBindingId: boolean;
verifiableCredential: VerifiableCredential;
walletBindingResponse: {};
KEBAB_POPUP: () => {};
DISMISS: () => {};
isKebabPopUp: boolean;

View File

@@ -1,19 +1,13 @@
import React, {useEffect, useState} from 'react';
import {useTranslation} from 'react-i18next';
import {Image, ImageBackground, View} from 'react-native';
import {Icon} from 'react-native-elements';
import {VC} from '../../../types/VC/ExistingMosipVC/vc';
import {
VerifiableCredential,
WalletBindingResponse,
} from '../../../types/VC/vc';
import {Button, Column, Row, Text} from '../../ui';
import {Theme} from '../../ui/styleUtils';
import {QrCodeOverlay} from '../../QrCodeOverlay';
import {VCMetadata} from '../../../shared/VCMetadata';
import {
VcIdType,
VerifiableCredential,
VerifiablePresentation,
} from '../../../types/VC/EsignetMosipVC/vc';
import {WalletBindingResponse} from '../../../shared/cryptoutil/cryptoUtil';
import {logoType} from '../../../machines/issuersMachine';
import {SvgImage} from '../../ui/svg';
import {
getDetailedViewFields,
@@ -31,40 +25,10 @@ import {setTextColor} from '../common/VCItemField';
import {ActivityIndicator} from '../../ui/ActivityIndicator';
import {ProfileIcon} from '../../ProfileIcon';
const getIssuerLogo = (isOpenId4VCI: boolean, issuerLogo: logoType) => {
if (isOpenId4VCI) {
const getProfileImage = (face: any) => {
if (face) {
return (
<Image
testID="esignetLogo"
src={issuerLogo?.url}
alt={issuerLogo?.alt_text}
style={Theme.Styles.issuerLogo}
/>
);
}
return SvgImage.MosipLogo(Theme.Styles.vcDetailsLogo);
};
const getProfileImage = (
props: ExistingVCItemDetailsProps | EsignetVCItemDetailsProps,
verifiableCredential,
isOpenId4VCI,
) => {
if (isOpenId4VCI) {
if (verifiableCredential?.credentialSubject?.face) {
return (
<Image
source={{uri: verifiableCredential?.credentialSubject.face}}
style={Theme.Styles.detailedViewImage}
/>
);
}
} else if (props?.vc?.credential?.biometrics?.face) {
return (
<Image
source={{uri: props?.vc?.credential.biometrics.face}}
style={Theme.Styles.detailedViewImage}
/>
<Image source={{uri: face}} style={Theme.Styles.detailedViewImage} />
);
}
return (
@@ -75,33 +39,25 @@ const getProfileImage = (
);
};
export const VCDetailView: React.FC<
ExistingVCItemDetailsProps | EsignetVCItemDetailsProps
> = props => {
export const VCDetailView: React.FC<VCItemDetailsProps> = props => {
const {t, i18n} = useTranslation('VcDetails');
let isOpenId4VCI = VCMetadata.fromVC(props.vc.vcMetadata).isFromOpenId4VCI();
const issuerLogo = getIssuerLogo(
isOpenId4VCI,
props.vc?.verifiableCredential?.issuerLogo,
);
const verifiableCredential = isOpenId4VCI
? props.vc?.verifiableCredential.credential
: props.vc?.verifiableCredential;
const logo = props.verifiableCredentialData.issuerLogo;
const face = props.verifiableCredentialData.face;
const verifiableCredential = props.credential;
let [fields, setFields] = useState([]);
const [wellknown, setWellknown] = useState(null);
useEffect(() => {
getDetailedViewFields(
VCMetadata.fromVC(props.vc.vcMetadata).issuer,
props.vc?.verifiableCredential?.wellKnown,
props.vc?.verifiableCredential?.credentialTypes,
props.verifiableCredentialData?.issuer,
props.verifiableCredentialData?.wellKnown,
props.verifiableCredentialData?.credentialTypes,
DETAIL_VIEW_DEFAULT_FIELDS,
).then(response => {
setWellknown(response.wellknown);
setFields(response.fields);
});
}, [props.verifiableCredential?.wellKnown]);
}, [props.verifiableCredentialData?.wellKnown]);
const shouldShowHrLine = verifiableCredential => {
const availableFieldNames = Object.keys(
@@ -141,14 +97,20 @@ export const VCDetailView: React.FC<
source={Theme.OpenCard}>
<Row padding="14 14 0 14" margin="0 0 0 0">
<Column crossAlign="center">
{getProfileImage(props, verifiableCredential, isOpenId4VCI)}
{getProfileImage(face)}
<QrCodeOverlay qrCodeDetails={String(verifiableCredential)} />
<Column
width={80}
height={59}
crossAlign="center"
margin="12 0 0 0">
{issuerLogo}
<Image
src={logo?.url}
alt={logo?.alt_text}
style={Theme.Styles.issuerLogo}
resizeMethod="scale"
resizeMode="contain"
/>
</Column>
</Column>
<Column
@@ -187,15 +149,15 @@ export const VCDetailView: React.FC<
</Column>
</Column>
</Column>
{props.vcHasImage ? (
{props.vcHasImage && (
<View
style={{
position: 'relative',
backgroundColor: Theme.Colors.DetailedViewBackground,
}}>
{props.activeTab !== 1 ? (
props.isBindingPending &&
isActivationNeeded(props.vc.vcMetadata.issuer) ? (
{props.activeTab !== 1 && (
!props.walletBindingResponse &&
isActivationNeeded(props.verifiableCredentialData?.issuer)? (
<Column
padding="10"
style={Theme.Styles.detailedViewActivationPopupContainer}>
@@ -252,7 +214,9 @@ export const VCDetailView: React.FC<
fontSize: 14,
}}
margin={'0 18 0 0'}>
{isActivationNeeded(props.vc.vcMetadata.issuer)
{isActivationNeeded(
props.verifiableCredentialData?.issuer,
)
? t('profileAuthenticated')
: t('credentialActivated')}
</Text>
@@ -260,45 +224,18 @@ export const VCDetailView: React.FC<
</Row>
</Column>
)
) : (
<></>
)}
) }
</View>
) : (
<></>
)}
) }
</>
);
};
export interface ExistingVCItemDetailsProps {
vc: VC;
isBindingPending: boolean;
export interface VCItemDetailsProps {
credential: VerifiableCredential | Credential;
verifiableCredentialData: any;
walletBindingResponse: WalletBindingResponse;
onBinding?: () => void;
activeTab?: Number;
vcHasImage: boolean;
}
export interface EsignetVCItemDetailsProps {
vc: EsignetVC;
isBindingPending: boolean;
onBinding?: () => void;
activeTab?: number;
vcHasImage: boolean;
}
export interface EsignetVC {
id: string;
idType: VcIdType;
verifiableCredential: VerifiableCredential;
verifiablePresentation?: VerifiablePresentation;
generatedOn: Date;
requestId: string;
isVerified: boolean;
lastVerifiedOn: number;
shouldVerifyPresence?: boolean;
walletBindingResponse?: WalletBindingResponse;
credentialRegistry: string;
isPinned?: boolean;
hashedId: string;
}

View File

@@ -1,50 +1,52 @@
import {Theme} from '../../ui/styleUtils';
import {Column, Row} from '../../ui';
import {ImageBackground} from 'react-native';
import {ImageBackground, View} from 'react-native';
import React from 'react';
import LinearGradient from 'react-native-linear-gradient';
import ShimmerPlaceholder from 'react-native-shimmer-placeholder';
export const VCCardSkeleton = () => {
return (
<ImageBackground
source={Theme.CloseCard}
resizeMode="stretch"
style={Theme.Styles.vertloadingContainer}>
<Column>
<Row crossAlign="center">
<ShimmerPlaceholder
LinearGradient={LinearGradient}
width={40}
height={53}
style={{borderRadius: 5}}
/>
<Column fill align={'space-around'} margin={'0 10 0 10'}>
<View style={Theme.Styles.closeCardBgContainer}>
<ImageBackground
source={Theme.CloseCard}
resizeMode="stretch"
style={Theme.Styles.vertloadingContainer}>
<Column>
<Row crossAlign="center">
<ShimmerPlaceholder
LinearGradient={LinearGradient}
width={100}
style={{borderRadius: 5, marginTop: 5}}
width={40}
height={53}
style={{borderRadius: 5}}
/>
<Column fill align={'space-around'} margin={'0 10 0 10'}>
<ShimmerPlaceholder
LinearGradient={LinearGradient}
width={100}
style={{borderRadius: 5, marginTop: 5}}
/>
<ShimmerPlaceholder
LinearGradient={LinearGradient}
width={50}
style={{borderRadius: 5, marginTop: 5}}
/>
</Column>
<ShimmerPlaceholder
LinearGradient={LinearGradient}
width={35}
height={35}
style={{borderRadius: 5}}
/>
<ShimmerPlaceholder
LinearGradient={LinearGradient}
width={50}
style={{borderRadius: 5, marginTop: 5}}
width={18}
height={22}
style={{borderRadius: 5, marginLeft: 10}}
/>
</Column>
<ShimmerPlaceholder
LinearGradient={LinearGradient}
width={35}
height={35}
style={{borderRadius: 5}}
/>
<ShimmerPlaceholder
LinearGradient={LinearGradient}
width={18}
height={22}
style={{borderRadius: 5, marginLeft: 10}}
/>
</Row>
</Column>
</ImageBackground>
</Row>
</Column>
</ImageBackground>
</View>
);
};

View File

@@ -1,18 +1,13 @@
import {
CredentialSubject,
VerifiableCredential,
} from '../../../types/VC/ExistingMosipVC/vc';
import {CredentialSubject, VerifiableCredential} from '../../../types/VC/vc';
import i18n, {getLocalizedField} from '../../../i18n';
import {Row} from '../../ui';
import {VCItemField} from './VCItemField';
import React from 'react';
import {logoType} from '../../../machines/issuersMachine';
import {Image} from 'react-native';
import {Theme} from '../../ui/styleUtils';
import {SvgImage} from '../../ui/svg';
import {CREDENTIAL_REGISTRY_EDIT} from 'react-native-dotenv';
import {getIDType} from '../../../shared/openId4VCI/Utils';
import {VCVerification} from '../../VCVerification';
import {MIMOTO_BASE_URL} from '../../../shared/constants';
export const CARD_VIEW_DEFAULT_FIELDS = ['fullName'];
export const DETAIL_VIEW_DEFAULT_FIELDS = [
@@ -179,17 +174,9 @@ export const isVCLoaded = (verifiableCredential: any, fields: string[]) => {
return verifiableCredential != null && fields.length > 0;
};
export const getIssuerLogo = (isOpenId4VCI: boolean, issuerLogo: logoType) => {
if (isOpenId4VCI) {
return (
<Image
src={issuerLogo?.url}
alt={issuerLogo?.alt_text}
style={Theme.Styles.issuerLogo}
resizeMethod="scale"
resizeMode="contain"
/>
);
}
return SvgImage.MosipLogo(Theme.Styles.logo);
export const getMosipLogo = () => {
return {
url: `${MIMOTO_BASE_URL}/inji/mosip-logo.png`,
alt_text: 'a square logo of mosip',
};
};

View File

@@ -1,135 +0,0 @@
import React from 'react';
import {useTranslation} from 'react-i18next';
import {Dimensions} from 'react-native';
import {Icon} from 'react-native-elements';
import {ActorRefFrom} from 'xstate';
import {vcItemMachine} from '../machines/vcItem';
import {VerifiableCredential} from '../types/vc';
import {Row, Text} from './ui';
import {Theme} from './ui/styleUtils';
const WalletUnverifiedIcon: React.FC = () => {
return (
<Icon
name="shield-alert"
color={Theme.Colors.Icon}
size={28}
type="material-community"
containerStyle={{marginStart: 4, bottom: 1}}
/>
);
};
const WalletVerifiedIcon: React.FC = () => {
return (
<Icon
name="verified-user"
color={Theme.Colors.VerifiedIcon}
size={28}
containerStyle={{marginStart: 4, bottom: 1}}
/>
);
};
const WalletUnverifiedActivationDetails: React.FC<
WalletUnVerifiedDetailsProps
> = props => {
const {t} = useTranslation('VcDetails');
return (
<Row
width={Dimensions.get('screen').width * 0.8}
align="space-between"
crossAlign="center">
<Row
crossAlign="center"
style={{
flex: 1,
}}>
{props.verifiableCredential && <WalletUnverifiedIcon />}
<Text
color={Theme.Colors.Details}
weight="semibold"
size="small"
margin="10 33 10 10"
style={
!props.verifiableCredential
? Theme.Styles.loadingTitle
: Theme.Styles.statusLabel
}
children={t('offlineAuthDisabledHeader')}></Text>
</Row>
</Row>
);
};
const WalletVerifiedActivationDetails: React.FC<WalletVerifiedDetailsProps> = (
props
) => {
const { t } = useTranslation('VcDetails');
return (
<Row
width={Dimensions.get('screen').width * 0.8}
align="space-between"
crossAlign="center">
<Row
crossAlign="center"
style={{
flex: 1,
}}>
<WalletVerifiedIcon />
<Text
color={Theme.Colors.statusLabel}
weight="semibold"
size="smaller"
margin="10 10 10 10"
style={
!props.verifiableCredential
? Theme.Styles.loadingTitle
: Theme.Styles.subtitle
}
children={t('profileAuthenticated')}></Text>
</Row>
</Row>
);
};
export const VcItemActivationStatus: React.FC<VcItemActivationStatusProps> = (
props
) => {
return (
<Row>
{props.emptyWalletBindingId ? (
<WalletUnverifiedActivationDetails
verifiableCredential={props.verifiableCredential}
onPress={props.onPress}
/>
) : (
<WalletVerifiedActivationDetails
verifiableCredential={props.verifiableCredential}
showOnlyBindedVc={props.showOnlyBindedVc}
onPress={props.onPress}
/>
)}
</Row>
);
};
interface VcItemActivationStatusProps {
showOnlyBindedVc: boolean;
onPress: (vcRef?: ActorRefFrom<typeof vcItemMachine>) => void;
verifiableCredential: VerifiableCredential;
emptyWalletBindingId: boolean;
}
interface WalletVerifiedDetailsProps {
showOnlyBindedVc: boolean;
onPress: (vcRef?: ActorRefFrom<typeof vcItemMachine>) => void;
verifiableCredential: VerifiableCredential;
}
interface WalletUnVerifiedDetailsProps {
onPress: (vcRef?: ActorRefFrom<typeof vcItemMachine>) => void;
verifiableCredential: VerifiableCredential;
}

View File

@@ -1,19 +1,12 @@
import {
EsignetMosipVCItemContentProps,
ExistingMosipVCItemContentProps,
} from './VC/Views/VCCardViewContent';
import {VerifiableCredential} from '../types/VC/ExistingMosipVC/vc';
import {VCItemContentProps} from './VC/Views/VCCardViewContent';
import {ImageBackground} from 'react-native';
import {Theme} from './ui/styleUtils';
import React from 'react';
import {ProfileIcon} from './ProfileIcon';
import {VCMetadata} from '../shared/VCMetadata';
import {SvgImage} from './ui/svg';
export const VcItemContainerProfileImage = (
props: ExistingMosipVCItemContentProps | EsignetMosipVCItemContentProps,
) => {
const imageUri = faceImageSource(props);
export const VcItemContainerProfileImage = (props: VCItemContentProps) => {
const imageUri = props.verifiableCredentialData.face;
return imageUri ? (
<ImageBackground
@@ -32,15 +25,3 @@ export const VcItemContainerProfileImage = (
</>
);
};
export function faceImageSource(props: faceImageSourceProps) {
return new VCMetadata(props?.vcMetadata)?.isFromOpenId4VCI()
? props?.credential?.credentialSubject?.face
: props?.context?.credential?.biometrics?.face;
}
interface faceImageSourceProps {
vcMetadata: VCMetadata;
credential: VerifiableCredential;
context: any;
}

View File

@@ -1,205 +0,0 @@
import React from 'react';
import {useTranslation} from 'react-i18next';
import {Image, ImageBackground, View} from 'react-native';
import {getLocalizedField} from '../i18n';
import {VerifiableCredential} from '../types/vc';
import {VcItemTags} from './VcItemTags';
import VerifiedIcon from './VerifiedIcon';
import {Column, Row, Text} from './ui';
import {Theme} from './ui/styleUtils';
import {CheckBox, Icon} from 'react-native-elements';
const getDetails = (arg1, arg2, verifiableCredential) => {
if (arg1 === 'Status') {
return (
<Column>
<Text
weight="bold"
size="smaller"
color={
!verifiableCredential
? Theme.Colors.LoadingDetailsLabel
: Theme.Colors.DetailsLabel
}>
{arg1}
</Text>
<Row>
<Text
numLines={1}
color={Theme.Colors.Details}
weight="bold"
size="smaller"
style={
!verifiableCredential
? Theme.Styles.loadingTitle
: Theme.Styles.subtitle
}>
{!verifiableCredential ? '' : arg2}
</Text>
{!verifiableCredential ? null : <VerifiedIcon />}
</Row>
</Column>
);
} else {
return (
<Column>
<Text
color={
!verifiableCredential
? Theme.Colors.LoadingDetailsLabel
: Theme.Colors.DetailsLabel
}
size="smaller"
weight={'bold'}
style={Theme.Styles.vcItemLabelHeader}>
{arg1}
</Text>
<Text
numLines={4}
color={Theme.Colors.Details}
weight="bold"
size="smaller"
style={
!verifiableCredential
? Theme.Styles.loadingTitle
: Theme.Styles.subtitle
}>
{!verifiableCredential ? '' : arg2}
</Text>
</Column>
);
}
};
export const VcItemContent: React.FC<VcItemContentProps> = (props) => {
//Assigning the UIN and VID from the VC details to display the idtype label
const uin = props.verifiableCredential?.credentialSubject.UIN;
const vid = props.verifiableCredential?.credentialSubject.VID;
const fullName = !props.verifiableCredential
? ''
: getLocalizedField(props.verifiableCredential.credentialSubject.fullName);
const { t } = useTranslation('VcDetails');
const isvalid = !props.verifiableCredential ? '' : t('valid');
const selectableOrCheck = props.selectable ? (
<CheckBox
checked={props.selected}
checkedIcon={<Icon name="radio-button-checked" />}
uncheckedIcon={<Icon name="radio-button-unchecked" />}
onPress={() => props.onPress()}
/>
) : null;
return (
<ImageBackground
source={!props.verifiableCredential ? null : Theme.CloseCard}
resizeMode="stretch"
borderRadius={4}
style={
!props.verifiableCredential
? Theme.Styles.vertloadingContainer
: Theme.Styles.backgroundImageContainer
}>
<Column>
<Row align="space-between">
<Row>
<ImageBackground
source={
!props.verifiableCredential
? Theme.ProfileIcon
: { uri: props.context.credential.biometrics.face }
}
style={Theme.Styles.closeCardImage}>
{props.iconName && (
<Icon
name={props.iconName}
type={props.iconType}
color={Theme.Colors.Icon}
style={{ marginLeft: -80 }}
/>
)}
</ImageBackground>
<Column margin="0 0 0 10">
{getDetails(t('fullName'), fullName, props.verifiableCredential)}
<Column margin="10 0 0 0">
<Text
color={
!props.verifiableCredential
? Theme.Colors.LoadingDetailsLabel
: Theme.Colors.DetailsLabel
}
weight="semibold"
size="smaller"
align="left">
{t('idType')}
</Text>
<Text
weight="semibold"
color={Theme.Colors.Details}
size="smaller"
style={
!props.verifiableCredential
? Theme.Styles.loadingTitle
: Theme.Styles.subtitle
}>
{t('nationalCard')}
</Text>
</Column>
</Column>
</Row>
<Column>
{props.verifiableCredential ? selectableOrCheck : null}
</Column>
</Row>
<Row
align="space-between"
margin="5 0 0 0"
style={
!props.verifiableCredential ? Theme.Styles.loadingContainer : null
}>
<Column>
{uin ? getDetails(t('uin'), uin, props.verifiableCredential) : null}
{vid ? getDetails(t('vid'), vid, props.verifiableCredential) : null}
{!props.verifiableCredential
? getDetails(t('id'), uin || vid, props.verifiableCredential)
: null}
{getDetails(
t('generatedOn'),
props.generatedOn,
props.verifiableCredential
)}
</Column>
<Column>
{props.verifiableCredential
? getDetails(t('status'), isvalid, props.verifiableCredential)
: null}
</Column>
<Column
style={{ display: props.verifiableCredential ? 'flex' : 'none' }}>
<Image
source={Theme.MosipLogo}
style={Theme.Styles.logo}
resizeMethod="auto"
/>
</Column>
</Row>
</Column>
<VcItemTags tag={props.tag} />
</ImageBackground>
);
};
interface VcItemContentProps {
context: any;
verifiableCredential: VerifiableCredential;
generatedOn: string;
tag: string;
selectable: boolean;
selected: boolean;
iconName?: string;
iconType?: string;
service: any;
onPress?: () => void;
}

View File

@@ -1,110 +0,0 @@
import React, {useContext, useRef} from 'react';
import {useInterpret, useSelector} from '@xstate/react';
import {Pressable} from 'react-native';
import {CheckBox} from 'react-native-elements';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import {ActorRefFrom} from 'xstate';
import {
selectVerifiableCredential,
selectGeneratedOn,
} from '../machines/VCItemMachine/commonSelectors';
import {
createExistingMosipVCItemMachine,
selectId,
ExistingMosipVCItemMachine,
} from '../machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine';
import {Column, Row, Text} from './ui';
import {Theme} from './ui/styleUtils';
import {RotatingIcon} from './RotatingIcon';
import {GlobalContext} from '../shared/GlobalContext';
import {getLocalizedField} from '../i18n';
import {VCMetadata} from '../shared/VCMetadata';
export const VidItem: React.FC<VcItemProps> = props => {
const {appService} = useContext(GlobalContext);
const machine = useRef(
createExistingMosipVCItemMachine(
appService.getSnapshot().context.serviceRefs,
props.vcMetadata,
),
);
const service = useInterpret(machine.current);
const uin = useSelector(service, selectId);
const verifiableCredential = useSelector(service, selectVerifiableCredential);
const generatedOn = useSelector(service, selectGeneratedOn);
const selectableOrCheck = props.selectable ? (
<CheckBox
checked={props.selected}
checkedIcon={<Icon name="checkbox-intermediate" size={24} />}
uncheckedIcon={<Icon name="checkbox-blank-outline" size={24} />}
onPress={() => props.onPress(service)}
/>
) : (
<Icon name="chevron-right" />
);
return (
<Pressable
onPress={() => props.onPress(service)}
disabled={!verifiableCredential}>
<Row
elevation={!verifiableCredential ? 0 : 2}
crossAlign="center"
margin={props.margin}
backgroundColor={
!verifiableCredential
? Theme.Colors.lightGreyBackgroundColor
: Theme.Colors.whiteBackgroundColor
}
padding={[16, 16]}
style={
!verifiableCredential
? Theme.VidItemStyles.loadingContainer
: Theme.VidItemStyles.container
}>
<Column fill margin="0 24 0 0">
<Text
weight="semibold"
style={
!verifiableCredential
? Theme.VidItemStyles.loadingTitle
: Theme.VidItemStyles.title
}
margin="0 0 6 0">
{!verifiableCredential ? '' : uin}
</Text>
<Text
size="smaller"
numLines={1}
style={
!verifiableCredential
? Theme.VidItemStyles.loadingSubtitle
: Theme.VidItemStyles.subtitle
}>
{!verifiableCredential
? ''
: getLocalizedField(
verifiableCredential.credentialSubject.fullName,
) +
' · ' +
generatedOn}
</Text>
</Column>
{verifiableCredential ? (
selectableOrCheck
) : (
<RotatingIcon name="sync" color={Theme.Colors.rotatingIcon} />
)}
</Row>
</Pressable>
);
};
interface VcItemProps {
vcMetadata: VCMetadata;
margin?: string;
selectable?: boolean;
selected?: boolean;
onPress?: (vcRef?: ActorRefFrom<typeof ExistingMosipVCItemMachine>) => void;
}

View File

@@ -4,7 +4,7 @@ import {useSelector} from '@xstate/react';
import {
VcEvents,
selectWalletBindingSuccess,
} from '../machines/VCItemMachine/vc';
} from '../machines/VerifiableCredential/VCMetaMachine/vc';
export const UseWalletBindingSuccess = () => {
const {appService} = useContext(GlobalContext);

View File

@@ -3,13 +3,10 @@ import {SvgImage} from './ui/svg';
import {useKebabPopUp} from './KebabPopUpController';
import {isActivationNeeded} from '../shared/openId4VCI/Utils';
import {VCShareFlowType} from '../shared/Utils';
import {useNavigation} from '@react-navigation/native';
import {BOTTOM_TAB_ROUTES} from '../routes/routesConstants';
export const getKebabMenuOptions = props => {
const controller = useKebabPopUp(props);
const {t} = useTranslation('HomeScreenKebabPopUp');
const navigation = useNavigation();
const loadScanScreen = flowType => () => {
controller.SELECT_VC_ITEM(props.service, flowType),
@@ -18,7 +15,7 @@ export const getKebabMenuOptions = props => {
};
const activationNotCompleted =
controller.emptyWalletBindingId &&
!controller.walletBindingResponse &&
isActivationNeeded(props?.vcMetadata.issuer);
const vcActionsList = [
@@ -38,7 +35,6 @@ export const getKebabMenuOptions = props => {
label: t('viewActivityLog'),
icon: SvgImage.OutlinedScheduleIcon(),
onPress: controller.SHOW_ACTIVITY,
testID: 'viewActivityLog',
},
{
@@ -66,7 +62,7 @@ export const getKebabMenuOptions = props => {
onPress: activationNotCompleted
? controller.ADD_WALLET_BINDING_ID
: loadScanScreen(VCShareFlowType.MINI_VIEW_QR_LOGIN),
testID: 'pinOrUnPinCard',
testID: 'pendingActivationOrActivated',
};
if (props.vcHasImage) {

View File

@@ -1,5 +1,5 @@
import React from 'react';
import {I18nManager, Pressable, Modal as RNModal, View} from 'react-native';
import {I18nManager, Modal as RNModal, Pressable, View} from 'react-native';
import {Icon} from 'react-native-elements';
import {Column, Row, Text} from '.';
import {useSendVcScreen} from '../../screens/Scan/SendVcScreenController';
@@ -109,5 +109,5 @@ export interface ModalProps {
headerLeft?: React.ReactElement;
arrowLeft?: boolean;
onShow?: () => void;
children: React.ReactNode;
children?: React.ReactNode;
}

View File

@@ -200,6 +200,7 @@ export class SvgImage {
/>
);
}
static settings(focused: boolean) {
//NOTE: Here tab icons names should be same with key "name" in main.ts
return (
@@ -463,6 +464,7 @@ export class SvgImage {
/>
);
}
static ICloudIcon(width, height) {
return (
<ICloudLogo
@@ -472,6 +474,7 @@ export class SvgImage {
/>
);
}
static SearchIcon() {
return <Search {...testIDProps('searchIcon')} />;
}

View File

@@ -1337,31 +1337,6 @@ export const DefaultTheme = {
borderRadius: 16,
},
}),
VidItemStyles: StyleSheet.create({
title: {
color: Colors.Black,
backgroundColor: 'transparent',
},
loadingTitle: {
color: 'transparent',
backgroundColor: Colors.Grey5,
borderRadius: 4,
},
subtitle: {
backgroundColor: 'transparent',
},
loadingSubtitle: {
backgroundColor: Colors.Grey,
borderRadius: 4,
},
container: {
backgroundColor: Colors.White,
},
loadingContainer: {
backgroundColor: Colors.Grey6,
borderRadius: 4,
},
}),
OnboardingOverlayStyles: StyleSheet.create({
overlay: {
padding: 24,

View File

@@ -1339,31 +1339,6 @@ export const PurpleTheme = {
borderRadius: 16,
},
}),
VidItemStyles: StyleSheet.create({
title: {
color: Colors.Black,
backgroundColor: 'transparent',
},
loadingTitle: {
color: 'transparent',
backgroundColor: Colors.Grey5,
borderRadius: 4,
},
subtitle: {
backgroundColor: 'transparent',
},
loadingSubtitle: {
backgroundColor: Colors.Grey,
borderRadius: 4,
},
container: {
backgroundColor: Colors.White,
},
loadingContainer: {
backgroundColor: Colors.Grey6,
borderRadius: 4,
},
}),
OnboardingOverlayStyles: StyleSheet.create({
overlay: {
padding: 24,

View File

@@ -10,9 +10,10 @@ import kn from './locales/kan.json';
import ta from './locales/tam.json';
import {iso6393To1} from 'iso-639-3';
import {LocalizedField} from './types/VC/ExistingMosipVC/vc';
import Keychain from 'react-native-keychain';
import {getItem} from './machines/store';
import {LocalizedField} from './types/VC/vc';
const resources = {en, fil, ar, hi, kn, ta};
const locale = Localization.locale;

View File

@@ -14,7 +14,7 @@ import {
MY_VCS_STORE_KEY,
} from '../shared/constants';
import {StoreEvents} from './store';
import {linkTransactionResponse, VC} from '../types/VC/ExistingMosipVC/vc';
import {linkTransactionResponse, VC} from '../types/VC/vc';
import {request} from '../shared/request';
import {
getJWT,
@@ -31,9 +31,9 @@ import {
sendEndEvent,
} from '../shared/telemetry/TelemetryUtils';
import {TelemetryConstants} from '../shared/telemetry/TelemetryConstants';
import {API_URLS} from '../shared/api';
import getAllConfigurations from '../shared/api';
import getAllConfigurations, {API_URLS} from '../shared/api';
import {VCShareFlowType} from '../shared/Utils';
import {getMosipLogo} from '../components/VC/common/VCUtils';
const model = createModel(
{
@@ -598,6 +598,7 @@ type State = StateFrom<typeof qrLoginMachine>;
export function selectMyVcs(state: State) {
return state.context.myVcs;
}
export function selectIsWaitingForData(state: State) {
return state.matches('waitingForData');
}
@@ -633,6 +634,7 @@ export function selectIsShowError(state: State) {
export function selectIsRequestConsent(state: State) {
return state.matches('requestConsent');
}
export function selectIsSendingAuthenticate(state: State) {
return state.matches('sendingAuthenticate');
}
@@ -645,13 +647,37 @@ export function selectIsVerifyingSuccesful(state: State) {
return state.matches('success');
}
export function selectSelectedVc(state: State) {
return state.context.selectedVc;
export function selectCredential(state: State) {
return new VCMetadata(state.context.selectedVc?.vcMetadata).isFromOpenId4VCI()
? state.context.selectedVc?.verifiableCredential?.credential
: state.context.selectedVc?.credential;
}
export function selectVerifiableCredentialData(state: State) {
const vcMetadata = new VCMetadata(state.context.selectedVc?.vcMetadata);
return vcMetadata.isFromOpenId4VCI()
? {
vcMetadata: vcMetadata,
face: state.context.selectedVc?.verifiableCredential?.credential
?.credentialSubject?.face,
issuerLogo: state.context.selectedVc?.verifiableCredential?.issuerLogo,
wellKnown: state.context.selectedVc?.verifiableCredential?.wellKnown,
credentialTypes:
state.context.selectedVc?.verifiableCredential?.credentialTypes,
issuer: vcMetadata.issuer,
}
: {
vcMetadata: vcMetadata,
issuer: vcMetadata.issuer,
face: state.context.selectedVc?.credential?.biometrics?.face,
issuerLogo: getMosipLogo(),
};
}
export function selectLinkTransactionResponse(state: State) {
return state.context.linkTransactionResponse;
}
export function selectEssentialClaims(state: State) {
return state.context.essentialClaims;
}
@@ -671,6 +697,7 @@ export function selectClientName(state: State) {
export function selectErrorMessage(state: State) {
return state.context.errorMessage;
}
export function selectIsSharing(state: State) {
return state.context.isSharing;
}

View File

@@ -48,20 +48,20 @@ export interface Typegen0 {
loadMyVcs: 'done.invoke.QrLogin.linkTransaction:invocation[0]';
loadThumbprint: 'FACE_VALID';
resetFlowType: 'xstate.init';
logValue: 'VERIFY';
resetLinkTransactionId: 'GET';
resetSelectedVc: 'xstate.init';
resetSelectedVoluntaryClaims: 'GET';
setClaims: 'done.invoke.QrLogin.linkTransaction:invocation[0]';
setConsentClaims: 'TOGGLE_CONSENT_CLAIM';
setFaceAuthConsent: 'GET';
setLinkedTransactionId: 'done.invoke.QrLogin.sendingAuthenticate:invocation[0]';
setMyVcs: 'STORE_RESPONSE';
setScanData: 'GET';
setSelectedVc: 'SELECT_VC';
setShowAgainConsent: 'FACE_VERIFICATION_CONSENT';
setShowFaceAuthConsent: 'FACE_VERIFICATION_CONSENT';
setThumbprint: 'STORE_RESPONSE';
setlinkTransactionResponse: 'done.invoke.QrLogin.linkTransaction:invocation[0]';
storeContext: 'FACE_VERIFICATION_CONSENT';
storeShowFaceAuthConsent: 'FACE_VERIFICATION_CONSENT';
};
eventsCausingDelays: {};
eventsCausingGuards: {
@@ -69,7 +69,7 @@ export interface Typegen0 {
isSimpleShareFlow:
| 'CANCEL'
| 'done.invoke.QrLogin.linkTransaction:invocation[0]';
isConsentGiven: 'VERIFY';
showFaceAuthConsentScreen: 'VERIFY';
};
eventsCausingServices: {
linkTransaction: 'GET';

View File

@@ -1,870 +0,0 @@
import {assign, ErrorPlatformEvent, EventFrom, send} from 'xstate';
import {createModel} from 'xstate/lib/model';
import {AppServices} from '../../../shared/GlobalContext';
import {VCMetadata} from '../../../shared/VCMetadata';
import {VC} from '../../../types/VC/ExistingMosipVC/vc';
import {
generateKeys,
isHardwareKeystoreExists,
WalletBindingResponse,
} from '../../../shared/cryptoutil/cryptoUtil';
import {getIdType, Protocols} from '../../../shared/openId4VCI/Utils';
import {StoreEvents} from '../../../machines/store';
import {MIMOTO_BASE_URL, MY_VCS_STORE_KEY} from '../../../shared/constants';
import {VcEvents} from '../vc';
import i18n from '../../../i18n';
import {KeyPair} from 'react-native-rsa-native';
import {
getBindingCertificateConstant,
savePrivateKey,
} from '../../../shared/keystore/SecureKeystore';
import {ActivityLogEvents} from '../../../machines/activityLog';
import {request} from '../../../shared/request';
import SecureKeystore from '@mosip/secure-keystore';
import {VerifiableCredential} from './vc';
import {
getEndEventData,
getInteractEventData,
getStartEventData,
sendEndEvent,
sendInteractEvent,
sendStartEvent,
} from '../../../shared/telemetry/TelemetryUtils';
import {TelemetryConstants} from '../../../shared/telemetry/TelemetryConstants';
import {API_URLS} from '../../../shared/api';
import {getHomeMachineService} from '../../../screens/Home/HomeScreenController';
import {BackupEvents} from '../../backupAndRestore/backup';
import Cloud, {
isSignedInResult,
} from '../../../shared/CloudBackupAndRestoreUtils';
import {getMosipIdentifier} from '../../../shared/commonUtil';
const model = createModel(
{
serviceRefs: {} as AppServices,
vcMetadata: {} as VCMetadata,
generatedOn: new Date() as Date,
verifiableCredential: null as VerifiableCredential,
hashedId: '',
publicKey: '',
privateKey: '',
otp: '',
otpError: '',
idError: '',
transactionId: '',
bindingTransactionId: '',
walletBindingResponse: null as WalletBindingResponse,
tempWalletBindingIdResponse: null as WalletBindingResponse,
walletBindingError: '',
isMachineInKebabPopupState: false,
bindingAuthFailedMessage: '' as string,
phoneNumber: '' as string,
email: '' as string,
},
{
events: {
KEY_RECEIVED: (key: string) => ({key}),
KEY_ERROR: (error: Error) => ({error}),
STORE_READY: () => ({}),
DISMISS: () => ({}),
CREDENTIAL_DOWNLOADED: (vc: VC) => ({vc}),
STORE_RESPONSE: (response: VC) => ({response}),
POLL: () => ({}),
DOWNLOAD_READY: () => ({}),
GET_VC_RESPONSE: (vc: VC) => ({vc}),
VERIFY: () => ({}),
RESEND_OTP: () => ({}),
INPUT_OTP: (otp: string) => ({otp}),
REFRESH: () => ({}),
ADD_WALLET_BINDING_ID: () => ({}),
CANCEL: () => ({}),
CONFIRM: () => ({}),
STORE_ERROR: (error: Error) => ({error}),
PIN_CARD: () => ({}),
KEBAB_POPUP: () => ({}),
SHOW_ACTIVITY: () => ({}),
CLOSE_VC_MODAL: () => ({}),
REMOVE: (vcMetadata: VCMetadata) => ({vcMetadata}),
UPDATE_VC_METADATA: (vcMetadata: VCMetadata) => ({vcMetadata}),
SHOW_BINDING_STATUS: () => ({}),
},
},
);
export const EsignetMosipVCItemEvents = model.events;
export const EsignetMosipVCItemMachine = model.createMachine(
{
predictableActionArguments: true,
preserveActionOrder: true,
tsTypes: {} as import('./EsignetMosipVCItemMachine.typegen').Typegen0,
schema: {
context: model.initialContext,
events: {} as EventFrom<typeof model>,
},
on: {
REFRESH: {
target: '.checkingStore',
},
UPDATE_VC_METADATA: {
actions: 'setVcMetadata',
},
},
description: 'VC',
id: 'vc-item-openid4vci',
initial: 'checkingVc',
states: {
checkingVc: {
entry: ['requestVcContext'],
description: 'Fetch the VC data from the Memory.',
on: {
GET_VC_RESPONSE: [
{
actions: [
'setVerifiableCredential',
'setContext',
'setGeneratedOn',
],
cond: 'hasCredential',
target: 'idle',
},
{
target: 'checkingStore',
},
],
},
},
checkingStore: {
entry: 'requestStoredContext',
description: 'Check if VC data is in secured local storage.',
on: {
STORE_RESPONSE: {
actions: ['setVerifiableCredential', 'setContext', 'updateVc'],
target: 'idle',
},
},
},
showBindingWarning: {
on: {
CONFIRM: {
actions: 'sendActivationStartEvent',
target: 'requestingBindingOtp',
},
CANCEL: [
{
cond: context => context.isMachineInKebabPopupState,
target: '#vc-item-openid4vci.kebabPopUp',
},
{
target: 'idle',
},
],
},
},
requestingBindingOtp: {
invoke: {
src: 'requestBindingOtp',
onDone: [
{
target: 'acceptingBindingOtp',
actions: ['setPhoneNumber', 'setEmail'],
},
],
onError: [
{
actions: ['setWalletBindingError', 'logWalletBindingFailure'],
target: 'showingWalletBindingError',
},
],
},
},
showingWalletBindingError: {
on: {
CANCEL: [
{
cond: context => context.isMachineInKebabPopupState,
actions: ['setWalletBindingErrorEmpty'],
target: '#vc-item-openid4vci.kebabPopUp',
},
{
actions: ['setWalletBindingErrorEmpty'],
target: 'idle',
},
],
},
},
acceptingBindingOtp: {
entry: ['clearOtp'],
on: {
INPUT_OTP: {
target: 'addKeyPair',
actions: ['setOtp'],
},
DISMISS: [
{
cond: context => context.isMachineInKebabPopupState,
target: '#vc-item-openid4vci.kebabPopUp',
actions: [
'sendActivationFailedEndEvent',
'clearOtp',
'clearTransactionId',
],
},
{
target: 'idle',
actions: [
'sendActivationFailedEndEvent',
'clearOtp',
'clearTransactionId',
],
},
],
RESEND_OTP: {
target: '.resendOTP',
},
},
initial: 'idle',
states: {
idle: {},
resendOTP: {
invoke: {
src: 'requestBindingOtp',
onDone: {
target: 'idle',
actions: ['setPhoneNumber', 'setEmail'],
},
onError: {
actions: 'setWalletBindingError',
target: '#vc-item-openid4vci.showingWalletBindingError',
},
},
},
},
},
addKeyPair: {
invoke: {
src: 'generateKeyPair',
onDone: [
{
cond: 'isCustomSecureKeystore',
target: 'addingWalletBindingId',
actions: ['setPublicKey'],
},
{
target: 'addingWalletBindingId',
actions: ['setPublicKey', 'setPrivateKey'],
},
],
onError: [
{
actions: ['setWalletBindingError', 'logWalletBindingFailure'],
target: 'showingWalletBindingError',
},
],
},
},
addingWalletBindingId: {
invoke: {
src: 'addWalletBindnigId',
onDone: [
{
cond: 'isCustomSecureKeystore',
target: 'updatingContextVariables',
},
{
target: 'updatingPrivateKey',
/*The walletBindingResponse is used for conditional rendering in wallet binding.
However, it wrongly considers activation as successful even when there's an error
in updatingPrivateKey state. So created a temporary context variable to store the binding
response and use it in updatingPrivateKey state*/
actions: 'setTempWalletBindingResponse',
},
],
onError: [
{
actions: ['setWalletBindingError', 'logWalletBindingFailure'],
target: 'showingWalletBindingError',
},
],
},
},
updatingPrivateKey: {
invoke: {
src: 'updatePrivateKey',
onDone: {
target: 'updatingContextVariables',
},
onError: {
actions: [
'setWalletBindingError',
'logWalletBindingFailure',
'sendActivationFailedEndEvent',
],
target: 'showingWalletBindingError',
},
},
},
updatingContextVariables: {
entry: [
'setWalletBindingId',
'setThumbprintForWalletBindingId',
'storeContext',
'updatePrivateKey',
'updateVc',
'setWalletBindingErrorEmpty',
'sendActivationSuccessEvent',
'logWalletBindingSuccess',
send('SHOW_BINDING_STATUS'),
],
on: {
SHOW_BINDING_STATUS: [
{
cond: context => context.isMachineInKebabPopupState,
actions: 'sendWalletBindingSuccess',
target: '#vc-item-openid4vci.kebabPopUp',
},
{
actions: 'sendWalletBindingSuccess',
target: 'idle',
},
],
},
},
idle: {
on: {
DISMISS: {
target: 'checkingVc',
},
KEBAB_POPUP: {
target: 'kebabPopUp',
},
ADD_WALLET_BINDING_ID: {
target: 'showBindingWarning',
},
PIN_CARD: {
target: 'pinCard',
actions: 'setPinCard',
},
},
},
pinCard: {
entry: 'sendVcUpdated',
always: {
target: 'idle',
},
},
kebabPopUp: {
entry: assign({isMachineInKebabPopupState: () => true}),
exit: assign({isMachineInKebabPopupState: () => false}),
on: {
DISMISS: {
actions: assign({
isMachineInKebabPopupState: () => false,
}),
target: 'idle',
},
ADD_WALLET_BINDING_ID: {
target: '#vc-item-openid4vci.showBindingWarning',
},
PIN_CARD: {
target: '#vc-item-openid4vci.pinCard',
actions: 'setPinCard',
},
SHOW_ACTIVITY: {
target: '#vc-item-openid4vci.kebabPopUp.showActivities',
},
REMOVE: {
actions: 'setVcKey',
target: '#vc-item-openid4vci.kebabPopUp.removeWallet',
},
CLOSE_VC_MODAL: {
actions: ['closeViewVcModal'],
target: '#vc-item-openid4vci',
},
},
initial: 'idle',
states: {
idle: {},
showActivities: {
on: {
DISMISS: '#vc-item-openid4vci',
},
},
removeWallet: {
on: {
CONFIRM: {
target: 'removingVc',
},
CANCEL: {
target: '#vc-item-openid4vci',
},
},
},
removingVc: {
entry: 'removeVcItem',
on: {
STORE_RESPONSE: {
actions: ['closeViewVcModal', 'removedVc', 'logVCremoved'],
target: 'triggerAutoBackup',
},
},
},
triggerAutoBackup: {
invoke: {
src: 'isUserSignedAlready',
onDone: [
{
cond: 'isSignedIn',
actions: ['sendBackupEvent', 'removedVc', 'logVCremoved'],
target: '#vc-item-openid4vci',
},
{
actions: ['removedVc', 'logVCremoved'],
target: '#vc-item-openid4vci',
},
],
},
},
},
},
},
},
{
actions: {
setVcMetadata: assign({
vcMetadata: (_, event) => event.vcMetadata,
}),
requestVcContext: send(
context => ({
type: 'GET_VC_ITEM',
vcMetadata: context.vcMetadata,
protocol: Protocols.OpenId4VCI,
}),
{
to: context => context.serviceRefs.vc,
},
),
requestStoredContext: send(
context => {
return StoreEvents.GET(
VCMetadata.fromVC(context.vcMetadata).getVcKey(),
);
},
{
to: context => context.serviceRefs.store,
},
),
updateVc: send(
context => {
const {serviceRefs, ...verifiableCredential} = context;
return {
type: 'VC_DOWNLOADED_FROM_OPENID4VCI',
vc: verifiableCredential,
vcMetadata: context.vcMetadata,
};
},
{
to: context => context.serviceRefs.vc,
},
),
setVerifiableCredential: model.assign({
verifiableCredential: (_, event) => {
if (event.type === 'GET_VC_RESPONSE') {
return event.vc.verifiableCredential
? event.vc.verifiableCredential
: event.vc;
}
return event.response.verifiableCredential;
},
}),
setContext: model.assign((context, event) => {
if (event.type === 'STORE_RESPONSE') {
const {verifiableCredential, ...data} = event.response;
return {...context, ...data};
}
if (event.type === 'GET_VC_RESPONSE') {
const {verifiableCredential, ...data} = event.vc;
return {...context, ...data};
}
return context;
}),
setGeneratedOn: model.assign({
generatedOn: (_context, event) => {
if (event.type === 'GET_VC_RESPONSE') {
return event.vc.generatedOn;
}
return event.response.generatedOn;
},
}),
storeContext: send(
context => {
const {
serviceRefs,
isMachineInKebabPopupState,
tempWalletBindingIdResponse,
...data
} = context;
data.credentialRegistry = MIMOTO_BASE_URL;
return StoreEvents.SET(
VCMetadata.fromVC(context.vcMetadata).getVcKey(),
data,
);
},
{
to: context => context.serviceRefs.store,
},
),
setPinCard: assign({
vcMetadata: context =>
new VCMetadata({
...context.vcMetadata,
isPinned: !context.vcMetadata.isPinned,
}),
}),
sendBackupEvent: send(BackupEvents.DATA_BACKUP(true), {
to: context => context.serviceRefs.backup,
}),
sendVcUpdated: send(
context => VcEvents.VC_METADATA_UPDATED(context.vcMetadata),
{
to: context => context.serviceRefs.vc,
},
),
setWalletBindingError: assign({
walletBindingError: () =>
i18n.t(`errors.genericError`, {
ns: 'common',
}),
bindingAuthFailedMessage: (_context, event) => {
const error = JSON.parse(JSON.stringify(event.data)).name;
if (error) {
return error;
}
return '';
},
}),
setWalletBindingErrorEmpty: assign({
walletBindingError: () => '',
bindingAuthFailedMessage: () => '',
}),
sendWalletBindingSuccess: send(
context => {
return {
type: 'WALLET_BINDING_SUCCESS',
};
},
{
to: context => context.serviceRefs.vc,
},
),
sendActivationStartEvent: context => {
sendStartEvent(
getStartEventData(
context.isMachineInKebabPopupState
? TelemetryConstants.FlowType.vcActivationFromKebab
: TelemetryConstants.FlowType.vcActivation,
),
);
sendInteractEvent(
getInteractEventData(
context.isMachineInKebabPopupState
? TelemetryConstants.FlowType.vcActivationFromKebab
: TelemetryConstants.FlowType.vcActivation,
TelemetryConstants.InteractEventSubtype.click,
'Activate Button',
),
);
},
sendActivationFailedEndEvent: (context, event, meta) => {
const [errorId, errorMessage] =
event.data?.message === 'Could not store private key in keystore'
? [
TelemetryConstants.ErrorId.updatePrivateKey,
TelemetryConstants.ErrorMessage.privateKeyUpdationFailed,
]
: [
TelemetryConstants.ErrorId.userCancel,
TelemetryConstants.ErrorMessage.activationCancelled,
];
sendEndEvent(
getEndEventData(
context.isMachineInKebabPopupState
? TelemetryConstants.FlowType.vcActivationFromKebab
: TelemetryConstants.FlowType.vcActivation,
TelemetryConstants.EndEventStatus.failure,
{
errorId: errorId,
errorMessage: errorMessage,
},
),
);
},
sendActivationSuccessEvent: context =>
sendEndEvent(
getEndEventData(
context.isMachineInKebabPopupState
? TelemetryConstants.FlowType.vcActivationFromKebab
: TelemetryConstants.FlowType.vcActivation,
TelemetryConstants.EndEventStatus.success,
),
),
setPublicKey: assign({
publicKey: (context, event) => {
if (!isHardwareKeystoreExists) {
return (event.data as KeyPair).public;
}
return event.data as string;
},
}),
setPrivateKey: assign({
privateKey: (context, event) => (event.data as KeyPair).private,
}),
updatePrivateKey: assign({
privateKey: () => '',
}),
setWalletBindingId: assign({
walletBindingResponse: (context, event) => {
return isHardwareKeystoreExists
? (event.data as WalletBindingResponse)
: context.tempWalletBindingIdResponse;
},
}),
setTempWalletBindingResponse: assign({
tempWalletBindingIdResponse: (context, event) =>
event.data as WalletBindingResponse,
}),
setThumbprintForWalletBindingId: send(
context => {
const {walletBindingResponse} = context;
const walletBindingIdKey = getBindingCertificateConstant(
walletBindingResponse.walletBindingId,
);
return StoreEvents.SET(
walletBindingIdKey,
walletBindingResponse.thumbprint,
);
},
{
to: context => context.serviceRefs.store,
},
),
removedVc: send(
() => ({
type: 'REFRESH_MY_VCS',
}),
{
to: context => context.serviceRefs.vc,
},
),
logWalletBindingSuccess: send(
context =>
ActivityLogEvents.LOG_ACTIVITY({
_vcKey: VCMetadata.fromVC(context.vcMetadata).getVcKey(),
type: 'WALLET_BINDING_SUCCESSFULL',
idType: getIdType(context.vcMetadata.issuer),
id: context.vcMetadata.id,
timestamp: Date.now(),
deviceName: '',
vcLabel: VCMetadata.fromVC(context.vcMetadata).id,
}),
{
to: context => context.serviceRefs.activityLog,
},
),
logWalletBindingFailure: send(
context =>
ActivityLogEvents.LOG_ACTIVITY({
_vcKey: VCMetadata.fromVC(context.vcMetadata).getVcKey(),
type: 'WALLET_BINDING_FAILURE',
id: context.vcMetadata.id,
idType: getIdType(context.vcMetadata.issuer),
timestamp: Date.now(),
deviceName: '',
vcLabel: VCMetadata.fromVC(context.vcMetadata).id,
}),
{
to: context => context.serviceRefs.activityLog,
},
),
setOtp: model.assign({
otp: (_, event) => event.otp,
}),
setOtpError: assign({
otpError: (_context, event) =>
(event as ErrorPlatformEvent).data.message,
}),
setPhoneNumber: assign({
phoneNumber: (_context, event) => event.data.response.maskedMobile,
}),
setEmail: model.assign({
email: (_context, event) => event.data.response.maskedEmail,
}),
clearOtp: assign({otp: ''}),
removeVcItem: send(
_context => {
return StoreEvents.REMOVE(
MY_VCS_STORE_KEY,
_context.vcMetadata.getVcKey(),
);
},
{to: context => context.serviceRefs.store},
),
closeViewVcModal: send('DISMISS_MODAL', {
to: () => getHomeMachineService(),
}),
setVcKey: model.assign({
vcMetadata: (_, event) => event.vcMetadata,
}),
logVCremoved: send(
(context, _) =>
ActivityLogEvents.LOG_ACTIVITY({
idType: getIdType(context.vcMetadata.issuer),
id: context.vcMetadata.id,
_vcKey: VCMetadata.fromVC(context.vcMetadata).getVcKey(),
type: 'VC_REMOVED',
timestamp: Date.now(),
deviceName: '',
vcLabel: VCMetadata.fromVC(context.vcMetadata).id,
}),
{
to: context => context.serviceRefs.activityLog,
},
),
},
services: {
isUserSignedAlready: () => async () => {
return await Cloud.isSignedInAlready();
},
updatePrivateKey: async context => {
const hasSetPrivateKey: boolean = await savePrivateKey(
context.tempWalletBindingIdResponse.walletBindingId,
context.privateKey,
);
if (!hasSetPrivateKey) {
throw new Error('Could not store private key in keystore.');
}
return '';
},
addWalletBindnigId: async context => {
const response = await request(
API_URLS.walletBinding.method,
API_URLS.walletBinding.buildURL(),
{
requestTime: String(new Date().toISOString()),
request: {
authFactorType: 'WLA',
format: 'jwt',
individualId: VCMetadata.fromVC(context.vcMetadata).id,
transactionId: context.transactionId,
publicKey: context.publicKey,
challengeList: [
{
authFactorType: 'OTP',
challenge: context.otp,
format: 'alpha-numeric',
},
],
},
},
);
const certificate = response.response.certificate;
await savePrivateKey(
getBindingCertificateConstant(
VCMetadata.fromVC(context.vcMetadata).id,
),
certificate,
);
const walletResponse: WalletBindingResponse = {
walletBindingId: response.response.encryptedWalletBindingId,
keyId: response.response.keyId,
thumbprint: response.response.thumbprint,
expireDateTime: response.response.expireDateTime,
};
return walletResponse;
},
generateKeyPair: async context => {
if (!isHardwareKeystoreExists) {
return await generateKeys();
}
const isBiometricsEnabled = SecureKeystore.hasBiometricsEnabled();
return SecureKeystore.generateKeyPair(
VCMetadata.fromVC(context.vcMetadata).id,
isBiometricsEnabled,
0,
);
},
requestBindingOtp: async context => {
const response = await request(
API_URLS.bindingOtp.method,
API_URLS.bindingOtp.buildURL(),
{
requestTime: String(new Date().toISOString()),
request: {
individualId: getMosipIdentifier(
context.verifiableCredential.credential.credentialSubject,
),
otpChannels: ['EMAIL', 'PHONE'],
},
},
);
if (response.response == null) {
throw new Error('Could not process request');
}
return response;
},
},
guards: {
hasCredential: (_, event) => {
const vc = event.vc;
return vc != null;
},
isSignedIn: (_context, event) =>
(event.data as isSignedInResult).isSignedIn,
isCustomSecureKeystore: () => isHardwareKeystoreExists,
},
},
);
export const createEsignetMosipVCItemMachine = (
serviceRefs: AppServices,
vcMetadata: VCMetadata,
) => {
return EsignetMosipVCItemMachine.withContext({
...EsignetMosipVCItemMachine.context,
serviceRefs,
vcMetadata,
});
};

View File

@@ -1,184 +0,0 @@
// This file was automatically generated. Edits will be overwritten
export interface Typegen0 {
'@@xstate/typegen': true;
internalEvents: {
'done.invoke.vc-item-openid4vci.addKeyPair:invocation[0]': {
type: 'done.invoke.vc-item-openid4vci.addKeyPair:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.vc-item-openid4vci.addingWalletBindingId:invocation[0]': {
type: 'done.invoke.vc-item-openid4vci.addingWalletBindingId:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.vc-item-openid4vci.kebabPopUp.triggerAutoBackup:invocation[0]': {
type: 'done.invoke.vc-item-openid4vci.kebabPopUp.triggerAutoBackup:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.vc-item-openid4vci.requestingBindingOtp:invocation[0]': {
type: 'done.invoke.vc-item-openid4vci.requestingBindingOtp:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.vc-item-openid4vci.updatingPrivateKey:invocation[0]': {
type: 'done.invoke.vc-item-openid4vci.updatingPrivateKey:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'error.platform.vc-item-openid4vci.acceptingBindingOtp.resendOTP:invocation[0]': {
type: 'error.platform.vc-item-openid4vci.acceptingBindingOtp.resendOTP:invocation[0]';
data: unknown;
};
'error.platform.vc-item-openid4vci.addKeyPair:invocation[0]': {
type: 'error.platform.vc-item-openid4vci.addKeyPair:invocation[0]';
data: unknown;
};
'error.platform.vc-item-openid4vci.addingWalletBindingId:invocation[0]': {
type: 'error.platform.vc-item-openid4vci.addingWalletBindingId:invocation[0]';
data: unknown;
};
'error.platform.vc-item-openid4vci.requestingBindingOtp:invocation[0]': {
type: 'error.platform.vc-item-openid4vci.requestingBindingOtp:invocation[0]';
data: unknown;
};
'error.platform.vc-item-openid4vci.updatingPrivateKey:invocation[0]': {
type: 'error.platform.vc-item-openid4vci.updatingPrivateKey:invocation[0]';
data: unknown;
};
'xstate.init': {type: 'xstate.init'};
};
invokeSrcNameMap: {
addWalletBindnigId: 'done.invoke.vc-item-openid4vci.addingWalletBindingId:invocation[0]';
generateKeyPair: 'done.invoke.vc-item-openid4vci.addKeyPair:invocation[0]';
isUserSignedAlready: 'done.invoke.vc-item-openid4vci.kebabPopUp.triggerAutoBackup:invocation[0]';
requestBindingOtp:
| 'done.invoke.vc-item-openid4vci.acceptingBindingOtp.resendOTP:invocation[0]'
| 'done.invoke.vc-item-openid4vci.requestingBindingOtp:invocation[0]';
updatePrivateKey: 'done.invoke.vc-item-openid4vci.updatingPrivateKey:invocation[0]';
};
missingImplementations: {
actions: 'clearTransactionId';
delays: never;
guards: never;
services: never;
};
eventsCausingActions: {
clearOtp:
| 'DISMISS'
| 'done.invoke.vc-item-openid4vci.requestingBindingOtp:invocation[0]';
clearTransactionId: 'DISMISS';
closeViewVcModal: 'CLOSE_VC_MODAL' | 'STORE_RESPONSE';
logVCremoved:
| 'STORE_RESPONSE'
| 'done.invoke.vc-item-openid4vci.kebabPopUp.triggerAutoBackup:invocation[0]';
logWalletBindingFailure:
| 'error.platform.vc-item-openid4vci.addKeyPair:invocation[0]'
| 'error.platform.vc-item-openid4vci.addingWalletBindingId:invocation[0]'
| 'error.platform.vc-item-openid4vci.requestingBindingOtp:invocation[0]'
| 'error.platform.vc-item-openid4vci.updatingPrivateKey:invocation[0]';
logWalletBindingSuccess:
| 'done.invoke.vc-item-openid4vci.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item-openid4vci.updatingPrivateKey:invocation[0]';
removeVcItem: 'CONFIRM';
removedVc:
| 'STORE_RESPONSE'
| 'done.invoke.vc-item-openid4vci.kebabPopUp.triggerAutoBackup:invocation[0]';
requestStoredContext: 'GET_VC_RESPONSE' | 'REFRESH';
requestVcContext: 'DISMISS' | 'xstate.init';
sendActivationFailedEndEvent:
| 'DISMISS'
| 'error.platform.vc-item-openid4vci.updatingPrivateKey:invocation[0]';
sendActivationStartEvent: 'CONFIRM';
sendActivationSuccessEvent:
| 'done.invoke.vc-item-openid4vci.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item-openid4vci.updatingPrivateKey:invocation[0]';
sendBackupEvent: 'done.invoke.vc-item-openid4vci.kebabPopUp.triggerAutoBackup:invocation[0]';
sendVcUpdated: 'PIN_CARD';
sendWalletBindingSuccess: 'SHOW_BINDING_STATUS';
setContext: 'GET_VC_RESPONSE' | 'STORE_RESPONSE';
setGeneratedOn: 'GET_VC_RESPONSE';
setOtp: 'INPUT_OTP';
setPinCard: 'PIN_CARD';
setPrivateKey: 'done.invoke.vc-item-openid4vci.addKeyPair:invocation[0]';
setPublicKey: 'done.invoke.vc-item-openid4vci.addKeyPair:invocation[0]';
setTempWalletBindingResponse: 'done.invoke.vc-item-openid4vci.addingWalletBindingId:invocation[0]';
setThumbprintForWalletBindingId:
| 'done.invoke.vc-item-openid4vci.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item-openid4vci.updatingPrivateKey:invocation[0]';
setVcKey: 'REMOVE';
setVcMetadata: 'UPDATE_VC_METADATA';
setVerifiableCredential: 'GET_VC_RESPONSE' | 'STORE_RESPONSE';
setWalletBindingError:
| 'error.platform.vc-item-openid4vci.acceptingBindingOtp.resendOTP:invocation[0]'
| 'error.platform.vc-item-openid4vci.addKeyPair:invocation[0]'
| 'error.platform.vc-item-openid4vci.addingWalletBindingId:invocation[0]'
| 'error.platform.vc-item-openid4vci.requestingBindingOtp:invocation[0]'
| 'error.platform.vc-item-openid4vci.updatingPrivateKey:invocation[0]';
setWalletBindingErrorEmpty:
| 'CANCEL'
| 'done.invoke.vc-item-openid4vci.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item-openid4vci.updatingPrivateKey:invocation[0]';
setWalletBindingId:
| 'done.invoke.vc-item-openid4vci.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item-openid4vci.updatingPrivateKey:invocation[0]';
storeContext:
| 'done.invoke.vc-item-openid4vci.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item-openid4vci.updatingPrivateKey:invocation[0]';
updatePrivateKey:
| 'done.invoke.vc-item-openid4vci.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item-openid4vci.updatingPrivateKey:invocation[0]';
updateVc:
| 'STORE_RESPONSE'
| 'done.invoke.vc-item-openid4vci.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item-openid4vci.updatingPrivateKey:invocation[0]';
};
eventsCausingDelays: {};
eventsCausingGuards: {
hasCredential: 'GET_VC_RESPONSE';
isCustomSecureKeystore:
| 'done.invoke.vc-item-openid4vci.addKeyPair:invocation[0]'
| 'done.invoke.vc-item-openid4vci.addingWalletBindingId:invocation[0]';
isSignedIn: 'done.invoke.vc-item-openid4vci.kebabPopUp.triggerAutoBackup:invocation[0]';
};
eventsCausingServices: {
addWalletBindnigId: 'done.invoke.vc-item-openid4vci.addKeyPair:invocation[0]';
generateKeyPair: 'INPUT_OTP';
isUserSignedAlready: 'STORE_RESPONSE';
requestBindingOtp: 'CONFIRM' | 'RESEND_OTP';
updatePrivateKey: 'done.invoke.vc-item-openid4vci.addingWalletBindingId:invocation[0]';
};
matchesStates:
| 'acceptingBindingOtp'
| 'acceptingBindingOtp.idle'
| 'acceptingBindingOtp.resendOTP'
| 'addKeyPair'
| 'addingWalletBindingId'
| 'checkingStore'
| 'checkingVc'
| 'idle'
| 'kebabPopUp'
| 'kebabPopUp.idle'
| 'kebabPopUp.removeWallet'
| 'kebabPopUp.removingVc'
| 'kebabPopUp.showActivities'
| 'kebabPopUp.triggerAutoBackup'
| 'pinCard'
| 'requestingBindingOtp'
| 'showBindingWarning'
| 'showingWalletBindingError'
| 'updatingContextVariables'
| 'updatingPrivateKey'
| {
acceptingBindingOtp?: 'idle' | 'resendOTP';
kebabPopUp?:
| 'idle'
| 'removeWallet'
| 'removingVc'
| 'showActivities'
| 'triggerAutoBackup';
};
tags: never;
}

View File

@@ -1,301 +0,0 @@
// 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.addKeyPair:invocation[0]': {
type: 'done.invoke.vc-item.addKeyPair:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.vc-item.addingWalletBindingId:invocation[0]': {
type: 'done.invoke.vc-item.addingWalletBindingId:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.vc-item.checkingServerData.loadDownloadLimitConfig:invocation[0]': {
type: 'done.invoke.vc-item.checkingServerData.loadDownloadLimitConfig:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.vc-item.checkingServerData.verifyingDownloadLimitExpiry:invocation[0]': {
type: 'done.invoke.vc-item.checkingServerData.verifyingDownloadLimitExpiry:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.vc-item.kebabPopUp.removingVc.triggerAutoBackup:invocation[0]': {
type: 'done.invoke.vc-item.kebabPopUp.removingVc.triggerAutoBackup:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.vc-item.requestingBindingOtp:invocation[0]': {
type: 'done.invoke.vc-item.requestingBindingOtp:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.vc-item.updatingPrivateKey:invocation[0]': {
type: 'done.invoke.vc-item.updatingPrivateKey:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.vc-item.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]': {
type: 'done.invoke.vc-item.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.vc-item.verifyingCredential:invocation[0]': {
type: 'done.invoke.vc-item.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.acceptingBindingOtp.resendOTP:invocation[0]': {
type: 'error.platform.vc-item.acceptingBindingOtp.resendOTP:invocation[0]';
data: unknown;
};
'error.platform.vc-item.addKeyPair:invocation[0]': {
type: 'error.platform.vc-item.addKeyPair:invocation[0]';
data: unknown;
};
'error.platform.vc-item.addingWalletBindingId:invocation[0]': {
type: 'error.platform.vc-item.addingWalletBindingId:invocation[0]';
data: unknown;
};
'error.platform.vc-item.checkingServerData.verifyingDownloadLimitExpiry:invocation[0]': {
type: 'error.platform.vc-item.checkingServerData.verifyingDownloadLimitExpiry:invocation[0]';
data: unknown;
};
'error.platform.vc-item.requestingBindingOtp:invocation[0]': {
type: 'error.platform.vc-item.requestingBindingOtp:invocation[0]';
data: unknown;
};
'error.platform.vc-item.updatingPrivateKey:invocation[0]': {
type: 'error.platform.vc-item.updatingPrivateKey:invocation[0]';
data: unknown;
};
'error.platform.vc-item.verifyingCredential:invocation[0]': {
type: 'error.platform.vc-item.verifyingCredential:invocation[0]';
data: unknown;
};
'xstate.init': {type: 'xstate.init'};
};
invokeSrcNameMap: {
addWalletBindnigId: 'done.invoke.vc-item.addingWalletBindingId:invocation[0]';
checkDownloadExpiryLimit: 'done.invoke.vc-item.checkingServerData.verifyingDownloadLimitExpiry:invocation[0]';
checkStatus: 'done.invoke.checkStatus';
downloadCredential: 'done.invoke.downloadCredential';
generateKeyPair: 'done.invoke.vc-item.addKeyPair:invocation[0]';
isUserSignedAlready:
| 'done.invoke.vc-item.kebabPopUp.removingVc.triggerAutoBackup:invocation[0]'
| 'done.invoke.vc-item.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]';
loadDownloadLimitConfig: 'done.invoke.vc-item.checkingServerData.loadDownloadLimitConfig:invocation[0]';
requestBindingOtp:
| 'done.invoke.vc-item.acceptingBindingOtp.resendOTP:invocation[0]'
| 'done.invoke.vc-item.requestingBindingOtp:invocation[0]';
updatePrivateKey: 'done.invoke.vc-item.updatingPrivateKey:invocation[0]';
verifyCredential: 'done.invoke.vc-item.verifyingCredential:invocation[0]';
};
missingImplementations: {
actions: never;
delays: never;
guards: never;
services: never;
};
eventsCausingActions: {
addVcToInProgressDownloads: 'STORE_RESPONSE';
clearOtp:
| ''
| 'CANCEL'
| 'DISMISS'
| 'SHOW_BINDING_STATUS'
| 'done.invoke.vc-item.requestingBindingOtp:invocation[0]'
| 'done.invoke.vc-item.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]';
clearTransactionId:
| ''
| 'CANCEL'
| 'DISMISS'
| 'SHOW_BINDING_STATUS'
| 'done.invoke.vc-item.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]';
closeViewVcModal: 'CLOSE_VC_MODAL' | 'STORE_RESPONSE';
incrementDownloadCounter:
| 'POLL'
| 'done.invoke.vc-item.checkingServerData.loadDownloadLimitConfig:invocation[0]';
logDownloaded: 'STORE_RESPONSE';
logVCremoved:
| 'STORE_RESPONSE'
| 'done.invoke.vc-item.kebabPopUp.removingVc.triggerAutoBackup:invocation[0]';
logWalletBindingFailure:
| 'error.platform.vc-item.addKeyPair:invocation[0]'
| 'error.platform.vc-item.addingWalletBindingId:invocation[0]'
| 'error.platform.vc-item.requestingBindingOtp:invocation[0]'
| 'error.platform.vc-item.updatingPrivateKey:invocation[0]';
logWalletBindingSuccess:
| 'done.invoke.vc-item.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item.updatingPrivateKey:invocation[0]';
refreshMyVcs:
| 'STORE_RESPONSE'
| 'done.invoke.vc-item.kebabPopUp.removingVc.triggerAutoBackup:invocation[0]';
removeVcFromInProgressDownloads: 'STORE_RESPONSE';
removeVcItem: 'CONFIRM';
removeVcMetaDataFromStorage:
| 'STORE_ERROR'
| 'error.platform.vc-item.verifyingCredential:invocation[0]';
removeVcMetaDataFromVcMachine: 'DISMISS';
requestStoredContext: 'GET_VC_RESPONSE' | 'REFRESH';
requestVcContext: 'DISMISS' | 'xstate.init';
sendActivationFailedEndEvent:
| 'DISMISS'
| 'error.platform.vc-item.updatingPrivateKey:invocation[0]';
sendActivationStartEvent: 'CONFIRM';
sendActivationSuccessEvent:
| 'done.invoke.vc-item.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item.updatingPrivateKey:invocation[0]';
sendBackupEvent:
| 'done.invoke.vc-item.kebabPopUp.removingVc.triggerAutoBackup:invocation[0]'
| 'done.invoke.vc-item.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]';
sendDownloadLimitExpire:
| 'FAILED'
| 'error.platform.vc-item.checkingServerData.verifyingDownloadLimitExpiry:invocation[0]';
sendTamperedVc: 'TAMPERED_VC';
sendTelemetryEvents: 'STORE_RESPONSE';
sendVcUpdated: 'PIN_CARD';
sendVerificationError: 'STORE_RESPONSE';
sendWalletBindingSuccess: 'SHOW_BINDING_STATUS';
setCredential:
| 'CREDENTIAL_DOWNLOADED'
| 'GET_VC_RESPONSE'
| 'STORE_RESPONSE';
setDownloadInterval: 'done.invoke.vc-item.checkingServerData.loadDownloadLimitConfig:invocation[0]';
setMaxDownloadCount: 'done.invoke.vc-item.checkingServerData.loadDownloadLimitConfig:invocation[0]';
setOtp: 'INPUT_OTP';
setPinCard: 'PIN_CARD';
setPrivateKey: 'done.invoke.vc-item.addKeyPair:invocation[0]';
setPublicKey: 'done.invoke.vc-item.addKeyPair:invocation[0]';
setTempWalletBindingResponse: 'done.invoke.vc-item.addingWalletBindingId:invocation[0]';
setThumbprintForWalletBindingId:
| 'done.invoke.vc-item.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item.updatingPrivateKey:invocation[0]';
setVcKey: 'REMOVE';
setVcMetadata: 'UPDATE_VC_METADATA';
setWalletBindingError:
| 'error.platform.vc-item.acceptingBindingOtp.resendOTP:invocation[0]'
| 'error.platform.vc-item.addKeyPair:invocation[0]'
| 'error.platform.vc-item.addingWalletBindingId:invocation[0]'
| 'error.platform.vc-item.requestingBindingOtp:invocation[0]'
| 'error.platform.vc-item.updatingPrivateKey:invocation[0]';
setWalletBindingErrorEmpty:
| 'CANCEL'
| 'done.invoke.vc-item.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item.updatingPrivateKey:invocation[0]';
setWalletBindingId:
| 'done.invoke.vc-item.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item.updatingPrivateKey:invocation[0]';
storeContext:
| 'done.invoke.vc-item.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item.updatingPrivateKey:invocation[0]'
| 'done.invoke.vc-item.verifyingCredential:invocation[0]';
updatePrivateKey:
| 'done.invoke.vc-item.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item.updatingPrivateKey:invocation[0]';
updateVc:
| 'STORE_RESPONSE'
| 'done.invoke.vc-item.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item.updatingPrivateKey:invocation[0]';
updateVerificationErrorMessage: 'error.platform.vc-item.verifyingCredential:invocation[0]';
};
eventsCausingDelays: {};
eventsCausingGuards: {
hasCredential: 'GET_VC_RESPONSE' | 'STORE_RESPONSE';
isCustomSecureKeystore:
| 'done.invoke.vc-item.addKeyPair:invocation[0]'
| 'done.invoke.vc-item.addingWalletBindingId:invocation[0]';
isDownloadAllowed: 'POLL';
isSignedIn:
| 'done.invoke.vc-item.kebabPopUp.removingVc.triggerAutoBackup:invocation[0]'
| 'done.invoke.vc-item.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]';
};
eventsCausingServices: {
addWalletBindnigId: 'done.invoke.vc-item.addKeyPair:invocation[0]';
checkDownloadExpiryLimit:
| 'POLL'
| 'done.invoke.vc-item.checkingServerData.loadDownloadLimitConfig:invocation[0]';
checkStatus: 'done.invoke.vc-item.checkingServerData.verifyingDownloadLimitExpiry:invocation[0]';
downloadCredential: 'DOWNLOAD_READY';
generateKeyPair: 'INPUT_OTP';
isUserSignedAlready: 'STORE_RESPONSE';
loadDownloadLimitConfig: 'STORE_ERROR' | 'STORE_RESPONSE';
requestBindingOtp: 'CONFIRM' | 'RESEND_OTP';
updatePrivateKey: 'done.invoke.vc-item.addingWalletBindingId:invocation[0]';
verifyCredential: '' | 'VERIFY';
};
matchesStates:
| 'acceptingBindingOtp'
| 'acceptingBindingOtp.idle'
| 'acceptingBindingOtp.resendOTP'
| 'addKeyPair'
| 'addingWalletBindingId'
| 'checkingServerData'
| 'checkingServerData.checkingStatus'
| 'checkingServerData.downloadingCredential'
| 'checkingServerData.loadDownloadLimitConfig'
| 'checkingServerData.savingFailed'
| 'checkingServerData.savingFailed.idle'
| 'checkingServerData.savingFailed.viewingVc'
| 'checkingServerData.verifyingDownloadLimitExpiry'
| 'checkingStore'
| 'checkingVc'
| 'checkingVerificationStatus'
| 'handleVCVerificationFailure'
| 'idle'
| 'kebabPopUp'
| 'kebabPopUp.idle'
| 'kebabPopUp.removeWallet'
| 'kebabPopUp.removingVc'
| 'kebabPopUp.removingVc.triggerAutoBackup'
| 'kebabPopUp.showActivities'
| 'pinCard'
| 'requestingBindingOtp'
| 'showBindingWarning'
| 'showingWalletBindingError'
| 'updatingContextVariables'
| 'updatingPrivateKey'
| 'verifyingCredential'
| 'verifyingCredential.idle'
| 'verifyingCredential.triggerAutoBackupForVcDownload'
| {
acceptingBindingOtp?: 'idle' | 'resendOTP';
checkingServerData?:
| 'checkingStatus'
| 'downloadingCredential'
| 'loadDownloadLimitConfig'
| 'savingFailed'
| 'verifyingDownloadLimitExpiry'
| {savingFailed?: 'idle' | 'viewingVc'};
kebabPopUp?:
| 'idle'
| 'removeWallet'
| 'removingVc'
| 'showActivities'
| {removingVc?: 'triggerAutoBackup'};
verifyingCredential?: 'idle' | 'triggerAutoBackupForVcDownload';
};
tags: never;
}

View File

@@ -1,91 +0,0 @@
import {StateFrom} from 'xstate';
import {EsignetMosipVCItemMachine} from './EsignetMosipVCItem/EsignetMosipVCItemMachine';
import {ExistingMosipVCItemMachine} from './ExistingMosipVCItem/ExistingMosipVCItemMachine';
type State = StateFrom<
typeof ExistingMosipVCItemMachine & typeof EsignetMosipVCItemMachine
>;
export function selectVerifiableCredential(state: State) {
return state.context.verifiableCredential;
}
export function selectKebabPopUp(state: State) {
return state.context.isMachineInKebabPopupState;
}
export function selectContext(state: State) {
return state.context;
}
export function selectGeneratedOn(state: State) {
return state.context.generatedOn;
}
export function selectWalletBindingSuccess(state: State) {
return state.context.walletBindingSuccess;
}
export function selectIsPhoneNumber(state: State) {
return state.context.phoneNumber;
}
export function selectIsEmail(state: State) {
return state.context.email;
}
export function selectEmptyWalletBindingId(state: State) {
var val = state.context.walletBindingResponse
? state.context.walletBindingResponse.walletBindingId
: undefined;
return val == undefined || val == null || val.length <= 0 ? true : false;
}
export function selectWalletBindingError(state: State) {
return state.context.walletBindingError;
}
export function selectBindingAuthFailedError(state: State) {
return state.context.bindingAuthFailedMessage;
}
export function selectAcceptingBindingOtp(state: State) {
return state.matches('acceptingBindingOtp');
}
export function selectKebabPopUpShowWalletBindingError(state: State) {
return state.matches('showingWalletBindingError');
}
export function selectWalletBindingInProgress(state: State) {
return state.matches('requestingBindingOtp') ||
state.matches('addingWalletBindingId') ||
state.matches('addKeyPair') ||
state.matches('updatingPrivateKey')
? true
: false;
}
export function selectBindingWarning(state: State) {
return state.matches('showBindingWarning');
}
export function selectRemoveWalletWarning(state: State) {
return state.matches('kebabPopUp.removeWallet');
}
export function selectIsPinned(state: State) {
return state.context.vcMetadata.isPinned;
}
export function selectOtpError(state: State) {
return state.context.otpError;
}
export function selectShowActivities(state: State) {
return state.matches('kebabPopUp.showActivities');
}
export function selectShowWalletBindingError(state: State) {
return state.matches('showingWalletBindingError');
}

View File

@@ -0,0 +1,431 @@
import {assign, send} from 'xstate';
import {CommunicationDetails} from '../../../shared/Utils';
import {StoreEvents} from '../../store';
import {VCMetadata} from '../../../shared/VCMetadata';
import {MIMOTO_BASE_URL, MY_VCS_STORE_KEY} from '../../../shared/constants';
import {KeyPair} from 'react-native-rsa-native';
import i18n from '../../../i18n';
import {getHomeMachineService} from '../../../screens/Home/HomeScreenController';
import {DownloadProps} from '../../../shared/api';
import {isHardwareKeystoreExists} from '../../../shared/cryptoutil/cryptoUtil';
import {getBindingCertificateConstant} from '../../../shared/keystore/SecureKeystore';
import {getIdType} from '../../../shared/openId4VCI/Utils';
import {TelemetryConstants} from '../../../shared/telemetry/TelemetryConstants';
import {
sendStartEvent,
getStartEventData,
sendInteractEvent,
getInteractEventData,
sendEndEvent,
getEndEventData,
sendErrorEvent,
getErrorEventData,
} from '../../../shared/telemetry/TelemetryUtils';
import {WalletBindingResponse} from '../../../types/VC/vc';
import {ActivityLogEvents} from '../../activityLog';
import {BackupEvents} from '../../backupAndRestore/backup';
import {VcEvents} from '../VCMetaMachine/vc';
export const VCItemActions = model => {
return {
setCommunicationDetails: model.assign({
communicationDetails: (_context, event) => {
const communicationDetails: CommunicationDetails = {
phoneNumber: event.data.response.maskedMobile,
emailId: event.data.response.maskedEmail,
};
return communicationDetails;
},
}),
requestVcContext: send(
(context: any) => ({
type: 'GET_VC_ITEM',
vcMetadata: context.vcMetadata,
}),
{
to: context => context.serviceRefs.vc,
},
),
requestStoredContext: send(
(context: any) => {
return StoreEvents.GET(
VCMetadata.fromVC(context.vcMetadata).getVcKey(),
);
},
{
to: context => context.serviceRefs.store,
},
),
setContext: model.assign((context, event) => {
const {...data} = event.response;
return {...context, ...data};
}),
setCredential: model.assign((context, event) => {
return {
...context,
...event.response,
vcMetadata: context.vcMetadata,
};
}),
storeContext: send(
(context: any) => {
const {serviceRefs, isMachineInKebabPopupState, ...data} = context;
data.credentialRegistry = MIMOTO_BASE_URL;
return StoreEvents.SET(
VCMetadata.fromVC(context.vcMetadata).getVcKey(),
data,
);
},
{
to: context => context.serviceRefs.store,
},
),
setVcMetadata: assign({
vcMetadata: (_, event) => event.vcMetadata,
}),
storeVcInContext: send(
//todo : separate handling done for openid4vci , handle commonly from vc machine
(context: any) => {
const {serviceRefs, ...verifiableCredential} = context;
return {
type: 'VC_DOWNLOADED',
vc: verifiableCredential,
vcMetadata: context.vcMetadata,
};
},
{
to: context => context.serviceRefs.vc,
},
),
removeVcMetaDataFromStorage: send(
(context: any) => {
return StoreEvents.REMOVE_VC_METADATA(
MY_VCS_STORE_KEY,
context.vcMetadata.getVcKey(),
);
},
{
to: context => context.serviceRefs.store,
},
),
removeVcMetaDataFromVcMachineContext: send(
(context: any) => {
return {
type: 'REMOVE_VC_FROM_CONTEXT',
vcMetadata: context.vcMetadata,
};
},
{
to: context => context.serviceRefs.vc,
},
),
sendDownloadLimitExpire: send(
(context: any, event) => {
return {
type: 'DOWNLOAD_LIMIT_EXPIRED',
vcMetadata: context.vcMetadata,
};
},
{
to: context => context.serviceRefs.vc,
},
),
sendVerificationError: send(
(context: any, _event) => {
return {
type: 'VERIFY_VC_FAILED',
errorMessage: context.error,
vcMetadata: context.vcMetadata,
};
},
{
to: context => context.serviceRefs.vc,
},
),
refreshAllVcs: send(
() => ({
type: 'REFRESH_MY_VCS',
}),
{
to: (context: any) => context.serviceRefs.vc,
},
),
setPinCard: assign({
vcMetadata: (context: any) =>
new VCMetadata({
...context.vcMetadata,
isPinned: !context.vcMetadata.isPinned,
}),
}),
sendBackupEvent: send(BackupEvents.DATA_BACKUP(true), {
to: (context: any) => context.serviceRefs.backup,
}),
//todo: revisit on this for naming and impl
sendVcUpdated: send(
(context: any) => VcEvents.VC_METADATA_UPDATED(context.vcMetadata),
{
to: (context: any) => context.serviceRefs.vc,
},
),
sendTamperedVc: send(
(context: any) => VcEvents.TAMPERED_VC(context.vcMetadata),
{
to: context => context.serviceRefs.vc,
},
),
setErrorAsWalletBindingError: assign({
error: () =>
i18n.t('errors.genericError', {
ns: 'common',
}),
}),
setErrorAsVerificationError: assign({
//todo handle error message from different actions
error: (_context, event) => (event.data as Error).message,
}),
unSetError: assign({
error: () => '',
}),
unSetBindingTransactionId: assign({bindingTransactionId: () => ''}),
sendWalletBindingSuccess: send(
context => {
return {
type: 'WALLET_BINDING_SUCCESS',
};
},
{
to: (context: any) => context.serviceRefs.vc,
},
),
setWalletBindingResponse: assign({
walletBindingResponse: (_context, event) =>
event.data as WalletBindingResponse,
}),
incrementDownloadCounter: model.assign({
downloadCounter: ({downloadCounter}) => downloadCounter + 1,
}),
setMaxDownloadCount: model.assign({
maxDownloadCount: (_context, event) =>
Number((event.data as DownloadProps).maxDownloadLimit),
}),
setDownloadInterval: model.assign({
downloadInterval: (_context, event) =>
Number((event.data as DownloadProps).downloadInterval),
}),
sendActivationStartEvent: context => {
sendStartEvent(
getStartEventData(
context.isMachineInKebabPopupState
? TelemetryConstants.FlowType.vcActivationFromKebab
: TelemetryConstants.FlowType.vcActivation,
),
);
sendInteractEvent(
getInteractEventData(
context.isMachineInKebabPopupState
? TelemetryConstants.FlowType.vcActivationFromKebab
: TelemetryConstants.FlowType.vcActivation,
TelemetryConstants.InteractEventSubtype.click,
'Activate Button',
),
);
},
sendUserCancelledActivationFailedEndEvent: context => {
const [errorId, errorMessage] = [
TelemetryConstants.ErrorId.userCancel,
TelemetryConstants.ErrorMessage.activationCancelled,
];
sendEndEvent(
getEndEventData(
context.isMachineInKebabPopupState
? TelemetryConstants.FlowType.vcActivationFromKebab
: TelemetryConstants.FlowType.vcActivation,
TelemetryConstants.EndEventStatus.failure,
{
errorId: errorId,
errorMessage: errorMessage,
},
),
);
},
sendWalletBindingErrorEvent: (context, event) => {
if (context.error) {
const error = JSON.parse(JSON.stringify(event.data)).name
? JSON.parse(JSON.stringify(event.data)).name + '-' + context.error
: context.error;
sendErrorEvent(
getErrorEventData(
TelemetryConstants.FlowType.vcActivation,
TelemetryConstants.ErrorId.activationFailed,
error,
),
);
}
sendEndEvent(
getEndEventData(
TelemetryConstants.FlowType.vcActivation,
TelemetryConstants.EndEventStatus.failure,
),
);
},
sendActivationSuccessEvent: context =>
sendEndEvent(
getEndEventData(
context.isMachineInKebabPopupState
? TelemetryConstants.FlowType.vcActivationFromKebab
: TelemetryConstants.FlowType.vcActivation,
TelemetryConstants.EndEventStatus.success,
),
),
setPublicKey: assign({
publicKey: (_context, event) => {
if (!isHardwareKeystoreExists) {
return (event.data as KeyPair).public;
}
return event.data as string;
},
}),
setPrivateKey: assign({
privateKey: (_context, event) => (event.data as KeyPair).private,
}),
resetPrivateKey: assign({
privateKey: () => '',
}),
setThumbprintForWalletBindingId: send(
(context: any) => {
const {walletBindingResponse} = context;
const walletBindingIdKey = getBindingCertificateConstant(
walletBindingResponse.walletBindingId,
);
return StoreEvents.SET(
walletBindingIdKey,
walletBindingResponse.thumbprint,
);
},
{
to: context => context.serviceRefs.store,
},
),
setOTP: model.assign({
OTP: (_, event) => event.OTP,
}),
unSetOTP: model.assign({OTP: () => ''}),
removeVcItem: send(
(context: any) => {
return StoreEvents.REMOVE(
MY_VCS_STORE_KEY,
context.vcMetadata.getVcKey(),
);
},
{to: context => context.serviceRefs.store},
),
setVcKey: model.assign({
vcMetadata: (_, event) => event.vcMetadata,
}),
removeVcFromInProgressDownloads: send(
(context: any) => {
return {
type: 'REMOVE_VC_FROM_IN_PROGRESS_DOWNLOADS',
vcMetadata: context.vcMetadata,
};
},
{
to: context => context.serviceRefs.vc,
},
),
addVcToInProgressDownloads: send(
(context: any) => {
return {
type: 'ADD_VC_TO_IN_PROGRESS_DOWNLOADS',
requestId: context.vcMetadata.requestId,
};
},
{
to: context => context.serviceRefs.vc,
},
),
sendTelemetryEvents: () => {
sendEndEvent({
type: TelemetryConstants.FlowType.vcDownload,
status: TelemetryConstants.EndEventStatus.success,
});
},
closeViewVcModal: send('DISMISS_MODAL', {
to: () => getHomeMachineService(),
}),
logDownloaded: send(
(context: any) => {
const {serviceRefs, ...data} = context;
return ActivityLogEvents.LOG_ACTIVITY({
_vcKey: context.vcMetadata.getVcKey(),
type: 'VC_DOWNLOADED',
id: context.vcMetadata.id,
idType: getIdType(context.vcMetadata.issuer),
timestamp: Date.now(),
deviceName: '',
vcLabel: data.id,
});
},
{
to: context => context.serviceRefs.activityLog,
},
),
logRemovedVc: send(
(context: any, _) =>
ActivityLogEvents.LOG_ACTIVITY({
idType: getIdType(context.vcMetadata.issuer),
id: context.vcMetadata.id,
_vcKey: VCMetadata.fromVC(context.vcMetadata).getVcKey(),
type: 'VC_REMOVED',
timestamp: Date.now(),
deviceName: '',
vcLabel: VCMetadata.fromVC(context.vcMetadata).id,
}),
{
to: context => context.serviceRefs.activityLog,
},
),
logWalletBindingSuccess: send(
(context: any) =>
ActivityLogEvents.LOG_ACTIVITY({
_vcKey: VCMetadata.fromVC(context.vcMetadata).getVcKey(),
type: 'WALLET_BINDING_SUCCESSFULL',
idType: getIdType(context.vcMetadata.issuer),
id: context.vcMetadata.id,
timestamp: Date.now(),
deviceName: '',
vcLabel: VCMetadata.fromVC(context.vcMetadata).id,
}),
{
to: context => context.serviceRefs.activityLog,
},
),
logWalletBindingFailure: send(
(context: any) =>
ActivityLogEvents.LOG_ACTIVITY({
_vcKey: VCMetadata.fromVC(context.vcMetadata).getVcKey(),
type: 'WALLET_BINDING_FAILURE',
id: context.vcMetadata.id,
idType: getIdType(context.vcMetadata.issuer),
timestamp: Date.now(),
deviceName: '',
vcLabel: VCMetadata.fromVC(context.vcMetadata).id,
}),
{
to: context => context.serviceRefs.activityLog,
},
),
};
};

View File

@@ -0,0 +1,27 @@
import {VCMetadata} from '../../../shared/VCMetadata';
import {VC} from '../../../types/VC/vc';
export const VCItemEvents = {
DISMISS: () => ({}),
CREDENTIAL_DOWNLOADED: (response: VC) => ({response}),
STORE_RESPONSE: (response: VC) => ({response}),
STORE_ERROR: (error: Error) => ({error}),
POLL: () => ({}),
DOWNLOAD_READY: () => ({}),
FAILED: () => ({}),
GET_VC_RESPONSE: (response: VC) => ({response}),
INPUT_OTP: (OTP: string) => ({OTP}),
RESEND_OTP: () => ({}),
REFRESH: () => ({}),
ADD_WALLET_BINDING_ID: () => ({}),
CANCEL: () => ({}),
CONFIRM: () => ({}),
PIN_CARD: () => ({}),
KEBAB_POPUP: () => ({}),
SHOW_ACTIVITY: () => ({}),
CLOSE_VC_MODAL: () => ({}),
REMOVE: (vcMetadata: VCMetadata) => ({vcMetadata}),
UPDATE_VC_METADATA: (vcMetadata: VCMetadata) => ({vcMetadata}),
TAMPERED_VC: (key: string) => ({key}),
SHOW_BINDING_STATUS: () => ({}),
};

View File

@@ -0,0 +1,19 @@
import {isSignedInResult} from '../../../shared/CloudBackupAndRestoreUtils';
import {isHardwareKeystoreExists} from '../../../shared/cryptoutil/cryptoUtil';
export const VCItemGaurds = () => {
return {
hasCredential: (_, event) => {
const vc = event.response;
return vc?.credential != null || vc?.verifiableCredential != null;
},
isSignedIn: (_context, event) =>
(event.data as isSignedInResult).isSignedIn,
isDownloadAllowed: _context => {
return _context.downloadCounter <= _context.maxDownloadCount;
},
isCustomSecureKeystore: () => isHardwareKeystoreExists,
};
};

View File

@@ -0,0 +1,536 @@
import {AppServices} from '../../../shared/GlobalContext';
import {VCMetadata} from '../../../shared/VCMetadata';
import {assign, EventFrom, send} from 'xstate';
import {log} from 'xstate/lib/actions';
import {VCItemActions} from './VCItemActions';
import {VCItemGaurds} from './VCItemGaurds';
import {VCItemServices} from './VCItemServices';
import {VCItemModel} from './VCItemModel';
const machineName = 'vc-item-machine';
const model = VCItemModel;
export const VCItemEvents = model.events;
export const VCItemMachine = model.createMachine(
{
predictableActionArguments: true,
preserveActionOrder: true,
tsTypes: {} as import('./VCItemMachine.typegen').Typegen0,
schema: {
context: model.initialContext,
events: {} as EventFrom<typeof model>,
},
on: {
REFRESH: {
target: 'loadVc',
},
UPDATE_VC_METADATA: {
actions: 'setVcMetadata',
},
},
description:
'This machine is spawned for every VC downloaded, and tracks its lifecycle.',
id: machineName,
initial: 'loadVc',
states: {
loadVc: {
initial: 'loadVcFromContext',
states: {
loadVcFromContext: {
entry: ['requestVcContext'],
description: 'Fetch the VC data from the Memory.',
on: {
GET_VC_RESPONSE: [
{
actions: ['setContext'],
cond: 'hasCredential',
target: `#vc-item-machine.idle`,
},
{
target: 'loadVcFromStore',
},
],
},
},
loadVcFromStore: {
entry: 'requestStoredContext',
description: 'Check if VC data is in secured local storage.',
on: {
STORE_RESPONSE: [
{
actions: ['setContext', 'storeVcInContext'],
cond: 'hasCredential',
target: '#vc-item-machine.idle',
},
{
actions: 'addVcToInProgressDownloads',
target: 'loadVcFromServer',
},
],
TAMPERED_VC: {
actions: 'sendTamperedVc',
},
},
},
loadVcFromServer: {
description:
"Download VC data from the server. Uses polling method to check when it's available.",
initial: 'loadDownloadLimitConfig',
states: {
loadDownloadLimitConfig: {
invoke: {
src: 'loadDownloadLimitConfig',
onDone: {
actions: ['setMaxDownloadCount', 'setDownloadInterval'],
target: 'verifyingDownloadLimitExpiry',
},
},
},
verifyingDownloadLimitExpiry: {
entry: ['incrementDownloadCounter'],
invoke: {
src: 'checkDownloadExpiryLimit',
onDone: {
target: 'checkingStatus',
},
onError: {
actions: [
log((_, event) => (event.data as Error).message),
'sendDownloadLimitExpire',
],
},
},
},
checkingStatus: {
invoke: {
src: 'checkStatus',
id: 'checkStatus',
},
on: {
POLL: {
actions: send('POLL_STATUS', {to: 'checkStatus'}),
},
DOWNLOAD_READY: {
target: 'downloadingCredential',
},
FAILED: {
actions: 'sendDownloadLimitExpire',
},
},
},
downloadingCredential: {
invoke: {
src: 'downloadCredential',
id: 'downloadCredential',
},
on: {
POLL: [
{
cond: 'isDownloadAllowed',
actions: [
send('POLL_DOWNLOAD', {to: 'downloadCredential'}),
'incrementDownloadCounter',
],
},
{
target: 'verifyingDownloadLimitExpiry',
},
],
CREDENTIAL_DOWNLOADED: {
actions: 'setCredential',
target: '#vc-item-machine.verifyingCredential',
},
},
},
savingFailed: {
entry: ['removeVcMetaDataFromStorage'],
initial: 'idle',
states: {
idle: {},
viewingVc: {},
},
on: {
DISMISS: {
actions: ['removeVcMetaDataFromVcMachineContext'],
target: '.viewingVc',
},
},
},
},
},
},
},
walletBinding: {
initial: 'showBindingWarning',
states: {
showBindingWarning: {
on: {
CONFIRM: {
actions: 'sendActivationStartEvent',
target: 'requestingBindingOTP',
},
CANCEL: [
{
cond: context => context.isMachineInKebabPopupState,
target: '#vc-item-machine.kebabPopUp',
},
{
target: '#vc-item-machine.idle',
},
],
},
},
requestingBindingOTP: {
invoke: {
src: 'requestBindingOTP',
onDone: [
{
target: 'acceptingBindingOTP',
actions: ['setCommunicationDetails'],
},
],
onError: [
{
actions: [
'setErrorAsWalletBindingError',
'sendWalletBindingErrorEvent',
'logWalletBindingFailure',
],
target: 'showingWalletBindingError',
},
],
},
},
showingWalletBindingError: {
on: {
CANCEL: [
{
cond: context => context.isMachineInKebabPopupState,
actions: ['unSetError'],
target: '#vc-item-machine.kebabPopUp',
},
{
actions: ['unSetError'],
target: '#vc-item-machine.idle',
},
],
},
},
acceptingBindingOTP: {
entry: ['unSetOTP'],
on: {
INPUT_OTP: {
target: 'addKeyPair',
actions: ['setOTP'],
},
DISMISS: [
{
cond: context => context.isMachineInKebabPopupState,
target: '#vc-item-machine.kebabPopUp',
actions: [
'sendUserCancelledActivationFailedEndEvent',
'unSetOTP',
'unSetBindingTransactionId',
],
},
{
target: '#vc-item-machine.idle',
actions: [
'sendUserCancelledActivationFailedEndEvent',
'unSetOTP',
'unSetBindingTransactionId',
],
},
],
RESEND_OTP: {
target: '.resendOTP',
},
},
initial: 'idle',
states: {
idle: {},
resendOTP: {
invoke: {
src: 'requestBindingOTP',
onDone: {
target: '#vc-item-machine.idle',
actions: ['setCommunicationDetails'],
},
onError: {
actions: [
'setErrorAsWalletBindingError',
'sendWalletBindingErrorEvent',
],
target:
'#vc-item-machine.walletBinding.showingWalletBindingError',
},
},
},
},
},
addKeyPair: {
invoke: {
src: 'generateKeyPair',
onDone: [
{
cond: 'isCustomSecureKeystore',
target: 'addingWalletBindingId',
actions: ['setPublicKey'],
},
{
target: 'addingWalletBindingId',
actions: ['setPublicKey', 'setPrivateKey'],
},
],
onError: [
{
actions: [
'setErrorAsWalletBindingError',
'sendWalletBindingErrorEvent',
'logWalletBindingFailure',
],
target: 'showingWalletBindingError',
},
],
},
},
addingWalletBindingId: {
invoke: {
src: 'addWalletBindingId',
onDone: [
{
cond: 'isCustomSecureKeystore',
target: 'updatingContextVariables',
actions: ['setWalletBindingResponse'],
},
{
target: 'updatingPrivateKey',
/*The walletBindingResponse is used for conditional rendering in wallet binding. response and use it in updatingPrivateKey state*/
actions: ['setWalletBindingResponse'],
},
],
onError: [
{
actions: [
'setErrorAsWalletBindingError',
'sendWalletBindingErrorEvent',
'logWalletBindingFailure',
],
target: 'showingWalletBindingError',
},
],
},
},
updatingPrivateKey: {
invoke: {
src: 'updatePrivateKey',
onDone: {
target: 'updatingContextVariables',
},
onError: {
actions: [
'setErrorAsWalletBindingError',
'sendWalletBindingErrorEvent',
'logWalletBindingFailure',
],
target: 'showingWalletBindingError',
},
},
},
updatingContextVariables: {
entry: [
'setThumbprintForWalletBindingId',
'storeContext',
'resetPrivateKey',
'storeVcInContext',
'unSetError',
'sendActivationSuccessEvent',
'logWalletBindingSuccess',
send('SHOW_BINDING_STATUS'),
],
on: {
SHOW_BINDING_STATUS: [
{
cond: context => context.isMachineInKebabPopupState,
actions: 'sendWalletBindingSuccess',
target: '#vc-item-machine.kebabPopUp',
},
{
actions: 'sendWalletBindingSuccess',
target: '#vc-item-machine.idle',
},
],
},
},
},
},
kebabPopUp: {
entry: assign({isMachineInKebabPopupState: () => true}),
exit: assign({isMachineInKebabPopupState: () => false}),
on: {
DISMISS: {
actions: assign({
isMachineInKebabPopupState: () => false,
}),
target: 'idle',
},
ADD_WALLET_BINDING_ID: {
target: '#vc-item-machine.walletBinding',
},
PIN_CARD: {
target: '.pinCard',
actions: 'setPinCard',
},
SHOW_ACTIVITY: {
target: '#vc-item-machine.kebabPopUp.showActivities',
},
REMOVE: {
actions: 'setVcKey',
target: '#vc-item-machine.kebabPopUp.removeWallet',
},
CLOSE_VC_MODAL: {
actions: ['closeViewVcModal'],
target: '#vc-item-machine',
},
},
initial: 'idle',
states: {
idle: {},
showActivities: {
on: {
DISMISS: '#vc-item-machine',
},
},
removeWallet: {
on: {
CONFIRM: {
target: 'removingVc',
},
CANCEL: {
target: '#vc-item-machine',
},
},
},
removingVc: {
entry: 'removeVcItem',
on: {
STORE_RESPONSE: {
actions: ['closeViewVcModal', 'refreshAllVcs', 'logRemovedVc'],
target: 'triggerAutoBackup',
},
},
},
pinCard: {
entry: 'sendVcUpdated',
always: {
target: '#vc-item-machine.idle',
},
},
triggerAutoBackup: {
invoke: {
src: 'isUserSignedAlready',
onDone: [
{
cond: 'isSignedIn',
actions: ['sendBackupEvent', 'refreshAllVcs', 'logRemovedVc'],
target: '#vc-item-machine',
},
{
actions: ['refreshAllVcs', 'logRemovedVc'],
target: '#vc-item-machine',
},
],
},
},
},
},
verifyingCredential: {
invoke: {
src: 'verifyCredential',
onDone: {
actions: ['storeContext'],
},
onError: {
//To-Do Handle Error Scenarios
actions: ['setErrorAsVerificationError'],
target: '.handleVCVerificationFailure',
},
},
on: {
STORE_RESPONSE: {
actions: [
'storeVcInContext',
'logDownloaded',
'sendTelemetryEvents',
'removeVcFromInProgressDownloads',
],
target: '.triggerAutoBackupForVcDownload',
},
STORE_ERROR: {
target: '#vc-item-machine.loadVc.loadVcFromServer.savingFailed',
},
},
initial: 'idle',
states: {
idle: {},
triggerAutoBackupForVcDownload: {
invoke: {
src: 'isUserSignedAlready',
onDone: [
{
cond: 'isSignedIn',
actions: ['sendBackupEvent'],
target: '#vc-item-machine.idle',
},
{
target: '#vc-item-machine.idle',
},
],
},
},
handleVCVerificationFailure: {
entry: ['removeVcMetaDataFromStorage'],
on: {
STORE_RESPONSE: {
actions: ['sendVerificationError'],
},
},
},
},
},
idle: {
on: {
DISMISS: {
target: '#vc-item-machine.loadVc.loadVcFromContext',
},
KEBAB_POPUP: {
target: 'kebabPopUp',
},
ADD_WALLET_BINDING_ID: {
target: '#vc-item-machine.walletBinding',
},
PIN_CARD: {
target: '#vc-item-machine.kebabPopUp.pinCard',
actions: 'setPinCard',
},
},
},
},
},
{
actions: VCItemActions(model),
services: VCItemServices(model),
guards: VCItemGaurds(),
},
);
export const createVCItemMachine = (
serviceRefs: AppServices,
vcMetadata: VCMetadata,
) => {
return VCItemMachine.withContext({
...VCItemMachine.context,
serviceRefs,
vcMetadata,
});
};

View File

@@ -0,0 +1,378 @@
// This file was automatically generated. Edits will be overwritten
export interface Typegen0 {
'@@xstate/typegen': true;
internalEvents: {
'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.kebabPopUp.triggerAutoBackup:invocation[0]': {
type: 'done.invoke.vc-item-machine.kebabPopUp.triggerAutoBackup:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.vc-item-machine.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]': {
type: 'done.invoke.vc-item-machine.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.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]': {
type: 'done.invoke.vc-item-machine.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.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]': {
type: 'done.invoke.vc-item-machine.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.vc-item-machine.verifyingCredential:invocation[0]': {
type: 'done.invoke.vc-item-machine.verifyingCredential:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.vc-item-machine.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]': {
type: 'done.invoke.vc-item-machine.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.walletBinding.addKeyPair:invocation[0]': {
type: 'done.invoke.vc-item-machine.walletBinding.addKeyPair:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.vc-item-machine.walletBinding.addingWalletBindingId:invocation[0]': {
type: 'done.invoke.vc-item-machine.walletBinding.addingWalletBindingId:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.vc-item-machine.walletBinding.requestingBindingOTP:invocation[0]': {
type: 'done.invoke.vc-item-machine.walletBinding.requestingBindingOTP:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.vc-item-machine.walletBinding.updatingPrivateKey:invocation[0]': {
type: 'done.invoke.vc-item-machine.walletBinding.updatingPrivateKey: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.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]': {
type: 'error.platform.vc-item-machine.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]';
data: unknown;
};
'error.platform.vc-item-machine.verifyingCredential:invocation[0]': {
type: 'error.platform.vc-item-machine.verifyingCredential:invocation[0]';
data: unknown;
};
'error.platform.vc-item-machine.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]': {
type: 'error.platform.vc-item-machine.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]';
data: unknown;
};
'error.platform.vc-item-machine.walletBinding.addKeyPair:invocation[0]': {
type: 'error.platform.vc-item-machine.walletBinding.addKeyPair:invocation[0]';
data: unknown;
};
'error.platform.vc-item-machine.walletBinding.addingWalletBindingId:invocation[0]': {
type: 'error.platform.vc-item-machine.walletBinding.addingWalletBindingId:invocation[0]';
data: unknown;
};
'error.platform.vc-item-machine.walletBinding.requestingBindingOTP:invocation[0]': {
type: 'error.platform.vc-item-machine.walletBinding.requestingBindingOTP:invocation[0]';
data: unknown;
};
'error.platform.vc-item-machine.walletBinding.updatingPrivateKey:invocation[0]': {
type: 'error.platform.vc-item-machine.walletBinding.updatingPrivateKey:invocation[0]';
data: unknown;
};
'xstate.init': {type: 'xstate.init'};
};
invokeSrcNameMap: {
addWalletBindingId: 'done.invoke.vc-item-machine.walletBinding.addingWalletBindingId:invocation[0]';
checkDownloadExpiryLimit: 'done.invoke.vc-item-machine.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]';
checkStatus: 'done.invoke.checkStatus';
downloadCredential: 'done.invoke.downloadCredential';
generateKeyPair: 'done.invoke.vc-item-machine.walletBinding.addKeyPair:invocation[0]';
isUserSignedAlready:
| 'done.invoke.vc-item-machine.kebabPopUp.triggerAutoBackup:invocation[0]'
| 'done.invoke.vc-item-machine.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]';
loadDownloadLimitConfig: 'done.invoke.vc-item-machine.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]';
requestBindingOTP:
| 'done.invoke.vc-item-machine.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]'
| 'done.invoke.vc-item-machine.walletBinding.requestingBindingOTP:invocation[0]';
updatePrivateKey: 'done.invoke.vc-item-machine.walletBinding.updatingPrivateKey:invocation[0]';
verifyCredential: 'done.invoke.vc-item-machine.verifyingCredential:invocation[0]';
};
missingImplementations: {
actions:
| 'addVcToInProgressDownloads'
| 'closeViewVcModal'
| 'incrementDownloadCounter'
| 'logDownloaded'
| 'logRemovedVc'
| 'logWalletBindingFailure'
| 'logWalletBindingSuccess'
| 'refreshAllVcs'
| 'removeVcFromInProgressDownloads'
| 'removeVcItem'
| 'removeVcMetaDataFromStorage'
| 'removeVcMetaDataFromVcMachineContext'
| 'requestStoredContext'
| 'requestVcContext'
| 'resetPrivateKey'
| 'sendActivationStartEvent'
| 'sendActivationSuccessEvent'
| 'sendBackupEvent'
| 'sendDownloadLimitExpire'
| 'sendTamperedVc'
| 'sendTelemetryEvents'
| 'sendUserCancelledActivationFailedEndEvent'
| 'sendVcUpdated'
| 'sendVerificationError'
| 'sendWalletBindingErrorEvent'
| 'sendWalletBindingSuccess'
| 'setCommunicationDetails'
| 'setContext'
| 'setCredential'
| 'setDownloadInterval'
| 'setErrorAsVerificationError'
| 'setErrorAsWalletBindingError'
| 'setMaxDownloadCount'
| 'setOTP'
| 'setPinCard'
| 'setPrivateKey'
| 'setPublicKey'
| 'setThumbprintForWalletBindingId'
| 'setVcKey'
| 'setVcMetadata'
| 'setWalletBindingResponse'
| 'storeContext'
| 'storeVcInContext'
| 'unSetBindingTransactionId'
| 'unSetError'
| 'unSetOTP';
delays: never;
guards:
| 'hasCredential'
| 'isCustomSecureKeystore'
| 'isDownloadAllowed'
| 'isSignedIn';
services:
| 'addWalletBindingId'
| 'checkDownloadExpiryLimit'
| 'checkStatus'
| 'downloadCredential'
| 'generateKeyPair'
| 'isUserSignedAlready'
| 'loadDownloadLimitConfig'
| 'requestBindingOTP'
| 'updatePrivateKey'
| 'verifyCredential';
};
eventsCausingActions: {
addVcToInProgressDownloads: 'STORE_RESPONSE';
closeViewVcModal: 'CLOSE_VC_MODAL' | 'STORE_RESPONSE';
incrementDownloadCounter:
| 'POLL'
| 'done.invoke.vc-item-machine.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]';
logDownloaded: 'STORE_RESPONSE';
logRemovedVc:
| 'STORE_RESPONSE'
| 'done.invoke.vc-item-machine.kebabPopUp.triggerAutoBackup:invocation[0]';
logWalletBindingFailure:
| 'error.platform.vc-item-machine.walletBinding.addKeyPair:invocation[0]'
| 'error.platform.vc-item-machine.walletBinding.addingWalletBindingId:invocation[0]'
| 'error.platform.vc-item-machine.walletBinding.requestingBindingOTP:invocation[0]'
| 'error.platform.vc-item-machine.walletBinding.updatingPrivateKey:invocation[0]';
logWalletBindingSuccess:
| 'done.invoke.vc-item-machine.walletBinding.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item-machine.walletBinding.updatingPrivateKey:invocation[0]';
refreshAllVcs:
| 'STORE_RESPONSE'
| 'done.invoke.vc-item-machine.kebabPopUp.triggerAutoBackup:invocation[0]';
removeVcFromInProgressDownloads: 'STORE_RESPONSE';
removeVcItem: 'CONFIRM';
removeVcMetaDataFromStorage:
| 'STORE_ERROR'
| 'error.platform.vc-item-machine.verifyingCredential:invocation[0]';
removeVcMetaDataFromVcMachineContext: 'DISMISS';
requestStoredContext: 'GET_VC_RESPONSE';
requestVcContext: 'DISMISS' | 'REFRESH' | 'STORE_ERROR' | 'xstate.init';
resetPrivateKey:
| 'done.invoke.vc-item-machine.walletBinding.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item-machine.walletBinding.updatingPrivateKey:invocation[0]';
sendActivationStartEvent: 'CONFIRM';
sendActivationSuccessEvent:
| 'done.invoke.vc-item-machine.walletBinding.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item-machine.walletBinding.updatingPrivateKey:invocation[0]';
sendBackupEvent:
| 'done.invoke.vc-item-machine.kebabPopUp.triggerAutoBackup:invocation[0]'
| 'done.invoke.vc-item-machine.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]';
sendDownloadLimitExpire:
| 'FAILED'
| 'error.platform.vc-item-machine.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]';
sendTamperedVc: 'TAMPERED_VC';
sendTelemetryEvents: 'STORE_RESPONSE';
sendUserCancelledActivationFailedEndEvent: 'DISMISS';
sendVcUpdated: 'PIN_CARD';
sendVerificationError: 'STORE_RESPONSE';
sendWalletBindingErrorEvent:
| 'error.platform.vc-item-machine.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]'
| 'error.platform.vc-item-machine.walletBinding.addKeyPair:invocation[0]'
| 'error.platform.vc-item-machine.walletBinding.addingWalletBindingId:invocation[0]'
| 'error.platform.vc-item-machine.walletBinding.requestingBindingOTP:invocation[0]'
| 'error.platform.vc-item-machine.walletBinding.updatingPrivateKey:invocation[0]';
sendWalletBindingSuccess: 'SHOW_BINDING_STATUS';
setCommunicationDetails:
| 'done.invoke.vc-item-machine.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]'
| 'done.invoke.vc-item-machine.walletBinding.requestingBindingOTP:invocation[0]';
setContext: 'GET_VC_RESPONSE' | 'STORE_RESPONSE';
setCredential: 'CREDENTIAL_DOWNLOADED';
setDownloadInterval: 'done.invoke.vc-item-machine.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]';
setErrorAsVerificationError: 'error.platform.vc-item-machine.verifyingCredential:invocation[0]';
setErrorAsWalletBindingError:
| 'error.platform.vc-item-machine.walletBinding.acceptingBindingOTP.resendOTP:invocation[0]'
| 'error.platform.vc-item-machine.walletBinding.addKeyPair:invocation[0]'
| 'error.platform.vc-item-machine.walletBinding.addingWalletBindingId:invocation[0]'
| 'error.platform.vc-item-machine.walletBinding.requestingBindingOTP:invocation[0]'
| 'error.platform.vc-item-machine.walletBinding.updatingPrivateKey:invocation[0]';
setMaxDownloadCount: 'done.invoke.vc-item-machine.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]';
setOTP: 'INPUT_OTP';
setPinCard: 'PIN_CARD';
setPrivateKey: 'done.invoke.vc-item-machine.walletBinding.addKeyPair:invocation[0]';
setPublicKey: 'done.invoke.vc-item-machine.walletBinding.addKeyPair:invocation[0]';
setThumbprintForWalletBindingId:
| 'done.invoke.vc-item-machine.walletBinding.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item-machine.walletBinding.updatingPrivateKey:invocation[0]';
setVcKey: 'REMOVE';
setVcMetadata: 'UPDATE_VC_METADATA';
setWalletBindingResponse: 'done.invoke.vc-item-machine.walletBinding.addingWalletBindingId:invocation[0]';
storeContext:
| 'done.invoke.vc-item-machine.verifyingCredential:invocation[0]'
| 'done.invoke.vc-item-machine.walletBinding.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item-machine.walletBinding.updatingPrivateKey:invocation[0]';
storeVcInContext:
| 'STORE_RESPONSE'
| 'done.invoke.vc-item-machine.walletBinding.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item-machine.walletBinding.updatingPrivateKey:invocation[0]';
unSetBindingTransactionId: 'DISMISS';
unSetError:
| 'CANCEL'
| 'done.invoke.vc-item-machine.walletBinding.addingWalletBindingId:invocation[0]'
| 'done.invoke.vc-item-machine.walletBinding.updatingPrivateKey:invocation[0]';
unSetOTP:
| 'DISMISS'
| 'done.invoke.vc-item-machine.walletBinding.requestingBindingOTP:invocation[0]';
};
eventsCausingDelays: {};
eventsCausingGuards: {
hasCredential: 'GET_VC_RESPONSE' | 'STORE_RESPONSE';
isCustomSecureKeystore:
| 'done.invoke.vc-item-machine.walletBinding.addKeyPair:invocation[0]'
| 'done.invoke.vc-item-machine.walletBinding.addingWalletBindingId:invocation[0]';
isDownloadAllowed: 'POLL';
isSignedIn:
| 'done.invoke.vc-item-machine.kebabPopUp.triggerAutoBackup:invocation[0]'
| 'done.invoke.vc-item-machine.verifyingCredential.triggerAutoBackupForVcDownload:invocation[0]';
};
eventsCausingServices: {
addWalletBindingId: 'done.invoke.vc-item-machine.walletBinding.addKeyPair:invocation[0]';
checkDownloadExpiryLimit:
| 'POLL'
| 'done.invoke.vc-item-machine.loadVc.loadVcFromServer.loadDownloadLimitConfig:invocation[0]';
checkStatus: 'done.invoke.vc-item-machine.loadVc.loadVcFromServer.verifyingDownloadLimitExpiry:invocation[0]';
downloadCredential: 'DOWNLOAD_READY';
generateKeyPair: 'INPUT_OTP';
isUserSignedAlready: 'STORE_RESPONSE';
loadDownloadLimitConfig: 'STORE_ERROR' | 'STORE_RESPONSE';
requestBindingOTP: 'CONFIRM' | 'RESEND_OTP';
updatePrivateKey: 'done.invoke.vc-item-machine.walletBinding.addingWalletBindingId:invocation[0]';
verifyCredential: 'CREDENTIAL_DOWNLOADED';
};
matchesStates:
| 'idle'
| 'kebabPopUp'
| 'kebabPopUp.idle'
| 'kebabPopUp.pinCard'
| 'kebabPopUp.removeWallet'
| 'kebabPopUp.removingVc'
| 'kebabPopUp.showActivities'
| 'kebabPopUp.triggerAutoBackup'
| 'loadVc'
| 'loadVc.loadVcFromContext'
| 'loadVc.loadVcFromServer'
| 'loadVc.loadVcFromServer.checkingStatus'
| 'loadVc.loadVcFromServer.downloadingCredential'
| 'loadVc.loadVcFromServer.loadDownloadLimitConfig'
| 'loadVc.loadVcFromServer.savingFailed'
| 'loadVc.loadVcFromServer.savingFailed.idle'
| 'loadVc.loadVcFromServer.savingFailed.viewingVc'
| 'loadVc.loadVcFromServer.verifyingDownloadLimitExpiry'
| 'loadVc.loadVcFromStore'
| 'verifyingCredential'
| 'verifyingCredential.handleVCVerificationFailure'
| 'verifyingCredential.idle'
| 'verifyingCredential.triggerAutoBackupForVcDownload'
| 'walletBinding'
| 'walletBinding.acceptingBindingOTP'
| 'walletBinding.acceptingBindingOTP.idle'
| 'walletBinding.acceptingBindingOTP.resendOTP'
| 'walletBinding.addKeyPair'
| 'walletBinding.addingWalletBindingId'
| 'walletBinding.requestingBindingOTP'
| 'walletBinding.showBindingWarning'
| 'walletBinding.showingWalletBindingError'
| 'walletBinding.updatingContextVariables'
| 'walletBinding.updatingPrivateKey'
| {
kebabPopUp?:
| 'idle'
| 'pinCard'
| 'removeWallet'
| 'removingVc'
| 'showActivities'
| 'triggerAutoBackup';
loadVc?:
| 'loadVcFromContext'
| 'loadVcFromServer'
| 'loadVcFromStore'
| {
loadVcFromServer?:
| 'checkingStatus'
| 'downloadingCredential'
| 'loadDownloadLimitConfig'
| 'savingFailed'
| 'verifyingDownloadLimitExpiry'
| {savingFailed?: 'idle' | 'viewingVc'};
};
verifyingCredential?:
| 'handleVCVerificationFailure'
| 'idle'
| 'triggerAutoBackupForVcDownload';
walletBinding?:
| 'acceptingBindingOTP'
| 'addKeyPair'
| 'addingWalletBindingId'
| 'requestingBindingOTP'
| 'showBindingWarning'
| 'showingWalletBindingError'
| 'updatingContextVariables'
| 'updatingPrivateKey'
| {acceptingBindingOTP?: 'idle' | 'resendOTP'};
};
tags: never;
}

View File

@@ -0,0 +1,34 @@
import {createModel} from 'xstate/lib/model';
import {AppServices} from '../../../shared/GlobalContext';
import {VCMetadata} from '../../../shared/VCMetadata';
import {
VerifiableCredential,
WalletBindingResponse,
} from '../../../types/VC/vc';
import {CommunicationDetails} from '../../../shared/Utils';
import {VCItemEvents} from './VCItemEvents';
export const VCItemModel = createModel(
{
serviceRefs: {} as AppServices,
vcMetadata: {} as VCMetadata,
generatedOn: new Date() as Date,
verifiableCredential: null as unknown as VerifiableCredential,
hashedId: '',
publicKey: '',
privateKey: '',
OTP: '',
error: '',
bindingTransactionId: '',
requestId: '',
downloadCounter: 0,
maxDownloadCount: null as unknown as number,
downloadInterval: null as unknown as number,
walletBindingResponse: null as unknown as WalletBindingResponse,
isMachineInKebabPopupState: false,
communicationDetails: null as unknown as CommunicationDetails,
},
{
events: VCItemEvents,
},
);

View File

@@ -0,0 +1,114 @@
import {StateFrom} from 'xstate';
import {VCMetadata} from '../../../shared/VCMetadata';
import {VCItemMachine} from './VCItemMachine';
import {getMosipLogo} from '../../../components/VC/common/VCUtils';
type State = StateFrom<typeof VCItemMachine>;
export function selectVerifiableCredential(state: State) {
return state.context.verifiableCredential;
}
export function selectCredential(state: State) {
return new VCMetadata(state.context.vcMetadata).isFromOpenId4VCI()
? state.context.verifiableCredential?.credential
: state.context.verifiableCredential;
}
export function selectVerifiableCredentialData(state: State) {
const vcMetadata = new VCMetadata(state.context.vcMetadata);
return vcMetadata.isFromOpenId4VCI()
? {
vcMetadata: vcMetadata,
face: state.context.verifiableCredential?.credential?.credentialSubject
.face,
issuerLogo: state.context.verifiableCredential?.issuerLogo,
wellKnown: state.context.verifiableCredential?.wellKnown,
credentialTypes: state.context.verifiableCredential?.credentialTypes,
issuer: vcMetadata.issuer,
}
: {
vcMetadata: vcMetadata,
issuer: vcMetadata.issuer,
face: state.context.credential?.biometrics?.face,
issuerLogo: getMosipLogo(),
};
}
export function selectKebabPopUp(state: State) {
return state.context.isMachineInKebabPopupState;
}
export function selectContext(state: State) {
return state.context;
}
export function selectGeneratedOn(state: State) {
return state.context.generatedOn;
}
export function selectWalletBindingSuccess(state: State) {
return state.context.walletBindingResponse;
}
export function selectWalletBindingResponse(state: State) {
return state.context.walletBindingResponse;
}
export function selectIsCommunicationDetails(state: State) {
return state.context.communicationDetails;
}
export function selectWalletBindingError(state: State) {
return state.context.error;
}
export function selectBindingAuthFailedError(state: State) {
return state.context.error;
}
export function selectAcceptingBindingOtp(state: State) {
return state.matches('walletBinding.acceptingBindingOTP');
}
export function selectWalletBindingInProgress(state: State) {
return (
state.matches('walletBinding.requestingBindingOTP') ||
state.matches('walletBinding.addingWalletBindingId') ||
state.matches('walletBinding.addKeyPair') ||
state.matches('walletBinding.updatingPrivateKey')
);
}
export function selectBindingWarning(state: State) {
return state.matches('walletBinding.showBindingWarning');
}
export function selectRemoveWalletWarning(state: State) {
return state.matches('kebabPopUp.removeWallet');
}
export function selectIsPinned(state: State) {
return state.context.vcMetadata.isPinned;
}
export function selectOtpError(state: State) {
return state.context.error;
}
export function selectShowActivities(state: State) {
return state.matches('kebabPopUp.showActivities');
}
export function selectShowWalletBindingError(state: State) {
return state.matches('walletBinding.showingWalletBindingError');
}
export function selectVc(state: State) {
const {serviceRefs, ...data} = state.context;
return data;
}
export function selectId(state: State) {
return state.context.vcMetadata.id;
}

View File

@@ -0,0 +1,208 @@
import SecureKeystore from '@mosip/secure-keystore';
import Cloud from '../../../shared/CloudBackupAndRestoreUtils';
import {VCMetadata} from '../../../shared/VCMetadata';
import getAllConfigurations, {
API_URLS,
DownloadProps,
} from '../../../shared/api';
import {
generateKeys,
isHardwareKeystoreExists,
} from '../../../shared/cryptoutil/cryptoUtil';
import {
getBindingCertificateConstant,
savePrivateKey,
} from '../../../shared/keystore/SecureKeystore';
import {CredentialDownloadResponse, request} from '../../../shared/request';
import {WalletBindingResponse} from '../../../types/VC/vc';
import {verifyCredential} from '../../../shared/vcjs/verifyCredential';
import {getMosipIdentifier} from '../../../shared/commonUtil';
export const VCItemServices = model => {
return {
isUserSignedAlready: () => async () => {
return await Cloud.isSignedInAlready();
},
updatePrivateKey: async context => {
const hasSetPrivateKey: boolean = await savePrivateKey(
context.walletBindingResponse.walletBindingId,
context.privateKey,
);
if (!hasSetPrivateKey) {
throw new Error('Could not store private key in keystore.');
}
return '';
},
loadDownloadLimitConfig: async context => {
var resp = await getAllConfigurations();
const maxLimit: number = resp.vcDownloadMaxRetry;
const vcDownloadPoolInterval: number = resp.vcDownloadPoolInterval;
const downloadProps: DownloadProps = {
maxDownloadLimit: maxLimit,
downloadInterval: vcDownloadPoolInterval,
};
return downloadProps;
},
checkDownloadExpiryLimit: async context => {
if (context.downloadCounter > context.maxDownloadCount) {
throw new Error(
'Download limit expired for request id: ' +
context.vcMetadata.requestId,
);
}
},
addWalletBindingId: async context => {
const response = await request(
API_URLS.walletBinding.method,
API_URLS.walletBinding.buildURL(),
{
requestTime: String(new Date().toISOString()),
request: {
authFactorType: 'WLA',
format: 'jwt',
individualId: VCMetadata.fromVC(context.vcMetadata).id,
transactionId: context.bindingTransactionId,
publicKey: context.publicKey,
challengeList: [
{
authFactorType: 'OTP',
challenge: context.OTP,
format: 'alpha-numeric',
},
],
},
},
);
const certificate = response.response.certificate;
await savePrivateKey(
getBindingCertificateConstant(VCMetadata.fromVC(context.vcMetadata).id),
certificate,
);
const walletResponse: WalletBindingResponse = {
walletBindingId: response.response.encryptedWalletBindingId,
keyId: response.response.keyId,
thumbprint: response.response.thumbprint,
expireDateTime: response.response.expireDateTime,
};
return walletResponse;
},
generateKeyPair: async context => {
if (!isHardwareKeystoreExists) {
return await generateKeys();
}
const isBiometricsEnabled = SecureKeystore.hasBiometricsEnabled();
return SecureKeystore.generateKeyPair(
VCMetadata.fromVC(context.vcMetadata).id,
isBiometricsEnabled,
0,
);
},
requestBindingOTP: async context => {
const vc = VCMetadata.fromVC(context.vcMetadata).isFromOpenId4VCI()
? context.verifiableCredential.credential
: context.verifiableCredential;
const response = await request(
API_URLS.bindingOtp.method,
API_URLS.bindingOtp.buildURL(),
{
requestTime: String(new Date().toISOString()),
request: {
individualId: getMosipIdentifier(vc.credentialSubject),
otpChannels: ['EMAIL', 'PHONE'],
},
},
);
if (response.response == null) {
throw new Error('Could not process request');
}
return response;
},
checkStatus: context => (callback, onReceive) => {
const pollInterval = setInterval(
() => callback(model.events.POLL()),
context.downloadInterval,
);
onReceive(async event => {
if (event.type === 'POLL_STATUS') {
try {
const response = await request(
API_URLS.credentialStatus.method,
API_URLS.credentialStatus.buildURL(context.vcMetadata.requestId),
);
switch (response.response?.statusCode) {
case 'NEW':
break;
case 'ISSUED':
case 'printing':
callback(model.events.DOWNLOAD_READY());
break;
case 'FAILED':
default:
callback(model.events.FAILED());
clearInterval(pollInterval);
break;
}
} catch (error) {
callback(model.events.FAILED());
clearInterval(pollInterval);
}
}
});
return () => clearInterval(pollInterval);
},
downloadCredential: context => (callback, onReceive) => {
const pollInterval = setInterval(
() => callback(model.events.POLL()),
context.downloadInterval,
);
onReceive(async event => {
if (event.type === 'POLL_DOWNLOAD') {
const response: CredentialDownloadResponse = await request(
API_URLS.credentialDownload.method,
API_URLS.credentialDownload.buildURL(),
{
individualId: context.vcMetadata.id,
requestId: context.vcMetadata.requestId,
},
);
callback(
model.events.CREDENTIAL_DOWNLOADED({
credential: response.credential,
verifiableCredential: response.verifiableCredential,
generatedOn: new Date(),
id: context.vcMetadata.id,
idType: context.vcMetadata.idType,
requestId: context.vcMetadata.requestId,
lastVerifiedOn: null,
walletBindingResponse: null,
credentialRegistry: '',
}),
);
}
});
return () => clearInterval(pollInterval);
},
verifyCredential: async context => {
if (context.verifiableCredential) {
const verificationResult = await verifyCredential(
context.verifiableCredential,
);
if (!verificationResult.isVerified) {
throw new Error(verificationResult.errorMessage);
}
}
},
};
};

View File

@@ -1,15 +1,20 @@
import {EventFrom, send, sendParent, StateFrom} from 'xstate';
import {createModel} from 'xstate/lib/model';
import {StoreEvents} from '../store';
import {VC} from '../../types/VC/ExistingMosipVC/vc';
import {AppServices} from '../../shared/GlobalContext';
import {StoreEvents} from '../../store';
import {VC} from '../../../types/VC/vc';
import {AppServices} from '../../../shared/GlobalContext';
import {log, respond} from 'xstate/lib/actions';
import {MY_VCS_STORE_KEY, RECEIVED_VCS_STORE_KEY} from '../../shared/constants';
import {parseMetadatas, VCMetadata} from '../../shared/VCMetadata';
import {ActivityLogEvents} from '../activityLog';
import {ActivityLog} from '../../components/ActivityLogEvent';
import Cloud, {isSignedInResult} from '../../shared/CloudBackupAndRestoreUtils';
import {BackupEvents} from '../backupAndRestore/backup';
import {
MY_VCS_STORE_KEY,
RECEIVED_VCS_STORE_KEY,
} from '../../../shared/constants';
import {parseMetadatas, VCMetadata} from '../../../shared/VCMetadata';
import {ActivityLogEvents} from '../../activityLog';
import {ActivityLog} from '../../../components/ActivityLogEvent';
import Cloud, {
isSignedInResult,
} from '../../../shared/CloudBackupAndRestoreUtils';
import {BackupEvents} from '../../backupAndRestore/backup';
const model = createModel(
{
@@ -17,11 +22,10 @@ const model = createModel(
myVcs: [] as VCMetadata[],
receivedVcs: [] as VCMetadata[],
vcs: {} as Record<string, VC>,
inProgressVcDownloads: new Set<string>(),
areAllVcsDownloaded: false as boolean,
inProgressVcDownloads: new Set<string>(), //VCDownloadInProgress
walletBindingSuccess: false,
tamperedVcs: [] as VCMetadata[],
downloadingFailedVcs: [] as VCMetadata[],
downloadingFailedVcs: [] as VCMetadata[], //VCDownloadFailed
verificationErrorMessage: '' as string,
},
{
@@ -33,22 +37,20 @@ const model = createModel(
VC_ADDED: (vcMetadata: VCMetadata) => ({vcMetadata}),
REMOVE_VC_FROM_CONTEXT: (vcMetadata: VCMetadata) => ({vcMetadata}),
VC_METADATA_UPDATED: (vcMetadata: VCMetadata) => ({vcMetadata}),
VC_DOWNLOADED: (vc: VC) => ({vc}),
VC_DOWNLOADED_FROM_OPENID4VCI: (vc: VC, vcMetadata: VCMetadata) => ({
VC_DOWNLOADED: (vc: VC, vcMetadata?: VCMetadata) => ({
vc,
vcMetadata,
}),
REFRESH_MY_VCS: () => ({}),
REFRESH_MY_VCS_TWO: (vc: VC) => ({vc}),
REFRESH_RECEIVED_VCS: () => ({}),
GET_RECEIVED_VCS: () => ({}),
WALLET_BINDING_SUCCESS: () => ({}),
RESET_WALLET_BINDING_SUCCESS: () => ({}),
ADD_VC_TO_IN_PROGRESS_DOWNLOADS: (requestId: string) => ({requestId}),
REMOVE_VC_FROM_IN_PROGRESS_DOWNLOADS: (vcMetadata: VCMetadata) => ({
vcMetadata,
}),
RESET_ARE_ALL_VCS_DOWNLOADED: () => ({}),
RESET_IN_PROGRESS_VCS_DOWNLOADED: () => ({}),
TAMPERED_VC: (VC: VCMetadata) => ({VC}),
REMOVE_TAMPERED_VCS: () => ({}),
DOWNLOAD_LIMIT_EXPIRED: (vcMetadata: VCMetadata) => ({vcMetadata}),
@@ -174,11 +176,8 @@ export const vcMachine =
REMOVE_VC_FROM_IN_PROGRESS_DOWNLOADS: {
actions: 'removeVcFromInProgressDownlods',
},
RESET_ARE_ALL_VCS_DOWNLOADED: {
actions: 'resetAreAllVcsDownloaded',
},
VC_DOWNLOADED_FROM_OPENID4VCI: {
actions: 'setDownloadedVCFromOpenId4VCI',
RESET_IN_PROGRESS_VCS_DOWNLOADED: {
actions: 'resetInProgressVcsDownloaded',
},
RESET_WALLET_BINDING_SUCCESS: {
actions: 'resetWalletBindingSuccess',
@@ -266,17 +265,11 @@ export const vcMachine =
to: context => context.serviceRefs.backup,
}),
getReceivedVcsResponse: respond(context => ({
type: 'VC_RESPONSE',
response: context.receivedVcs || [],
})),
getVcItemResponse: respond((context, event) => {
const vc =
context.vcs[VCMetadata.fromVC(event.vcMetadata)?.getVcKey()];
return {
type: 'GET_VC_RESPONSE',
vc: vc,
response:
context.vcs[VCMetadata.fromVC(event.vcMetadata)?.getVcKey()],
};
}),
@@ -324,7 +317,8 @@ export const vcMachine =
}),
setDownloadedVc: (context, event) => {
const vcUniqueId = VCMetadata.fromVC(event.vc).getVcKey();
const vcMetaData = event.vcMetadata ? event.vcMetadata : event.vc;
const vcUniqueId = VCMetadata.fromVC(vcMetaData).getVcKey();
context.vcs[vcUniqueId] = event.vc;
},
@@ -350,23 +344,11 @@ export const vcMachine =
return updatedInProgressList;
},
areAllVcsDownloaded: context => {
if (context.inProgressVcDownloads.size == 0) {
return true;
}
return false;
},
}),
resetAreAllVcsDownloaded: model.assign({
areAllVcsDownloaded: () => false,
resetInProgressVcsDownloaded: model.assign({
inProgressVcDownloads: new Set<string>(),
}),
setDownloadedVCFromOpenId4VCI: (context, event) => {
if (event.vc)
context.vcs[VCMetadata.fromVC(event.vcMetadata).getVcKey()] =
event.vc;
},
setUpdatedVcMetadatas: send(
_context => {
@@ -488,10 +470,6 @@ export function selectBindedVcsMetadata(state: State): VCMetadata[] {
});
}
export function selectAreAllVcsDownloaded(state: State) {
return state.context.areAllVcsDownloaded;
}
export function selectInProgressVcDownloads(state: State) {
return state.context.inProgressVcDownloads;
}

View File

@@ -1,3 +1,5 @@
// This file was automatically generated. Edits will be overwritten
export interface Typegen0 {
'@@xstate/typegen': true;
internalEvents: {
@@ -37,12 +39,11 @@ export interface Typegen0 {
| 'REMOVE_VC_FROM_IN_PROGRESS_DOWNLOADS'
| 'VERIFY_VC_FAILED';
removeVcFromMyVcs: 'REMOVE_VC_FROM_CONTEXT';
resetAreAllVcsDownloaded: 'RESET_ARE_ALL_VCS_DOWNLOADED';
resetDownloadFailedVcs: 'STORE_RESPONSE';
resetInProgressVcsDownloaded: 'RESET_IN_PROGRESS_VCS_DOWNLOADED';
resetVerificationErrorMessage: 'RESET_VERIFY_ERROR';
resetWalletBindingSuccess: 'RESET_WALLET_BINDING_SUCCESS';
sendBackupEvent: 'done.invoke.vc.tamperedVCs.triggerAutoBackupForTamperedVcDeletion:invocation[0]';
setDownloadedVCFromOpenId4VCI: 'VC_DOWNLOADED_FROM_OPENID4VCI';
setDownloadedVc: 'VC_DOWNLOADED';
setDownloadingFailedVcs: 'DOWNLOAD_LIMIT_EXPIRED';
setMyVcs: 'STORE_RESPONSE';
@@ -73,6 +74,7 @@ export interface Typegen0 {
| 'ready.receivedVcs.idle'
| 'ready.receivedVcs.refreshing'
| 'tamperedVCs'
| 'tamperedVCs.idle'
| 'tamperedVCs.refreshVcsMetadata'
| 'tamperedVCs.triggerAutoBackupForTamperedVcDeletion'
| {
@@ -85,6 +87,7 @@ export interface Typegen0 {
receivedVcs?: 'idle' | 'refreshing';
};
tamperedVCs?:
| 'idle'
| 'refreshVcsMetadata'
| 'triggerAutoBackupForTamperedVcDeletion';
};

View File

@@ -6,7 +6,10 @@ import {createModel} from 'xstate/lib/model';
import {authMachine, createAuthMachine} from './auth';
import {createSettingsMachine, settingsMachine} from './settings';
import {StoreEvents, storeMachine} from './store';
import {createVcMachine, vcMachine} from './VCItemMachine/vc';
import {
createVcMachine,
vcMachine,
} from './VerifiableCredential/VCMetaMachine/vc';
import {activityLogMachine, createActivityLogMachine} from './activityLog';
import {
createRequestMachine,

View File

@@ -30,6 +30,7 @@ export interface Typegen0 {
requestStoredContext: 'xstate.init';
setBiometrics: 'SETUP_BIOMETRICS';
setContext: 'STORE_RESPONSE';
setIsToggleFromSettings: 'CHANGE_METHOD';
setLanguage: 'SETUP_BIOMETRICS' | 'SETUP_PASSCODE';
setPasscode: 'SETUP_PASSCODE';
setPasscodeSalt: 'done.invoke.auth.introSlider:invocation[0]';
@@ -48,7 +49,7 @@ export interface Typegen0 {
hasPasscodeSet: '';
};
eventsCausingServices: {
downloadFaceSdkModel: 'LOGIN' | 'SETUP_PASSCODE';
downloadFaceSdkModel: 'LOGIN' | 'SETUP_BIOMETRICS' | 'SETUP_PASSCODE';
generatePasscodeSalt: 'SELECT';
};
matchesStates:

View File

@@ -20,7 +20,7 @@ import {
sendErrorEvent,
getErrorEventData,
} from '../../shared/telemetry/TelemetryUtils';
import {VcEvents} from '../VCItemMachine/vc';
import {VcEvents} from '../VerifiableCredential/VCMetaMachine/vc';
import {NETWORK_REQUEST_FAILED, TECHNICAL_ERROR} from '../../shared/constants';
import NetInfo, {NetInfoState} from '@react-native-community/netinfo';

View File

@@ -12,7 +12,7 @@ import {createModel} from 'xstate/lib/model';
import {DeviceInfo} from '../../../components/DeviceInfoList';
import {getDeviceNameSync} from 'react-native-device-info';
import {StoreEvents} from '../../store';
import {VC} from '../../../types/VC/ExistingMosipVC/vc';
import {VC} from '../../../types/VC/vc';
import {AppServices} from '../../../shared/GlobalContext';
import {
androidVersion,
@@ -20,9 +20,8 @@ import {
RECEIVED_VCS_STORE_KEY,
} from '../../../shared/constants';
import {ActivityLogEvents, ActivityLogType} from '../../activityLog';
import {VcEvents} from '../../VCItemMachine/vc';
import {VcEvents} from '../../VerifiableCredential/VCMetaMachine/vc';
import {subscribe} from '../../../shared/openIdBLE/verifierEventHandler';
import {log} from 'xstate/lib/actions';
import {VerifierDataEvent} from '@mosip/tuvali/src/types/events';
import {BLEError} from '../types';
import Storage from '../../../shared/storage';
@@ -39,7 +38,6 @@ import {
} from '../../../shared/telemetry/TelemetryUtils';
import {TelemetryConstants} from '../../../shared/telemetry/TelemetryConstants';
import {getIdType} from '../../../shared/openId4VCI/Utils';
// import { verifyPresentation } from '../shared/vcjs/verifyPresentation';
const {verifier, EventTypes, VerificationStatus} = tuvali;
@@ -103,11 +101,6 @@ export const requestMachine =
schema: {
context: model.initialContext,
events: {} as EventFrom<typeof model>,
services: {} as {
verifyVp: {
data: VC;
};
},
},
invoke: {
src: 'monitorConnection',
@@ -324,7 +317,6 @@ export const requestMachine =
states: {
idle: {},
verifyingIdentity: {
exit: 'clearShouldVerifyPresence',
on: {
FACE_VALID: {
target: 'accepting',
@@ -352,22 +344,6 @@ export const requestMachine =
},
},
},
verifyingVp: {
invoke: {
src: 'verifyVp',
onDone: [
{
target: 'accepting',
},
],
onError: [
{
target: 'idle',
actions: log('Failed to verify Verifiable Presentation'),
},
],
},
},
accepting: {
initial: 'prependingReceivedVcMetadata',
states: {
@@ -537,15 +513,7 @@ export const requestMachine =
}),
setIncomingVc: assign({
incomingVc: (_context, event) => {
const vp = event.vc.verifiablePresentation;
return vp != null
? {
...event.vc,
verifiableCredential: vp.verifiableCredential[0],
}
: event.vc;
},
incomingVc: (_context, event) => event.vc,
}),
setOpenID4VpUri: assign({
@@ -666,13 +634,6 @@ export const requestMachine =
to: context => context.serviceRefs.vc,
}),
clearShouldVerifyPresence: assign({
incomingVc: context => ({
...context.incomingVc,
shouldVerifyPresence: false,
}),
}),
sendVCReceivingStartEvent: () => {
sendStartEvent(
getStartEventData(TelemetryConstants.FlowType.receiverVcShare),
@@ -887,26 +848,10 @@ export const requestMachine =
return () => subscription.remove();
},
sendVcResponse: (context, _event, meta) => async () => {
sendVcResponse: (_context, _event, meta) => async () => {
verifier.sendVerificationStatus(meta.data.status);
},
verifyVp: context => async () => {
const vp = context.incomingVc.verifiablePresentation;
// TODO
// const challenge = ?
// await verifyPresentation(vp, challenge);
const vc: VC = {
...context.incomingVc,
verifiablePresentation: null,
verifiableCredential: vp.verifiableCredential[0],
};
return Promise.resolve(vc);
},
checkStorageAvailability: () => async () => {
return Promise.resolve(
Storage.isMinimumLimitReached('minStorageRequired'),
@@ -915,15 +860,6 @@ export const requestMachine =
},
guards: {
hasExistingVc: (context, event) => {
const receivedVcs = event.vcMetadatas;
const incomingVcMetadata = VCMetadata.fromVC(context.incomingVc);
return receivedVcs?.some(
vcMetadata =>
vcMetadata.getVcKey() == incomingVcMetadata.getVcKey(),
);
},
isMinimumStorageLimitReached: (_context, event) => Boolean(event.data),
},

View File

@@ -9,11 +9,6 @@ export interface Typegen0 {
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.request.reviewing.verifyingVp:invocation[0]': {
type: 'done.invoke.request.reviewing.verifyingVp:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'xstate.after(DESTROY_TIMEOUT)#request.clearingConnection': {
type: 'xstate.after(DESTROY_TIMEOUT)#request.clearingConnection';
};
@@ -21,7 +16,6 @@ export interface Typegen0 {
type: 'xstate.after(SHARING_TIMEOUT)#request.waitingForVc.inProgress';
};
'xstate.init': {type: 'xstate.init'};
'xstate.stop': {type: 'xstate.stop'};
};
invokeSrcNameMap: {
advertiseDevice: 'done.invoke.request.waitingForConnection:invocation[0]';
@@ -40,7 +34,6 @@ export interface Typegen0 {
| 'done.invoke.request.reviewing.accepted:invocation[0]'
| 'done.invoke.request.reviewing.rejected:invocation[0]'
| 'done.invoke.request.reviewing.savingFailed:invocation[0]';
verifyVp: 'done.invoke.request.reviewing.verifyingVp:invocation[0]';
};
missingImplementations: {
actions: never;
@@ -49,31 +42,20 @@ export interface Typegen0 {
services: never;
};
eventsCausingActions: {
clearShouldVerifyPresence:
| 'ACCEPT'
| 'BLE_ERROR'
| 'CANCEL'
| 'FACE_INVALID'
| 'FACE_VALID'
| 'REJECT'
| 'RESET'
| 'SCREEN_BLUR'
| 'SCREEN_FOCUS'
| 'xstate.stop';
logReceived: 'CANCEL' | 'REJECT' | 'STORE_ERROR' | 'STORE_RESPONSE';
openAppPermission: 'GOTO_SETTINGS';
prependReceivedVcMetadata:
| 'ACCEPT'
| 'DISMISS'
| 'FACE_VALID'
| 'VC_RECEIVED'
| 'done.invoke.request.reviewing.verifyingVp:invocation[0]';
| 'VC_RECEIVED';
registerLoggers:
| 'DISCONNECT'
| 'RESET'
| 'xstate.after(DESTROY_TIMEOUT)#request.clearingConnection';
removeLoggers:
| 'DISCONNECT'
| 'GOTO_HOME'
| 'RESET'
| 'SCREEN_BLUR'
| 'xstate.after(DESTROY_TIMEOUT)#request.clearingConnection'
@@ -118,13 +100,12 @@ export interface Typegen0 {
| 'RESET'
| 'done.invoke.request.checkStorage:invocation[0]';
checkStorageAvailability: 'SCREEN_FOCUS';
disconnect: '' | 'DISMISS' | 'GO_TO_RECEIVED_VC_TAB';
monitorConnection: 'xstate.init';
disconnect: '' | 'DISMISS' | 'GOTO_HOME' | 'GO_TO_RECEIVED_VC_TAB';
monitorConnection: 'GOTO_HOME' | 'xstate.init';
receiveVc: 'CONNECTED';
requestBluetooth: 'BLUETOOTH_STATE_DISABLED';
requestNearByDevicesPermission: 'NEARBY_DISABLED';
sendVcResponse: 'CANCEL' | 'REJECT' | 'STORE_ERROR' | 'STORE_RESPONSE';
verifyVp: never;
};
matchesStates:
| 'bluetoothDenied'
@@ -157,7 +138,6 @@ export interface Typegen0 {
| 'reviewing.savingFailed'
| 'reviewing.savingFailed.idle'
| 'reviewing.verifyingIdentity'
| 'reviewing.verifyingVp'
| 'storageLimitReached'
| 'waitingForConnection'
| 'waitingForVc'
@@ -178,7 +158,6 @@ export interface Typegen0 {
| 'rejected'
| 'savingFailed'
| 'verifyingIdentity'
| 'verifyingVp'
| {
accepting?: 'prependingReceivedVcMetadata' | 'storingVc';
savingFailed?: 'idle';

View File

@@ -1,5 +1,7 @@
import {StateFrom} from 'xstate';
import {requestMachine} from './requestMachine';
import {VCMetadata} from '../../../shared/VCMetadata';
import {getMosipLogo} from '../../../components/VC/common/VCUtils';
type State = StateFrom<typeof requestMachine>;
@@ -7,16 +9,31 @@ export function selectSenderInfo(state: State) {
return state.context.senderInfo;
}
export function selectIncomingVc(state: State) {
return state.context.incomingVc;
export function selectCredential(state: State) {
return new VCMetadata(state.context.incomingVc?.vcMetadata).isFromOpenId4VCI()
? state.context.incomingVc?.verifiableCredential?.credential
: state.context.incomingVc?.verifiableCredential;
}
export function selectSharingProtocol(state: State) {
return state.context.sharingProtocol;
}
export function selectIsIncomingVp(state: State) {
return state.context.incomingVc?.verifiablePresentation != null;
export function selectVerifiableCredentialData(state: State) {
const vcMetadata = new VCMetadata(state.context.incomingVc?.vcMetadata);
return vcMetadata.isFromOpenId4VCI()
? {
vcMetadata: vcMetadata,
face: state.context.incomingVc?.verifiableCredential.credential
.credentialSubject.face,
issuerLogo: state.context.incomingVc?.verifiableCredential?.issuerLogo,
wellKnown: state.context.incomingVc?.verifiableCredential?.wellKnown,
credentialTypes:
state.context.incomingVc?.verifiableCredential?.credentialTypes,
issuer: vcMetadata.issuer,
}
: {
vcMetadata: vcMetadata,
issuer: vcMetadata.issuer,
face: state.context.incomingVc?.credential?.biometrics?.face,
issuerLogo: getMosipLogo(),
};
}
export function selectIsReviewingInIdle(state: State) {

View File

@@ -14,15 +14,15 @@ import {createModel} from 'xstate/lib/model';
import {EmitterSubscription, Linking} from 'react-native';
import {DeviceInfo} from '../../../components/DeviceInfoList';
import {getDeviceNameSync} from 'react-native-device-info';
import {VC, VerifiablePresentation} from '../../../types/VC/ExistingMosipVC/vc';
import {VC} from '../../../types/VC/vc';
import {AppServices} from '../../../shared/GlobalContext';
import {ActivityLogEvents, ActivityLogType} from '../../activityLog';
import {
androidVersion,
FACE_AUTH_CONSENT,
isAndroid,
isIOS,
MY_LOGIN_STORE_KEY,
FACE_AUTH_CONSENT,
} from '../../../shared/constants';
import {subscribe} from '../../../shared/openIdBLE/walletEventHandler';
import {
@@ -39,7 +39,6 @@ import {
requestLocationPermission,
} from '../../../shared/location';
import {CameraCapturedPicture} from 'expo-camera';
import {log} from 'xstate/lib/actions';
import {createQrLoginMachine, qrLoginMachine} from '../../QrLoginMachine';
import {StoreEvents} from '../../store';
import {WalletDataEvent} from '@mosip/tuvali/lib/typescript/types/events';
@@ -70,7 +69,6 @@ const model = createModel(
receiverInfo: {} as DeviceInfo,
selectedVc: {} as VC,
bleError: {} as BLEError,
createdVp: null as VC,
loggers: [] as EmitterSubscription[],
vcName: '',
flowType: VCShareFlowType.SIMPLE_SHARE,
@@ -122,8 +120,6 @@ const model = createModel(
FACE_VALID: () => ({}),
FACE_INVALID: () => ({}),
RETRY_VERIFICATION: () => ({}),
VP_CREATED: (vp: VerifiablePresentation) => ({vp}),
TOGGLE_USER_CONSENT: () => ({}),
RESET: () => ({}),
FACE_VERIFICATION_CONSENT: (isConsentGiven: boolean) => ({
isConsentGiven,
@@ -144,11 +140,6 @@ export const scanMachine =
schema: {
context: model.initialContext,
events: {} as EventFrom<typeof model>,
services: {} as {
createVp: {
data: VC;
};
},
},
invoke: {
src: 'monitorConnection',
@@ -160,7 +151,7 @@ export const scanMachine =
target: '#scan.disconnectDevice',
},
SCREEN_FOCUS: {
target: 'checkStorage',
target: '.checkStorage',
},
BLE_ERROR: {
target: '.handlingBleError',
@@ -206,6 +197,7 @@ export const scanMachine =
},
},
restrictSharingVc: {},
startPermissionCheck: {
on: {
START_PERMISSION_CHECK: [
@@ -516,7 +508,7 @@ export const scanMachine =
},
reviewing: {
initial: 'idle',
entry: ['resetShouldVerifyPresence', send('CHECK_FLOW_TYPE')],
entry: [send('CHECK_FLOW_TYPE')],
on: {
CHECK_FLOW_TYPE: [
{
@@ -534,7 +526,6 @@ export const scanMachine =
},
],
},
exit: ['clearCreatedVp'],
states: {
idle: {},
selectingVc: {
@@ -565,9 +556,6 @@ export const scanMachine =
target: 'cancelling',
actions: 'sendVCShareFlowCancelEndEvent',
},
TOGGLE_USER_CONSENT: {
actions: 'toggleShouldVerifyPresence',
},
},
},
cancelling: {
@@ -707,23 +695,7 @@ export const scanMachine =
],
},
},
creatingVp: {
invoke: {
src: 'createVp',
onDone: [
{
target: 'sendingVc',
actions: 'setCreatedVp',
},
],
onError: [
{
target: 'selectingVc',
actions: log('Could not create Verifiable Presentation'),
},
],
},
},
invalidIdentity: {
on: {
DISMISS: [
@@ -915,12 +887,7 @@ export const scanMachine =
}),
setSelectedVc: assign({
selectedVc: (context, event) => {
return {
...event.vc,
shouldVerifyPresence: context.selectedVc.shouldVerifyPresence,
};
},
selectedVc: (_context, event) => event.vc,
}),
resetSelectedVc: assign({
@@ -935,14 +902,6 @@ export const scanMachine =
flowType: VCShareFlowType.SIMPLE_SHARE,
}),
setCreatedVp: assign({
createdVp: (_context, event) => event.data,
}),
clearCreatedVp: assign({
createdVp: () => null,
}),
registerLoggers: assign({
loggers: () => {
if (__DEV__) {
@@ -989,9 +948,9 @@ export const scanMachine =
const vcMetadata = context.selectedVc?.vcMetadata;
return ActivityLogEvents.LOG_ACTIVITY({
_vcKey: VCMetadata.fromVC(vcMetadata).getVcKey(),
type: context.selectedVc.shouldVerifyPresence
? 'VC_SHARED_WITH_VERIFICATION_CONSENT'
: context.shareLogType,
type: context.shareLogType
? context.shareLogType
: 'VC_SHARED_WITH_VERIFICATION_CONSENT',
id: vcMetadata.id,
idType: getIdType(vcMetadata.issuer),
timestamp: Date.now(),
@@ -1018,25 +977,11 @@ export const scanMachine =
{to: context => context.serviceRefs.activityLog},
),
toggleShouldVerifyPresence: assign({
selectedVc: context => ({
...context.selectedVc,
shouldVerifyPresence: !context.selectedVc.shouldVerifyPresence,
}),
}),
setLinkCode: assign({
linkCode: (_, event) =>
new URL(event.params).searchParams.get('linkCode'),
}),
resetShouldVerifyPresence: assign({
selectedVc: context => ({
...context.selectedVc,
shouldVerifyPresence: false,
}),
}),
storeLoginItem: send(
(_context, event) => {
return StoreEvents.PREPEND(
@@ -1264,11 +1209,6 @@ export const scanMachine =
},
sendVc: context => callback => {
const vp = context.createdVp;
const vc = {
...(vp != null ? vp : context.selectedVc),
};
const statusCallback = (event: WalletDataEvent) => {
if (event.type === EventTypes.onDataSent) {
callback({type: 'VC_SENT'});
@@ -1283,7 +1223,7 @@ export const scanMachine =
};
wallet.sendData(
JSON.stringify({
...vc,
...context.selectedVc,
}),
);
const subscription = subscribe(statusCallback);
@@ -1298,25 +1238,6 @@ export const scanMachine =
}
},
createVp: context => async () => {
// const verifiablePresentation = await createVerifiablePresentation(...);
const verifiablePresentation: VerifiablePresentation = {
'@context': [''],
proof: null,
type: 'VerifiablePresentation',
verifiableCredential: [context.selectedVc.verifiableCredential],
};
const vc: VC = {
...context.selectedVc,
verifiableCredential: null,
verifiablePresentation,
};
return Promise.resolve(vc);
},
checkStorageAvailability: () => async () => {
return Promise.resolve(
Storage.isMinimumLimitReached('minStorageRequiredForAuditEntry'),

View File

@@ -14,16 +14,10 @@ export interface Typegen0 {
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'done.invoke.scan.reviewing.creatingVp:invocation[0]': {
type: 'done.invoke.scan.reviewing.creatingVp:invocation[0]';
data: unknown;
__tip: 'See the XState TS docs to learn how to strongly type this.';
};
'xstate.after(DESTROY_TIMEOUT)#scan.clearingConnection': {
type: 'xstate.after(DESTROY_TIMEOUT)#scan.clearingConnection';
};
'xstate.init': {type: 'xstate.init'};
'xstate.stop': {type: 'xstate.stop'};
};
invokeSrcNameMap: {
checkBluetoothPermission: 'done.invoke.scan.checkBluetoothPermission.checking:invocation[0]';
@@ -34,7 +28,6 @@ export interface Typegen0 {
checkLocationStatus: 'done.invoke.scan.checkingLocationState.checkLocationService:invocation[0]';
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]'
| 'done.invoke.scan.disconnectDevice:invocation[0]'
@@ -53,16 +46,6 @@ export interface Typegen0 {
services: never;
};
eventsCausingActions: {
clearCreatedVp:
| ''
| 'BLE_ERROR'
| 'DISCONNECT'
| 'RESET'
| 'RETRY'
| 'SCREEN_BLUR'
| 'SCREEN_FOCUS'
| 'SELECT_VC'
| 'xstate.stop';
clearUri: 'STORE_RESPONSE';
getFaceAuthConsent:
| 'DISCONNECT'
@@ -77,13 +60,11 @@ export interface Typegen0 {
| 'DISCONNECT'
| 'DISMISS'
| 'SCREEN_BLUR'
| 'SCREEN_FOCUS'
| 'STORE_RESPONSE'
| 'xstate.init';
resetFaceCaptureBannerStatus: 'ACCEPT_REQUEST' | 'CLOSE_BANNER';
resetFlowType: 'DISMISS';
resetSelectedVc: 'DISMISS';
resetShouldVerifyPresence: 'CANCEL' | 'CONNECTED' | 'DISMISS' | 'RETRY';
resetFlowType: 'GOTO_HISTORY';
resetSelectedVc: 'GOTO_HISTORY';
sendBLEConnectionErrorEvent: 'BLE_ERROR';
sendScanData: 'SCAN';
sendVCShareFlowCancelEndEvent: 'CANCEL';
@@ -92,7 +73,6 @@ export interface Typegen0 {
sendVcSharingStartEvent: 'SCAN';
setBleError: 'BLE_ERROR';
setChildRef: 'STORE_RESPONSE';
setCreatedVp: 'done.invoke.scan.reviewing.creatingVp:invocation[0]';
setFlowType: 'SELECT_VC';
setLinkCode: 'SCAN';
setReadyForBluetoothStateCheck: 'BLUETOOTH_PERMISSION_ENABLED';
@@ -106,18 +86,13 @@ export interface Typegen0 {
storeLoginItem: 'done.invoke.QrLogin';
storeShowFaceAuthConsent: 'FACE_VERIFICATION_CONSENT';
storingActivityLog: 'STORE_RESPONSE';
toggleShouldVerifyPresence: 'TOGGLE_USER_CONSENT';
updateFaceCaptureBannerStatus: 'FACE_VALID';
updateShowFaceAuthConsent: 'STORE_RESPONSE';
};
eventsCausingDelays: {
CONNECTION_TIMEOUT: 'SCAN';
DESTROY_TIMEOUT: '' | 'DISMISS' | 'LOCATION_ENABLED' | 'RETRY';
SHARING_TIMEOUT:
| 'ACCEPT_REQUEST'
| 'CHECK_FLOW_TYPE'
| 'FACE_VALID'
| 'done.invoke.scan.reviewing.creatingVp:invocation[0]';
SHARING_TIMEOUT: 'ACCEPT_REQUEST' | 'CHECK_FLOW_TYPE' | 'FACE_VALID';
};
eventsCausingGuards: {
isFlowTypeMiniViewShare: 'CHECK_FLOW_TYPE';
@@ -142,21 +117,12 @@ export interface Typegen0 {
checkLocationStatus: '' | 'LOCATION_REQUEST';
checkNearByDevicesPermission: 'APP_ACTIVE' | 'START_PERMISSION_CHECK';
checkStorageAvailability: 'RESET' | 'SCREEN_FOCUS' | 'SELECT_VC';
createVp: never;
disconnect: '' | 'DISMISS' | 'LOCATION_ENABLED' | 'RETRY' | 'SCREEN_BLUR';
monitorConnection:
| 'DISMISS'
| 'SCREEN_BLUR'
| 'SCREEN_FOCUS'
| 'xstate.init';
monitorConnection: 'DISMISS' | 'SCREEN_BLUR' | 'xstate.init';
requestBluetooth: 'BLUETOOTH_STATE_DISABLED';
requestNearByDevicesPermission: 'NEARBY_DISABLED';
requestToEnableLocationPermission: 'LOCATION_DISABLED';
sendVc:
| 'ACCEPT_REQUEST'
| 'CHECK_FLOW_TYPE'
| 'FACE_VALID'
| 'done.invoke.scan.reviewing.creatingVp:invocation[0]';
sendVc: 'ACCEPT_REQUEST' | 'CHECK_FLOW_TYPE' | 'FACE_VALID';
startConnection: 'SCAN';
};
matchesStates:
@@ -199,7 +165,6 @@ export interface Typegen0 {
| 'reviewing'
| 'reviewing.accepted'
| 'reviewing.cancelling'
| 'reviewing.creatingVp'
| 'reviewing.disconnect'
| 'reviewing.faceVerificationConsent'
| 'reviewing.idle'
@@ -232,7 +197,6 @@ export interface Typegen0 {
reviewing?:
| 'accepted'
| 'cancelling'
| 'creatingVp'
| 'disconnect'
| 'faceVerificationConsent'
| 'idle'

View File

@@ -1,5 +1,7 @@
import {StateFrom} from 'xstate';
import {scanMachine} from './scanMachine';
import {VCMetadata} from '../../../shared/VCMetadata';
import {getMosipLogo} from '../../../components/VC/common/VCUtils';
type State = StateFrom<typeof scanMachine>;
@@ -15,8 +17,31 @@ export function selectVcName(state: State) {
return state.context.vcName;
}
export function selectSelectedVc(state: State) {
return state.context.selectedVc;
export function selectCredential(state: State) {
return new VCMetadata(state.context.selectedVc?.vcMetadata).isFromOpenId4VCI()
? state.context.selectedVc?.verifiableCredential?.credential
: state.context.selectedVc?.verifiableCredential;
}
export function selectVerifiableCredentialData(state: State) {
const vcMetadata = new VCMetadata(state.context.selectedVc?.vcMetadata);
return vcMetadata.isFromOpenId4VCI()
? {
vcMetadata: vcMetadata,
issuer: vcMetadata.issuer,
issuerLogo: state.context.selectedVc?.verifiableCredential?.issuerLogo,
wellKnown: state.context.selectedVc?.verifiableCredential?.wellKnown,
face: state.context.selectedVc?.verifiableCredential?.credential
.credentialSubject?.face,
credentialTypes:
state.context.selectedVc?.verifiableCredential?.credentialTypes,
}
: {
vcMetadata: vcMetadata,
issuer: vcMetadata.issuer,
face: state.context.selectedVc?.credential?.biometrics?.face,
issuerLogo: getMosipLogo(),
};
}
export function selectQrLoginRef(state: State) {

View File

@@ -39,10 +39,7 @@ import {
} from '../shared/telemetry/TelemetryUtils';
import {TelemetryConstants} from '../shared/telemetry/TelemetryConstants';
import {
CredentialWrapper,
VerifiableCredential,
} from '../types/VC/EsignetMosipVC/vc';
import {CredentialWrapper, VerifiableCredential} from '../types/VC/vc';
import {CACHED_API} from '../shared/api';
import {request} from '../shared/request';
import {BiometricCancellationError} from '../shared/error/BiometricCancellationError';
@@ -532,7 +529,7 @@ export const IssuersMachine = model.createMachine(
storeVcsContext: send(
context => {
return {
type: 'VC_DOWNLOADED_FROM_OPENID4VCI',
type: 'VC_DOWNLOADED',
vcMetadata: getVCMetadata(context),
vc: context.credentialWrapper,
};

View File

@@ -125,6 +125,7 @@ export interface Typegen0 {
| 'SELECTED_ISSUER'
| 'TRY_AGAIN'
| 'done.invoke.issuersMachine.performAuthorization:invocation[0]';
setMetadataInCredentialData: 'done.invoke.issuersMachine.verifyingCredential:invocation[0]';
setNoInternet: 'done.invoke.checkInternet';
setOIDCConfigError: 'error.platform.issuersMachine.performAuthorization:invocation[0]';
setPrivateKey: 'done.invoke.issuersMachine.generateKeyPair:invocation[0]';
@@ -132,6 +133,7 @@ export interface Typegen0 {
setSelectedIssuerId: 'SELECTED_ISSUER';
setSelectedIssuers: 'done.invoke.issuersMachine.downloadIssuerConfig:invocation[0]';
setTokenResponse: 'done.invoke.issuersMachine.performAuthorization:invocation[0]';
setVCMetadata: 'done.invoke.issuersMachine.verifyingCredential:invocation[0]';
setVerifiableCredential: 'done.invoke.issuersMachine.downloadCredentials:invocation[0]';
storeKeyPair: 'done.invoke.issuersMachine.generateKeyPair:invocation[0]';
storeVcMetaContext: 'done.invoke.issuersMachine.verifyingCredential:invocation[0]';

View File

@@ -4,15 +4,15 @@ import {AppServices} from '../shared/GlobalContext';
import {
APP_ID_DICTIONARY,
APP_ID_LENGTH,
MIMOTO_BASE_URL,
isIOS,
SETTINGS_STORE_KEY,
COMMON_PROPS_KEY,
ESIGNET_BASE_URL,
isIOS,
MIMOTO_BASE_URL,
SETTINGS_STORE_KEY,
} from '../shared/constants';
import {VCLabel} from '../types/VC/ExistingMosipVC/vc';
import {VCLabel} from '../types/VC/vc';
import {StoreEvents} from './store';
import getAllConfigurations from '../shared/api';
import {COMMON_PROPS_KEY} from '../shared/constants';
import Storage from '../shared/storage';
import ShortUniqueId from 'short-unique-id';
import {__AppId} from '../shared/GlobalVariables';

View File

@@ -26,8 +26,10 @@ export interface Typegen0 {
eventsCausingActions: {
requestStoredContext: 'xstate.init';
resetCredentialRegistryResponse: 'CANCEL' | 'UPDATE_HOST';
resetIsBiometricToggled: 'DISMISS';
setBackupAndRestoreOptionExplored: 'SET_IS_BACKUP_AND_RESTORE_EXPLORED';
setContext: 'STORE_RESPONSE';
setIsBiometricToggled: 'TOGGLE_BIOMETRIC_UNLOCK';
storeContext:
| 'ACCEPT_HARDWARE_SUPPORT_NOT_EXISTS'
| 'SET_IS_BACKUP_AND_RESTORE_EXPLORED'

View File

@@ -10,13 +10,13 @@ import {useHomeScreen} from './HomeScreenController';
import {TabRef} from './HomeScreenMachine';
import {useTranslation} from 'react-i18next';
import {ActorRefFrom} from 'xstate';
import {ExistingMosipVCItemMachine} from '../../machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine';
import LinearGradient from 'react-native-linear-gradient';
import {EsignetMosipVCItemMachine} from '../../machines/VCItemMachine/EsignetMosipVCItem/EsignetMosipVCItemMachine';
import {ErrorMessageOverlay} from '../../components/MessageOverlay';
import {Pressable} from 'react-native';
import testIDProps from '../../shared/commonUtil';
import {BannerNotificationContainer} from '../../components/BannerNotificationContainer';
import {VCItemMachine} from '../../machines/VerifiableCredential/VCItemMachine/VCItemMachine';
import {VerifiableCredential} from '../../types/VC/vc';
export const HomeScreen: React.FC<HomeRouteProps> = props => {
const controller = useHomeScreen(props);
@@ -107,7 +107,6 @@ export const HomeScreen: React.FC<HomeRouteProps> = props => {
export interface HomeScreenTabProps {
isVisible: boolean;
service: TabRef;
vcItemActor:
| ActorRefFrom<typeof ExistingMosipVCItemMachine>
| ActorRefFrom<typeof EsignetMosipVCItemMachine>;
vcItemActor: ActorRefFrom<typeof VCItemMachine>;
vc: VerifiableCredential | Credential;
}

View File

@@ -13,6 +13,7 @@ import {
selectIssuersMachine,
selectIsMinimumStorageLimitReached,
} from './HomeScreenMachine';
import {selectVc} from '../../machines/VerifiableCredential/VCItemMachine/VCItemSelectors';
let homeMachineService;
function useCreateHomeMachineService() {
@@ -31,8 +32,6 @@ export function getHomeMachineService() {
}
export function useHomeScreen(props: HomeRouteProps) {
const {appService} = useContext(GlobalContext);
const vcService = appService.children.get('vc');
const service = useCreateHomeMachineService();
useEffect(() => {
@@ -43,20 +42,17 @@ export function useHomeScreen(props: HomeRouteProps) {
return {
service,
activeTab: useSelector(service, selectActiveTab),
selectedVc: useSelector(service, selectSelectedVc),
vc: useSelector(service, selectVc),
tabRefs: useSelector(service, selectTabRefs),
isViewingVc: useSelector(service, selectViewingVc),
haveTabsLoaded: useSelector(service, selectTabsLoaded),
IssuersService: useSelector(service, selectIssuersMachine),
isMinimumStorageLimitReached: useSelector(
service,
selectIsMinimumStorageLimitReached,
),
DISMISS: () => service.send(HomeScreenEvents.DISMISS()),
GOTO_ISSUERS: () => service.send(HomeScreenEvents.GOTO_ISSUERS()),
DISMISS_MODAL: () => service.send(HomeScreenEvents.DISMISS_MODAL()),

View File

@@ -1,15 +1,14 @@
import {ActorRefFrom, assign, EventFrom, send, spawn, StateFrom} from 'xstate';
import {createModel} from 'xstate/lib/model';
import {ExistingMosipVCItemMachine} from '../../machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine';
import {AppServices} from '../../shared/GlobalContext';
import {createMyVcsTabMachine, MyVcsTabMachine} from './MyVcsTabMachine';
import {
createReceivedVcsTabMachine,
ReceivedVcsTabMachine,
} from './ReceivedVcsTabMachine';
import {EsignetMosipVCItemMachine} from '../../machines/VCItemMachine/EsignetMosipVCItem/EsignetMosipVCItemMachine';
import {IssuersMachine} from '../../machines/issuersMachine';
import Storage from '../../shared/storage';
import {VCItemMachine} from '../../machines/VerifiableCredential/VCItemMachine/VCItemMachine';
const model = createModel(
{
@@ -18,9 +17,7 @@ const model = createModel(
myVcs: {} as ActorRefFrom<typeof MyVcsTabMachine>,
receivedVcs: {} as ActorRefFrom<typeof ReceivedVcsTabMachine>,
},
selectedVc: null as
| ActorRefFrom<typeof ExistingMosipVCItemMachine>
| ActorRefFrom<typeof EsignetMosipVCItemMachine>,
selectedVc: ActorRefFrom<typeof VCItemMachine>,
activeTab: 0,
},
{
@@ -28,11 +25,7 @@ const model = createModel(
SELECT_MY_VCS: () => ({}),
SELECT_RECEIVED_VCS: () => ({}),
SELECT_HISTORY: () => ({}),
VIEW_VC: (
vcItemActor:
| ActorRefFrom<typeof ExistingMosipVCItemMachine>
| ActorRefFrom<typeof EsignetMosipVCItemMachine>,
) => ({
VIEW_VC: (vcItemActor: ActorRefFrom<typeof VCItemMachine>) => ({
vcItemActor,
}),
DISMISS_MODAL: () => ({}),

View File

@@ -9,7 +9,7 @@ import {
} from 'xstate';
import {createModel} from 'xstate/lib/model';
import {BackendResponseError, request} from '../../../shared/request';
import {VcIdType} from '../../../types/VC/ExistingMosipVC/vc';
import {VcIdType} from '../../../types/VC/vc';
import i18n from '../../../i18n';
import {VCMetadata} from '../../../shared/VCMetadata';
import {

View File

@@ -7,7 +7,7 @@ import {ActivityLogText} from '../../../components/ActivityLogText';
import {useKebabPopUp} from '../../../components/KebabPopUpController';
import {VCMetadata} from '../../../shared/VCMetadata';
import {ActorRefFrom} from 'xstate';
import {ExistingMosipVCItemMachine} from '../../../machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine';
import {VCItemMachine} from '../../../machines/VerifiableCredential/VCItemMachine/VCItemMachine';
export const HistoryTab: React.FC<HistoryTabProps> = props => {
const {t} = useTranslation('HistoryTab');
@@ -57,6 +57,6 @@ export const HistoryTab: React.FC<HistoryTabProps> = props => {
};
export interface HistoryTabProps {
service: ActorRefFrom<typeof ExistingMosipVCItemMachine>;
service: ActorRefFrom<typeof VCItemMachine>;
vcMetadata: VCMetadata;
}

View File

@@ -5,16 +5,16 @@ import {ModalProps} from '../../../components/ui/Modal';
import {
AddVcModalEvents,
AddVcModalMachine,
selectIsAcceptingOtpInput,
selectIsInvalid,
selectIsRequestingOtp,
selectOtpError,
selectId,
selectIdError,
selectIdInputRef,
selectIdType,
selectIsAcceptingOtpInput,
selectIsInvalid,
selectIsRequestingOtp,
selectOtpError,
} from './AddVcModalMachine';
import {VcIdType} from '../../../types/VC/ExistingMosipVC/vc';
import {VcIdType} from '../../../types/VC/vc';
import {IndividualId} from '../../../shared/constants';
export function useIdInputModal({service}: IdInputModalProps) {

View File

@@ -6,6 +6,7 @@ import {
import {ActorRefFrom} from 'xstate';
import {ModalProps} from '../../../components/ui/Modal';
import {useSelector} from '@xstate/react';
import {VCItemMachine} from '../../../machines/VerifiableCredential/VCItemMachine/VCItemMachine';
export function useOtpVerificationModal({service}: OtpVerificationModalProps) {
return {
@@ -18,7 +19,7 @@ export function useOtpVerificationModal({service}: OtpVerificationModalProps) {
}
export interface OtpVerificationModalProps extends ModalProps {
service: ActorRefFrom<typeof AddVcModalMachine>;
service: ActorRefFrom<typeof AddVcModalMachine | typeof VCItemMachine>;
onInputDone: (otp: string) => void;
error?: string;
resend?: () => void;

View File

@@ -8,7 +8,7 @@ import {SvgImage} from '../../../components/ui/svg';
import {useKebabPopUp} from '../../../components/KebabPopUpController';
import {VCMetadata} from '../../../shared/VCMetadata';
import {ActorRefFrom} from 'xstate';
import {ExistingMosipVCItemEvents} from '../../../machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine';
import {VCItemEvents} from '../../../machines/VerifiableCredential/VCItemMachine/VCItemMachine';
export const RemoveVcWarningOverlay: React.FC<
RemoveVcWarningOverlayProps
@@ -80,6 +80,6 @@ export const RemoveVcWarningOverlay: React.FC<
interface RemoveVcWarningOverlayProps {
testID: string;
service: ActorRefFrom<typeof ExistingMosipVCItemEvents>;
service: ActorRefFrom<typeof VCItemEvents>;
vcMetadata: VCMetadata;
}

View File

@@ -1,4 +1,4 @@
import React, {useEffect} from 'react';
import React from 'react';
import {Icon} from 'react-native-elements';
import {Theme} from '../../../components/ui/styleUtils';
import {useTranslation} from 'react-i18next';
@@ -7,15 +7,9 @@ import {OtpVerificationModal} from './OtpVerificationModal';
import {MessageOverlay} from '../../../components/MessageOverlay';
import {useKebabPopUp} from '../../../components/KebabPopUpController';
import {ActorRefFrom} from 'xstate';
import {ExistingMosipVCItemMachine} from '../../../machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine';
import {VCMetadata} from '../../../shared/VCMetadata';
import {
getEndEventData,
getErrorEventData,
sendEndEvent,
sendErrorEvent,
} from '../../../shared/telemetry/TelemetryUtils';
import {TelemetryConstants} from '../../../shared/telemetry/TelemetryConstants';
import {VCItemMachine} from '../../../machines/VerifiableCredential/VCItemMachine/VCItemMachine';
export const WalletVerified: React.FC = () => {
return (
@@ -30,29 +24,6 @@ export const WalletVerified: React.FC = () => {
export const WalletBinding: React.FC<WalletBindingProps> = props => {
const controller = useKebabPopUp(props);
useEffect(() => {
let error = controller.walletBindingError;
if (error) {
error = controller.bindingAuthFailedError
? controller.bindingAuthFailedError + '-' + error
: error;
sendErrorEvent(
getErrorEventData(
TelemetryConstants.FlowType.vcActivation,
TelemetryConstants.ErrorId.activationFailed,
error,
),
);
sendEndEvent(
getEndEventData(
TelemetryConstants.FlowType.vcActivation,
TelemetryConstants.EndEventStatus.failure,
),
);
}
}, [controller.walletBindingError]);
const {t} = useTranslation('WalletBinding');
return (
<>
@@ -70,8 +41,8 @@ export const WalletBinding: React.FC<WalletBindingProps> = props => {
onInputDone={controller.INPUT_OTP}
error={controller.otpError}
resend={controller.RESEND_OTP}
phone={controller.phoneNumber}
email={controller.email}
phone={controller.communicationDetails.phoneNumber}
email={controller.communicationDetails.emailId}
flow={TelemetryConstants.FlowType.vcActivationFromKebab}
/>
)}
@@ -83,7 +54,7 @@ export const WalletBinding: React.FC<WalletBindingProps> = props => {
onButtonPress={controller.CANCEL}
/>
<MessageOverlay
isVisible={controller.WalletBindingInProgress}
isVisible={controller.walletBindingInProgress}
title={t('inProgress')}
progress
/>
@@ -93,6 +64,6 @@ export const WalletBinding: React.FC<WalletBindingProps> = props => {
interface WalletBindingProps {
testID?: string;
service: ActorRefFrom<typeof ExistingMosipVCItemMachine>;
service: ActorRefFrom<typeof VCItemMachine>;
vcMetadata: VCMetadata;
}

View File

@@ -132,9 +132,11 @@ export const MyVcsTab: React.FC<HomeScreenTabProps> = props => {
};
useEffect(() => {
if (controller.areAllVcsLoaded) {
const areAllVcsLoaded =
controller.inProgressVcDownloads.size == 0 ? true : false;
if (areAllVcsLoaded) {
controller.RESET_STORE_VC_ITEM_STATUS();
controller.RESET_ARE_ALL_VCS_DOWNLOADED();
controller.RESET_IN_PROGRESS_VCS_DOWNLOADED();
}
if (controller.inProgressVcDownloads?.size > 0) {
controller.SET_STORE_VC_ITEM_STATUS();
@@ -159,11 +161,7 @@ export const MyVcsTab: React.FC<HomeScreenTabProps> = props => {
),
);
}
}, [
controller.areAllVcsLoaded,
controller.inProgressVcDownloads,
controller.isTampered,
]);
}, [controller.inProgressVcDownloads, controller.isTampered]);
let failedVCsList = [];
controller.downloadFailedVcs.forEach(vc => {

View File

@@ -2,57 +2,48 @@ import {useSelector} from '@xstate/react';
import {useContext} from 'react';
import {ActorRefFrom} from 'xstate';
import {
selectDownloadingFailedVcs,
selectInProgressVcDownloads,
selectIsRefreshingMyVcs,
selectIsTampered,
selectMyVcs,
selectMyVcsMetadata,
selectVerificationErrorMessage,
selectWalletBindingSuccess,
VcEvents,
selectAreAllVcsDownloaded,
selectInProgressVcDownloads,
selectIsTampered,
selectDownloadingFailedVcs,
selectMyVcs,
selectVerificationErrorMessage,
} from '../../machines/VCItemMachine/vc';
} from '../../machines/VerifiableCredential/VCMetaMachine/vc';
import {
selectWalletBindingError,
selectShowWalletBindingError,
} from '../../machines/VCItemMachine/commonSelectors';
import {ExistingMosipVCItemMachine} from '../../machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine';
} from '../../machines/VerifiableCredential/VCItemMachine/VCItemSelectors';
import {GlobalContext} from '../../shared/GlobalContext';
import {HomeScreenTabProps} from './HomeScreen';
import {
MyVcsTabEvents,
MyVcsTabMachine,
selectAddVcModal,
selectIsRequestSuccessful,
selectGetVcModal,
selectIsSavingFailedInIdle,
selectIsNetworkOff,
selectIsRequestSuccessful,
selectIsSavingFailedInIdle,
} from './MyVcsTabMachine';
import {
selectShowHardwareKeystoreNotExistsAlert,
SettingsEvents,
} from '../../machines/settings';
import {EsignetMosipVCItemMachine} from '../../machines/VCItemMachine/EsignetMosipVCItem/EsignetMosipVCItemMachine';
import {NavigationProp, useNavigation} from '@react-navigation/native';
import {RootRouteProps} from '../../routes';
type MyVcsTabNavigation = NavigationProp<RootRouteProps>;
import {VCItemMachine} from '../../machines/VerifiableCredential/VCItemMachine/VCItemMachine';
export function useMyVcsTab(props: HomeScreenTabProps) {
const service = props.service as ActorRefFrom<typeof MyVcsTabMachine>;
const {appService} = useContext(GlobalContext);
const vcService = appService.children.get('vc');
const settingsService = appService.children.get('settings');
const navigation = useNavigation<MyVcsTabNavigation>();
const vcService = appService.children.get('vc')!!;
const settingsService = appService.children.get('settings')!!;
return {
service,
AddVcModalService: useSelector(service, selectAddVcModal),
GetVcModalService: useSelector(service, selectGetVcModal),
vcMetadatas: useSelector(vcService, selectMyVcsMetadata),
isRefreshingVcs: useSelector(vcService, selectIsRefreshingMyVcs),
isRequestSuccessful: useSelector(service, selectIsRequestSuccessful),
isSavingFailedInIdle: useSelector(service, selectIsSavingFailedInIdle),
@@ -60,31 +51,27 @@ export function useMyVcsTab(props: HomeScreenTabProps) {
isBindingError: useSelector(service, selectShowWalletBindingError),
isBindingSuccess: useSelector(vcService, selectWalletBindingSuccess),
isNetworkOff: useSelector(service, selectIsNetworkOff),
inProgressVcDownloads: useSelector(vcService, selectInProgressVcDownloads),
isTampered: useSelector(vcService, selectIsTampered),
downloadFailedVcs: useSelector(vcService, selectDownloadingFailedVcs),
vcData: useSelector(vcService, selectMyVcs),
showHardwareKeystoreNotExistsAlert: useSelector(
settingsService,
selectShowHardwareKeystoreNotExistsAlert,
),
areAllVcsLoaded: useSelector(vcService, selectAreAllVcsDownloaded),
inProgressVcDownloads: useSelector(vcService, selectInProgressVcDownloads),
isTampered: useSelector(vcService, selectIsTampered),
downloadFailedVcs: useSelector(vcService, selectDownloadingFailedVcs),
verificationErrorMessage: useSelector(
vcService,
selectVerificationErrorMessage,
),
vcData: useSelector(vcService, selectMyVcs),
SET_STORE_VC_ITEM_STATUS: () =>
service.send(MyVcsTabEvents.SET_STORE_VC_ITEM_STATUS()),
RESET_STORE_VC_ITEM_STATUS: () =>
service.send(MyVcsTabEvents.RESET_STORE_VC_ITEM_STATUS()),
RESET_ARE_ALL_VCS_DOWNLOADED: () =>
vcService.send(VcEvents.RESET_ARE_ALL_VCS_DOWNLOADED()),
RESET_IN_PROGRESS_VCS_DOWNLOADED: () =>
vcService.send(VcEvents.RESET_IN_PROGRESS_VCS_DOWNLOADED()),
DISMISS: () => service.send(MyVcsTabEvents.DISMISS()),
@@ -96,11 +83,7 @@ export function useMyVcsTab(props: HomeScreenTabProps) {
REFRESH: () => vcService.send(VcEvents.REFRESH_MY_VCS()),
VIEW_VC: (
vcRef:
| ActorRefFrom<typeof ExistingMosipVCItemMachine>
| ActorRefFrom<typeof EsignetMosipVCItemMachine>,
) => {
VIEW_VC: (vcRef: ActorRefFrom<typeof VCItemMachine>) => {
return service.send(MyVcsTabEvents.VIEW_VC(vcRef));
},
@@ -111,7 +94,9 @@ export function useMyVcsTab(props: HomeScreenTabProps) {
settingsService.send(SettingsEvents.ACCEPT_HARDWARE_SUPPORT_NOT_EXISTS()),
REMOVE_TAMPERED_VCS: () => vcService?.send(VcEvents.REMOVE_TAMPERED_VCS()),
DELETE_VC: () => vcService?.send(VcEvents.DELETE_VC()),
RESET_VERIFY_ERROR: () => {
vcService?.send(VcEvents.RESET_VERIFY_ERROR());
},

View File

@@ -9,15 +9,14 @@ import {
} from 'xstate';
import {createModel} from 'xstate/lib/model';
import {StoreEvents} from '../../machines/store';
import {VcEvents} from '../../machines/VCItemMachine/vc';
import {ExistingMosipVCItemMachine} from '../../machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine';
import {VcEvents} from '../../machines/VerifiableCredential/VCMetaMachine/vc';
import {AppServices} from '../../shared/GlobalContext';
import {MY_VCS_STORE_KEY} from '../../shared/constants';
import {AddVcModalMachine} from './MyVcs/AddVcModalMachine';
import {GetVcModalMachine} from './MyVcs/GetVcModalMachine';
import {VCMetadata} from '../../shared/VCMetadata';
import {EsignetMosipVCItemMachine} from '../../machines/VCItemMachine/EsignetMosipVCItem/EsignetMosipVCItemMachine';
import NetInfo from '@react-native-community/netinfo';
import {VCItemMachine} from '../../machines/VerifiableCredential/VCItemMachine/VCItemMachine';
const model = createModel(
{
@@ -26,11 +25,7 @@ const model = createModel(
},
{
events: {
VIEW_VC: (
vcItemActor:
| ActorRefFrom<typeof ExistingMosipVCItemMachine>
| ActorRefFrom<typeof EsignetMosipVCItemMachine>,
) => ({
VIEW_VC: (vcItemActor: ActorRefFrom<typeof VCItemMachine>) => ({
vcItemActor,
}),
DISMISS: () => ({}),

View File

@@ -1,12 +1,10 @@
import {useSelector, useInterpret} from '@xstate/react';
import {useInterpret, useSelector} from '@xstate/react';
import {useContext, useRef, useState} from 'react';
import {ActorRefFrom} from 'xstate';
import {
VcEvents,
selectIsRefreshingReceivedVcs,
selectReceivedVcsMetadata,
} from '../../machines/VCItemMachine/vc';
import {ExistingMosipVCItemMachine} from '../../machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine';
} from '../../machines/VerifiableCredential/VCMetaMachine/vc';
import {GlobalContext} from '../../shared/GlobalContext';
import {
ReceivedVcsTabEvents,
@@ -20,6 +18,8 @@ import {
selectTabRefs,
selectViewingVc,
} from './HomeScreenMachine';
import {VCItemMachine} from '../../machines/VerifiableCredential/VCItemMachine/VCItemMachine';
import {selectVc} from '../../machines/VerifiableCredential/VCItemMachine/VCItemSelectors';
export function useReceivedVcsTab() {
const [isVisible, setIsVisible] = useState(false);
@@ -37,6 +37,8 @@ export function useReceivedVcsTab() {
const selectedVc = useSelector(service, selectSelectedVc);
const vc = useSelector(service, selectVc);
const isViewingVc = useSelector(service, selectViewingVc);
const ReceivedVcsService = tabRefs.receivedVcs as ActorRefFrom<
@@ -54,11 +56,12 @@ export function useReceivedVcsTab() {
TOGGLE_RECEIVED_CARDS: () => setIsVisible(!isVisible),
VIEW_VC: (vcRef: ActorRefFrom<typeof ExistingMosipVCItemMachine>) => {
VIEW_VC: (vcRef: ActorRefFrom<typeof VCItemMachine>) => {
return myVcservice.send(MyVcsTabEvents.VIEW_VC(vcRef));
},
isViewingVc,
selectedVc,
vc,
activeTab: 1,
DISMISS_MODAL: () => service.send(HomeScreenEvents.DISMISS_MODAL()),
REFRESH: () => ReceivedVcsService.send(ReceivedVcsTabEvents.REFRESH()),

View File

@@ -1,7 +1,7 @@
import {ActorRefFrom, EventFrom, sendParent} from 'xstate';
import {createModel} from 'xstate/lib/model';
import {ExistingMosipVCItemMachine} from '../../machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine';
import {AppServices} from '../../shared/GlobalContext';
import {VCItemMachine} from '../../machines/VerifiableCredential/VCItemMachine/VCItemMachine';
const model = createModel(
{
@@ -10,9 +10,7 @@ const model = createModel(
},
{
events: {
VIEW_VC: (
vcItemActor: ActorRefFrom<typeof ExistingMosipVCItemMachine>,
) => ({
VIEW_VC: (vcItemActor: ActorRefFrom<typeof VCItemMachine>) => ({
vcItemActor,
}),
REFRESH: () => ({}),

View File

@@ -1,5 +1,5 @@
import React, {useEffect} from 'react';
import {Column, Row} from '../../components/ui';
import React from 'react';
import {Row} from '../../components/ui';
import {Modal} from '../../components/ui/Modal';
import {MessageOverlay} from '../../components/MessageOverlay';
import {ToastItem} from '../../components/ui/ToastItem';
@@ -8,12 +8,6 @@ import {useTranslation} from 'react-i18next';
import {OtpVerificationModal} from './MyVcs/OtpVerificationModal';
import {BindingVcWarningOverlay} from './MyVcs/BindingVcWarningOverlay';
import {VcDetailsContainer} from '../../components/VC/VcDetailsContainer';
import {
getEndEventData,
getErrorEventData,
sendEndEvent,
sendErrorEvent,
} from '../../shared/telemetry/TelemetryUtils';
import {TelemetryConstants} from '../../shared/telemetry/TelemetryConstants';
import {BannerNotificationContainer} from '../../components/BannerNotificationContainer';
import {Icon} from 'react-native-elements';
@@ -23,7 +17,6 @@ import {HelpScreen} from '../../components/HelpScreen';
import {Pressable} from 'react-native';
import {KebabPopUp} from '../../components/KebabPopUp';
import {SvgImage} from '../../components/ui/svg';
import {faceImageSource} from '../../components/VcItemContainerProfileImage';
import {VCMetadata} from '../../shared/VCMetadata';
import {WalletBinding} from './MyVcs/WalletBinding';
import {RemoveVcWarningOverlay} from './MyVcs/RemoveVcWarningOverlay';
@@ -32,42 +25,7 @@ import {HistoryTab} from './MyVcs/HistoryTab';
export const ViewVcModal: React.FC<ViewVcModalProps> = props => {
const {t} = useTranslation('ViewVcModal');
const controller = useViewVcModal(props);
useEffect(() => {
let error = controller.walletBindingError;
if (error) {
error = controller.bindingAuthFailedError
? controller.bindingAuthFailedError + '-' + error
: error;
sendErrorEvent(
getErrorEventData(
TelemetryConstants.FlowType.vcActivation,
TelemetryConstants.ErrorId.activationFailed,
error,
),
);
sendEndEvent(
getEndEventData(
TelemetryConstants.FlowType.vcActivation,
TelemetryConstants.EndEventStatus.failure,
),
);
}
}, [controller.walletBindingError]);
let selectedVcContext = props.vcItemActor.getSnapshot()?.context;
const credential = new VCMetadata(
selectedVcContext?.vcMetadata,
).isFromOpenId4VCI()
? selectedVcContext?.verifiableCredential?.credential
: selectedVcContext?.verifiableCredential;
const getVcProfileImage = faceImageSource({
vcMetadata: new VCMetadata(selectedVcContext?.vcMetadata),
context: props.vcItemActor.getSnapshot()?.context,
credential: credential,
});
const profileImage = controller.verifiableCredentialData.face;
const headerRight = flow => {
return flow === 'downloadedVc' ? (
@@ -91,7 +49,7 @@ export const ViewVcModal: React.FC<ViewVcModalProps> = props => {
<KebabPopUp
icon={SvgImage.kebabIcon()}
iconColor={null}
vcMetadata={VCMetadata.fromVC(controller.vc.vcMetadata)}
vcMetadata={controller.verifiableCredentialData.vcMetadata}
iconName="dots-three-horizontal"
iconType="entypo"
isVisible={
@@ -100,7 +58,7 @@ export const ViewVcModal: React.FC<ViewVcModalProps> = props => {
}
onDismiss={() => props.vcItemActor.send('DISMISS')}
service={props.vcItemActor}
vcHasImage={getVcProfileImage !== undefined}
vcHasImage={profileImage !== undefined}
/>
</Pressable>
</Row>
@@ -117,11 +75,12 @@ export const ViewVcModal: React.FC<ViewVcModalProps> = props => {
headerElevation={2}>
<BannerNotificationContainer />
<VcDetailsContainer
vc={controller.vc}
credential={controller.credential}
verifiableCredentialData={controller.verifiableCredentialData}
onBinding={controller.addtoWallet}
isBindingPending={controller.isWalletBindingPending}
walletBindingResponse={controller.walletBindingResponse}
activeTab={props.activeTab}
vcHasImage={getVcProfileImage !== undefined}
vcHasImage={profileImage !== undefined}
/>
{controller.isAcceptingBindingOtp && (
@@ -132,8 +91,8 @@ export const ViewVcModal: React.FC<ViewVcModalProps> = props => {
onInputDone={controller.inputOtp}
error={controller.otpError}
resend={controller.RESEND_OTP}
phone={controller.isPhoneNumber}
email={controller.isEmail}
phone={controller.isCommunicationDetails.phoneNumber}
email={controller.isCommunicationDetails.emailId}
flow={TelemetryConstants.FlowType.vcActivation}
/>
)}
@@ -163,18 +122,20 @@ export const ViewVcModal: React.FC<ViewVcModalProps> = props => {
<WalletBinding
service={props.vcItemActor}
vcMetadata={controller.vc.vcMetadata}
vcMetadata={controller.verifiableCredentialData.vcMetadata}
/>
<RemoveVcWarningOverlay
testID="removeVcWarningOverlay"
service={props.vcItemActor}
vcMetadata={controller.vc.vcMetadata}
vcMetadata={controller.verifiableCredentialData.vcMetadata}
/>
<HistoryTab
service={props.vcItemActor}
vcMetadata={VCMetadata.fromVC(controller.vc.vcMetadata)}
vcMetadata={VCMetadata.fromVC(
controller.verifiableCredentialData.vcMetadata,
)}
/>
</Modal>
);

View File

@@ -1,32 +1,31 @@
import {useMachine, useSelector} from '@xstate/react';
import {useContext, useEffect, useState} from 'react';
import {ActorRefFrom} from 'xstate';
import {useTranslation} from 'react-i18next';
import NetInfo from '@react-native-community/netinfo';
import {ModalProps} from '../../components/ui/Modal';
import {GlobalContext} from '../../shared/GlobalContext';
import {
selectOtpError,
selectWalletBindingError,
selectEmptyWalletBindingId,
selectShowWalletBindingError,
selectWalletBindingSuccess,
selectBindingAuthFailedError,
selectAcceptingBindingOtp,
selectWalletBindingInProgress,
selectBindingAuthFailedError,
selectBindingWarning,
selectIsPhoneNumber,
selectIsEmail,
} from '../../machines/VCItemMachine/commonSelectors';
import {
selectIsAcceptingOtpInput,
selectIsCommunicationDetails,
selectOtpError,
selectShowWalletBindingError,
selectVc,
ExistingMosipVCItemEvents,
ExistingMosipVCItemMachine,
selectRequestBindingOtp,
} from '../../machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine';
selectCredential,
selectVerifiableCredentialData,
selectWalletBindingError,
selectWalletBindingInProgress,
selectWalletBindingResponse,
selectWalletBindingSuccess,
} from '../../machines/VerifiableCredential/VCItemMachine/VCItemSelectors';
import {selectPasscode} from '../../machines/auth';
import {biometricsMachine, selectIsSuccess} from '../../machines/biometrics';
import {
VCItemEvents,
VCItemMachine,
} from '../../machines/VerifiableCredential/VCItemMachine/VCItemMachine';
import {selectIsAcceptingOtpInput} from './MyVcs/AddVcModalMachine';
export function useViewVcModal({vcItemActor, isVisible}: ViewVcModalProps) {
const [toastVisible, setToastVisible] = useState(false);
@@ -62,9 +61,9 @@ export function useViewVcModal({vcItemActor, isVisible}: ViewVcModalProps) {
const netInfoFetch = (otp: string) => {
NetInfo.fetch().then(state => {
if (state.isConnected) {
vcItemActor.send(ExistingMosipVCItemEvents.INPUT_OTP(otp));
vcItemActor.send(VCItemEvents.INPUT_OTP(otp));
} else {
vcItemActor.send(ExistingMosipVCItemEvents.DISMISS());
vcItemActor.send(VCItemEvents.DISMISS());
showToast('Request network failed');
}
});
@@ -77,27 +76,31 @@ export function useViewVcModal({vcItemActor, isVisible}: ViewVcModalProps) {
}, [reAuthenticating, isSuccessBio, otError, vc]);
useEffect(() => {
vcItemActor.send(ExistingMosipVCItemEvents.REFRESH());
vcItemActor.send(VCItemEvents.REFRESH());
}, [isVisible]);
return {
error,
message,
toastVisible,
vc,
credential: useSelector(vcItemActor, selectCredential),
verifiableCredentialData: useSelector(
vcItemActor,
selectVerifiableCredentialData,
),
otpError: useSelector(vcItemActor, selectOtpError),
bindingAuthFailedError: useSelector(
vcItemActor,
selectBindingAuthFailedError,
),
reAuthenticating,
isAcceptingOtpInput: useSelector(vcItemActor, selectIsAcceptingOtpInput),
storedPasscode: useSelector(authService, selectPasscode),
isBindingOtp: useSelector(vcItemActor, selectRequestBindingOtp),
isAcceptingBindingOtp: useSelector(vcItemActor, selectAcceptingBindingOtp),
walletBindingError: useSelector(vcItemActor, selectWalletBindingError),
isWalletBindingPending: useSelector(
walletBindingResponse: useSelector(
vcItemActor,
selectEmptyWalletBindingId,
selectWalletBindingResponse,
),
walletBindingError: useSelector(vcItemActor, selectWalletBindingError),
isWalletBindingInProgress: useSelector(
vcItemActor,
selectWalletBindingInProgress,
@@ -105,31 +108,29 @@ export function useViewVcModal({vcItemActor, isVisible}: ViewVcModalProps) {
isBindingError: useSelector(vcItemActor, selectShowWalletBindingError),
isBindingSuccess: useSelector(vcItemActor, selectWalletBindingSuccess),
isBindingWarning: useSelector(vcItemActor, selectBindingWarning),
isPhoneNumber: useSelector(vcItemActor, selectIsPhoneNumber),
isEmail: useSelector(vcItemActor, selectIsEmail),
isCommunicationDetails: useSelector(
vcItemActor,
selectIsCommunicationDetails,
),
setReAuthenticating,
onError,
addtoWallet: () => {
vcItemActor.send(ExistingMosipVCItemEvents.ADD_WALLET_BINDING_ID());
vcItemActor.send(VCItemEvents.ADD_WALLET_BINDING_ID());
},
inputOtp: (otp: string) => {
netInfoFetch(otp);
},
ADD_WALLET: () =>
vcItemActor.send(ExistingMosipVCItemEvents.ADD_WALLET_BINDING_ID()),
onSuccess,
DISMISS: () => vcItemActor.send(ExistingMosipVCItemEvents.DISMISS()),
INPUT_OTP: (otp: string) =>
vcItemActor.send(ExistingMosipVCItemEvents.INPUT_OTP(otp)),
RESEND_OTP: () => vcItemActor.send(ExistingMosipVCItemEvents.RESEND_OTP()),
CANCEL: () => vcItemActor.send(ExistingMosipVCItemEvents.CANCEL()),
CONFIRM: () => vcItemActor.send(ExistingMosipVCItemEvents.CONFIRM()),
DISMISS: () => vcItemActor.send(VCItemEvents.DISMISS()),
INPUT_OTP: (otp: string) => vcItemActor.send(VCItemEvents.INPUT_OTP(otp)),
RESEND_OTP: () => vcItemActor.send(VCItemEvents.RESEND_OTP()),
CANCEL: () => vcItemActor.send(VCItemEvents.CANCEL()),
CONFIRM: () => vcItemActor.send(VCItemEvents.CONFIRM()),
};
}
export interface ViewVcModalProps extends ModalProps {
vcItemActor: ActorRefFrom<typeof ExistingMosipVCItemMachine>;
vcItemActor: ActorRefFrom<typeof VCItemMachine>;
onDismiss: () => void;
activeTab: Number;
flow: string;

View File

@@ -12,7 +12,7 @@ import {Icon} from 'react-native-elements';
import {View} from 'react-native';
import {FaceVerificationAlertOverlay} from '../Scan/FaceVerificationAlertOverlay';
import {Error} from '../../components/ui/Error';
import { SvgImage } from '../../components/ui/svg';
import {SvgImage} from '../../components/ui/svg';
export const QrLogin: React.FC<QrLoginProps> = props => {
const controller = useQrLogin(props);
@@ -50,11 +50,15 @@ export const QrLogin: React.FC<QrLoginProps> = props => {
/>
<VerifyIdentityOverlay
vc={controller.selectedVc}
credential={controller.selectCredential}
verifiableCredentialData={controller.verifiableCredentialData}
isVerifyingIdentity={controller.isVerifyingIdentity}
onCancel={controller.CANCEL}
onFaceValid={controller.FACE_VALID}
onFaceInvalid={controller.FACE_INVALID}
isInvalidIdentity={controller.isInvalidIdentity}
onDismiss={controller.DISMISS}
onRetryVerification={controller.RETRY_VERIFICATION}
/>
<FaceVerificationAlertOverlay

View File

@@ -5,11 +5,14 @@ import {
QrLoginEvents,
selectClientName,
selectErrorMessage,
selectEssentialClaims,
selectIsFaceVerificationConsent,
selectIsInvalidIdentity,
selectIsisVerifyingIdentity,
selectIsLinkTransaction,
selectIsloadMyVcs,
selectIsRequestConsent,
selectIsSendingAuthenticate,
selectIsSendingConsent,
selectIsSharing,
selectIsShowError,
@@ -19,20 +22,17 @@ import {
selectLinkTransactionResponse,
selectLogoUrl,
selectDomainName,
selectSelectedVc,
selectVoluntaryClaims,
selectIsSendingAuthenticate,
selectEssentialClaims,
selectIsFaceVerificationConsent,
selectCredential,
selectVerifiableCredentialData,
} from '../../machines/QrLoginMachine';
import {selectBindedVcsMetadata} from '../../machines/VCItemMachine/vc';
import {selectBindedVcsMetadata} from '../../machines/VerifiableCredential/VCMetaMachine/vc';
import {GlobalContext} from '../../shared/GlobalContext';
import {VC} from '../../types/VC/ExistingMosipVC/vc';
import {QrLoginProps} from './QrLogin';
import {EsignetMosipVCItemMachine} from '../../machines/VCItemMachine/EsignetMosipVCItem/EsignetMosipVCItemMachine';
import {NavigationProp, useNavigation} from '@react-navigation/native';
import {RootRouteProps} from '../../routes';
import {BOTTOM_TAB_ROUTES} from '../../routes/routesConstants';
import {VCItemMachine} from '../../machines/VerifiableCredential/VCItemMachine/VCItemMachine';
type MyVcsTabNavigation = NavigationProp<RootRouteProps>;
@@ -40,50 +40,29 @@ export function useQrLogin({service}: QrLoginProps) {
const {appService} = useContext(GlobalContext);
const navigation = useNavigation<MyVcsTabNavigation>();
const vcService = appService.children.get('vc');
const vcService = appService.children.get('vc')!!;
const [selectedIndex, setSelectedIndex] = useState<number>(null);
const SELECT_VC = (vc: VC) => service.send(QrLoginEvents.SELECT_VC(vc));
const SELECT_CONSENT = (value: boolean, claim: string) => {
service.send(QrLoginEvents.TOGGLE_CONSENT_CLAIM(value, claim));
};
const isShare = useSelector(service, selectIsSharing);
return {
SELECT_VC_ITEM:
(index: number) =>
(
vcRef: ActorRefFrom<
typeof EsignetMosipVCItemMachine | typeof EsignetMosipVCItemMachine
>,
) => {
setSelectedIndex(index);
const vcData = vcRef.getSnapshot().context;
SELECT_VC(vcData);
},
isFaceVerificationConsent: useSelector(service, selectIsFaceVerificationConsent),
shareableVcsMetadata: useSelector(vcService, selectBindedVcsMetadata),
selectedVc: useSelector(service, selectSelectedVc),
isFaceVerificationConsent: useSelector(
service,
selectIsFaceVerificationConsent,
),
linkTransactionResponse: useSelector(
service,
selectLinkTransactionResponse,
),
shareableVcsMetadata: useSelector(vcService, selectBindedVcsMetadata),
verifiableCredentialData: useSelector(
service,
selectVerifiableCredentialData,
),
domainName: useSelector(service, selectDomainName),
logoUrl: useSelector(service, selectLogoUrl),
essentialClaims: useSelector(service, selectEssentialClaims),
voluntaryClaims: useSelector(service, selectVoluntaryClaims),
clientName: useSelector(service, selectClientName),
error: useSelector(service, selectErrorMessage),
isShare,
selectedIndex,
SELECT_VC,
SELECT_CONSENT,
FACE_VERIFICATION_CONSENT: (isConsentGiven: boolean) => service.send(QrLoginEvents.FACE_VERIFICATION_CONSENT(isConsentGiven)),
selectCredential: useSelector(service, selectCredential),
isWaitingForData: useSelector(service, selectIsWaitingForData),
isShowingVcList: useSelector(service, selectIsShowingVcList),
isLinkTransaction: useSelector(service, selectIsLinkTransaction),
@@ -95,14 +74,25 @@ export function useQrLogin({service}: QrLoginProps) {
isVerifyingIdentity: useSelector(service, selectIsisVerifyingIdentity),
isInvalidIdentity: useSelector(service, selectIsInvalidIdentity),
isVerifyingSuccesful: useSelector(service, selectIsVerifyingSuccesful),
isShare: useSelector(service, selectIsSharing),
selectedIndex,
SELECT_CONSENT: (value: boolean, claim: string) => {
service.send(QrLoginEvents.TOGGLE_CONSENT_CLAIM(value, claim));
},
SELECT_VC_ITEM:
(index: number) => (vcRef: ActorRefFrom<typeof VCItemMachine>) => {
setSelectedIndex(index);
const vcData = vcRef.getSnapshot().context;
service.send(QrLoginEvents.SELECT_VC(vcData));
},
FACE_VERIFICATION_CONSENT: (isConsentGiven: boolean) =>
service.send(QrLoginEvents.FACE_VERIFICATION_CONSENT(isConsentGiven)),
DISMISS: () => service.send(QrLoginEvents.DISMISS()),
SCANNING_DONE: (qrCode: string) =>
service.send(QrLoginEvents.SCANNING_DONE(qrCode)),
CONFIRM: () => service.send(QrLoginEvents.CONFIRM()),
VERIFY: () => service.send(QrLoginEvents.VERIFY()),
CANCEL: () => service.send(QrLoginEvents.CANCEL()),
FACE_VALID: () => service.send(QrLoginEvents.FACE_VALID()),
FACE_INVALID: () => service.send(QrLoginEvents.FACE_INVALID()),
RETRY_VERIFICATION: () => service.send(QrLoginEvents.RETRY_VERIFICATION()),

View File

@@ -1,14 +1,11 @@
import React from 'react';
import {useTranslation} from 'react-i18next';
import {DeviceInfoList} from '../../components/DeviceInfoList';
import {Button, Column, Row, Text} from '../../components/ui';
import {Button, Column, Text} from '../../components/ui';
import {Theme} from '../../components/ui/styleUtils';
import {useReceiveVcScreen} from './ReceiveVcScreenController';
import {VerifyIdentityOverlay} from '../VerifyIdentityOverlay';
import {
ErrorMessageOverlay,
MessageOverlay,
} from '../../components/MessageOverlay';
import {MessageOverlay} from '../../components/MessageOverlay';
import {useOverlayVisibleAfterTimeout} from '../../shared/hooks/useOverlayVisibleAfterTimeout';
import {VcDetailsContainer} from '../../components/VC/VcDetailsContainer';
import {SharingStatusModal} from '../Scan/SharingStatusModal';
@@ -34,7 +31,8 @@ export const ReceiveVcScreen: React.FC = () => {
{t('header')}
</Text>
<VcDetailsContainer
vc={controller.incomingVc}
credential={controller.credential}
verifiableCredentialData={controller.verifiableCredentialData}
isBindingPending={false}
activeTab={1}
/>
@@ -50,7 +48,8 @@ export const ReceiveVcScreen: React.FC = () => {
)}
<VerifyIdentityOverlay
vc={controller.incomingVc}
credential={controller.selectCredential}
verifiableCredentialData={controller.verifiableCredentialData}
isVerifyingIdentity={controller.isVerifyingIdentity}
onCancel={controller.CANCEL}
onFaceValid={controller.FACE_VALID}

View File

@@ -2,13 +2,13 @@ import {useSelector} from '@xstate/react';
import {useContext} from 'react';
import {GlobalContext} from '../../shared/GlobalContext';
import {
selectIncomingVc,
selectCredential,
selectIsAccepting,
selectIsDisplayingIncomingVC,
selectIsIncomingVp,
selectIsReviewingInIdle,
selectIsSavingFailedInIdle,
selectSenderInfo,
selectVerifiableCredentialData,
} from '../../machines/bleShare/request/selectors';
import {
selectIsInvalidIdentity,
@@ -18,13 +18,15 @@ import {RequestEvents} from '../../machines/bleShare/request/requestMachine';
export function useReceiveVcScreen() {
const {appService} = useContext(GlobalContext);
const requestService = appService.children.get('request');
const requestService = appService.children.get('request')!!;
return {
senderInfo: useSelector(requestService, selectSenderInfo),
incomingVc: useSelector(requestService, selectIncomingVc),
isIncomingVp: useSelector(requestService, selectIsIncomingVp),
credential: useSelector(requestService, selectCredential),
verifiableCredentialData: useSelector(
requestService,
selectVerifiableCredentialData,
),
isReviewingInIdle: useSelector(requestService, selectIsReviewingInIdle),
isAccepting: useSelector(requestService, selectIsAccepting),
isDisplayingIncomingVC: useSelector(

View File

@@ -11,7 +11,6 @@ import {
selectIsWaitingForVcTimeout,
selectOpenId4VpUri,
selectSenderInfo,
selectSharingProtocol,
} from '../../machines/bleShare/request/selectors';
import {
selectIsBluetoothDenied,
@@ -81,8 +80,6 @@ export function useRequestScreen() {
statusTitle,
statusMessage,
statusHint,
sharingProtocol: useSelector(requestService, selectSharingProtocol),
isWaitingForConnection,
isWaitingForVc,
isWaitingForVcTimeout,

View File

@@ -51,7 +51,8 @@ export const ScanLayout: React.FC = () => {
return (
<React.Fragment>
<VerifyIdentityOverlay
vc={controller.selectedVc}
credential={controller.credential}
verifiableCredentialData={controller.verifiableCredentialData}
isVerifyingIdentity={controller.isVerifyingIdentity}
onCancel={controller.CANCEL}
onFaceValid={controller.FACE_VALID}

View File

@@ -21,8 +21,9 @@ import {
selectIsSent,
selectIsDone,
selectFlowType,
selectSelectedVc,
selectIsFaceIdentityVerified,
selectCredential,
selectVerifiableCredentialData,
} from '../../machines/bleShare/scan/selectors';
import {
selectBleError,
@@ -56,7 +57,7 @@ const changeTabBarVisible = (visible: string) => {
export function useScanLayout() {
const {t} = useTranslation('ScanScreen');
const {appService} = useContext(GlobalContext);
const scanService = appService.children.get('scan');
const scanService = appService.children.get('scan')!!;
const navigation = useNavigation<ScanLayoutNavigation>();
const isLocationDisabled = useSelector(scanService, selectIsLocationDisabled);
@@ -68,8 +69,12 @@ export function useScanLayout() {
scanService,
selectIsVerifyingIdentity,
);
const selectedVc = useSelector(scanService, selectSelectedVc);
const bleError = useSelector(scanService, selectBleError);
const credential = useSelector(scanService, selectCredential);
const verifiableCredentialData = useSelector(
scanService,
selectVerifiableCredentialData,
);
const locationError = {message: '', button: ''};
@@ -282,6 +287,8 @@ export function useScanLayout() {
]);
return {
credential,
verifiableCredentialData,
isInvalid,
isReviewing,
isDone,
@@ -302,7 +309,6 @@ export function useScanLayout() {
flowType,
isVerifyingIdentity,
isInvalidIdentity,
selectedVc,
FACE_INVALID,
FACE_VALID,
RETRY_VERIFICATION,

View File

@@ -1,7 +1,7 @@
import {useSelector} from '@xstate/react';
import {useContext} from 'react';
import {useTranslation} from 'react-i18next';
import {selectShareableVcsMetadata} from '../../machines/VCItemMachine/vc';
import {selectShareableVcsMetadata} from '../../machines/VerifiableCredential/VCMetaMachine/vc';
import {GlobalContext} from '../../shared/GlobalContext';
import {
selectIsLocationDenied,

View File

@@ -1,13 +1,13 @@
import {useState} from 'react';
import {ActorRefFrom} from 'xstate';
import {ExistingMosipVCItemMachine} from '../../machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine';
import {VC} from '../../types/VC/ExistingMosipVC/vc';
import {VC} from '../../types/VC/vc';
import {VCMetadata} from '../../shared/VCMetadata';
import {VCItemMachine} from '../../machines/VerifiableCredential/VCItemMachine/VCItemMachine';
export function useSelectVcOverlay(props: SelectVcOverlayProps) {
const [selectedIndex, setSelectedIndex] = useState<number>(null);
const [selectedVcRef, setSelectedVcRef] =
useState<ActorRefFrom<typeof ExistingMosipVCItemMachine>>(null);
useState<ActorRefFrom<typeof VCItemMachine>>(null);
return {
selectVcItem,
@@ -25,7 +25,7 @@ export function useSelectVcOverlay(props: SelectVcOverlayProps) {
};
function selectVcItem(index: number) {
return (vcRef: ActorRefFrom<typeof ExistingMosipVCItemMachine>) => {
return (vcRef: ActorRefFrom<typeof VCItemMachine>) => {
setSelectedIndex(index);
setSelectedVcRef(vcRef);
};

View File

@@ -1,25 +1,24 @@
import React, {useContext, useEffect, useRef} from 'react';
import {useTranslation} from 'react-i18next';
import {Button, Column, Row, Text} from '../../components/ui';
import {Button, Column, Text} from '../../components/ui';
import {Theme} from '../../components/ui/styleUtils';
import {useSendVcScreen} from './SendVcScreenController';
import {VerifyIdentityOverlay} from '../VerifyIdentityOverlay';
import {BackHandler} from 'react-native';
import {useInterpret} from '@xstate/react';
import {createExistingMosipVCItemMachine} from '../../machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine';
import {GlobalContext} from '../../shared/GlobalContext';
import {useFocusEffect} from '@react-navigation/native';
import {VcItemContainer} from '../../components/VC/VcItemContainer';
import {VCMetadata} from '../../shared/VCMetadata';
import {createEsignetMosipVCItemMachine} from '../../machines/VCItemMachine/EsignetMosipVCItem/EsignetMosipVCItemMachine';
import {createVCItemMachine} from '../../machines/VerifiableCredential/VCItemMachine/VCItemMachine';
import {
getImpressionEventData,
sendImpressionEvent,
} from '../../shared/telemetry/TelemetryUtils';
import {TelemetryConstants} from '../../shared/telemetry/TelemetryConstants';
import {
VCItemContainerFlowType,
getVCsOrderedByPinStatus,
VCItemContainerFlowType,
} from '../../shared/Utils';
import {Issuers} from '../../shared/openId4VCI/Utils';
import {FaceVerificationAlertOverlay} from './FaceVerificationAlertOverlay';
@@ -38,15 +37,10 @@ export const SendVcScreen: React.FC = () => {
if (shareableVcsMetadataOrderedByPinStatus?.length > 0) {
const vcMetadata = shareableVcsMetadataOrderedByPinStatus[0];
const firstVCMachine = useRef(
VCMetadata.fromVC(vcMetadata).isFromOpenId4VCI()
? createEsignetMosipVCItemMachine(
appService.getSnapshot().context.serviceRefs,
vcMetadata,
)
: createExistingMosipVCItemMachine(
appService.getSnapshot().context.serviceRefs,
vcMetadata,
),
createVCItemMachine(
appService.getSnapshot().context.serviceRefs,
vcMetadata,
),
);
service = useInterpret(firstVCMachine.current);
@@ -108,20 +102,17 @@ export const SendVcScreen: React.FC = () => {
<Column
style={Theme.SendVcScreenStyles.shareOptionButtonsContainer}
backgroundColor={Theme.Colors.whiteBackgroundColor}>
{!controller.selectedVc.shouldVerifyPresence &&
controller.selectedVc?.vcMetadata &&
[Issuers.Mosip, Issuers.ESignet].indexOf(
VCMetadata.fromVcMetadataString(controller.selectedVc.vcMetadata)
.issuer,
) !== -1 && (
<Button
type="gradient"
title={t('acceptRequestAndVerify')}
styles={{marginTop: 12}}
disabled={controller.selectedIndex == null}
onPress={controller.VERIFY_AND_ACCEPT_REQUEST}
/>
)}
{[Issuers.Mosip, Issuers.ESignet].indexOf(
controller.verifiableCredentialData.issuer,
) !== -1 && (
<Button
type="gradient"
title={t('acceptRequestAndVerify')}
styles={{marginTop: 12}}
disabled={controller.selectedIndex == null}
onPress={controller.VERIFY_AND_ACCEPT_REQUEST}
/>
)}
<Button
type="gradient"
@@ -141,7 +132,8 @@ export const SendVcScreen: React.FC = () => {
</Column>
<VerifyIdentityOverlay
vc={controller.selectedVc}
credential={controller.credential}
verifiableCredentialData={controller.verifiableCredentialData}
isVerifyingIdentity={controller.isVerifyingIdentity}
onCancel={controller.CANCEL}
onFaceValid={controller.FACE_VALID}

View File

@@ -1,14 +1,14 @@
import {useSelector} from '@xstate/react';
import {useContext, useState} from 'react';
import {ActorRefFrom} from 'xstate';
import {selectShareableVcsMetadata} from '../../machines/VCItemMachine/vc';
import {ExistingMosipVCItemMachine} from '../../machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine';
import {selectShareableVcsMetadata} from '../../machines/VerifiableCredential/VCMetaMachine/vc';
import {GlobalContext} from '../../shared/GlobalContext';
import {
selectCredential,
selectIsSelectingVc,
selectReceiverInfo,
selectSelectedVc,
selectVcName,
selectVerifiableCredentialData,
} from '../../machines/bleShare/scan/selectors';
import {
selectIsCancelling,
@@ -23,38 +23,23 @@ import {VCShareFlowType} from '../../shared/Utils';
import {NavigationProp, useNavigation} from '@react-navigation/native';
import {RootRouteProps} from '../../routes';
import {BOTTOM_TAB_ROUTES} from '../../routes/routesConstants';
import {VCItemMachine} from '../../machines/VerifiableCredential/VCItemMachine/VCItemMachine';
type MyVcsTabNavigation = NavigationProp<RootRouteProps>;
export function useSendVcScreen() {
const {appService} = useContext(GlobalContext);
const scanService = appService.children.get('scan');
const vcService = appService.children.get('vc');
const scanService = appService.children.get('scan')!!;
const vcService = appService.children.get('vc')!!;
const navigation = useNavigation<MyVcsTabNavigation>();
const CANCEL = () => scanService.send(ScanEvents.CANCEL());
const [selectedIndex, setSelectedIndex] = useState<number>(null);
return {
selectedIndex,
TOGGLE_USER_CONSENT: () =>
scanService.send(ScanEvents.TOGGLE_USER_CONSENT()),
SELECT_VC_ITEM:
(index: number) =>
(vcRef: ActorRefFrom<typeof ExistingMosipVCItemMachine>) => {
setSelectedIndex(index);
const {serviceRefs, ...vcData} = vcRef.getSnapshot().context;
scanService.send(
ScanEvents.SELECT_VC(vcData, VCShareFlowType.SIMPLE_SHARE),
);
},
receiverInfo: useSelector(scanService, selectReceiverInfo),
vcName: useSelector(scanService, selectVcName),
shareableVcsMetadata: useSelector(vcService, selectShareableVcsMetadata),
selectedVc: useSelector(scanService, selectSelectedVc),
isSelectingVc: useSelector(scanService, selectIsSelectingVc),
isVerifyingIdentity: useSelector(scanService, selectIsVerifyingIdentity),
isInvalidIdentity: useSelector(scanService, selectIsInvalidIdentity),
@@ -63,8 +48,12 @@ export function useSendVcScreen() {
scanService,
selectIsFaceVerificationConsent,
),
CANCEL,
credential: useSelector(scanService, selectCredential),
verifiableCredentialData: useSelector(
scanService,
selectVerifiableCredentialData,
),
CANCEL: () => scanService.send(ScanEvents.CANCEL()),
ACCEPT_REQUEST: () => scanService.send(ScanEvents.ACCEPT_REQUEST()),
FACE_VERIFICATION_CONSENT: (isConsentGiven: boolean) =>
scanService.send(ScanEvents.FACE_VERIFICATION_CONSENT(isConsentGiven)),
@@ -79,5 +68,13 @@ export function useSendVcScreen() {
GO_TO_HOME: () => {
navigation.navigate(BOTTOM_TAB_ROUTES.home, {screen: 'HomeScreen'});
},
SELECT_VC_ITEM:
(index: number) => (vcRef: ActorRefFrom<typeof VCItemMachine>) => {
setSelectedIndex(index);
const {serviceRefs, ...vcData} = vcRef.getSnapshot().context;
scanService.send(
ScanEvents.SELECT_VC(vcData, VCShareFlowType.SIMPLE_SHARE),
);
},
};
}

View File

@@ -1,26 +1,17 @@
import React from 'react';
import {FaceScanner} from '../components/FaceScanner';
import {Column} from '../components/ui';
import {Theme} from '../components/ui/styleUtils';
import {VC} from '../types/VC/ExistingMosipVC/vc';
import {VerifiableCredential} from '../types/VC/vc';
import {Modal} from '../components/ui/Modal';
import {useTranslation} from 'react-i18next';
import {VCMetadata} from '../shared/VCMetadata';
export const VerifyIdentityOverlay: React.FC<
VerifyIdentityOverlayProps
> = props => {
const {t} = useTranslation('VerifyIdentityOverlay');
const isOpenId4VCI =
props.vc?.vcMetadata &&
VCMetadata.fromVC(props.vc?.vcMetadata).isFromOpenId4VCI();
const credential = isOpenId4VCI
? props.vc?.verifiableCredential
: props.vc?.credential;
const vcImage = isOpenId4VCI
? props.vc?.verifiableCredential.credential.credentialSubject.face
: props.vc?.credential?.biometrics.face;
const credential = props.credential;
const vcImage = props.verifiableCredentialData.face;
return (
<>
@@ -47,7 +38,8 @@ export const VerifyIdentityOverlay: React.FC<
};
export interface VerifyIdentityOverlayProps {
vc?: VC;
credential?: VerifiableCredential | Credential;
verifiableCredentialData: any;
isVerifyingIdentity: boolean;
onCancel: () => void;
onFaceValid: () => void;

View File

@@ -7,7 +7,7 @@ import {requestMachine} from '../machines/bleShare/request/requestMachine';
import {scanMachine} from '../machines/bleShare/scan/scanMachine';
import {settingsMachine} from '../machines/settings';
import {storeMachine} from '../machines/store';
import {vcMachine} from '../machines/VCItemMachine/vc';
import {vcMachine} from '../machines/VerifiableCredential/VCMetaMachine/vc';
import {backupMachine} from '../machines/backupAndRestore/backup';
import {backupRestoreMachine} from '../machines/backupAndRestore/backupRestore';

View File

@@ -20,3 +20,8 @@ export enum VCItemContainerFlowType {
QR_LOGIN = 'qr login',
VC_SHARE = 'vc share',
}
export interface CommunicationDetails {
phoneNumber: string;
emailId: string;
}

View File

@@ -1,4 +1,4 @@
import {VC, VcIdType} from '../types/VC/ExistingMosipVC/vc';
import {VC, VcIdType} from '../types/VC/vc';
import {Issuers, Protocols} from './openId4VCI/Utils';
import {getMosipIdentifier} from './commonUtil';

View File

@@ -6,7 +6,7 @@ import {generateSecureRandom} from 'react-native-securerandom';
import forge from 'node-forge';
import {useEffect, useState} from 'react';
import {Dimensions, Keyboard} from 'react-native';
import {CredentialSubject} from '../types/VC/ExistingMosipVC/vc';
import { CredentialSubject } from '../types/VC/vc';
export const hashData = async (
data: string,

View File

@@ -1,7 +1,7 @@
import {Platform} from 'react-native';
import {DEBUG_MODE, ESIGNET_HOST, MIMOTO_HOST} from 'react-native-dotenv';
import {Argon2iConfig} from './commonUtil';
import {VcIdType} from '../types/VC/ExistingMosipVC/vc';
import {VcIdType} from '../types/VC/vc';
export let MIMOTO_BASE_URL = MIMOTO_HOST;
export let ESIGNET_BASE_URL = ESIGNET_HOST;

View File

@@ -93,13 +93,6 @@ function isCustomSecureKeystore() {
return !isIOS() ? SecureKeystore.deviceSupportsHardware() : false;
}
export interface WalletBindingResponse {
walletBindingId: string;
keyId: string;
thumbprint: string;
expireDateTime: string;
}
export async function encryptJson(
encryptionKey: string,
data: string,

View File

@@ -9,8 +9,7 @@ import i18next from 'i18next';
import {getJWT} from '../cryptoutil/cryptoUtil';
import {CACHED_API} from '../api';
import i18n from '../../i18n';
import {VerifiableCredential} from '../../types/VC/ExistingMosipVC/vc';
import {CredentialWrapper} from '../../types/VC/EsignetMosipVC/vc';
import {CredentialWrapper, VerifiableCredential} from '../../types/VC/vc';
import {
BOTTOM_SECTION_FIELDS_WITH_DETAILED_ADDRESS_FIELDS,
DETAIL_VIEW_ADD_ON_FIELDS,

View File

@@ -1,7 +1,4 @@
import {
DecodedCredential,
VerifiableCredential,
} from '../types/VC/ExistingMosipVC/vc';
import {DecodedCredential, VerifiableCredential} from '../types/VC/vc';
import {__AppId} from './GlobalVariables';
import {MIMOTO_BASE_URL, REQUEST_TIMEOUT} from './constants';

View File

@@ -2,10 +2,7 @@ import vcjs from '@digitalcredentials/vc';
import jsonld from '@digitalcredentials/jsonld';
// import { RSAKeyPair } from '@digitalcredentials/jsonld-signatures';
import {RsaSignature2018} from '../../lib/jsonld-signatures/suites/rsa2018/RsaSignature2018';
import {
VerifiableCredential,
VerifiablePresentation,
} from '../../types/VC/ExistingMosipVC/vc';
import {VerifiableCredential, VerifiablePresentation} from '../../types/VC/vc';
export function createVerifiablePresentation(
vc: VerifiableCredential,

View File

@@ -1,11 +1,10 @@
import vcjs from '@digitalcredentials/vc';
import jsonld from '@digitalcredentials/jsonld';
import vcjs from '@digitalcredentials/vc';
import {RsaSignature2018} from '../../lib/jsonld-signatures/suites/rsa2018/RsaSignature2018';
import {Ed25519Signature2018} from '../../lib/jsonld-signatures/suites/ed255192018/Ed25519Signature2018';
import {AssertionProofPurpose} from '../../lib/jsonld-signatures/purposes/AssertionProofPurpose';
import {PublicKeyProofPurpose} from '../../lib/jsonld-signatures/purposes/PublicKeyProofPurpose';
import {VerifiableCredential} from '../../types/VC/ExistingMosipVC/vc';
import {Credential} from '../../types/VC/EsignetMosipVC/vc';
import {Credential, VerifiableCredential} from '../../types/VC/vc';
import {getErrorEventData, sendErrorEvent} from '../telemetry/TelemetryUtils';
import {TelemetryConstants} from '../telemetry/TelemetryConstants';
import {getMosipIdentifier} from '../commonUtil';
@@ -84,6 +83,10 @@ function handleResponse(
errorMessage = VerificationErrorType.TECHNICAL_ERROR;
isVerifiedFlag = false;
console.log('Verification: ', result['results'][0]);
console.log('Verifiable Credential: ', verifiableCredential);
if (errorCodeName == 'jsonld.InvalidUrl') {
errorMessage = VerificationErrorType.NETWORK_ERROR;
} else if (errorCodeName == VerificationErrorType.RANGE_ERROR) {

View File

@@ -1,7 +1,7 @@
import vcjs from '@digitalcredentials/vc';
import jsonld from '@digitalcredentials/jsonld';
import {RsaSignature2018} from '../../lib/jsonld-signatures/suites/rsa2018/RsaSignature2018';
import {VerifiablePresentation} from '../../types/VC/ExistingMosipVC/vc';
import {VerifiablePresentation} from '../../types/VC/vc';
export async function verifyPresentation(
presentation: VerifiablePresentation,

View File

@@ -1,111 +0,0 @@
import {WalletBindingResponse} from '../../../shared/cryptoutil/cryptoUtil';
export interface VC {
id: string;
idType: VcIdType;
tag: string;
credential: DecodedCredential;
verifiableCredential: VerifiableCredential;
verifiablePresentation?: VerifiablePresentation;
generatedOn: Date;
requestId: string;
isVerified: boolean;
lastVerifiedOn: number;
shouldVerifyPresence?: boolean;
walletBindingResponse?: WalletBindingResponse;
credentialRegistry?: string;
isPinned?: boolean;
}
export type VcIdType = 'UIN' | 'VID';
export interface DecodedCredential {
biometrics: {
face: string;
finger: {
left_thumb: string;
right_thumb: string;
};
};
}
export interface CredentialSubject {
UIN: string;
VID: string;
addressLine1: LocalizedField[] | string;
addressLine2: LocalizedField[] | string;
addressLine3: LocalizedField[] | string;
biometrics: string; // Encrypted Base64Encoded Biometrics
city: LocalizedField[] | string;
dateOfBirth: string;
email: string;
fullName: string;
gender: LocalizedField[] | string;
id: string;
phone: string;
postalCode: string;
province: LocalizedField[] | string;
region: LocalizedField[] | string;
vcVer: 'VC-V1' | string;
}
type VCContext = (string | Record<string, unknown>)[];
export interface VerifiableCredential {
'@context': VCContext;
credentialSubject: CredentialSubject;
id: string;
issuanceDate: string;
issuer: string;
proof: {
created: string;
jws: string;
proofPurpose: 'assertionMethod' | string;
type: 'RsaSignature2018' | string;
verificationMethod: string;
};
type: VerifiableCredentialType[];
wellKnown: string;
credentialTypes: Object[];
}
export interface VerifiablePresentation {
'@context': VCContext;
verifiableCredential: VerifiableCredential[];
type: 'VerifiablePresentation';
proof: {
created: string;
jws: string;
proofPurpose: 'authentication' | string;
type: 'RsaSignature2018' | string;
verificationMethod: string;
challenge: string;
domain: string;
};
}
export type VerifiableCredentialType =
| 'VerifiableCredential'
| 'MOSIPVerfiableCredential'
| string;
export interface VCLabel {
singular: string;
plural: string;
}
export interface LocalizedField {
language: string;
value: string;
}
export interface linkTransactionResponse {
authFactors: Object[];
authorizeScopes: null;
clientName: string;
configs: {};
essentialClaims: string[];
linkTransactionId: string;
logoUrl: string;
voluntaryClaims: string[];
}

View File

@@ -1,20 +1,14 @@
import {WalletBindingResponse} from '../../../shared/cryptoutil/cryptoUtil';
import {logoType} from '../../../machines/issuersMachine';
import {VCMetadata} from '../../../shared/VCMetadata';
import {logoType} from '../../machines/issuersMachine';
export interface VC {
id?: string;
idType?: VcIdType;
credential?: DecodedCredential;
verifiableCredential: VerifiableCredential;
verifiablePresentation?: VerifiablePresentation;
requestId?: string;
isVerified?: boolean;
lastVerifiedOn: number;
shouldVerifyPresence?: boolean;
walletBindingResponse?: WalletBindingResponse;
credentialRegistry?: string;
isPinned?: boolean;
hashedId?: string;
}
@@ -73,27 +67,11 @@ export interface VerifiableCredential {
export interface CredentialWrapper {
verifiableCredential: VerifiableCredential;
vcMetadata: VCMetadata;
identifier: string;
generatedOn: Date;
issuerLogo: string;
}
export interface VerifiablePresentation {
'@context': VCContext;
verifiableCredential: VerifiableCredential[];
type: 'VerifiablePresentation';
proof: {
created: string;
jws: string;
proofPurpose: 'authentication' | string;
type: 'RsaSignature2018' | string;
verificationMethod: string;
challenge: string;
domain: string;
};
}
export type VerifiableCredentialType =
| 'VerifiableCredential'
| 'MOSIPVerfiableCredential'
@@ -119,3 +97,10 @@ export interface linkTransactionResponse {
logoUrl: string;
voluntaryClaims: string[];
}
export interface WalletBindingResponse {
walletBindingId: string;
keyId: string;
thumbprint: string;
expireDateTime: string;
}