From 5351a909b87df49c1d1f4759cb6ced27a8f033a3 Mon Sep 17 00:00:00 2001 From: abhip2565 <74866247+abhip2565@users.noreply.github.com> Date: Thu, 2 May 2024 18:36:52 +0530 Subject: [PATCH] [INJIMOB-1240] : Fix face auth consent for minified view share (#1397) * [INJIMOB-1240] Resolve conflicts Signed-off-by: Abhishek Paul * [INJIMOB-1240] Refactor scan machine and QrLogin machine Signed-off-by: Abhishek Paul * [INJIMOB-1240] Refactor scan machine and QrLogin machine Signed-off-by: Abhishek Paul * [INJIMOB-1240] Refactor scan machine and QrLogin machine Signed-off-by: Abhishek Paul * [INJIMOB-1240]: Fix.Share with selfie pop up bug Signed-off-by: Abhishek Paul * [INJIMOB-1240]: Refactor. scanMachine and qrLoginMachine Signed-off-by: Abhishek Paul * [INJIMOB-1240]: Refactor. scanMachine and qrLoginMachine Signed-off-by: Abhishek Paul --------- Signed-off-by: Abhishek Paul --- components/KebabPopUpController.tsx | 2 +- machines/Issuers/IssuersMachine.typegen.ts | 6 +- machines/QrLogin/QrLoginActions.ts | 170 +++++ machines/QrLogin/QrLoginGuards.ts | 13 + machines/QrLogin/QrLoginMachine.ts | 277 +++++++ machines/QrLogin/QrLoginMachine.typegen.ts | 64 ++ machines/QrLogin/QrLoginModel.ts | 69 ++ machines/QrLogin/QrLoginSelectors.ts | 117 +++ machines/QrLogin/QrLoginServices.ts | 111 +++ machines/QrLoginMachine.ts | 710 ------------------ machines/QrLoginMachine.typegen.ts | 95 --- .../VCItemMachine/VCItemMachine.typegen.ts | 505 +++---------- .../VCMetaMachine/VCMetaMachine.typegen.ts | 162 ++-- machines/bleShare/scan/scanActions.ts | 327 ++++++++ machines/bleShare/scan/scanGuards.ts | 45 ++ machines/bleShare/scan/scanMachine.ts | 699 +---------------- machines/bleShare/scan/scanMachine.typegen.ts | 357 +++------ machines/bleShare/scan/scanModel.ts | 84 +++ .../scan/{selectors.ts => scanSelectors.ts} | 10 + machines/bleShare/scan/scanServices.ts | 197 +++++ machines/store.ts | 6 +- machines/store.typegen.ts | 123 ++- screens/Home/HomeScreenMachine.typegen.ts | 103 +-- screens/QrLogin/MyBindedVcs.tsx | 2 +- screens/QrLogin/QrConsent.tsx | 2 +- screens/QrLogin/QrLogin.tsx | 2 +- screens/QrLogin/QrLoginController.ts | 8 +- screens/QrLogin/QrLoginSuccessMessage.tsx | 2 +- screens/Scan/FaceVerificationAlertOverlay.tsx | 2 +- screens/Scan/ScanLayoutController.ts | 2 +- screens/Scan/ScanScreen.tsx | 72 +- screens/Scan/ScanScreenController.ts | 4 +- screens/Scan/SendVcScreen.tsx | 1 - screens/Scan/SendVcScreenController.ts | 8 +- shared/constants.ts | 4 +- 35 files changed, 1972 insertions(+), 2389 deletions(-) create mode 100644 machines/QrLogin/QrLoginActions.ts create mode 100644 machines/QrLogin/QrLoginGuards.ts create mode 100644 machines/QrLogin/QrLoginMachine.ts create mode 100644 machines/QrLogin/QrLoginMachine.typegen.ts create mode 100644 machines/QrLogin/QrLoginModel.ts create mode 100644 machines/QrLogin/QrLoginSelectors.ts create mode 100644 machines/QrLogin/QrLoginServices.ts delete mode 100644 machines/QrLoginMachine.ts delete mode 100644 machines/QrLoginMachine.typegen.ts create mode 100644 machines/bleShare/scan/scanActions.ts create mode 100644 machines/bleShare/scan/scanGuards.ts create mode 100644 machines/bleShare/scan/scanModel.ts rename machines/bleShare/scan/{selectors.ts => scanSelectors.ts} (92%) create mode 100644 machines/bleShare/scan/scanServices.ts diff --git a/components/KebabPopUpController.tsx b/components/KebabPopUpController.tsx index 6ddde3adb8..662ae0ed80 100644 --- a/components/KebabPopUpController.tsx +++ b/components/KebabPopUpController.tsx @@ -21,7 +21,7 @@ import {ScanEvents} from '../machines/bleShare/scan/scanMachine'; 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 {selectIsScanning} from '../machines/bleShare/scan/scanSelectors'; import { VCItemEvents, VCItemMachine, diff --git a/machines/Issuers/IssuersMachine.typegen.ts b/machines/Issuers/IssuersMachine.typegen.ts index f7b589a221..aa2d5c5663 100644 --- a/machines/Issuers/IssuersMachine.typegen.ts +++ b/machines/Issuers/IssuersMachine.typegen.ts @@ -34,10 +34,10 @@ "verifyCredential": "done.invoke.issuersMachine.verifyingCredential:invocation[0]"; }; missingImplementations: { - actions: never; + actions: "getKeyPairFromStore" | "loadKeyPair" | "logDownloaded" | "resetError" | "resetLoadingReason" | "resetVerificationErrorMessage" | "sendBackupEvent" | "sendErrorEndEvent" | "sendImpressionEvent" | "sendSuccessEndEvent" | "setCredentialTypes" | "setCredentialWrapper" | "setError" | "setIssuers" | "setLoadingReasonAsDisplayIssuers" | "setLoadingReasonAsDownloadingCredentials" | "setLoadingReasonAsSettingUp" | "setMetadataInCredentialData" | "setNoInternet" | "setOIDCConfigError" | "setPrivateKey" | "setPublicKey" | "setSelectedCredentialType" | "setSelectedIssuerId" | "setSelectedIssuers" | "setTokenResponse" | "setVCMetadata" | "setVerifiableCredential" | "storeKeyPair" | "storeVcMetaContext" | "storeVcsContext" | "storeVerifiableCredentialData" | "storeVerifiableCredentialMeta" | "updateVerificationErrorMessage"; delays: never; - guards: never; - services: never; + guards: "canSelectIssuerAgain" | "hasKeyPair" | "hasUserCancelledBiometric" | "isCustomSecureKeystore" | "isInternetConnected" | "isMultipleCredentialsSupported" | "isOIDCConfigError" | "isOIDCflowCancelled" | "isSignedIn" | "shouldFetchIssuersAgain"; + services: "checkInternet" | "downloadCredential" | "downloadCredentialTypes" | "downloadIssuerConfig" | "downloadIssuersList" | "generateKeyPair" | "invokeAuthorization" | "isUserSignedAlready" | "verifyCredential"; }; eventsCausingActions: { "getKeyPairFromStore": "TRY_AGAIN" | "done.invoke.issuersMachine.performAuthorization:invocation[0]"; diff --git a/machines/QrLogin/QrLoginActions.ts b/machines/QrLogin/QrLoginActions.ts new file mode 100644 index 0000000000..484051931e --- /dev/null +++ b/machines/QrLogin/QrLoginActions.ts @@ -0,0 +1,170 @@ +import { assign, send, sendParent } from "xstate"; +import i18n from "../../i18n"; +import { VCShareFlowType } from "../../shared/Utils"; +import { parseMetadatas } from "../../shared/VCMetadata"; +import { SHOW_FACE_AUTH_CONSENT_QR_LOGIN_FLOW, MY_VCS_STORE_KEY } from "../../shared/constants"; +import { getBindingCertificateConstant } from "../../shared/keystore/SecureKeystore"; +import { VC, linkTransactionResponse } from "../VerifiableCredential/VCMetaMachine/vc"; +import { StoreEvents } from "../store"; + + + +export const QrLoginActions=(model:any)=>{ + + return{ + setShowFaceAuthConsent: model.assign({ + showFaceAuthConsent: (_, event) => { + return !event.isDoNotAskAgainChecked; + }, + }), + + storeShowFaceAuthConsent: send( + (context, event) => + StoreEvents.SET(SHOW_FACE_AUTH_CONSENT_QR_LOGIN_FLOW, !event.isDoNotAskAgainChecked), + { + to: context => context.serviceRefs.store, + }, + ), + + forwardToParent: sendParent('DISMISS'), + + setScanData: model.assign((context, event) => { + const linkCode = event.linkCode; + const flowType = event.flowType; + const selectedVc = event.selectedVc; + return { + ...context, + linkCode: linkCode, + flowType: flowType, + selectedVc: selectedVc, + }; + }), + getFaceAuthConsent: send(StoreEvents.GET(SHOW_FACE_AUTH_CONSENT_QR_LOGIN_FLOW), { + to: (context:any) => context.serviceRefs.store, + }), + + updateShowFaceAuthConsent: model.assign({ + showFaceAuthConsent: (_, event) => { + return event.response || event.response === null; + }, + }), + + // TODO: loaded VCMetadatas are not used anywhere. remove? + loadMyVcs: send(StoreEvents.GET(MY_VCS_STORE_KEY), { + to: context => context.serviceRefs.store, + }), + + setMyVcs: model.assign({ + myVcs: (_context, event) => + parseMetadatas((event.response || []) as object[]), + }), + + loadThumbprint: send( + context => + StoreEvents.GET( + getBindingCertificateConstant( + context.selectedVc.walletBindingResponse?.walletBindingId, + ), + ), + {to: context => context.serviceRefs.store}, + ), + setThumbprint: assign({ + thumbprint: (_context, event) => { + return (event.response || '') as string; + }, + }), + resetLinkTransactionId: model.assign({ + linkTransactionId: () => '', + }), + + resetSelectedVoluntaryClaims: model.assign({ + selectedVoluntaryClaims: () => [], + }), + + setSelectedVc: assign({ + selectedVc: (context, event) => { + return {...event.vc}; + }, + }), + + resetSelectedVc: assign({ + selectedVc: {} as VC, + }), + + resetFlowType: assign({ + flowType: VCShareFlowType.SIMPLE_SHARE, + }), + + setlinkTransactionResponse: assign({ + linkTransactionResponse: (context, event) => + event.data as linkTransactionResponse, + }), + + expandLinkTransResp: assign({ + authFactors: context => context.linkTransactionResponse.authFactors, + + authorizeScopes: context => + context.linkTransactionResponse.authorizeScopes, + + clientName: context => context.linkTransactionResponse.clientName, + + configs: context => context.linkTransactionResponse.configs, + + essentialClaims: context => + context.linkTransactionResponse.essentialClaims, + + linkTransactionId: context => + context.linkTransactionResponse.linkTransactionId, + + logoUrl: context => context.linkTransactionResponse.logoUrl, + + voluntaryClaims: context => + context.linkTransactionResponse.voluntaryClaims, + }), + + setClaims: context => { + context.voluntaryClaims.map(claim => { + context.isSharing[claim] = false; + }); + }, + + SetErrorMessage: assign({ + errorMessage: (context, event) => { + const message = event.data.name; + const ID_ERRORS_MAP = { + invalid_link_code: 'invalidQR', + }; + const errorMessage = ID_ERRORS_MAP[message] + ? i18n.t(`errors.${ID_ERRORS_MAP[message]}`, { + ns: 'QrLogin', + }) + : i18n.t(`errors.genericError`, { + ns: 'common', + }); + + return errorMessage; + }, + }), + + setConsentClaims: assign({ + isSharing: (context, event) => { + context.isSharing[event.claim] = !event.enable; + if (!event.enable) { + context.selectedVoluntaryClaims.push(event.claim); + } else { + context.selectedVoluntaryClaims = + context.selectedVoluntaryClaims.filter( + eachClaim => eachClaim !== event.claim, + ); + } + return {...context.isSharing}; + }, + }), + setLinkedTransactionId: assign({ + linkedTransactionId: (context, event) => + event.data.linkedTransactionId as string, + }), + } + } + + diff --git a/machines/QrLogin/QrLoginGuards.ts b/machines/QrLogin/QrLoginGuards.ts new file mode 100644 index 0000000000..cd45abdfce --- /dev/null +++ b/machines/QrLogin/QrLoginGuards.ts @@ -0,0 +1,13 @@ +import { VCShareFlowType } from "../../shared/Utils"; + +export const QrLoginGuards={ + showFaceAuthConsentScreen: context => { + return context.showFaceAuthConsent; + }, + + isConsentAlreadyCaptured: (_, event) => + event.data?.consentAction === 'NOCAPTURE', + + isSimpleShareFlow: (context, _event) => + context.flowType === VCShareFlowType.SIMPLE_SHARE, + } \ No newline at end of file diff --git a/machines/QrLogin/QrLoginMachine.ts b/machines/QrLogin/QrLoginMachine.ts new file mode 100644 index 0000000000..28af0a9d3e --- /dev/null +++ b/machines/QrLogin/QrLoginMachine.ts @@ -0,0 +1,277 @@ +import { + ActorRefFrom, + EventFrom +} from 'xstate'; +import { AppServices } from '../../shared/GlobalContext'; +import { TelemetryConstants } from '../../shared/telemetry/TelemetryConstants'; +import { + getEndEventData, + sendEndEvent, +} from '../../shared/telemetry/TelemetryUtils'; +import { QrLoginActions } from './QrLoginActions'; +import { QrLoginmodel } from './QrLoginModel'; +import { QrLoginServices } from './QrLoginServices'; +import { QrLoginGuards } from './QrLoginGuards'; + +const model = QrLoginmodel; + +export const QrLoginEvents = model.events; +export type QrLoginRef = ActorRefFrom; + +export const qrLoginMachine = + /** @xstate-layout N4IgpgJg5mDOIC5QEUBOAZA9lAlgOwDocIAbMAYgGUBhAQQDl6BJegcQH0ARAeXoFEA2gAYAuolAAHTLBwAXHJjziQAD0QBGACzqATAQCs+nZv0BmABzqL50zoA0IAJ6IA7KaEFNATnPmv6oUMhHUMAX1CHNCxcQmIyck4mSgBZJMphMSQQKRl5RWU1BF1zFwIvHQrTFxdNCxcANgdnBH16j1NbdT8vfW8q9XDIjGx8AhJ8AGsAFVQAQzxYWYBjPLxyCEUwIjwAN0wJraiRwnG8abmF5dWEfD2l2dWMjOUcuQUlLMKtXQMjEwsrL5bE1EF4XOYCEJ6iEXF4ekIOppzIMQEcYmNJjN5osVu9yGBUKhMKgCBISA8AGbEgC2BDRo1O52xV3eN12mHuj1Ezyyr1WBQ0JQhmlhotMZmM+hcIIQNX0nnUhh65h06hcOhKKPphFgAAtMAB3ADqs1QeHwUHI1F4ADEmAAlZI8yTSN75T6IEIeHT+eo1Lyaeriwwy+pggiwtXw9SKjU6LXDdF6w0ms0Wq0Mah8dDO7Ku-kehBegg+9R+7yB4P6GV+dQRlwBIRqoTqjX1BPRUaUfUGviE4kZ+hZnOiF7594Coo9TSQtyqqUx9zApyINpeCNIoVaYzlUwd45jTCzCDJRwANSWsCoU249r47DvlAACrxKIJR7zx+7QIU-fLofoMaATYWjaKGLjylCOjQi4gSmJoOgNPuSY9jsSzoDgsCyFQ2Z8NQUzsGe1C5nyE6Fr4M4BkI3j6DYtEttWK4tDGEb1H6DbmEYAZschozJgaaEYVh5Bnnw9pMDaACaJFfh8P6uLRZRIoqKl0UI5gyiK9SQtobjUZu0KaLxOqoehmHYYkKRpDJuRkfJRTqRCpj1PoTYBj01QVKGPwVIBHT6AGqq1MZBAUssYC0AArrIurkDatBZoRtDoEwnA2W6cmqJ6rklr6-qVoYjHNP4kI2Jo1ENr01EBiFYVLBF0WxfFiUsGeyWpelBb2cWpbltxVahiKuVqmGXT1IG6heLV4VRTFg7Dp1dlZUWOW9flQaFTW2glrBYK0SqZaqiFtyzOMEBMBAYB4PIsiOAkSSpJQ6Qfi6tnfstf4EABQFdKYoHqKG1EECUrnmEIcJ+FC7YRKiiajCdZ0XVdN13XeUz2pJhFiRJTB0FMTC8It72FD1eUVhtIZMQF2mRjUHT1FYPTQ0MnaEKgYAAI6RXAsjUIosDI1atoOk6L15m9mW-hBX0hD9IGaGBTEIfKvTNoGOhVF4zOw6zBDs1zPN8wsgt0EO2ZE5Lq7S99ql-QrANMe4M6RqNDa6NC5hGTD2oEBseAUJZj3PZkr0ZZOAS+AQzmuZNNGefYSshAYunUdCmvaz7+vc1hFpGwL13rJs2x7AcdJw2znPZ-IeBQHnyNsncDzvE8YukcTq42GUYYtuNgFsQGMqqnWNjwSNiFeACe7e+XeuVzzuf84LBJEiSZKUjSZe61n8813X10NxyTeKC3Ifi2HhYR05LluXHrY1qYO2OanY1sciKJ4Jgl3wFk2pjhLk4AFpGhMQAfKOE4CIGQKnizA8cQwB-3PvZYoEJVT+FVCUaC-hNDeXlDYCoipwRCCIeKEKjIsSXFxO9NulsiguWdpYIMQZoK9F6DKOmX0FYQSITHHoU1p6634qmc0NcEFdWWghNh4MCBlnqGDLQ7EAxvxgeibsho+wr1EUtEmLYIQqmjvbeCKoiqrgCCWTc4JtzeA1qQo8J5zyXk0e3BAIph7jTYvBQIwQLDgWdv4Bo5UkTqjMCFfiglzKOJoX4bS4oGyIR9FUIhCdmgMz0EEqw4pApaGgTrA8dUGoxQiZOGoX0Si1CDFYAKCEkkaChKVUeHQNYNGosdXYp1iBI2unIZoocxGFCRHoKU40VT+H2n4QG8oqig3Bj4LwUIXAhW3lhPeshCmFiROucqhlYK6AXA7Zoxg6wTwgv09JHRfAhT9vAz8-9Cz+HXJUxUCIzBIiRJpaCOkRoNlMGCME8EFlzxzrvRe11Vn2RBtI1oDM-pGAsF4GsdZXJEI8n8Go41wjhCAA */ + model.createMachine( + { + predictableActionArguments: true, + preserveActionOrder: true, + tsTypes: {} as import('./QrLoginMachine.typegen').Typegen0, + schema: { + context: model.initialContext, + events: {} as EventFrom, + }, + id: 'QrLogin', + initial: 'waitingForData', + entry: ['resetSelectedVc', 'resetFlowType'], + states: { + waitingForData: { + on: { + GET: { + actions: [ + 'setScanData', + 'resetLinkTransactionId', + 'resetSelectedVoluntaryClaims', + ], + target: 'checkFaceAuthConsent', + }, + }, + }, + checkFaceAuthConsent: { + entry: 'getFaceAuthConsent', + on: { + STORE_RESPONSE: { + actions: 'updateShowFaceAuthConsent', + target: 'linkTransaction', + }, + }, + }, + linkTransaction: { + invoke: { + src: 'linkTransaction', + onDone: [ + { + cond: 'isSimpleShareFlow', + actions: [ + 'setlinkTransactionResponse', + 'expandLinkTransResp', + 'setClaims', + ], + target: 'loadMyVcs', + }, + { + cond: 'showFaceAuthConsentScreen', + target: 'faceVerificationConsent', + }, + { + actions: [ + 'setlinkTransactionResponse', + 'expandLinkTransResp', + 'setClaims', + ], + target: 'faceAuth', + }, + ], + onError: [ + { + actions: 'SetErrorMessage', + target: 'ShowError', + }, + ], + }, + }, + ShowError: { + on: { + DISMISS: { + actions: 'forwardToParent', + target: 'waitingForData', + }, + }, + }, + loadMyVcs: { + entry: 'loadMyVcs', + on: { + STORE_RESPONSE: { + actions: 'setMyVcs', + target: 'showvcList', + }, + }, + }, + showvcList: { + on: { + SELECT_VC: { + actions: 'setSelectedVc', + }, + VERIFY: [ + { + cond: 'showFaceAuthConsentScreen', + target: 'faceVerificationConsent', + }, + { + target: 'faceAuth', + }, + ], + DISMISS: { + actions: 'forwardToParent', + target: 'waitingForData', + }, + }, + }, + faceVerificationConsent: { + on: { + FACE_VERIFICATION_CONSENT: { + actions: ['storeShowFaceAuthConsent', 'setShowFaceAuthConsent'], + target: 'faceAuth', + }, + DISMISS: [{ + cond:'isSimpleShareFlow', + target: 'showvcList', + }, + { + actions: 'forwardToParent', + target: 'waitingForData', + } + ] + }, + }, + faceAuth: { + on: { + FACE_VALID: { + target: 'loadingThumbprint', + }, + FACE_INVALID: { + target: 'invalidIdentity', + }, + CANCEL: [ + { + cond: 'isSimpleShareFlow', + target: 'showvcList', + }, + { + actions: 'forwardToParent', + target: 'waitingForData', + }, + ], + }, + }, + invalidIdentity: { + on: { + DISMISS: [ + { + cond: 'isSimpleShareFlow', + target: 'showvcList', + }, + { + actions: 'forwardToParent', + target: 'waitingForData', + }, + ,], + RETRY_VERIFICATION: { + target: 'faceAuth', + }, + }, + }, + sendingAuthenticate: { + invoke: { + src: 'sendAuthenticate', + onDone: [ + { + cond: 'isConsentAlreadyCaptured', + target: 'success', + }, + { + target: 'requestConsent', + actions: 'setLinkedTransactionId', + }, + ], + onError: [ + { + actions: 'SetErrorMessage', + target: 'ShowError', + }, + ], + }, + }, + requestConsent: { + on: { + CONFIRM: { + target: 'sendingConsent', + }, + TOGGLE_CONSENT_CLAIM: { + actions: 'setConsentClaims', + target: 'requestConsent', + }, + DISMISS: { + actions: 'forwardToParent', + target: 'waitingForData', + }, + }, + }, + loadingThumbprint: { + entry: 'loadThumbprint', + on: { + STORE_RESPONSE: { + actions: 'setThumbprint', + target: 'sendingAuthenticate', + }, + }, + }, + sendingConsent: { + invoke: { + src: 'sendConsent', + onDone: { + target: 'success', + }, + onError: [ + { + actions: 'SetErrorMessage', + target: 'ShowError', + }, + ], + }, + }, + success: { + entry: [ + () => + sendEndEvent( + getEndEventData( + TelemetryConstants.FlowType.qrLogin, + TelemetryConstants.EndEventStatus.success, + ), + ), + ], + on: { + CONFIRM: { + target: 'done', + }, + }, + }, + done: { + type: 'final', + data: context => context, + }, + }, + }, + { + actions:QrLoginActions(model), + services:QrLoginServices, + guards: QrLoginGuards, + }, + ); + +export function createQrLoginMachine(serviceRefs: AppServices) { + return qrLoginMachine.withContext({ + ...qrLoginMachine.context, + serviceRefs, + }); +} + + diff --git a/machines/QrLogin/QrLoginMachine.typegen.ts b/machines/QrLogin/QrLoginMachine.typegen.ts new file mode 100644 index 0000000000..336f080ef9 --- /dev/null +++ b/machines/QrLogin/QrLoginMachine.typegen.ts @@ -0,0 +1,64 @@ + + // This file was automatically generated. Edits will be overwritten + + export interface Typegen0 { + '@@xstate/typegen': true; + internalEvents: { + "done.invoke.QrLogin.linkTransaction:invocation[0]": { type: "done.invoke.QrLogin.linkTransaction:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.QrLogin.sendingAuthenticate:invocation[0]": { type: "done.invoke.QrLogin.sendingAuthenticate:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"error.platform.QrLogin.linkTransaction:invocation[0]": { type: "error.platform.QrLogin.linkTransaction:invocation[0]"; data: unknown }; +"error.platform.QrLogin.sendingAuthenticate:invocation[0]": { type: "error.platform.QrLogin.sendingAuthenticate:invocation[0]"; data: unknown }; +"error.platform.QrLogin.sendingConsent:invocation[0]": { type: "error.platform.QrLogin.sendingConsent:invocation[0]"; data: unknown }; +"xstate.init": { type: "xstate.init" }; + }; + invokeSrcNameMap: { + "linkTransaction": "done.invoke.QrLogin.linkTransaction:invocation[0]"; +"sendAuthenticate": "done.invoke.QrLogin.sendingAuthenticate:invocation[0]"; +"sendConsent": "done.invoke.QrLogin.sendingConsent:invocation[0]"; + }; + missingImplementations: { + actions: "SetErrorMessage" | "expandLinkTransResp" | "forwardToParent" | "getFaceAuthConsent" | "loadMyVcs" | "loadThumbprint" | "resetFlowType" | "resetLinkTransactionId" | "resetSelectedVc" | "resetSelectedVoluntaryClaims" | "setClaims" | "setConsentClaims" | "setLinkedTransactionId" | "setMyVcs" | "setScanData" | "setSelectedVc" | "setShowFaceAuthConsent" | "setThumbprint" | "setlinkTransactionResponse" | "storeShowFaceAuthConsent" | "updateShowFaceAuthConsent"; + delays: never; + guards: "isConsentAlreadyCaptured" | "isSimpleShareFlow" | "showFaceAuthConsentScreen"; + services: "linkTransaction" | "sendAuthenticate" | "sendConsent"; + }; + eventsCausingActions: { + "SetErrorMessage": "error.platform.QrLogin.linkTransaction:invocation[0]" | "error.platform.QrLogin.sendingAuthenticate:invocation[0]" | "error.platform.QrLogin.sendingConsent:invocation[0]"; +"expandLinkTransResp": "done.invoke.QrLogin.linkTransaction:invocation[0]"; +"forwardToParent": "CANCEL" | "DISMISS"; +"getFaceAuthConsent": "GET"; +"loadMyVcs": "done.invoke.QrLogin.linkTransaction:invocation[0]"; +"loadThumbprint": "FACE_VALID"; +"resetFlowType": "xstate.init"; +"resetLinkTransactionId": "GET"; +"resetSelectedVc": "xstate.init"; +"resetSelectedVoluntaryClaims": "GET"; +"setClaims": "done.invoke.QrLogin.linkTransaction:invocation[0]"; +"setConsentClaims": "TOGGLE_CONSENT_CLAIM"; +"setLinkedTransactionId": "done.invoke.QrLogin.sendingAuthenticate:invocation[0]"; +"setMyVcs": "STORE_RESPONSE"; +"setScanData": "GET"; +"setSelectedVc": "SELECT_VC"; +"setShowFaceAuthConsent": "FACE_VERIFICATION_CONSENT"; +"setThumbprint": "STORE_RESPONSE"; +"setlinkTransactionResponse": "done.invoke.QrLogin.linkTransaction:invocation[0]"; +"storeShowFaceAuthConsent": "FACE_VERIFICATION_CONSENT"; +"updateShowFaceAuthConsent": "STORE_RESPONSE"; + }; + eventsCausingDelays: { + + }; + eventsCausingGuards: { + "isConsentAlreadyCaptured": "done.invoke.QrLogin.sendingAuthenticate:invocation[0]"; +"isSimpleShareFlow": "CANCEL" | "DISMISS" | "done.invoke.QrLogin.linkTransaction:invocation[0]"; +"showFaceAuthConsentScreen": "VERIFY" | "done.invoke.QrLogin.linkTransaction:invocation[0]"; + }; + eventsCausingServices: { + "linkTransaction": "STORE_RESPONSE"; +"sendAuthenticate": "STORE_RESPONSE"; +"sendConsent": "CONFIRM"; + }; + matchesStates: "ShowError" | "checkFaceAuthConsent" | "done" | "faceAuth" | "faceVerificationConsent" | "invalidIdentity" | "linkTransaction" | "loadMyVcs" | "loadingThumbprint" | "requestConsent" | "sendingAuthenticate" | "sendingConsent" | "showvcList" | "success" | "waitingForData"; + tags: never; + } + \ No newline at end of file diff --git a/machines/QrLogin/QrLoginModel.ts b/machines/QrLogin/QrLoginModel.ts new file mode 100644 index 0000000000..468a495e15 --- /dev/null +++ b/machines/QrLogin/QrLoginModel.ts @@ -0,0 +1,69 @@ +import { createModel } from "xstate/lib/model"; +import { AppServices } from "../../shared/GlobalContext"; +import { VCShareFlowType } from "../../shared/Utils"; +import { VCMetadata } from "../../shared/VCMetadata"; +import { VC, linkTransactionResponse } from "../VerifiableCredential/VCMetaMachine/vc"; + +const QrLoginEvents= { + SELECT_VC: (vc: VC) => ({vc}), + SCANNING_DONE: (params: string) => ({params}), + STORE_RESPONSE: (response: unknown) => ({response}), + STORE_ERROR: (error: Error) => ({error}), + TOGGLE_CONSENT_CLAIM: (enable: boolean, claim: string) => ({ + enable, + claim, + }), + DISMISS: () => ({}), + CONFIRM: () => ({}), + GET: ( + linkCode: string, + flowType: string, + selectedVc: VC, + faceAuthConsentGiven: boolean, + ) => ({ + linkCode, + flowType, + selectedVc, + faceAuthConsentGiven, + }), + VERIFY: () => ({}), + CANCEL: () => ({}), + FACE_VALID: () => ({}), + FACE_INVALID: () => ({}), + RETRY_VERIFICATION: () => ({}), + FACE_VERIFICATION_CONSENT: (isDoNotAskAgainChecked: boolean) => ({ + isDoNotAskAgainChecked, + }), +} + +export const QrLoginmodel = createModel( + { + serviceRefs: {} as AppServices, + selectedVc: {} as VC, + linkCode: '', + flowType: VCShareFlowType.SIMPLE_SHARE, + myVcs: [] as VCMetadata[], + thumbprint: '', + linkTransactionResponse: {} as linkTransactionResponse, + authFactors: [], + authorizeScopes: null, + clientName: {}, + configs: {}, + essentialClaims: [], + linkTransactionId: '', + logoUrl: '', + voluntaryClaims: [], + selectedVoluntaryClaims: [], + errorMessage: '', + domainName: '', + consentClaims: ['name', 'picture'], + isSharing: {}, + linkedTransactionId: '', + showFaceAuthConsent: true as boolean, + }, + { + events:QrLoginEvents, + }, + ); + + \ No newline at end of file diff --git a/machines/QrLogin/QrLoginSelectors.ts b/machines/QrLogin/QrLoginSelectors.ts new file mode 100644 index 0000000000..98e08dcf17 --- /dev/null +++ b/machines/QrLogin/QrLoginSelectors.ts @@ -0,0 +1,117 @@ +import { StateFrom } from "xstate"; +import { getMosipLogo } from "../../components/VC/common/VCUtils"; +import { VCMetadata } from "../../shared/VCMetadata"; +import { qrLoginMachine } from "./QrLoginMachine"; + +type State = StateFrom; + +export function selectMyVcs(state: State) { + return state.context.myVcs; +} + +export function selectIsWaitingForData(state: State) { + return state.matches('waitingForData'); +} + +export function selectDomainName(state: State) { + return state.context.domainName; +} + +export function selectIsLinkTransaction(state: State) { + return state.matches('linkTransaction'); +} + +export function selectIsloadMyVcs(state: State) { + return state.matches('loadMyVcs'); +} + +export function selectIsShowingVcList(state: State) { + return state.matches('showvcList'); +} + +export function selectIsisVerifyingIdentity(state: State) { + return state.matches('faceAuth'); +} + +export function selectIsInvalidIdentity(state: State) { + return state.matches('invalidIdentity'); +} + +export function selectIsShowError(state: State) { + return state.matches('ShowError'); +} + +export function selectIsRequestConsent(state: State) { + return state.matches('requestConsent'); +} + +export function selectIsSendingAuthenticate(state: State) { + return state.matches('sendingAuthenticate'); +} + +export function selectIsSendingConsent(state: State) { + return state.matches('sendingConsent'); +} + +export function selectIsVerifyingSuccesful(state: State) { + return state.matches('success'); +} + +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; +} + +export function selectVoluntaryClaims(state: State) { + return state.context.voluntaryClaims; +} + +export function selectLogoUrl(state: State) { + return state.context.logoUrl; +} + +export function selectClientName(state: State) { + return state.context.clientName; +} + +export function selectErrorMessage(state: State) { + return state.context.errorMessage; +} + +export function selectIsSharing(state: State) { + return state.context.isSharing; +} + +export function selectIsFaceVerificationConsent(state: State) { + return state.matches('faceVerificationConsent'); +} \ No newline at end of file diff --git a/machines/QrLogin/QrLoginServices.ts b/machines/QrLogin/QrLoginServices.ts new file mode 100644 index 0000000000..509525a2d2 --- /dev/null +++ b/machines/QrLogin/QrLoginServices.ts @@ -0,0 +1,111 @@ +import {request} from '../../shared/request'; +import getAllConfigurations, { API_URLS } from "../../shared/api"; +import { ESIGNET_BASE_URL } from "../../shared/constants"; +import { isHardwareKeystoreExists, getJWT } from "../../shared/cryptoutil/cryptoUtil"; +import { getPrivateKey } from "../../shared/keystore/SecureKeystore"; + +export const QrLoginServices= { + linkTransaction: async context => { + const response = await request( + API_URLS.linkTransaction.method, + API_URLS.linkTransaction.buildURL(), + { + requestTime: String(new Date().toISOString()), + request: { + linkCode: context.linkCode, + }, + }, + ESIGNET_BASE_URL, + ); + return response.response; + }, + + sendAuthenticate: async context => { + let privateKey; + const individualId = context.selectedVc.vcMetadata.id; + if (!isHardwareKeystoreExists) { + privateKey = await getPrivateKey( + context.selectedVc.walletBindingResponse?.walletBindingId, + ); + } + + var config = await getAllConfigurations(); + const header = { + alg: 'RS256', + 'x5t#S256': context.thumbprint, + }; + + const payload = { + iss: config.issuer, + sub: individualId, + aud: config.audience, + iat: Math.floor(new Date().getTime() / 1000), + exp: Math.floor(new Date().getTime() / 1000) + 18000, + }; + + const jwt = await getJWT(header, payload, individualId, privateKey); + + const response = await request( + API_URLS.authenticate.method, + API_URLS.authenticate.buildURL(), + { + requestTime: String(new Date().toISOString()), + request: { + linkedTransactionId: context.linkTransactionId, + individualId: individualId, + challengeList: [ + { + authFactorType: 'WLA', + challenge: jwt, + format: 'jwt', + }, + ], + }, + }, + ESIGNET_BASE_URL, + ); + return response.response; + }, + + sendConsent: async context => { + let privateKey; + const individualId = context.selectedVc.vcMetadata.id; + if (!isHardwareKeystoreExists) { + privateKey = await getPrivateKey( + context.selectedVc.walletBindingResponse?.walletBindingId, + ); + } + + const header = { + alg: 'RS256', + 'x5t#S256': context.thumbprint, + }; + const payload = { + accepted_claims: context.essentialClaims + .concat(context.selectedVoluntaryClaims) + .sort(), + permitted_authorized_scopes: context.authorizeScopes, + }; + + const JWT = await getJWT(header, payload, individualId, privateKey); + const jwtComponents = JWT.split('.'); + const detachedSignature = jwtComponents[0] + '.' + jwtComponents[2]; + + const resp = await request( + API_URLS.sendConsent.method, + API_URLS.sendConsent.buildURL(), + { + requestTime: String(new Date().toISOString()), + request: { + linkedTransactionId: context.linkedTransactionId, + acceptedClaims: context.essentialClaims + .concat(context.selectedVoluntaryClaims) + .sort(), + permittedAuthorizeScopes: context.authorizeScopes, + signature: detachedSignature, + }, + }, + ESIGNET_BASE_URL, + ); + }, + } \ No newline at end of file diff --git a/machines/QrLoginMachine.ts b/machines/QrLoginMachine.ts deleted file mode 100644 index b1390db69b..0000000000 --- a/machines/QrLoginMachine.ts +++ /dev/null @@ -1,710 +0,0 @@ -import { - ActorRefFrom, - assign, - EventFrom, - send, - sendParent, - StateFrom, -} from 'xstate'; -import {createModel} from 'xstate/lib/model'; -import {AppServices} from '../shared/GlobalContext'; -import { - ESIGNET_BASE_URL, - FACE_AUTH_CONSENT, - MY_VCS_STORE_KEY, -} from '../shared/constants'; -import {StoreEvents} from './store'; -import { - linkTransactionResponse, - VC, -} from './VerifiableCredential/VCMetaMachine/vc'; -import {request} from '../shared/request'; -import { - getJWT, - isHardwareKeystoreExists, -} from '../shared/cryptoutil/cryptoUtil'; -import { - getBindingCertificateConstant, - getPrivateKey, -} from '../shared/keystore/SecureKeystore'; -import i18n from '../i18n'; -import {parseMetadatas, VCMetadata} from '../shared/VCMetadata'; -import { - getEndEventData, - sendEndEvent, -} from '../shared/telemetry/TelemetryUtils'; -import {TelemetryConstants} from '../shared/telemetry/TelemetryConstants'; -import getAllConfigurations, {API_URLS} from '../shared/api'; -import {VCShareFlowType} from '../shared/Utils'; -import {getMosipLogo} from '../components/VC/common/VCUtils'; - -const model = createModel( - { - serviceRefs: {} as AppServices, - selectedVc: {} as VC, - linkCode: '', - flowType: VCShareFlowType.SIMPLE_SHARE, - myVcs: [] as VCMetadata[], - thumbprint: '', - linkTransactionResponse: {} as linkTransactionResponse, - authFactors: [], - authorizeScopes: null, - clientName: {}, - configs: {}, - essentialClaims: [], - linkTransactionId: '', - logoUrl: '', - voluntaryClaims: [], - selectedVoluntaryClaims: [], - errorMessage: '', - domainName: '', - consentClaims: ['name', 'picture'], - isSharing: {}, - linkedTransactionId: '', - showFaceAuthConsent: true as boolean, - }, - { - events: { - SELECT_VC: (vc: VC) => ({vc}), - SCANNING_DONE: (params: string) => ({params}), - STORE_RESPONSE: (response: unknown) => ({response}), - STORE_ERROR: (error: Error) => ({error}), - TOGGLE_CONSENT_CLAIM: (enable: boolean, claim: string) => ({ - enable, - claim, - }), - DISMISS: () => ({}), - CONFIRM: () => ({}), - GET: ( - linkCode: string, - flowType: string, - selectedVc: VC, - faceAuthConsentGiven: boolean, - ) => ({ - linkCode, - flowType, - selectedVc, - faceAuthConsentGiven, - }), - VERIFY: () => ({}), - CANCEL: () => ({}), - FACE_VALID: () => ({}), - FACE_INVALID: () => ({}), - RETRY_VERIFICATION: () => ({}), - FACE_VERIFICATION_CONSENT: (isConsentGiven: boolean) => ({ - isConsentGiven, - }), - }, - }, -); - -export const QrLoginEvents = model.events; -export type QrLoginRef = ActorRefFrom; - -export const qrLoginMachine = - /** @xstate-layout N4IgpgJg5mDOIC5QEUBOAZA9lAlgOwDocIAbMAYgGUBhAQQDl6BJegcQH0ARAeXoFEA2gAYAuolAAHTLBwAXHJjziQAD0QBGACzqATAQCs+nZv0BmABzqL50zoA0IAJ6IA7KaEFNATnPmv6oUMhHUMAX1CHNCxcQmIyck4mSgBZJMphMSQQKRl5RWU1BF1zFwIvHQrTFxdNCxcANgdnBH16j1NbdT8vfW8q9XDIjGx8AhJ8AGsAFVQAQzxYWYBjPLxyCEUwIjwAN0wJraiRwnG8abmF5dWEfD2l2dWMjOUcuQUlLMKtXQMjEwsrL5bE1EF4XOYCEJ6iEXF4ekIOppzIMQEcYmNJjN5osVu9yGBUKhMKgCBISA8AGbEgC2BDRo1O52xV3eN12mHuj1Ezyyr1WBQ0JQhmlhotMZmM+hcIIQNX0nnUhh65h06hcOhKKPphFgAAtMAB3ADqs1QeHwUHI1F4ADEmAAlZI8yTSN75T6IEIeHT+eo1Lyaeriwwy+pggiwtXw9SKjU6LXDdF6w0ms0Wq0Mah8dDO7Ku-kehBegg+9R+7yB4P6GV+dQRlwBIRqoTqjX1BPRUaUfUGviE4kZ+hZnOiF7594Coo9TSQtyqqUx9zApyINpeCNIoVaYzlUwd45jTCzCDJRwANSWsCoU249r47DvlAACrxKIJR7zx+7QIU-fLofoMaATYWjaKGLjylCOjQi4gSmJoOgNPuSY9jsSzoDgsCyFQ2Z8NQUzsGe1C5nyE6Fr4M4BkI3j6DYtEttWK4tDGEb1H6DbmEYAZschozJgaaEYVh5Bnnw9pMDaACaJFfh8P6uLRZRIoqKl0UI5gyiK9SQtobjUZu0KaLxOqoehmHYYkKRpDJuRkfJRTqRCpj1PoTYBj01QVKGPwVIBHT6AGqq1MZBAUssYC0AArrIurkDatBZoRtDoEwnA2W6cmqJ6rklr6-qVoYjHNP4kI2Jo1ENr01EBiFYVLBF0WxfFiUsGeyWpelBb2cWpbltxVahiKuVqmGXT1IG6heLV4VRTFg7Dp1dlZUWOW9flQaFTW2glrBYK0SqZaqiFtyzOMEBMBAYB4PIsiOAkSSpJQ6Qfi6tnfstf4EABQFdKYoHqKG1EECUrnmEIcJ+FC7YRKiiajCdZ0XVdN13XeUz2pJhFiRJTB0FMTC8It72FD1eUVhtIZMQF2mRjUHT1FYPTQ0MnaEKgYAAI6RXAsjUIosDI1atoOk6L15m9mW-hBX0hD9IGaGBTEIfKvTNoGOhVF4zOw6zBDs1zPN8wsgt0EO2ZE5Lq7S99ql-QrANMe4M6RqNDa6NC5hGTD2oEBseAUJZj3PZkr0ZZOAS+AQzmuZNNGefYSshAYunUdCmvaz7+vc1hFpGwL13rJs2x7AcdJw2znPZ-IeBQHnyNsncDzvE8YukcTq42GUYYtuNgFsQGMqqnWNjwSNiFeACe7e+XeuVzzuf84LBJEiSZKUjSZe61n8813X10NxyTeKC3Ifi2HhYR05LluXHrY1qYO2OanY1sciKJ4Jgl3wFk2pjhLk4AFpGhMQAfKOE4CIGQKnizA8cQwB-3PvZYoEJVT+FVCUaC-hNDeXlDYCoipwRCCIeKEKjIsSXFxO9NulsiguWdpYIMQZoK9F6DKOmX0FYQSITHHoU1p6634qmc0NcEFdWWghNh4MCBlnqGDLQ7EAxvxgeibsho+wr1EUtEmLYIQqmjvbeCKoiqrgCCWTc4JtzeA1qQo8J5zyXk0e3BAIph7jTYvBQIwQLDgWdv4Bo5UkTqjMCFfiglzKOJoX4bS4oGyIR9FUIhCdmgMz0EEqw4pApaGgTrA8dUGoxQiZOGoX0Si1CDFYAKCEkkaChKVUeHQNYNGosdXYp1iBI2unIZoocxGFCRHoKU40VT+H2n4QG8oqig3Bj4LwUIXAhW3lhPeshCmFiROucqhlYK6AXA7Zoxg6wTwgv09JHRfAhT9vAz8-9Cz+HXJUxUCIzBIiRJpaCOkRoNlMGCME8EFlzxzrvRe11Vn2RBtI1oDM-pGAsF4GsdZXJEI8n8Go41wjhCAA */ - model.createMachine( - { - predictableActionArguments: true, - preserveActionOrder: true, - tsTypes: {} as import('./QrLoginMachine.typegen').Typegen0, - schema: { - context: model.initialContext, - events: {} as EventFrom, - }, - id: 'QrLogin', - initial: 'waitingForData', - entry: ['resetSelectedVc', 'resetFlowType'], - states: { - waitingForData: { - on: { - GET: { - actions: [ - 'setScanData', - 'setFaceAuthConsent', - 'resetLinkTransactionId', - 'resetSelectedVoluntaryClaims', - ], - target: 'linkTransaction', - }, - }, - }, - linkTransaction: { - invoke: { - src: 'linkTransaction', - onDone: [ - { - cond: 'isSimpleShareFlow', - actions: [ - 'setlinkTransactionResponse', - 'expandLinkTransResp', - 'setClaims', - ], - target: 'loadMyVcs', - }, - { - actions: [ - 'setlinkTransactionResponse', - 'expandLinkTransResp', - 'setClaims', - ], - target: 'faceAuth', - }, - ], - onError: [ - { - actions: 'SetErrorMessage', - target: 'ShowError', - }, - ], - }, - }, - ShowError: { - on: { - DISMISS: { - actions: 'forwardToParent', - target: 'waitingForData', - }, - }, - }, - loadMyVcs: { - entry: 'loadMyVcs', - on: { - STORE_RESPONSE: { - actions: 'setMyVcs', - target: 'showvcList', - }, - }, - }, - showvcList: { - on: { - SELECT_VC: { - actions: 'setSelectedVc', - }, - VERIFY: [ - { - cond: 'showFaceAuthConsentScreen', - target: 'faceVerificationConsent', - }, - { - target: 'faceAuth', - }, - ], - DISMISS: { - actions: 'forwardToParent', - target: 'waitingForData', - }, - }, - }, - faceVerificationConsent: { - on: { - FACE_VERIFICATION_CONSENT: { - actions: ['storeShowFaceAuthConsent', 'setShowFaceAuthConsent'], - target: 'faceAuth', - }, - DISMISS: { - target: 'showvcList', - }, - }, - }, - faceAuth: { - on: { - FACE_VALID: { - target: 'loadingThumbprint', - }, - FACE_INVALID: { - target: 'invalidIdentity', - }, - CANCEL: [ - { - cond: 'isSimpleShareFlow', - target: 'showvcList', - }, - { - actions: 'forwardToParent', - target: 'waitingForData', - }, - ], - }, - }, - invalidIdentity: { - on: { - DISMISS: { - target: 'showvcList', - }, - RETRY_VERIFICATION: { - target: 'faceAuth', - }, - }, - }, - sendingAuthenticate: { - invoke: { - src: 'sendAuthenticate', - onDone: [ - { - cond: 'isConsentAlreadyCaptured', - target: 'success', - }, - { - target: 'requestConsent', - actions: 'setLinkedTransactionId', - }, - ], - onError: [ - { - actions: 'SetErrorMessage', - target: 'ShowError', - }, - ], - }, - }, - requestConsent: { - on: { - CONFIRM: { - target: 'sendingConsent', - }, - TOGGLE_CONSENT_CLAIM: { - actions: 'setConsentClaims', - target: 'requestConsent', - }, - DISMISS: { - actions: 'forwardToParent', - target: 'waitingForData', - }, - }, - }, - loadingThumbprint: { - entry: 'loadThumbprint', - on: { - STORE_RESPONSE: { - actions: 'setThumbprint', - target: 'sendingAuthenticate', - }, - }, - }, - sendingConsent: { - invoke: { - src: 'sendConsent', - onDone: { - target: 'success', - }, - onError: [ - { - actions: 'SetErrorMessage', - target: 'ShowError', - }, - ], - }, - }, - success: { - entry: [ - () => - sendEndEvent( - getEndEventData( - TelemetryConstants.FlowType.qrLogin, - TelemetryConstants.EndEventStatus.success, - ), - ), - ], - on: { - CONFIRM: { - target: 'done', - }, - }, - }, - done: { - type: 'final', - data: context => context, - }, - }, - }, - { - actions: { - setShowFaceAuthConsent: model.assign({ - showFaceAuthConsent: (_, event) => { - return !event.isConsentGiven; - }, - }), - - storeShowFaceAuthConsent: send( - (context, event) => - StoreEvents.SET(FACE_AUTH_CONSENT, !event.isConsentGiven), - { - to: context => context.serviceRefs.store, - }, - ), - - forwardToParent: sendParent('DISMISS'), - - setScanData: model.assign((context, event) => { - const linkCode = event.linkCode; - const flowType = event.flowType; - const selectedVc = event.selectedVc; - return { - ...context, - linkCode: linkCode, - flowType: flowType, - selectedVc: selectedVc, - }; - }), - - setFaceAuthConsent: assign({ - showFaceAuthConsent: (context, event) => { - return event.faceAuthConsentGiven; - }, - }), - - // TODO: loaded VCMetadatas are not used anywhere. remove? - loadMyVcs: send(StoreEvents.GET(MY_VCS_STORE_KEY), { - to: context => context.serviceRefs.store, - }), - - setMyVcs: model.assign({ - myVcs: (_context, event) => - parseMetadatas((event.response || []) as object[]), - }), - - loadThumbprint: send( - context => - StoreEvents.GET( - getBindingCertificateConstant( - context.selectedVc.walletBindingResponse?.walletBindingId, - ), - ), - {to: context => context.serviceRefs.store}, - ), - setThumbprint: assign({ - thumbprint: (_context, event) => { - return (event.response || '') as string; - }, - }), - resetLinkTransactionId: model.assign({ - linkTransactionId: () => '', - }), - - resetSelectedVoluntaryClaims: model.assign({ - selectedVoluntaryClaims: () => [], - }), - - setSelectedVc: assign({ - selectedVc: (context, event) => { - return {...event.vc}; - }, - }), - - resetSelectedVc: assign({ - selectedVc: {} as VC, - }), - - resetFlowType: assign({ - flowType: VCShareFlowType.SIMPLE_SHARE, - }), - - setlinkTransactionResponse: assign({ - linkTransactionResponse: (context, event) => - event.data as linkTransactionResponse, - }), - - expandLinkTransResp: assign({ - authFactors: context => context.linkTransactionResponse.authFactors, - - authorizeScopes: context => - context.linkTransactionResponse.authorizeScopes, - - clientName: context => context.linkTransactionResponse.clientName, - - configs: context => context.linkTransactionResponse.configs, - - essentialClaims: context => - context.linkTransactionResponse.essentialClaims, - - linkTransactionId: context => - context.linkTransactionResponse.linkTransactionId, - - logoUrl: context => context.linkTransactionResponse.logoUrl, - - voluntaryClaims: context => - context.linkTransactionResponse.voluntaryClaims, - }), - - setClaims: context => { - context.voluntaryClaims.map(claim => { - context.isSharing[claim] = false; - }); - }, - - SetErrorMessage: assign({ - errorMessage: (context, event) => { - const message = event.data.name; - const ID_ERRORS_MAP = { - invalid_link_code: 'invalidQR', - }; - const errorMessage = ID_ERRORS_MAP[message] - ? i18n.t(`errors.${ID_ERRORS_MAP[message]}`, { - ns: 'QrLogin', - }) - : i18n.t(`errors.genericError`, { - ns: 'common', - }); - - return errorMessage; - }, - }), - - setConsentClaims: assign({ - isSharing: (context, event) => { - context.isSharing[event.claim] = !event.enable; - if (!event.enable) { - context.selectedVoluntaryClaims.push(event.claim); - } else { - context.selectedVoluntaryClaims = - context.selectedVoluntaryClaims.filter( - eachClaim => eachClaim !== event.claim, - ); - } - return {...context.isSharing}; - }, - }), - setLinkedTransactionId: assign({ - linkedTransactionId: (context, event) => - event.data.linkedTransactionId as string, - }), - }, - services: { - linkTransaction: async context => { - const response = await request( - API_URLS.linkTransaction.method, - API_URLS.linkTransaction.buildURL(), - { - requestTime: String(new Date().toISOString()), - request: { - linkCode: context.linkCode, - }, - }, - ESIGNET_BASE_URL, - ); - return response.response; - }, - - sendAuthenticate: async context => { - let privateKey; - const individualId = context.selectedVc.vcMetadata.id; - if (!isHardwareKeystoreExists) { - privateKey = await getPrivateKey( - context.selectedVc.walletBindingResponse?.walletBindingId, - ); - } - - var config = await getAllConfigurations(); - const header = { - alg: 'RS256', - 'x5t#S256': context.thumbprint, - }; - - const payload = { - iss: config.issuer, - sub: individualId, - aud: config.audience, - iat: Math.floor(new Date().getTime() / 1000), - exp: Math.floor(new Date().getTime() / 1000) + 18000, - }; - - const jwt = await getJWT(header, payload, individualId, privateKey); - - const response = await request( - API_URLS.authenticate.method, - API_URLS.authenticate.buildURL(), - { - requestTime: String(new Date().toISOString()), - request: { - linkedTransactionId: context.linkTransactionId, - individualId: individualId, - challengeList: [ - { - authFactorType: 'WLA', - challenge: jwt, - format: 'jwt', - }, - ], - }, - }, - ESIGNET_BASE_URL, - ); - return response.response; - }, - - sendConsent: async context => { - let privateKey; - const individualId = context.selectedVc.vcMetadata.id; - if (!isHardwareKeystoreExists) { - privateKey = await getPrivateKey( - context.selectedVc.walletBindingResponse?.walletBindingId, - ); - } - - const header = { - alg: 'RS256', - 'x5t#S256': context.thumbprint, - }; - const payload = { - accepted_claims: context.essentialClaims - .concat(context.selectedVoluntaryClaims) - .sort(), - permitted_authorized_scopes: context.authorizeScopes, - }; - - const JWT = await getJWT(header, payload, individualId, privateKey); - const jwtComponents = JWT.split('.'); - const detachedSignature = jwtComponents[0] + '.' + jwtComponents[2]; - - const resp = await request( - API_URLS.sendConsent.method, - API_URLS.sendConsent.buildURL(), - { - requestTime: String(new Date().toISOString()), - request: { - linkedTransactionId: context.linkedTransactionId, - acceptedClaims: context.essentialClaims - .concat(context.selectedVoluntaryClaims) - .sort(), - permittedAuthorizeScopes: context.authorizeScopes, - signature: detachedSignature, - }, - }, - ESIGNET_BASE_URL, - ); - }, - }, - guards: { - showFaceAuthConsentScreen: context => { - return context.showFaceAuthConsent; - }, - - isConsentAlreadyCaptured: (_, event) => - event.data?.consentAction === 'NOCAPTURE', - - isSimpleShareFlow: (context, _event) => - context.flowType === VCShareFlowType.SIMPLE_SHARE, - }, - }, - ); - -export function createQrLoginMachine(serviceRefs: AppServices) { - return qrLoginMachine.withContext({ - ...qrLoginMachine.context, - serviceRefs, - }); -} - -type State = StateFrom; - -export function selectMyVcs(state: State) { - return state.context.myVcs; -} - -export function selectIsWaitingForData(state: State) { - return state.matches('waitingForData'); -} - -export function selectDomainName(state: State) { - return state.context.domainName; -} - -export function selectIsLinkTransaction(state: State) { - return state.matches('linkTransaction'); -} - -export function selectIsloadMyVcs(state: State) { - return state.matches('loadMyVcs'); -} - -export function selectIsShowingVcList(state: State) { - return state.matches('showvcList'); -} - -export function selectIsisVerifyingIdentity(state: State) { - return state.matches('faceAuth'); -} - -export function selectIsInvalidIdentity(state: State) { - return state.matches('invalidIdentity'); -} - -export function selectIsShowError(state: State) { - return state.matches('ShowError'); -} - -export function selectIsRequestConsent(state: State) { - return state.matches('requestConsent'); -} - -export function selectIsSendingAuthenticate(state: State) { - return state.matches('sendingAuthenticate'); -} - -export function selectIsSendingConsent(state: State) { - return state.matches('sendingConsent'); -} - -export function selectIsVerifyingSuccesful(state: State) { - return state.matches('success'); -} - -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; -} - -export function selectVoluntaryClaims(state: State) { - return state.context.voluntaryClaims; -} - -export function selectLogoUrl(state: State) { - return state.context.logoUrl; -} - -export function selectClientName(state: State) { - return state.context.clientName; -} - -export function selectErrorMessage(state: State) { - return state.context.errorMessage; -} - -export function selectIsSharing(state: State) { - return state.context.isSharing; -} - -export function selectIsFaceVerificationConsent(state: State) { - return state.matches('faceVerificationConsent'); -} diff --git a/machines/QrLoginMachine.typegen.ts b/machines/QrLoginMachine.typegen.ts deleted file mode 100644 index 9dfefd74cc..0000000000 --- a/machines/QrLoginMachine.typegen.ts +++ /dev/null @@ -1,95 +0,0 @@ -// This file was automatically generated. Edits will be overwritten - -export interface Typegen0 { - '@@xstate/typegen': true; - internalEvents: { - 'done.invoke.QrLogin.linkTransaction:invocation[0]': { - type: 'done.invoke.QrLogin.linkTransaction:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.QrLogin.sendingAuthenticate:invocation[0]': { - type: 'done.invoke.QrLogin.sendingAuthenticate:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'error.platform.QrLogin.linkTransaction:invocation[0]': { - type: 'error.platform.QrLogin.linkTransaction:invocation[0]'; - data: unknown; - }; - 'error.platform.QrLogin.sendingAuthenticate:invocation[0]': { - type: 'error.platform.QrLogin.sendingAuthenticate:invocation[0]'; - data: unknown; - }; - 'error.platform.QrLogin.sendingConsent:invocation[0]': { - type: 'error.platform.QrLogin.sendingConsent:invocation[0]'; - data: unknown; - }; - 'xstate.init': {type: 'xstate.init'}; - }; - invokeSrcNameMap: { - linkTransaction: 'done.invoke.QrLogin.linkTransaction:invocation[0]'; - sendAuthenticate: 'done.invoke.QrLogin.sendingAuthenticate:invocation[0]'; - sendConsent: 'done.invoke.QrLogin.sendingConsent:invocation[0]'; - }; - missingImplementations: { - actions: never; - delays: never; - guards: never; - services: never; - }; - eventsCausingActions: { - SetErrorMessage: - | 'error.platform.QrLogin.linkTransaction:invocation[0]' - | 'error.platform.QrLogin.sendingAuthenticate:invocation[0]' - | 'error.platform.QrLogin.sendingConsent:invocation[0]'; - expandLinkTransResp: 'done.invoke.QrLogin.linkTransaction:invocation[0]'; - forwardToParent: 'CANCEL' | 'DISMISS'; - loadMyVcs: 'done.invoke.QrLogin.linkTransaction:invocation[0]'; - loadThumbprint: 'FACE_VALID'; - resetFlowType: 'xstate.init'; - 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'; - setShowFaceAuthConsent: 'FACE_VERIFICATION_CONSENT'; - setThumbprint: 'STORE_RESPONSE'; - setlinkTransactionResponse: 'done.invoke.QrLogin.linkTransaction:invocation[0]'; - storeShowFaceAuthConsent: 'FACE_VERIFICATION_CONSENT'; - }; - eventsCausingDelays: {}; - eventsCausingGuards: { - isConsentAlreadyCaptured: 'done.invoke.QrLogin.sendingAuthenticate:invocation[0]'; - isSimpleShareFlow: - | 'CANCEL' - | 'done.invoke.QrLogin.linkTransaction:invocation[0]'; - showFaceAuthConsentScreen: 'VERIFY'; - }; - eventsCausingServices: { - linkTransaction: 'GET'; - sendAuthenticate: 'STORE_RESPONSE'; - sendConsent: 'CONFIRM'; - }; - matchesStates: - | 'ShowError' - | 'done' - | 'faceAuth' - | 'faceVerificationConsent' - | 'invalidIdentity' - | 'linkTransaction' - | 'loadMyVcs' - | 'loadingThumbprint' - | 'requestConsent' - | 'sendingAuthenticate' - | 'sendingConsent' - | 'showvcList' - | 'success' - | 'waitingForData'; - tags: never; -} diff --git a/machines/VerifiableCredential/VCItemMachine/VCItemMachine.typegen.ts b/machines/VerifiableCredential/VCItemMachine/VCItemMachine.typegen.ts index 2be8d9df30..ad284e1ffb 100644 --- a/machines/VerifiableCredential/VCItemMachine/VCItemMachine.typegen.ts +++ b/machines/VerifiableCredential/VCItemMachine/VCItemMachine.typegen.ts @@ -1,384 +1,123 @@ -// 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-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'}; - 'xstate.stop': {type: 'xstate.stop'}; - }; - 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' - | 'requestVcContext' - | 'resetIsMachineInKebabPopupState' - | 'resetPrivateKey' - | 'sendActivationStartEvent' - | 'sendActivationSuccessEvent' - | 'sendBackupEvent' - | 'sendDownloadLimitExpire' - | 'sendTelemetryEvents' - | 'sendUserCancelledActivationFailedEndEvent' - | 'sendVcUpdated' - | 'sendVerificationError' - | 'sendWalletBindingErrorEvent' - | 'sendWalletBindingSuccess' - | 'setCommunicationDetails' - | 'setContext' - | '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: 'GET_VC_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'; - requestVcContext: 'DISMISS' | 'REFRESH' | 'STORE_ERROR' | 'xstate.init'; - resetIsMachineInKebabPopupState: - | '' - | 'ADD_WALLET_BINDING_ID' - | 'CANCEL' - | 'CLOSE_VC_MODAL' - | 'DISMISS' - | 'REFRESH' - | 'REMOVE' - | 'SHOW_ACTIVITY' - | 'done.invoke.vc-item-machine.kebabPopUp.triggerAutoBackup:invocation[0]' - | 'xstate.stop'; - 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]'; - 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: 'CREDENTIAL_DOWNLOADED' | 'GET_VC_RESPONSE'; - 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'; - 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: 'GET_VC_RESPONSE' | 'STORE_ERROR'; - 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' - | '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' - | { - 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; -} + // 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-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" }; +"xstate.stop": { type: "xstate.stop" }; + }; + 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" | "requestVcContext" | "resetIsMachineInKebabPopupState" | "resetPrivateKey" | "sendActivationStartEvent" | "sendActivationSuccessEvent" | "sendBackupEvent" | "sendDownloadLimitExpire" | "sendTelemetryEvents" | "sendUserCancelledActivationFailedEndEvent" | "sendVcUpdated" | "sendVerificationError" | "sendWalletBindingErrorEvent" | "sendWalletBindingSuccess" | "setCommunicationDetails" | "setContext" | "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": "GET_VC_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"; +"requestVcContext": "DISMISS" | "REFRESH" | "STORE_ERROR" | "xstate.init"; +"resetIsMachineInKebabPopupState": "" | "ADD_WALLET_BINDING_ID" | "CANCEL" | "CLOSE_VC_MODAL" | "DISMISS" | "REFRESH" | "REMOVE" | "SHOW_ACTIVITY" | "done.invoke.vc-item-machine.kebabPopUp.triggerAutoBackup:invocation[0]" | "xstate.stop"; +"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]"; +"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": "CREDENTIAL_DOWNLOADED" | "GET_VC_RESPONSE"; +"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"; +"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": "GET_VC_RESPONSE" | "STORE_ERROR"; +"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" | "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" | { "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; + } + \ No newline at end of file diff --git a/machines/VerifiableCredential/VCMetaMachine/VCMetaMachine.typegen.ts b/machines/VerifiableCredential/VCMetaMachine/VCMetaMachine.typegen.ts index 4b1d7b9d52..ae8ec8f99f 100644 --- a/machines/VerifiableCredential/VCMetaMachine/VCMetaMachine.typegen.ts +++ b/machines/VerifiableCredential/VCMetaMachine/VCMetaMachine.typegen.ts @@ -1,106 +1,58 @@ -// This file was automatically generated. Edits will be overwritten -export interface Typegen0 { - '@@xstate/typegen': true; - internalEvents: { - 'done.invoke.vcMeta.ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion:invocation[0]': { - type: 'done.invoke.vcMeta.ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'xstate.init': {type: 'xstate.init'}; - }; - invokeSrcNameMap: { - isUserSignedAlready: 'done.invoke.vcMeta.ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion:invocation[0]'; - }; - missingImplementations: { - actions: - | 'addVcToInProgressDownloads' - | 'getVcItemResponse' - | 'loadMyVcs' - | 'loadReceivedVcs' - | 'logTamperedVCsremoved' - | 'prependToMyVcsMetadata' - | 'removeDownloadFailedVcsFromStorage' - | 'removeDownloadingFailedVcsFromMyVcs' - | 'removeVcFromInProgressDownlods' - | 'removeVcFromMyVcsMetadata' - | 'resetDownloadFailedVcs' - | 'resetInProgressVcsDownloaded' - | 'resetTamperedVcs' - | 'resetVerificationErrorMessage' - | 'resetWalletBindingSuccess' - | 'sendBackupEvent' - | 'setDownloadedVc' - | 'setDownloadingFailedVcs' - | 'setMyVcs' - | 'setReceivedVcs' - | 'setUpdatedVcMetadatas' - | 'setVerificationErrorMessage' - | 'setWalletBindingSuccess' - | 'updateMyVcsMetadata'; - delays: never; - guards: 'isAnyVcTampered' | 'isSignedIn'; - services: 'isUserSignedAlready'; - }; - eventsCausingActions: { - addVcToInProgressDownloads: 'ADD_VC_TO_IN_PROGRESS_DOWNLOADS'; - getVcItemResponse: 'GET_VC_ITEM'; - loadMyVcs: - | 'REFRESH_MY_VCS' - | 'REFRESH_RECEIVED_VCS' - | 'STORE_RESPONSE' - | 'VERIFY_VC_FAILED' - | 'xstate.init'; - loadReceivedVcs: 'REFRESH_RECEIVED_VCS' | 'STORE_RESPONSE'; - logTamperedVCsremoved: 'done.invoke.vcMeta.ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion:invocation[0]'; - prependToMyVcsMetadata: 'VC_ADDED'; - removeDownloadFailedVcsFromStorage: 'DELETE_VC'; - removeDownloadingFailedVcsFromMyVcs: 'STORE_RESPONSE'; - removeVcFromInProgressDownlods: - | 'DOWNLOAD_LIMIT_EXPIRED' - | 'REMOVE_VC_FROM_IN_PROGRESS_DOWNLOADS' - | 'VERIFY_VC_FAILED'; - removeVcFromMyVcsMetadata: 'REMOVE_VC_FROM_CONTEXT'; - resetDownloadFailedVcs: 'STORE_RESPONSE'; - resetInProgressVcsDownloaded: 'RESET_IN_PROGRESS_VCS_DOWNLOADED'; - resetTamperedVcs: 'REMOVE_TAMPERED_VCS'; - resetVerificationErrorMessage: 'RESET_VERIFY_ERROR'; - resetWalletBindingSuccess: 'RESET_WALLET_BINDING_SUCCESS'; - sendBackupEvent: 'done.invoke.vcMeta.ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion:invocation[0]'; - setDownloadedVc: 'VC_DOWNLOADED'; - setDownloadingFailedVcs: 'DOWNLOAD_LIMIT_EXPIRED'; - setMyVcs: 'STORE_RESPONSE'; - setReceivedVcs: 'STORE_RESPONSE'; - setUpdatedVcMetadatas: 'VC_METADATA_UPDATED'; - setVerificationErrorMessage: 'VERIFY_VC_FAILED'; - setWalletBindingSuccess: 'WALLET_BINDING_SUCCESS'; - updateMyVcsMetadata: 'VC_METADATA_UPDATED'; - }; - eventsCausingDelays: {}; - eventsCausingGuards: { - isAnyVcTampered: 'SHOW_TAMPERED_POPUP'; - isSignedIn: 'done.invoke.vcMeta.ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion:invocation[0]'; - }; - eventsCausingServices: { - isUserSignedAlready: 'REMOVE_TAMPERED_VCS'; - }; - matchesStates: - | 'deletingFailedVcs' - | 'ready' - | 'ready.myVcs' - | 'ready.receivedVcs' - | 'ready.showTamperedPopup' - | 'ready.tamperedVCs' - | 'ready.tamperedVCs.idle' - | 'ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion' - | { - ready?: - | 'myVcs' - | 'receivedVcs' - | 'showTamperedPopup' - | 'tamperedVCs' - | {tamperedVCs?: 'idle' | 'triggerAutoBackupForTamperedVcDeletion'}; - }; - tags: never; -} + // This file was automatically generated. Edits will be overwritten + + export interface Typegen0 { + '@@xstate/typegen': true; + internalEvents: { + "done.invoke.vcMeta.ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion:invocation[0]": { type: "done.invoke.vcMeta.ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"xstate.init": { type: "xstate.init" }; + }; + invokeSrcNameMap: { + "isUserSignedAlready": "done.invoke.vcMeta.ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion:invocation[0]"; + }; + missingImplementations: { + actions: "addVcToInProgressDownloads" | "getVcItemResponse" | "loadMyVcs" | "loadReceivedVcs" | "logTamperedVCsremoved" | "prependToMyVcsMetadata" | "removeDownloadFailedVcsFromStorage" | "removeDownloadingFailedVcsFromMyVcs" | "removeVcFromInProgressDownlods" | "removeVcFromMyVcsMetadata" | "resetDownloadFailedVcs" | "resetInProgressVcsDownloaded" | "resetTamperedVcs" | "resetVerificationErrorMessage" | "resetWalletBindingSuccess" | "sendBackupEvent" | "setDownloadedVc" | "setDownloadingFailedVcs" | "setMyVcs" | "setReceivedVcs" | "setUpdatedVcMetadatas" | "setVerificationErrorMessage" | "setWalletBindingSuccess" | "updateMyVcsMetadata"; + delays: never; + guards: "isAnyVcTampered" | "isSignedIn"; + services: "isUserSignedAlready"; + }; + eventsCausingActions: { + "addVcToInProgressDownloads": "ADD_VC_TO_IN_PROGRESS_DOWNLOADS"; +"getVcItemResponse": "GET_VC_ITEM"; +"loadMyVcs": "DOWNLOAD_LIMIT_EXPIRED" | "REFRESH_MY_VCS" | "REFRESH_RECEIVED_VCS" | "STORE_RESPONSE" | "VERIFY_VC_FAILED" | "xstate.init"; +"loadReceivedVcs": "REFRESH_RECEIVED_VCS" | "STORE_RESPONSE"; +"logTamperedVCsremoved": "done.invoke.vcMeta.ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion:invocation[0]"; +"prependToMyVcsMetadata": "VC_ADDED"; +"removeDownloadFailedVcsFromStorage": "DELETE_VC"; +"removeDownloadingFailedVcsFromMyVcs": "STORE_RESPONSE"; +"removeVcFromInProgressDownlods": "DOWNLOAD_LIMIT_EXPIRED" | "REMOVE_VC_FROM_IN_PROGRESS_DOWNLOADS" | "VERIFY_VC_FAILED"; +"removeVcFromMyVcsMetadata": "REMOVE_VC_FROM_CONTEXT"; +"resetDownloadFailedVcs": "STORE_RESPONSE"; +"resetInProgressVcsDownloaded": "RESET_IN_PROGRESS_VCS_DOWNLOADED"; +"resetTamperedVcs": "REMOVE_TAMPERED_VCS"; +"resetVerificationErrorMessage": "RESET_VERIFY_ERROR"; +"resetWalletBindingSuccess": "RESET_WALLET_BINDING_SUCCESS"; +"sendBackupEvent": "done.invoke.vcMeta.ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion:invocation[0]"; +"setDownloadedVc": "VC_DOWNLOADED"; +"setDownloadingFailedVcs": "DOWNLOAD_LIMIT_EXPIRED"; +"setMyVcs": "STORE_RESPONSE"; +"setReceivedVcs": "STORE_RESPONSE"; +"setUpdatedVcMetadatas": "VC_METADATA_UPDATED"; +"setVerificationErrorMessage": "VERIFY_VC_FAILED"; +"setWalletBindingSuccess": "WALLET_BINDING_SUCCESS"; +"updateMyVcsMetadata": "VC_METADATA_UPDATED"; + }; + eventsCausingDelays: { + + }; + eventsCausingGuards: { + "isAnyVcTampered": "SHOW_TAMPERED_POPUP"; +"isSignedIn": "done.invoke.vcMeta.ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion:invocation[0]"; + }; + eventsCausingServices: { + "isUserSignedAlready": "REMOVE_TAMPERED_VCS"; + }; + matchesStates: "deletingFailedVcs" | "ready" | "ready.myVcs" | "ready.receivedVcs" | "ready.showTamperedPopup" | "ready.tamperedVCs" | "ready.tamperedVCs.idle" | "ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion" | { "ready"?: "myVcs" | "receivedVcs" | "showTamperedPopup" | "tamperedVCs" | { "tamperedVCs"?: "idle" | "triggerAutoBackupForTamperedVcDeletion"; }; }; + tags: never; + } + \ No newline at end of file diff --git a/machines/bleShare/scan/scanActions.ts b/machines/bleShare/scan/scanActions.ts new file mode 100644 index 0000000000..b63210316d --- /dev/null +++ b/machines/bleShare/scan/scanActions.ts @@ -0,0 +1,327 @@ +import { Linking } from "react-native"; +import { getDeviceNameSync } from "react-native-device-info"; +import { assign, spawn, send, DoneInvokeEvent } from "xstate"; +import { VCShareFlowType } from "../../../shared/Utils"; +import { VCMetadata } from "../../../shared/VCMetadata"; +import { logState } from "../../../shared/commonUtil"; +import { SHOW_FACE_AUTH_CONSENT_SHARE_FLOW, isAndroid, DEFAULT_QR_HEADER, MY_VCS_STORE_KEY, MY_LOGIN_STORE_KEY } from "../../../shared/constants"; +import { getIdType } from "../../../shared/openId4VCI/Utils"; +import { TelemetryConstants } from "../../../shared/telemetry/TelemetryConstants"; +import { sendImpressionEvent, getImpressionEventData, sendEndEvent, getEndEventData, sendErrorEvent, getErrorEventData, sendStartEvent, getStartEventData } from "../../../shared/telemetry/TelemetryUtils"; +import { createQrLoginMachine } from "../../QrLogin/QrLoginMachine"; +import { VcMetaEvents } from "../../VerifiableCredential/VCMetaMachine/VCMetaEvents"; +import { ActivityLogEvents } from "../../activityLog"; +import { StoreEvents } from "../../store"; +import tuvali from '@mosip/tuvali'; +import BluetoothStateManager from 'react-native-bluetooth-state-manager'; + +const {wallet, EventTypes, VerificationStatus} = tuvali; +export const ScanActions =(model:any,QR_LOGIN_REF_ID:any)=>{ + return{ + setChildRef: assign({ + QrLoginRef: (context:any) => { + const service = spawn( + createQrLoginMachine(context.serviceRefs), + QR_LOGIN_REF_ID, + ); + service.subscribe(logState); + return service; + }, + }), + + updateShowFaceAuthConsent: model.assign({ + showFaceAuthConsent: (_, event) => { + return event.response || event.response === null; + }, + }), + + + setShowFaceAuthConsent: model.assign({ + showFaceAuthConsent: (_, event) => { + return !event.isDoNotAskAgainChecked; + }, + }), + + getFaceAuthConsent: send(StoreEvents.GET(SHOW_FACE_AUTH_CONSENT_SHARE_FLOW), { + to: (context:any) => context.serviceRefs.store, + }), + + storeShowFaceAuthConsent: send( + (context, event) => + StoreEvents.SET(SHOW_FACE_AUTH_CONSENT_SHARE_FLOW, !event.isDoNotAskAgainChecked), + { + to: (context:any) => context.serviceRefs.store, + }, + ), + + sendScanData: context => + context.QrLoginRef.send({ + type: 'GET', + linkCode: context.linkCode, + flowType: context.flowType, + selectedVc: context.selectedVc, + }), + + openBluetoothSettings: () => { + isAndroid() + ? BluetoothStateManager.openSettings().catch() + : Linking.openURL('App-Prefs:Bluetooth'); + }, + + openAppPermission: () => Linking.openSettings(), + + enableLocation: async () => { + await Linking.sendIntent('android.settings.LOCATION_SOURCE_SETTINGS'); + }, + + setUri: model.assign({ + openId4VpUri: (_context, event) => event.params, + }), + + clearUri: assign({ + openId4VpUri: '', + }), + + setSenderInfo: assign({ + senderInfo: () => { + return {name: 'Wallet', deviceName: 'Wallet', deviceId: ''}; + }, + }), + + setReceiverInfo: assign({ + receiverInfo: () => { + return {name: 'Verifier', deviceName: 'Verifier', deviceId: ''}; + }, + }), + + setReadyForBluetoothStateCheck: model.assign({ + readyForBluetoothStateCheck: () => true, + }), + + setBleError: assign({ + bleError: (_context, event) => event.bleError, + }), + + setSelectedVc: assign({ + selectedVc: (_context, event) => event.vc, + }), + + resetSelectedVc: assign({ + selectedVc: {}, + }), + + resetShowQuickShareSuccessBanner: assign({ + showQuickShareSuccessBanner: false, + }), + + setShowQuickShareSuccessBanner: assign({ + showQuickShareSuccessBanner: true, + }), + + setFlowType: assign({ + flowType: (_context, event) => event.flowType, + }), + + resetFlowType: assign({ + flowType: VCShareFlowType.SIMPLE_SHARE, + }), + + registerLoggers: assign({ + loggers: () => { + if (__DEV__) { + return [ + wallet.handleDataEvents(event => { + console.log( + getDeviceNameSync(), + '', + JSON.stringify(event).slice(0, 100), + ); + }), + ]; + } else { + return []; + } + }, + }), + + removeLoggers: assign({ + loggers: ({loggers}) => { + loggers?.forEach(logger => logger.remove()); + return []; + }, + }), + + setShareLogTypeUnverified: model.assign({ + shareLogType: 'VC_SHARED', + }), + + setShareLogTypeVerified: model.assign({ + shareLogType: 'PRESENCE_VERIFIED_AND_VC_SHARED', + }), + + updateFaceCaptureBannerStatus: model.assign({ + showFaceCaptureSuccessBanner: true, + }), + + resetFaceCaptureBannerStatus: model.assign({ + showFaceCaptureSuccessBanner: false, + }), + + logShared: send( + (context:any) => { + const vcMetadata = context.selectedVc?.vcMetadata; + return ActivityLogEvents.LOG_ACTIVITY({ + _vcKey: VCMetadata.fromVC(vcMetadata).getVcKey(), + type: context.shareLogType + ? context.shareLogType + : 'VC_SHARED_WITH_VERIFICATION_CONSENT', + id: vcMetadata.id, + idType: getIdType(vcMetadata.issuer), + timestamp: Date.now(), + deviceName: + context.receiverInfo.name || context.receiverInfo.deviceName, + vcLabel: vcMetadata.id, + }); + }, + {to: context => context.serviceRefs.activityLog}, + ), + + logFailedVerification: send( + context => + ActivityLogEvents.LOG_ACTIVITY({ + _vcKey: VCMetadata.fromVC(context.selectedVc).getVcKey(), + type: 'PRESENCE_VERIFICATION_FAILED', + timestamp: Date.now(), + idType: getIdType(context.selectedVc.vcMetadata.issuer), + id: context.selectedVc.vcMetadata.id, + deviceName: + context.receiverInfo.name || context.receiverInfo.deviceName, + vcLabel: context.selectedVc.vcMetadata.id, + }), + {to: context => context.serviceRefs.activityLog}, + ), + + setLinkCode: assign({ + linkCode: (_, event) => + new URL(event.params).searchParams.get('linkCode'), + }), + setQuickShareData: assign({ + quickShareData: (_, event) => + JSON.parse(decodeData(event.params.split(DEFAULT_QR_HEADER)[1])), + }), + loadMetaDataToMemory: send( + (context:any) => { + let metadata = VCMetadata.fromVC(context.quickShareData?.meta); + return StoreEvents.PREPEND(MY_VCS_STORE_KEY, metadata); + }, + {to: context => context.serviceRefs.store}, + ), + loadVCDataToMemory: send( + (context:any) => { + let metadata = VCMetadata.fromVC(context.quickShareData?.meta); + + let verifiableCredential = metadata.isFromOpenId4VCI() + ? {credential: context.quickShareData?.verifiableCredential} + : context.quickShareData?.verifiableCredential; + + return StoreEvents.SET(metadata.getVcKey(), { + verifiableCredential: verifiableCredential, + }); + }, + {to: context => context.serviceRefs.store}, + ), + refreshVCs: send(VcMetaEvents.REFRESH_MY_VCS, { + to: context => context.serviceRefs.vcMeta, + }), + storeLoginItem: send( + (_context, event) => { + return StoreEvents.PREPEND( + MY_LOGIN_STORE_KEY, + (event as DoneInvokeEvent).data, + ); + }, + {to: (context:any) => context.serviceRefs.store}, + ), + + storingActivityLog: send( + (_, event) => + ActivityLogEvents.LOG_ACTIVITY({ + _vcKey: '', + id: event.response.selectedVc.vcMetadata.id, + idType: getIdType(event.response.selectedVc.vcMetadata.issuer), + type: 'QRLOGIN_SUCCESFULL', + timestamp: Date.now(), + deviceName: '', + vcLabel: String(event.response.selectedVc.vcMetadata.id), + }), + { + to: (context:any) => context.serviceRefs.activityLog, + }, + ), + + sendVcShareSuccessEvent: () => { + sendImpressionEvent( + getImpressionEventData( + TelemetryConstants.FlowType.senderVcShare, + TelemetryConstants.Screens.vcShareSuccessPage, + ), + ); + sendEndEvent( + getEndEventData( + TelemetryConstants.FlowType.senderVcShare, + TelemetryConstants.EndEventStatus.success, + ), + ); + }, + + sendBLEConnectionErrorEvent: (_context, event) => { + sendErrorEvent( + getErrorEventData( + TelemetryConstants.FlowType.senderVcShare, + event.bleError.code, + event.bleError.message, + ), + ); + sendEndEvent( + getEndEventData( + TelemetryConstants.FlowType.senderVcShare, + TelemetryConstants.EndEventStatus.failure, + ), + ); + }, + + sendVcSharingStartEvent: () => { + sendStartEvent( + getStartEventData(TelemetryConstants.FlowType.senderVcShare), + ); + sendImpressionEvent( + getImpressionEventData( + TelemetryConstants.FlowType.senderVcShare, + TelemetryConstants.Screens.scanScreen, + ), + ); + }, + + sendVCShareFlowCancelEndEvent: () => { + sendEndEvent( + getEndEventData( + TelemetryConstants.FlowType.senderVcShare, + TelemetryConstants.EndEventStatus.cancel, + {comment: 'User cancelled VC share'}, + ), + ); + }, + + sendVCShareFlowTimeoutEndEvent: () => { + sendEndEvent( + getEndEventData( + TelemetryConstants.FlowType.senderVcShare, + TelemetryConstants.EndEventStatus.failure, + {comment: 'VC sharing timeout'}, + ), + ); + }, + + } +} + diff --git a/machines/bleShare/scan/scanGuards.ts b/machines/bleShare/scan/scanGuards.ts new file mode 100644 index 0000000000..062ff241a1 --- /dev/null +++ b/machines/bleShare/scan/scanGuards.ts @@ -0,0 +1,45 @@ +import { VCShareFlowType } from "../../../shared/Utils"; +import { androidVersion, isAndroid, isIOS } from "../../../shared/constants"; + +export const ScanGuards = () => { + return { + showFaceAuthConsentScreen: context => { + return context.showFaceAuthConsent; + }, + + // sample: 'OPENID4VP://connect:?name=OVPMOSIP&key=69dc92a2cc91f02258aa8094d6e2b62877f5b6498924fbaedaaa46af30abb364' + isOpenIdQr: (_context, event) => + event.params.startsWith('OPENID4VP://'), + // sample: 'INJIQUICKSHARE://NAKDFK:DB:JAHDIHAIDJXKABDAJDHUHW' + isQuickShare: (_context, event) => + // event.params.startsWith(DEFAULT_QR_HEADER), + // toggling the feature for now + false, + isQrLogin: (context, event) => { + try { + let linkCode = new URL(event.params); + // sample: 'inji://landing-page-name?linkCode=sTjp0XVH3t3dGCU&linkExpireDateTime=2023-11-09T06:56:18.482Z' + return linkCode.searchParams.get('linkCode') !== null; + } catch (e) { + return false; + } + }, + + uptoAndroid11: () => isAndroid() && androidVersion < 31, + + isIOS: () => isIOS(), + + isMinimumStorageRequiredForAuditEntryReached: (_context, event) => + Boolean(event.data), + + isFlowTypeMiniViewShareWithSelfie: context => + context.flowType === VCShareFlowType.MINI_VIEW_SHARE_WITH_SELFIE, + + isFlowTypeMiniViewShare: context => + context.flowType === VCShareFlowType.MINI_VIEW_SHARE, + + isFlowTypeSimpleShare: context => + context.flowType === VCShareFlowType.SIMPLE_SHARE, + }; + }; + \ No newline at end of file diff --git a/machines/bleShare/scan/scanMachine.ts b/machines/bleShare/scan/scanMachine.ts index 7008db1b27..90f327e3b0 100644 --- a/machines/bleShare/scan/scanMachine.ts +++ b/machines/bleShare/scan/scanMachine.ts @@ -1,141 +1,23 @@ /* eslint-disable sonarjs/no-duplicate-string */ -import tuvali from '@mosip/tuvali'; -import BluetoothStateManager from 'react-native-bluetooth-state-manager'; import { - ActorRefFrom, - assign, - DoneInvokeEvent, EventFrom, send, - spawn, - StateFrom, + StateFrom } from 'xstate'; -import {createModel} from 'xstate/lib/model'; -import {EmitterSubscription, Linking} from 'react-native'; -import {DeviceInfo} from '../../../components/DeviceInfoList'; -import {getDeviceNameSync, isLocationEnabled} from 'react-native-device-info'; -import {VC} from '../../VerifiableCredential/VCMetaMachine/vc'; -import {AppServices} from '../../../shared/GlobalContext'; -import {ActivityLogEvents, ActivityLogType} from '../../activityLog'; +import { AppServices } from '../../../shared/GlobalContext'; +import { TelemetryConstants } from '../../../shared/telemetry/TelemetryConstants'; import { - androidVersion, - DEFAULT_QR_HEADER, - FACE_AUTH_CONSENT, - isAndroid, - isIOS, - MY_LOGIN_STORE_KEY, - MY_VCS_STORE_KEY, -} from '../../../shared/constants'; -import {subscribe} from '../../../shared/openIdBLE/walletEventHandler'; -import { - check, - checkMultiple, - PERMISSIONS, - PermissionStatus, - requestMultiple, - RESULTS, -} from 'react-native-permissions'; -import { - checkLocationPermissionStatus, - requestLocationPermission, -} from '../../../shared/location'; -import {CameraCapturedPicture} from 'expo-camera'; -import {createQrLoginMachine, qrLoginMachine} from '../../QrLoginMachine'; -import {StoreEvents} from '../../store'; -import {WalletDataEvent} from '@mosip/tuvali/lib/typescript/types/events'; -import {BLEError} from '../types'; -import Storage from '../../../shared/storage'; -import {VCMetadata} from '../../../shared/VCMetadata'; -import { - getEndEventData, - getErrorEventData, - getImpressionEventData, getStartEventData, - sendEndEvent, - sendErrorEvent, - sendImpressionEvent, - sendStartEvent, + sendStartEvent } from '../../../shared/telemetry/TelemetryUtils'; -import {TelemetryConstants} from '../../../shared/telemetry/TelemetryConstants'; -import {logState} from '../../../shared/commonUtil'; -import {VCShareFlowType} from '../../../shared/Utils'; -import {getIdType} from '../../../shared/openId4VCI/Utils'; -import {VcMetaEvents} from '../../VerifiableCredential/VCMetaMachine/VCMetaMachine'; +import { qrLoginMachine } from '../../QrLogin/QrLoginMachine'; // @ts-ignore -import {decodeData} from '@mosip/pixelpass'; - -const {wallet, EventTypes, VerificationStatus} = tuvali; +import { ScanActions } from './scanActions'; +import { ScanGuards } from './scanGuards'; +import { ScanModel } from './scanModel'; +import { ScanServices } from './scanServices'; -const model = createModel( - { - serviceRefs: {} as AppServices, - senderInfo: {} as DeviceInfo, - receiverInfo: {} as DeviceInfo, - selectedVc: {} as VC, - bleError: {} as BLEError, - loggers: [] as EmitterSubscription[], - vcName: '', - flowType: VCShareFlowType.SIMPLE_SHARE, - verificationImage: {} as CameraCapturedPicture, - openId4VpUri: '', - shareLogType: '' as ActivityLogType, - QrLoginRef: {} as ActorRefFrom, - showQuickShareSuccessBanner: false, - linkCode: '', - quickShareData: {}, - showFaceAuthConsent: true as boolean, - readyForBluetoothStateCheck: false, - showFaceCaptureSuccessBanner: false, - }, - { - events: { - SELECT_VC: (vc: VC, flowType: string) => ({vc, flowType}), - SCAN: (params: string) => ({params}), - ACCEPT_REQUEST: () => ({}), - VERIFY_AND_ACCEPT_REQUEST: () => ({}), - VC_ACCEPTED: () => ({}), - VC_REJECTED: () => ({}), - VC_SENT: () => ({}), - CANCEL: () => ({}), - CLOSE_BANNER: () => ({}), - STAY_IN_PROGRESS: () => ({}), - RETRY: () => ({}), - DISMISS: () => ({}), - DISMISS_QUICK_SHARE_BANNER: () => ({}), - GOTO_HISTORY: () => ({}), - CONNECTED: () => ({}), - DISCONNECT: () => ({}), - BLE_ERROR: (bleError: BLEError) => ({bleError}), - CONNECTION_DESTROYED: () => ({}), - SCREEN_BLUR: () => ({}), - SCREEN_FOCUS: () => ({}), - BLUETOOTH_PERMISSION_ENABLED: () => ({}), - BLUETOOTH_PERMISSION_DENIED: () => ({}), - BLUETOOTH_STATE_ENABLED: () => ({}), - BLUETOOTH_STATE_DISABLED: () => ({}), - NEARBY_ENABLED: () => ({}), - NEARBY_DISABLED: () => ({}), - GOTO_SETTINGS: () => ({}), - START_PERMISSION_CHECK: () => ({}), - LOCATION_ENABLED: () => ({}), - LOCATION_DISABLED: () => ({}), - LOCATION_REQUEST: () => ({}), - CHECK_FLOW_TYPE: () => ({}), - UPDATE_VC_NAME: (vcName: string) => ({vcName}), - STORE_RESPONSE: (response: any) => ({response}), - APP_ACTIVE: () => ({}), - FACE_VALID: () => ({}), - FACE_INVALID: () => ({}), - RETRY_VERIFICATION: () => ({}), - RESET: () => ({}), - FACE_VERIFICATION_CONSENT: (isConsentGiven: boolean) => ({ - isConsentGiven, - }), - ALLOWED: () => ({}), - DENIED: () => ({}), - }, - }, -); +const model=ScanModel; const QR_LOGIN_REF_ID = 'QrLogin'; export const ScanEvents = model.events; @@ -167,6 +49,7 @@ export const scanMachine = actions: ['sendBLEConnectionErrorEvent', 'setBleError'], }, RESET: { + actions:['removeLoggers', 'resetFlowType', 'resetSelectedVc'], target: '.checkStorage', }, DISMISS: { @@ -204,7 +87,7 @@ export const scanMachine = target: 'restrictSharingVc', }, { - target: 'startPermissionCheck', + target: 'startPermissionCheck', }, ], }, @@ -562,7 +445,7 @@ export const scanMachine = }, { cond: 'isFlowTypeMiniViewShareWithSelfie', - target: '.verifyingIdentity', + target:'.checkFaceAuthConsentForMiniView' , }, ], }, @@ -701,6 +584,16 @@ export const scanMachine = entry: ['resetFlowType', 'resetSelectedVc'], always: '#scan.disconnected', }, + checkFaceAuthConsentForMiniView: { + always:[ + { + cond: 'showFaceAuthConsentScreen', + target: 'faceVerificationConsent' + }, + { + target: 'verifyingIdentity' + } + ],}, faceVerificationConsent: { on: { FACE_VERIFICATION_CONSENT: { @@ -710,9 +603,15 @@ export const scanMachine = ], target: 'verifyingIdentity', }, - DISMISS: { - target: '#scan.reviewing.selectingVc', - }, + DISMISS:[ + { + cond: 'isFlowTypeMiniViewShareWithSelfie', + target: '#scan.checkFaceAuthConsent', + }, + { + target: '#scan.reviewing.selectingVc', + } + ], }, }, verifyingIdentity: { @@ -860,534 +759,19 @@ export const scanMachine = }, }, { - actions: { - setChildRef: assign({ - QrLoginRef: context => { - const service = spawn( - createQrLoginMachine(context.serviceRefs), - QR_LOGIN_REF_ID, - ); - service.subscribe(logState); - return service; - }, - }), - - updateShowFaceAuthConsent: model.assign({ - showFaceAuthConsent: (_, event) => { - return event.response || event.response === null; - }, - }), - - setShowFaceAuthConsent: model.assign({ - showFaceAuthConsent: (_, event) => { - return !event.isConsentGiven; - }, - }), - - getFaceAuthConsent: send(StoreEvents.GET(FACE_AUTH_CONSENT), { - to: context => context.serviceRefs.store, - }), - - storeShowFaceAuthConsent: send( - (context, event) => - StoreEvents.SET(FACE_AUTH_CONSENT, !event.isConsentGiven), - { - to: context => context.serviceRefs.store, - }, - ), - - sendScanData: context => - context.QrLoginRef.send({ - type: 'GET', - linkCode: context.linkCode, - flowType: context.flowType, - selectedVc: context.selectedVc, - faceAuthConsentGiven: context.showFaceAuthConsent, - }), - - openBluetoothSettings: () => { - isAndroid() - ? BluetoothStateManager.openSettings().catch() - : Linking.openURL('App-Prefs:Bluetooth'); - }, - - openAppPermission: () => Linking.openSettings(), - - enableLocation: async () => { - await Linking.sendIntent('android.settings.LOCATION_SOURCE_SETTINGS'); - }, - - setUri: model.assign({ - openId4VpUri: (_context, event) => event.params, - }), + actions: ScanActions(model,QR_LOGIN_REF_ID), - clearUri: assign({ - openId4VpUri: '', - }), - - setSenderInfo: assign({ - senderInfo: () => { - return {name: 'Wallet', deviceName: 'Wallet', deviceId: ''}; - }, - }), - - setReceiverInfo: assign({ - receiverInfo: () => { - return {name: 'Verifier', deviceName: 'Verifier', deviceId: ''}; - }, - }), - - setReadyForBluetoothStateCheck: model.assign({ - readyForBluetoothStateCheck: () => true, - }), - - setBleError: assign({ - bleError: (_context, event) => event.bleError, - }), - - setSelectedVc: assign({ - selectedVc: (_context, event) => event.vc, - }), - - resetSelectedVc: assign({ - selectedVc: {}, - }), - - resetShowQuickShareSuccessBanner: assign({ - showQuickShareSuccessBanner: false, - }), - - setShowQuickShareSuccessBanner: assign({ - showQuickShareSuccessBanner: true, - }), - - setFlowType: assign({ - flowType: (_context, event) => event.flowType, - }), - - resetFlowType: assign({ - flowType: VCShareFlowType.SIMPLE_SHARE, - }), - - registerLoggers: assign({ - loggers: () => { - if (__DEV__) { - return [ - wallet.handleDataEvents(event => { - console.log( - getDeviceNameSync(), - '', - JSON.stringify(event).slice(0, 100), - ); - }), - ]; - } else { - return []; - } - }, - }), - - removeLoggers: assign({ - loggers: ({loggers}) => { - loggers?.forEach(logger => logger.remove()); - return []; - }, - }), - - setShareLogTypeUnverified: model.assign({ - shareLogType: 'VC_SHARED', - }), - - setShareLogTypeVerified: model.assign({ - shareLogType: 'PRESENCE_VERIFIED_AND_VC_SHARED', - }), - - updateFaceCaptureBannerStatus: model.assign({ - showFaceCaptureSuccessBanner: true, - }), - - resetFaceCaptureBannerStatus: model.assign({ - showFaceCaptureSuccessBanner: false, - }), - - logShared: send( - context => { - const vcMetadata = context.selectedVc?.vcMetadata; - return ActivityLogEvents.LOG_ACTIVITY({ - _vcKey: VCMetadata.fromVC(vcMetadata).getVcKey(), - type: context.shareLogType - ? context.shareLogType - : 'VC_SHARED_WITH_VERIFICATION_CONSENT', - id: vcMetadata.id, - idType: getIdType(vcMetadata.issuer), - timestamp: Date.now(), - deviceName: - context.receiverInfo.name || context.receiverInfo.deviceName, - vcLabel: vcMetadata.id, - }); - }, - {to: context => context.serviceRefs.activityLog}, - ), - - logFailedVerification: send( - context => - ActivityLogEvents.LOG_ACTIVITY({ - _vcKey: VCMetadata.fromVC(context.selectedVc).getVcKey(), - type: 'PRESENCE_VERIFICATION_FAILED', - timestamp: Date.now(), - idType: getIdType(context.selectedVc.vcMetadata.issuer), - id: context.selectedVc.vcMetadata.id, - deviceName: - context.receiverInfo.name || context.receiverInfo.deviceName, - vcLabel: context.selectedVc.vcMetadata.id, - }), - {to: context => context.serviceRefs.activityLog}, - ), - - setLinkCode: assign({ - linkCode: (_, event) => - new URL(event.params).searchParams.get('linkCode'), - }), - setQuickShareData: assign({ - quickShareData: (_, event) => - JSON.parse(decodeData(event.params.split(DEFAULT_QR_HEADER)[1])), - }), - loadMetaDataToMemory: send( - context => { - let metadata = VCMetadata.fromVC(context.quickShareData?.meta); - return StoreEvents.PREPEND(MY_VCS_STORE_KEY, metadata); - }, - {to: context => context.serviceRefs.store}, - ), - loadVCDataToMemory: send( - context => { - let metadata = VCMetadata.fromVC(context.quickShareData?.meta); - - let verifiableCredential = metadata.isFromOpenId4VCI() - ? {credential: context.quickShareData?.verifiableCredential} - : context.quickShareData?.verifiableCredential; - - return StoreEvents.SET(metadata.getVcKey(), { - verifiableCredential: verifiableCredential, - }); - }, - {to: context => context.serviceRefs.store}, - ), - refreshVCs: send(VcMetaEvents.REFRESH_MY_VCS, { - to: context => context.serviceRefs.vcMeta, - }), - storeLoginItem: send( - (_context, event) => { - return StoreEvents.PREPEND( - MY_LOGIN_STORE_KEY, - (event as DoneInvokeEvent).data, - ); - }, - {to: context => context.serviceRefs.store}, - ), - - storingActivityLog: send( - (_, event) => - ActivityLogEvents.LOG_ACTIVITY({ - _vcKey: '', - id: event.response.selectedVc.vcMetadata.id, - idType: getIdType(event.response.selectedVc.vcMetadata.issuer), - type: 'QRLOGIN_SUCCESFULL', - timestamp: Date.now(), - deviceName: '', - vcLabel: String(event.response.selectedVc.vcMetadata.id), - }), - { - to: context => context.serviceRefs.activityLog, - }, - ), - - sendVcShareSuccessEvent: () => { - sendImpressionEvent( - getImpressionEventData( - TelemetryConstants.FlowType.senderVcShare, - TelemetryConstants.Screens.vcShareSuccessPage, - ), - ); - sendEndEvent( - getEndEventData( - TelemetryConstants.FlowType.senderVcShare, - TelemetryConstants.EndEventStatus.success, - ), - ); - }, - - sendBLEConnectionErrorEvent: (_context, event) => { - sendErrorEvent( - getErrorEventData( - TelemetryConstants.FlowType.senderVcShare, - event.bleError.code, - event.bleError.message, - ), - ); - sendEndEvent( - getEndEventData( - TelemetryConstants.FlowType.senderVcShare, - TelemetryConstants.EndEventStatus.failure, - ), - ); - }, - - sendVcSharingStartEvent: () => { - sendStartEvent( - getStartEventData(TelemetryConstants.FlowType.senderVcShare), - ); - sendImpressionEvent( - getImpressionEventData( - TelemetryConstants.FlowType.senderVcShare, - TelemetryConstants.Screens.scanScreen, - ), - ); - }, - - sendVCShareFlowCancelEndEvent: () => { - sendEndEvent( - getEndEventData( - TelemetryConstants.FlowType.senderVcShare, - TelemetryConstants.EndEventStatus.cancel, - {comment: 'User cancelled VC share'}, - ), - ); - }, - - sendVCShareFlowTimeoutEndEvent: () => { - sendEndEvent( - getEndEventData( - TelemetryConstants.FlowType.senderVcShare, - TelemetryConstants.EndEventStatus.failure, - {comment: 'VC sharing timeout'}, - ), - ); - }, - }, - - services: { - checkBluetoothPermission: () => async callback => { - // wait a bit for animation to finish when app becomes active - await new Promise(resolve => setTimeout(resolve, 250)); - try { - // Passing Granted for android since permission status is always granted even if its denied. - let response: PermissionStatus = RESULTS.GRANTED; - - if (isIOS()) { - response = await check(PERMISSIONS.IOS.BLUETOOTH_PERIPHERAL); - } - - if (response === RESULTS.GRANTED) { - callback(model.events.BLUETOOTH_PERMISSION_ENABLED()); - } else { - callback(model.events.BLUETOOTH_PERMISSION_DENIED()); - } - } catch (e) { - console.error(e); - } - }, - - checkBluetoothState: () => callback => { - const subscription = BluetoothStateManager.onStateChange(state => { - if (state === 'PoweredOn') { - callback(model.events.BLUETOOTH_STATE_ENABLED()); - } else { - callback(model.events.BLUETOOTH_STATE_DISABLED()); - } - }, true); - return () => subscription.remove(); - }, - - requestBluetooth: () => callback => { - BluetoothStateManager.requestToEnable() - .then(() => callback(model.events.BLUETOOTH_STATE_ENABLED())) - .catch(() => callback(model.events.BLUETOOTH_STATE_DISABLED())); - }, - - requestToEnableLocationPermission: () => callback => { - requestLocationPermission( - () => callback(model.events.LOCATION_ENABLED()), - () => callback(model.events.LOCATION_DISABLED()), - ); - }, - - monitorConnection: () => callback => { - const walletErrorCodePrefix = 'TVW'; - const subscription = wallet.handleDataEvents(event => { - if (event.type === EventTypes.onDisconnected) { - callback({type: 'DISCONNECT'}); - } - if ( - event.type === EventTypes.onError && - event.code.includes(walletErrorCodePrefix) - ) { - callback({ - type: 'BLE_ERROR', - bleError: {message: event.message, code: event.code}, - }); - console.error('BLE Exception: ' + event.message); - } - }); - - return () => subscription.remove(); - }, - - checkNearByDevicesPermission: () => callback => { - checkMultiple([ - PERMISSIONS.ANDROID.BLUETOOTH_CONNECT, - PERMISSIONS.ANDROID.BLUETOOTH_SCAN, - ]) - .then(response => { - if ( - response[PERMISSIONS.ANDROID.BLUETOOTH_ADVERTISE] === - RESULTS.GRANTED && - response[PERMISSIONS.ANDROID.BLUETOOTH_CONNECT] === - RESULTS.GRANTED - ) { - callback(model.events.NEARBY_ENABLED()); - } else { - callback(model.events.NEARBY_DISABLED()); - } - }) - .catch(err => { - callback(model.events.NEARBY_DISABLED()); - }); - }, - - requestNearByDevicesPermission: () => callback => { - requestMultiple([ - PERMISSIONS.ANDROID.BLUETOOTH_SCAN, - PERMISSIONS.ANDROID.BLUETOOTH_CONNECT, - ]) - .then(response => { - if ( - response[PERMISSIONS.ANDROID.BLUETOOTH_SCAN] === - RESULTS.GRANTED && - response[PERMISSIONS.ANDROID.BLUETOOTH_CONNECT] === - RESULTS.GRANTED - ) { - callback(model.events.NEARBY_ENABLED()); - } else { - callback(model.events.NEARBY_DISABLED()); - } - }) - .catch(err => { - callback(model.events.NEARBY_DISABLED()); - }); - }, - - checkLocationPermission: () => callback => { - checkLocationPermissionStatus( - () => callback(model.events.LOCATION_ENABLED()), - () => callback(model.events.LOCATION_DISABLED()), - ); - }, - - checkLocationStatus: () => async callback => { - const isEnabled: boolean = await isLocationEnabled(); - if (isEnabled) { - callback(model.events.LOCATION_ENABLED()); - } else { - callback(model.events.LOCATION_DISABLED()); - } - }, - - startConnection: context => callback => { - wallet.startConnection(context.openId4VpUri); - const statusCallback = (event: WalletDataEvent) => { - if (event.type === EventTypes.onSecureChannelEstablished) { - callback({type: 'CONNECTED'}); - } - }; - - const subscription = subscribe(statusCallback); - return () => subscription?.remove(); - }, - - sendVc: context => callback => { - const statusCallback = (event: WalletDataEvent) => { - if (event.type === EventTypes.onDataSent) { - callback({type: 'VC_SENT'}); - } else if (event.type === EventTypes.onVerificationStatusReceived) { - callback({ - type: - event.status === VerificationStatus.ACCEPTED - ? 'VC_ACCEPTED' - : 'VC_REJECTED', - }); - } - }; - wallet.sendData( - JSON.stringify({ - ...context.selectedVc, - }), - ); - const subscription = subscribe(statusCallback); - return () => subscription?.remove(); - }, - - disconnect: () => () => { - try { - wallet.disconnect(); - } catch (e) { - // pass - } - }, - - checkStorageAvailability: () => async () => { - return Promise.resolve( - Storage.isMinimumLimitReached('minStorageRequiredForAuditEntry'), - ); - }, - }, - - guards: { - showFaceAuthConsentScreen: context => { - return context.showFaceAuthConsent; - }, - - // sample: 'OPENID4VP://connect:?name=OVPMOSIP&key=69dc92a2cc91f02258aa8094d6e2b62877f5b6498924fbaedaaa46af30abb364' - isOpenIdQr: (_context, event) => - event.params.startsWith('OPENID4VP://'), - // sample: 'INJIQUICKSHARE://NAKDFK:DB:JAHDIHAIDJXKABDAJDHUHW' - isQuickShare: (_context, event) => - // event.params.startsWith(DEFAULT_QR_HEADER), - // toggling the feature for now - false, - isQrLogin: (context, event) => { - try { - let linkCode = new URL(event.params); - // sample: 'inji://landing-page-name?linkCode=sTjp0XVH3t3dGCU&linkExpireDateTime=2023-11-09T06:56:18.482Z' - return linkCode.searchParams.get('linkCode') !== null; - } catch (e) { - return false; - } - }, - - uptoAndroid11: () => isAndroid() && androidVersion < 31, - - isIOS: () => isIOS(), - - isMinimumStorageRequiredForAuditEntryReached: (_context, event) => - Boolean(event.data), - - isFlowTypeMiniViewShareWithSelfie: context => - context.flowType === VCShareFlowType.MINI_VIEW_SHARE_WITH_SELFIE, - - isFlowTypeMiniViewShare: context => - context.flowType === VCShareFlowType.MINI_VIEW_SHARE, - - isFlowTypeSimpleShare: context => - context.flowType === VCShareFlowType.SIMPLE_SHARE, - }, + services: ScanServices(model), + guards: ScanGuards(), delays: { DESTROY_TIMEOUT: 500, CONNECTION_TIMEOUT: 5 * 1000, SHARING_TIMEOUT: 15 * 1000, }, }, + + ); type State = StateFrom; @@ -1399,12 +783,3 @@ export function createScanMachine(serviceRefs: AppServices) { }); } -export function selectIsMinimumStorageRequiredForAuditEntryLimitReached( - state: State, -) { - return state.matches('restrictSharingVc'); -} - -export function selectIsFaceVerificationConsent(state: State) { - return state.matches('reviewing.faceVerificationConsent'); -} diff --git a/machines/bleShare/scan/scanMachine.typegen.ts b/machines/bleShare/scan/scanMachine.typegen.ts index 6073222ef2..94e01d33d6 100644 --- a/machines/bleShare/scan/scanMachine.typegen.ts +++ b/machines/bleShare/scan/scanMachine.typegen.ts @@ -1,238 +1,121 @@ -// This file was automatically generated. Edits will be overwritten -export interface Typegen0 { - '@@xstate/typegen': true; - internalEvents: { - '': {type: ''}; - 'done.invoke.QrLogin': { - type: 'done.invoke.QrLogin'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.scan.checkStorage:invocation[0]': { - type: 'done.invoke.scan.checkStorage: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'}; - }; - invokeSrcNameMap: { - checkBluetoothPermission: 'done.invoke.scan.checkBluetoothPermission.checking:invocation[0]'; - checkBluetoothState: - | 'done.invoke.scan.checkBluetoothState.checking:invocation[0]' - | 'done.invoke.scan.recheckBluetoothState.checking:invocation[0]'; - checkLocationPermission: 'done.invoke.scan.checkingLocationState.checkingPermissionStatus:invocation[0]'; - checkLocationStatus: 'done.invoke.scan.checkingLocationState.checkLocationService:invocation[0]'; - checkNearByDevicesPermission: 'done.invoke.scan.checkNearbyDevicesPermission.checking:invocation[0]'; - checkStorageAvailability: 'done.invoke.scan.checkStorage:invocation[0]'; - disconnect: - | 'done.invoke.scan.clearingConnection:invocation[0]' - | 'done.invoke.scan.disconnectDevice:invocation[0]' - | 'done.invoke.scan.reviewing.disconnect:invocation[0]'; - monitorConnection: 'done.invoke.scan:invocation[0]'; - requestBluetooth: 'done.invoke.scan.checkBluetoothState.requesting:invocation[0]'; - requestNearByDevicesPermission: 'done.invoke.scan.checkNearbyDevicesPermission.requesting:invocation[0]'; - requestToEnableLocationPermission: 'done.invoke.scan.checkingLocationState.requestToEnableLocation:invocation[0]'; - sendVc: 'done.invoke.scan.reviewing.sendingVc:invocation[0]'; - startConnection: 'done.invoke.scan.connecting:invocation[0]'; - }; - missingImplementations: { - actions: never; - delays: never; - guards: never; - services: never; - }; - eventsCausingActions: { - clearUri: 'STORE_RESPONSE'; - getFaceAuthConsent: - | 'DISCONNECT' - | 'DISMISS' - | 'xstate.after(DESTROY_TIMEOUT)#scan.clearingConnection'; - loadMetaDataToMemory: 'SCAN'; - loadVCDataToMemory: 'STORE_RESPONSE'; - logFailedVerification: 'FACE_INVALID'; - logShared: 'VC_ACCEPTED'; - openAppPermission: 'GOTO_SETTINGS' | 'LOCATION_REQUEST'; - openBluetoothSettings: 'GOTO_SETTINGS'; - refreshVCs: 'STORE_RESPONSE'; - registerLoggers: 'STORE_RESPONSE'; - removeLoggers: - | 'DISCONNECT' - | 'DISMISS' - | 'DISMISS_QUICK_SHARE_BANNER' - | 'SCREEN_BLUR' - | 'STORE_RESPONSE' - | 'xstate.init'; - resetFaceCaptureBannerStatus: 'ACCEPT_REQUEST' | 'CLOSE_BANNER'; - resetFlowType: - | 'DISCONNECT' - | 'DISMISS' - | 'DISMISS_QUICK_SHARE_BANNER' - | 'GOTO_HISTORY' - | 'SCREEN_BLUR' - | 'xstate.init'; - resetSelectedVc: - | 'DISCONNECT' - | 'DISMISS' - | 'DISMISS_QUICK_SHARE_BANNER' - | 'GOTO_HISTORY' - | 'SCREEN_BLUR' - | 'xstate.init'; - resetShowQuickShareSuccessBanner: 'DISMISS' | 'DISMISS_QUICK_SHARE_BANNER'; - sendBLEConnectionErrorEvent: 'BLE_ERROR'; - sendScanData: 'SCAN'; - sendVCShareFlowCancelEndEvent: 'CANCEL'; - sendVCShareFlowTimeoutEndEvent: 'CANCEL' | 'RETRY'; - sendVcShareSuccessEvent: 'VC_ACCEPTED'; - sendVcSharingStartEvent: 'SCAN'; - setBleError: 'BLE_ERROR'; - setChildRef: 'STORE_RESPONSE'; - setFlowType: 'SELECT_VC'; - setLinkCode: 'SCAN'; - setQuickShareData: 'SCAN'; - setReadyForBluetoothStateCheck: 'BLUETOOTH_PERMISSION_ENABLED'; - setReceiverInfo: 'CONNECTED'; - setSelectedVc: 'SELECT_VC'; - setSenderInfo: 'CONNECTED'; - setShareLogTypeUnverified: 'ACCEPT_REQUEST' | 'CHECK_FLOW_TYPE'; - setShareLogTypeVerified: 'FACE_VALID'; - setShowFaceAuthConsent: 'FACE_VERIFICATION_CONSENT'; - setShowQuickShareSuccessBanner: 'STORE_RESPONSE'; - setUri: 'SCAN'; - storeLoginItem: 'done.invoke.QrLogin'; - storeShowFaceAuthConsent: 'FACE_VERIFICATION_CONSENT'; - storingActivityLog: 'STORE_RESPONSE'; - 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'; - }; - eventsCausingGuards: { - isFlowTypeMiniViewShare: 'CHECK_FLOW_TYPE'; - isFlowTypeMiniViewShareWithSelfie: 'CHECK_FLOW_TYPE'; - isFlowTypeSimpleShare: 'CANCEL' | 'CHECK_FLOW_TYPE' | 'DISMISS'; - isIOS: 'BLUETOOTH_STATE_DISABLED' | 'START_PERMISSION_CHECK'; - isMinimumStorageRequiredForAuditEntryReached: 'done.invoke.scan.checkStorage:invocation[0]'; - isOpenIdQr: 'SCAN'; - isQrLogin: 'SCAN'; - isQuickShare: 'SCAN'; - showFaceAuthConsentScreen: 'VERIFY_AND_ACCEPT_REQUEST'; - uptoAndroid11: '' | 'START_PERMISSION_CHECK'; - }; - eventsCausingServices: { - QrLogin: 'SCAN'; - checkBluetoothPermission: - | '' - | 'BLUETOOTH_STATE_DISABLED' - | 'NEARBY_ENABLED' - | 'START_PERMISSION_CHECK'; - checkBluetoothState: '' | 'APP_ACTIVE'; - checkLocationPermission: 'APP_ACTIVE' | 'LOCATION_ENABLED'; - checkLocationStatus: '' | 'LOCATION_REQUEST'; - checkNearByDevicesPermission: 'APP_ACTIVE' | 'START_PERMISSION_CHECK'; - checkStorageAvailability: 'RESET' | 'SCREEN_FOCUS' | 'SELECT_VC'; - disconnect: '' | 'DISMISS' | 'LOCATION_ENABLED' | 'RETRY' | 'SCREEN_BLUR'; - monitorConnection: 'DISMISS' | 'SCREEN_BLUR' | 'xstate.init'; - requestBluetooth: 'BLUETOOTH_STATE_DISABLED'; - requestNearByDevicesPermission: 'NEARBY_DISABLED'; - requestToEnableLocationPermission: 'LOCATION_DISABLED'; - sendVc: 'ACCEPT_REQUEST' | 'CHECK_FLOW_TYPE' | 'FACE_VALID'; - startConnection: 'SCAN'; - }; - matchesStates: - | 'bluetoothDenied' - | 'bluetoothPermissionDenied' - | 'checkBluetoothPermission' - | 'checkBluetoothPermission.checking' - | 'checkBluetoothPermission.enabled' - | 'checkBluetoothState' - | 'checkBluetoothState.checking' - | 'checkBluetoothState.enabled' - | 'checkBluetoothState.requesting' - | 'checkFaceAuthConsent' - | 'checkNearbyDevicesPermission' - | 'checkNearbyDevicesPermission.checking' - | 'checkNearbyDevicesPermission.enabled' - | 'checkNearbyDevicesPermission.requesting' - | 'checkStorage' - | 'checkingLocationState' - | 'checkingLocationState.checkLocationService' - | 'checkingLocationState.checkingPermissionStatus' - | 'checkingLocationState.denied' - | 'checkingLocationState.disabled' - | 'checkingLocationState.requestToEnableLocation' - | 'clearingConnection' - | 'connecting' - | 'connecting.inProgress' - | 'connecting.timeout' - | 'decodeQuickShareData' - | 'disconnectDevice' - | 'disconnected' - | 'findingConnection' - | 'handlingBleError' - | 'inactive' - | 'invalid' - | 'loadVCS' - | 'loadVCS.idle' - | 'loadVCS.navigatingToHome' - | 'nearByDevicesPermissionDenied' - | 'recheckBluetoothState' - | 'recheckBluetoothState.checking' - | 'recheckBluetoothState.enabled' - | 'restrictSharingVc' - | 'reviewing' - | 'reviewing.accepted' - | 'reviewing.cancelling' - | 'reviewing.disconnect' - | 'reviewing.faceVerificationConsent' - | 'reviewing.idle' - | 'reviewing.invalidIdentity' - | 'reviewing.navigateToHistory' - | 'reviewing.rejected' - | 'reviewing.selectingVc' - | 'reviewing.sendingVc' - | 'reviewing.sendingVc.inProgress' - | 'reviewing.sendingVc.sent' - | 'reviewing.sendingVc.timeout' - | 'reviewing.verifyingIdentity' - | 'showQrLogin' - | 'showQrLogin.idle' - | 'showQrLogin.navigatingToHistory' - | 'showQrLogin.storing' - | 'startPermissionCheck' - | { - checkBluetoothPermission?: 'checking' | 'enabled'; - checkBluetoothState?: 'checking' | 'enabled' | 'requesting'; - checkNearbyDevicesPermission?: 'checking' | 'enabled' | 'requesting'; - checkingLocationState?: - | 'checkLocationService' - | 'checkingPermissionStatus' - | 'denied' - | 'disabled' - | 'requestToEnableLocation'; - connecting?: 'inProgress' | 'timeout'; - loadVCS?: 'idle' | 'navigatingToHome'; - recheckBluetoothState?: 'checking' | 'enabled'; - reviewing?: - | 'accepted' - | 'cancelling' - | 'disconnect' - | 'faceVerificationConsent' - | 'idle' - | 'invalidIdentity' - | 'navigateToHistory' - | 'rejected' - | 'selectingVc' - | 'sendingVc' - | 'verifyingIdentity' - | {sendingVc?: 'inProgress' | 'sent' | 'timeout'}; - showQrLogin?: 'idle' | 'navigatingToHistory' | 'storing'; - }; - tags: never; -} + // This file was automatically generated. Edits will be overwritten + + export interface Typegen0 { + '@@xstate/typegen': true; + internalEvents: { + "": { type: "" }; +"done.invoke.QrLogin": { type: "done.invoke.QrLogin"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.scan.checkStorage:invocation[0]": { type: "done.invoke.scan.checkStorage: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" }; + }; + invokeSrcNameMap: { + "checkBluetoothPermission": "done.invoke.scan.checkBluetoothPermission.checking:invocation[0]"; +"checkBluetoothState": "done.invoke.scan.checkBluetoothState.checking:invocation[0]" | "done.invoke.scan.recheckBluetoothState.checking:invocation[0]"; +"checkLocationPermission": "done.invoke.scan.checkingLocationState.checkingPermissionStatus:invocation[0]"; +"checkLocationStatus": "done.invoke.scan.checkingLocationState.checkLocationService:invocation[0]"; +"checkNearByDevicesPermission": "done.invoke.scan.checkNearbyDevicesPermission.checking:invocation[0]"; +"checkStorageAvailability": "done.invoke.scan.checkStorage:invocation[0]"; +"disconnect": "done.invoke.scan.clearingConnection:invocation[0]" | "done.invoke.scan.disconnectDevice:invocation[0]" | "done.invoke.scan.reviewing.disconnect:invocation[0]"; +"monitorConnection": "done.invoke.scan:invocation[0]"; +"requestBluetooth": "done.invoke.scan.checkBluetoothState.requesting:invocation[0]"; +"requestNearByDevicesPermission": "done.invoke.scan.checkNearbyDevicesPermission.requesting:invocation[0]"; +"requestToEnableLocationPermission": "done.invoke.scan.checkingLocationState.requestToEnableLocation:invocation[0]"; +"sendVc": "done.invoke.scan.reviewing.sendingVc:invocation[0]"; +"startConnection": "done.invoke.scan.connecting:invocation[0]"; + }; + missingImplementations: { + actions: "clearUri" | "enableLocation" | "getFaceAuthConsent" | "loadMetaDataToMemory" | "loadVCDataToMemory" | "logFailedVerification" | "logShared" | "openAppPermission" | "openBluetoothSettings" | "refreshVCs" | "registerLoggers" | "removeLoggers" | "resetFaceCaptureBannerStatus" | "resetFlowType" | "resetSelectedVc" | "resetShowQuickShareSuccessBanner" | "sendBLEConnectionErrorEvent" | "sendScanData" | "sendVCShareFlowCancelEndEvent" | "sendVCShareFlowTimeoutEndEvent" | "sendVcShareSuccessEvent" | "sendVcSharingStartEvent" | "setBleError" | "setChildRef" | "setFlowType" | "setLinkCode" | "setQuickShareData" | "setReadyForBluetoothStateCheck" | "setReceiverInfo" | "setSelectedVc" | "setSenderInfo" | "setShareLogTypeUnverified" | "setShareLogTypeVerified" | "setShowFaceAuthConsent" | "setShowQuickShareSuccessBanner" | "setUri" | "storeLoginItem" | "storeShowFaceAuthConsent" | "storingActivityLog" | "updateFaceCaptureBannerStatus" | "updateShowFaceAuthConsent"; + delays: never; + guards: "isFlowTypeMiniViewShare" | "isFlowTypeMiniViewShareWithSelfie" | "isFlowTypeSimpleShare" | "isIOS" | "isMinimumStorageRequiredForAuditEntryReached" | "isOpenIdQr" | "isQrLogin" | "isQuickShare" | "showFaceAuthConsentScreen" | "uptoAndroid11"; + services: "checkBluetoothPermission" | "checkBluetoothState" | "checkLocationPermission" | "checkLocationStatus" | "checkNearByDevicesPermission" | "checkStorageAvailability" | "disconnect" | "monitorConnection" | "requestBluetooth" | "requestNearByDevicesPermission" | "requestToEnableLocationPermission" | "sendVc" | "startConnection"; + }; + eventsCausingActions: { + "clearUri": "STORE_RESPONSE"; +"enableLocation": "ALLOWED" | "LOCATION_REQUEST"; +"getFaceAuthConsent": "DISCONNECT" | "DISMISS" | "xstate.after(DESTROY_TIMEOUT)#scan.clearingConnection"; +"loadMetaDataToMemory": "SCAN"; +"loadVCDataToMemory": "STORE_RESPONSE"; +"logFailedVerification": "FACE_INVALID"; +"logShared": "VC_ACCEPTED"; +"openAppPermission": "GOTO_SETTINGS" | "LOCATION_REQUEST"; +"openBluetoothSettings": "GOTO_SETTINGS"; +"refreshVCs": "STORE_RESPONSE"; +"registerLoggers": "STORE_RESPONSE"; +"removeLoggers": "DISCONNECT" | "DISMISS" | "DISMISS_QUICK_SHARE_BANNER" | "RESET" | "SCREEN_BLUR" | "STORE_RESPONSE" | "xstate.init"; +"resetFaceCaptureBannerStatus": "ACCEPT_REQUEST" | "CLOSE_BANNER"; +"resetFlowType": "DISCONNECT" | "DISMISS" | "DISMISS_QUICK_SHARE_BANNER" | "GOTO_HISTORY" | "RESET" | "SCREEN_BLUR" | "xstate.init"; +"resetSelectedVc": "DISCONNECT" | "DISMISS" | "DISMISS_QUICK_SHARE_BANNER" | "GOTO_HISTORY" | "RESET" | "SCREEN_BLUR" | "xstate.init"; +"resetShowQuickShareSuccessBanner": "DISMISS" | "DISMISS_QUICK_SHARE_BANNER"; +"sendBLEConnectionErrorEvent": "BLE_ERROR"; +"sendScanData": "SCAN"; +"sendVCShareFlowCancelEndEvent": "CANCEL"; +"sendVCShareFlowTimeoutEndEvent": "CANCEL" | "RETRY"; +"sendVcShareSuccessEvent": "VC_ACCEPTED"; +"sendVcSharingStartEvent": "SCAN"; +"setBleError": "BLE_ERROR"; +"setChildRef": "STORE_RESPONSE"; +"setFlowType": "SELECT_VC"; +"setLinkCode": "SCAN"; +"setQuickShareData": "SCAN"; +"setReadyForBluetoothStateCheck": "BLUETOOTH_PERMISSION_ENABLED"; +"setReceiverInfo": "CONNECTED"; +"setSelectedVc": "SELECT_VC"; +"setSenderInfo": "CONNECTED"; +"setShareLogTypeUnverified": "ACCEPT_REQUEST" | "CHECK_FLOW_TYPE"; +"setShareLogTypeVerified": "FACE_VALID"; +"setShowFaceAuthConsent": "FACE_VERIFICATION_CONSENT"; +"setShowQuickShareSuccessBanner": "STORE_RESPONSE"; +"setUri": "SCAN"; +"storeLoginItem": "done.invoke.QrLogin"; +"storeShowFaceAuthConsent": "FACE_VERIFICATION_CONSENT"; +"storingActivityLog": "STORE_RESPONSE"; +"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"; + }; + eventsCausingGuards: { + "isFlowTypeMiniViewShare": "CHECK_FLOW_TYPE"; +"isFlowTypeMiniViewShareWithSelfie": "CHECK_FLOW_TYPE" | "DISMISS"; +"isFlowTypeSimpleShare": "CANCEL" | "CHECK_FLOW_TYPE" | "DISMISS"; +"isIOS": "BLUETOOTH_STATE_DISABLED" | "START_PERMISSION_CHECK"; +"isMinimumStorageRequiredForAuditEntryReached": "done.invoke.scan.checkStorage:invocation[0]"; +"isOpenIdQr": "SCAN"; +"isQrLogin": "SCAN"; +"isQuickShare": "SCAN"; +"showFaceAuthConsentScreen": "" | "VERIFY_AND_ACCEPT_REQUEST"; +"uptoAndroid11": "" | "START_PERMISSION_CHECK"; + }; + eventsCausingServices: { + "QrLogin": "SCAN"; +"checkBluetoothPermission": "" | "BLUETOOTH_STATE_DISABLED" | "NEARBY_ENABLED" | "START_PERMISSION_CHECK"; +"checkBluetoothState": "" | "APP_ACTIVE"; +"checkLocationPermission": "LOCATION_ENABLED"; +"checkLocationStatus": "" | "APP_ACTIVE" | "LOCATION_REQUEST"; +"checkNearByDevicesPermission": "APP_ACTIVE" | "START_PERMISSION_CHECK"; +"checkStorageAvailability": "RESET" | "SCREEN_FOCUS" | "SELECT_VC"; +"disconnect": "" | "DISMISS" | "LOCATION_ENABLED" | "RETRY" | "SCREEN_BLUR"; +"monitorConnection": "DISMISS" | "SCREEN_BLUR" | "xstate.init"; +"requestBluetooth": "BLUETOOTH_STATE_DISABLED"; +"requestNearByDevicesPermission": "NEARBY_DISABLED"; +"requestToEnableLocationPermission": "LOCATION_DISABLED"; +"sendVc": "ACCEPT_REQUEST" | "CHECK_FLOW_TYPE" | "FACE_VALID"; +"startConnection": "SCAN"; + }; + matchesStates: "bluetoothDenied" | "bluetoothPermissionDenied" | "checkBluetoothPermission" | "checkBluetoothPermission.checking" | "checkBluetoothPermission.enabled" | "checkBluetoothState" | "checkBluetoothState.checking" | "checkBluetoothState.enabled" | "checkBluetoothState.requesting" | "checkFaceAuthConsent" | "checkNearbyDevicesPermission" | "checkNearbyDevicesPermission.checking" | "checkNearbyDevicesPermission.enabled" | "checkNearbyDevicesPermission.requesting" | "checkStorage" | "checkingLocationState" | "checkingLocationState.LocationPermissionRationale" | "checkingLocationState.checkLocationService" | "checkingLocationState.checkingPermissionStatus" | "checkingLocationState.denied" | "checkingLocationState.disabled" | "checkingLocationState.requestToEnableLocation" | "clearingConnection" | "connecting" | "connecting.inProgress" | "connecting.timeout" | "decodeQuickShareData" | "disconnectDevice" | "disconnected" | "findingConnection" | "handlingBleError" | "inactive" | "invalid" | "loadVCS" | "loadVCS.idle" | "loadVCS.navigatingToHome" | "nearByDevicesPermissionDenied" | "recheckBluetoothState" | "recheckBluetoothState.checking" | "recheckBluetoothState.enabled" | "restrictSharingVc" | "reviewing" | "reviewing.accepted" | "reviewing.cancelling" | "reviewing.checkFaceAuthConsentForMiniView" | "reviewing.disconnect" | "reviewing.faceVerificationConsent" | "reviewing.idle" | "reviewing.invalidIdentity" | "reviewing.navigateToHistory" | "reviewing.rejected" | "reviewing.selectingVc" | "reviewing.sendingVc" | "reviewing.sendingVc.inProgress" | "reviewing.sendingVc.sent" | "reviewing.sendingVc.timeout" | "reviewing.verifyingIdentity" | "showQrLogin" | "showQrLogin.idle" | "showQrLogin.navigatingToHistory" | "showQrLogin.storing" | "startPermissionCheck" | { "checkBluetoothPermission"?: "checking" | "enabled"; +"checkBluetoothState"?: "checking" | "enabled" | "requesting"; +"checkNearbyDevicesPermission"?: "checking" | "enabled" | "requesting"; +"checkingLocationState"?: "LocationPermissionRationale" | "checkLocationService" | "checkingPermissionStatus" | "denied" | "disabled" | "requestToEnableLocation"; +"connecting"?: "inProgress" | "timeout"; +"loadVCS"?: "idle" | "navigatingToHome"; +"recheckBluetoothState"?: "checking" | "enabled"; +"reviewing"?: "accepted" | "cancelling" | "checkFaceAuthConsentForMiniView" | "disconnect" | "faceVerificationConsent" | "idle" | "invalidIdentity" | "navigateToHistory" | "rejected" | "selectingVc" | "sendingVc" | "verifyingIdentity" | { "sendingVc"?: "inProgress" | "sent" | "timeout"; }; +"showQrLogin"?: "idle" | "navigatingToHistory" | "storing"; }; + tags: never; + } + \ No newline at end of file diff --git a/machines/bleShare/scan/scanModel.ts b/machines/bleShare/scan/scanModel.ts new file mode 100644 index 0000000000..a826a32000 --- /dev/null +++ b/machines/bleShare/scan/scanModel.ts @@ -0,0 +1,84 @@ +import { CameraCapturedPicture } from "expo-camera"; +import { EmitterSubscription } from "react-native"; +import { ActorRefFrom } from "xstate"; +import { createModel } from "xstate/lib/model"; +import { DeviceInfo } from "../../../components/DeviceInfoList"; +import { AppServices } from "../../../shared/GlobalContext"; +import { VCShareFlowType } from "../../../shared/Utils"; +import { qrLoginMachine } from "../../QrLogin/QrLoginMachine"; +import { VC } from "../../VerifiableCredential/VCMetaMachine/vc"; +import { ActivityLogType } from "../../activityLog"; +import { BLEError } from "../types"; + +const ScanEvents ={ + SELECT_VC: (vc: VC, flowType: string) => ({vc, flowType}), + SCAN: (params: string) => ({params}), + ACCEPT_REQUEST: () => ({}), + VERIFY_AND_ACCEPT_REQUEST: () => ({}), + VC_ACCEPTED: () => ({}), + VC_REJECTED: () => ({}), + VC_SENT: () => ({}), + CANCEL: () => ({}), + CLOSE_BANNER: () => ({}), + STAY_IN_PROGRESS: () => ({}), + RETRY: () => ({}), + DISMISS: () => ({}), + DISMISS_QUICK_SHARE_BANNER: () => ({}), + GOTO_HISTORY: () => ({}), + CONNECTED: () => ({}), + DISCONNECT: () => ({}), + BLE_ERROR: (bleError: BLEError) => ({bleError}), + CONNECTION_DESTROYED: () => ({}), + SCREEN_BLUR: () => ({}), + SCREEN_FOCUS: () => ({}), + BLUETOOTH_PERMISSION_ENABLED: () => ({}), + BLUETOOTH_PERMISSION_DENIED: () => ({}), + BLUETOOTH_STATE_ENABLED: () => ({}), + BLUETOOTH_STATE_DISABLED: () => ({}), + NEARBY_ENABLED: () => ({}), + NEARBY_DISABLED: () => ({}), + GOTO_SETTINGS: () => ({}), + START_PERMISSION_CHECK: () => ({}), + LOCATION_ENABLED: () => ({}), + LOCATION_DISABLED: () => ({}), + LOCATION_REQUEST: () => ({}), + CHECK_FLOW_TYPE: () => ({}), + UPDATE_VC_NAME: (vcName: string) => ({vcName}), + STORE_RESPONSE: (response: any) => ({response}), + APP_ACTIVE: () => ({}), + FACE_VALID: () => ({}), + FACE_INVALID: () => ({}), + RETRY_VERIFICATION: () => ({}), + RESET: () => ({}), + FACE_VERIFICATION_CONSENT: (isDoNotAskAgainChecked: boolean) => ({ + isDoNotAskAgainChecked, + }), + ALLOWED: () => ({}), + DENIED: () => ({}), +} + +export const ScanModel = createModel( + { + serviceRefs: {} as AppServices, + senderInfo: {} as DeviceInfo, + receiverInfo: {} as DeviceInfo, + selectedVc: {} as VC, + bleError: {} as BLEError, + loggers: [] as EmitterSubscription[], + vcName: '', + flowType: VCShareFlowType.SIMPLE_SHARE, + verificationImage: {} as CameraCapturedPicture, + openId4VpUri: '', + shareLogType: '' as ActivityLogType, + QrLoginRef: {} as ActorRefFrom, + showQuickShareSuccessBanner: false, + linkCode: '', + quickShareData: {}, + showFaceAuthConsent: true as boolean, + readyForBluetoothStateCheck: false, + showFaceCaptureSuccessBanner: false, + }, + { + events: ScanEvents, + }, + ); diff --git a/machines/bleShare/scan/selectors.ts b/machines/bleShare/scan/scanSelectors.ts similarity index 92% rename from machines/bleShare/scan/selectors.ts rename to machines/bleShare/scan/scanSelectors.ts index bfab28f076..a8f5c200f3 100644 --- a/machines/bleShare/scan/selectors.ts +++ b/machines/bleShare/scan/scanSelectors.ts @@ -117,3 +117,13 @@ export function selectIsQrLoginStoring(state: State) { export function selectIsDone(state: State) { return state.matches('reviewing.disconnect'); } + +export function selectIsMinimumStorageRequiredForAuditEntryLimitReached( + state: State, +) { + return state.matches('restrictSharingVc'); +} + +export function selectIsFaceVerificationConsent(state: State) { + return state.matches('reviewing.faceVerificationConsent'); +} diff --git a/machines/bleShare/scan/scanServices.ts b/machines/bleShare/scan/scanServices.ts new file mode 100644 index 0000000000..8e482f330e --- /dev/null +++ b/machines/bleShare/scan/scanServices.ts @@ -0,0 +1,197 @@ +import {WalletDataEvent} from '@mosip/tuvali/lib/typescript/types/events'; +import { isLocationEnabled } from "react-native-device-info"; +import Storage from '../../../shared/storage'; +import BluetoothStateManager from 'react-native-bluetooth-state-manager'; +import tuvali from '@mosip/tuvali'; +import { + check, + checkMultiple, + PERMISSIONS, + PermissionStatus, + requestMultiple, + RESULTS, +} from 'react-native-permissions'; +import {subscribe} from '../../../shared/openIdBLE/walletEventHandler'; +import { requestLocationPermission, checkLocationPermissionStatus } from "../../../shared/location"; +import { isIOS } from "../../../shared/constants"; + +const {wallet, EventTypes, VerificationStatus} = tuvali; + +export const ScanServices=(model:any)=>{ + return { checkBluetoothPermission: () => async callback => { + // wait a bit for animation to finish when app becomes active + await new Promise(resolve => setTimeout(resolve, 250)); + try { + // Passing Granted for android since permission status is always granted even if its denied. + let response: PermissionStatus = RESULTS.GRANTED; + + if (isIOS()) { + response = await check(PERMISSIONS.IOS.BLUETOOTH_PERIPHERAL); + } + + if (response === RESULTS.GRANTED) { + callback(model.events.BLUETOOTH_PERMISSION_ENABLED()); + } else { + callback(model.events.BLUETOOTH_PERMISSION_DENIED()); + } + } catch (e) { + console.error(e); + } + }, + + checkBluetoothState: () => callback => { + const subscription = BluetoothStateManager.onStateChange(state => { + if (state === 'PoweredOn') { + callback(model.events.BLUETOOTH_STATE_ENABLED()); + } else { + callback(model.events.BLUETOOTH_STATE_DISABLED()); + } + }, true); + return () => subscription.remove(); + }, + + requestBluetooth: () => callback => { + BluetoothStateManager.requestToEnable() + .then(() => callback(model.events.BLUETOOTH_STATE_ENABLED())) + .catch(() => callback(model.events.BLUETOOTH_STATE_DISABLED())); + }, + + requestToEnableLocationPermission: () => callback => { + requestLocationPermission( + () => callback(model.events.LOCATION_ENABLED()), + () => callback(model.events.LOCATION_DISABLED()), + ); + }, + + monitorConnection: () => callback => { + const walletErrorCodePrefix = 'TVW'; + const subscription = wallet.handleDataEvents(event => { + if (event.type === EventTypes.onDisconnected) { + callback({type: 'DISCONNECT'}); + } + if ( + event.type === EventTypes.onError && + event.code.includes(walletErrorCodePrefix) + ) { + callback({ + type: 'BLE_ERROR', + bleError: {message: event.message, code: event.code}, + }); + console.error('BLE Exception: ' + event.message); + } + }); + + return () => subscription.remove(); + }, + + checkNearByDevicesPermission: () => callback => { + checkMultiple([ + PERMISSIONS.ANDROID.BLUETOOTH_CONNECT, + PERMISSIONS.ANDROID.BLUETOOTH_SCAN, + ]) + .then(response => { + if ( + response[PERMISSIONS.ANDROID.BLUETOOTH_ADVERTISE] === + RESULTS.GRANTED && + response[PERMISSIONS.ANDROID.BLUETOOTH_CONNECT] === + RESULTS.GRANTED + ) { + callback(model.events.NEARBY_ENABLED()); + } else { + callback(model.events.NEARBY_DISABLED()); + } + }) + .catch(err => { + callback(model.events.NEARBY_DISABLED()); + }); + }, + + requestNearByDevicesPermission: () => callback => { + requestMultiple([ + PERMISSIONS.ANDROID.BLUETOOTH_SCAN, + PERMISSIONS.ANDROID.BLUETOOTH_CONNECT, + ]) + .then(response => { + if ( + response[PERMISSIONS.ANDROID.BLUETOOTH_SCAN] === + RESULTS.GRANTED && + response[PERMISSIONS.ANDROID.BLUETOOTH_CONNECT] === + RESULTS.GRANTED + ) { + callback(model.events.NEARBY_ENABLED()); + } else { + callback(model.events.NEARBY_DISABLED()); + } + }) + .catch(err => { + callback(model.events.NEARBY_DISABLED()); + }); + }, + + checkLocationPermission: () => callback => { + checkLocationPermissionStatus( + () => callback(model.events.LOCATION_ENABLED()), + () => callback(model.events.LOCATION_DISABLED()), + ); + }, + + checkLocationStatus: () => async callback => { + const isEnabled: boolean = await isLocationEnabled(); + if (isEnabled) { + callback(model.events.LOCATION_ENABLED()); + } else { + callback(model.events.LOCATION_DISABLED()); + } + }, + + startConnection: (context:any) => callback => { + wallet.startConnection(context.openId4VpUri); + const statusCallback = (event: WalletDataEvent) => { + if (event.type === EventTypes.onSecureChannelEstablished) { + callback({type: 'CONNECTED'}); + } + }; + + const subscription = subscribe(statusCallback); + return () => subscription?.remove(); + }, + + sendVc: context => callback => { + const statusCallback = (event: WalletDataEvent) => { + if (event.type === EventTypes.onDataSent) { + callback({type: 'VC_SENT'}); + } else if (event.type === EventTypes.onVerificationStatusReceived) { + callback({ + type: + event.status === VerificationStatus.ACCEPTED + ? 'VC_ACCEPTED' + : 'VC_REJECTED', + }); + } + }; + wallet.sendData( + JSON.stringify({ + ...context.selectedVc, + }), + ); + const subscription = subscribe(statusCallback); + return () => subscription?.remove(); + }, + + disconnect: () => () => { + try { + console.log("inside wallet disconnect"); + wallet.disconnect(); + } catch (e) { + // pass + } + }, + + checkStorageAvailability: () => async () => { + return Promise.resolve( + Storage.isMinimumLimitReached('minStorageRequiredForAuditEntry'), + ); + }, + }; + +} \ No newline at end of file diff --git a/machines/store.ts b/machines/store.ts index ccffc37207..76f9f39d2e 100644 --- a/machines/store.ts +++ b/machines/store.ts @@ -17,7 +17,7 @@ import { MY_VCS_STORE_KEY, RECEIVED_VCS_STORE_KEY, SETTINGS_STORE_KEY, - FACE_AUTH_CONSENT, + SHOW_FACE_AUTH_CONSENT_SHARE_FLOW, ENOENT, } from '../shared/constants'; import SecureKeystore from '@mosip/secure-keystore'; @@ -563,7 +563,7 @@ export async function setItem( appId, }; encryptedData = JSON.stringify(settings); - } else if (key === FACE_AUTH_CONSENT) { + } else if (key === SHOW_FACE_AUTH_CONSENT_SHARE_FLOW) { encryptedData = JSON.stringify(value); } else { encryptedData = await encryptJson(encryptionKey, JSON.stringify(value)); @@ -632,7 +632,7 @@ export async function getItem( parsedData.encryptedData = JSON.parse(decryptedData); } return parsedData; - } else if (key === FACE_AUTH_CONSENT) { + } else if (key === SHOW_FACE_AUTH_CONSENT_SHARE_FLOW) { return JSON.parse(data); } decryptedData = await decryptJson(encryptionKey, data); diff --git a/machines/store.typegen.ts b/machines/store.typegen.ts index dac362686e..333993e67c 100644 --- a/machines/store.typegen.ts +++ b/machines/store.typegen.ts @@ -1,77 +1,48 @@ -// This file was automatically generated. Edits will be overwritten -export interface Typegen0 { - '@@xstate/typegen': true; - internalEvents: { - 'done.invoke._store': { - type: 'done.invoke._store'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'done.invoke.store.resettingStorage:invocation[0]': { - type: 'done.invoke.store.resettingStorage:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'error.platform._store': {type: 'error.platform._store'; data: unknown}; - 'xstate.init': {type: 'xstate.init'}; - }; - invokeSrcNameMap: { - checkStorageInitialisedOrNot: 'done.invoke.store.checkStorageInitialisation:invocation[0]'; - clear: 'done.invoke.store.resettingStorage:invocation[0]'; - generateEncryptionKey: 'done.invoke.store.generatingEncryptionKey:invocation[0]'; - getEncryptionKey: 'done.invoke.store.gettingEncryptionKey:invocation[0]'; - hasAndroidEncryptionKey: 'done.invoke.store.checkEncryptionKey:invocation[0]'; - store: 'done.invoke._store'; - }; - missingImplementations: { - actions: never; - delays: never; - guards: never; - services: never; - }; - eventsCausingActions: { - forwardStoreRequest: - | 'APPEND' - | 'CLEAR' - | 'EXPORT' - | 'GET' - | 'GET_VCS_DATA' - | 'PREPEND' - | 'REMOVE' - | 'REMOVE_ITEMS' - | 'REMOVE_VC_METADATA' - | 'RESTORE_BACKUP' - | 'SET' - | 'UPDATE'; - notifyParent: - | 'KEY_RECEIVED' - | 'READY' - | 'done.invoke.store.resettingStorage:invocation[0]'; - setEncryptionKey: 'KEY_RECEIVED'; - }; - eventsCausingDelays: {}; - eventsCausingGuards: { - isCustomSecureKeystore: 'KEY_RECEIVED'; - }; - eventsCausingServices: { - checkStorageInitialisedOrNot: 'ERROR'; - clear: 'KEY_RECEIVED'; - generateEncryptionKey: 'ERROR' | 'IGNORE' | 'READY'; - getEncryptionKey: 'TRY_AGAIN'; - hasAndroidEncryptionKey: never; - store: - | 'KEY_RECEIVED' - | 'READY' - | 'done.invoke.store.resettingStorage:invocation[0]'; - }; - matchesStates: - | 'checkEncryptionKey' - | 'checkStorageInitialisation' - | 'failedReadingKey' - | 'generatingEncryptionKey' - | 'gettingEncryptionKey' - | 'ready' - | 'resettingStorage'; - tags: never; -} + // This file was automatically generated. Edits will be overwritten + + export interface Typegen0 { + '@@xstate/typegen': true; + internalEvents: { + "done.invoke._store": { type: "done.invoke._store"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"done.invoke.store.resettingStorage:invocation[0]": { type: "done.invoke.store.resettingStorage:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"error.platform._store": { type: "error.platform._store"; data: unknown }; +"xstate.init": { type: "xstate.init" }; + }; + invokeSrcNameMap: { + "checkStorageInitialisedOrNot": "done.invoke.store.checkStorageInitialisation:invocation[0]"; +"clear": "done.invoke.store.resettingStorage:invocation[0]"; +"generateEncryptionKey": "done.invoke.store.generatingEncryptionKey:invocation[0]"; +"getEncryptionKey": "done.invoke.store.gettingEncryptionKey:invocation[0]"; +"hasAndroidEncryptionKey": "done.invoke.store.checkEncryptionKey:invocation[0]"; +"store": "done.invoke._store"; + }; + missingImplementations: { + actions: never; + delays: never; + guards: never; + services: never; + }; + eventsCausingActions: { + "forwardStoreRequest": "APPEND" | "CLEAR" | "EXPORT" | "GET" | "GET_VCS_DATA" | "PREPEND" | "REMOVE" | "REMOVE_ITEMS" | "REMOVE_VC_METADATA" | "RESTORE_BACKUP" | "SET" | "UPDATE"; +"notifyParent": "KEY_RECEIVED" | "READY" | "done.invoke.store.resettingStorage:invocation[0]"; +"setEncryptionKey": "KEY_RECEIVED"; + }; + eventsCausingDelays: { + + }; + eventsCausingGuards: { + "isCustomSecureKeystore": "KEY_RECEIVED"; + }; + eventsCausingServices: { + "checkStorageInitialisedOrNot": "ERROR"; +"clear": "KEY_RECEIVED"; +"generateEncryptionKey": "ERROR" | "IGNORE" | "READY"; +"getEncryptionKey": "TRY_AGAIN"; +"hasAndroidEncryptionKey": never; +"store": "KEY_RECEIVED" | "READY" | "done.invoke.store.resettingStorage:invocation[0]"; + }; + matchesStates: "checkEncryptionKey" | "checkStorageInitialisation" | "failedReadingKey" | "generatingEncryptionKey" | "gettingEncryptionKey" | "ready" | "resettingStorage"; + tags: never; + } + \ No newline at end of file diff --git a/screens/Home/HomeScreenMachine.typegen.ts b/screens/Home/HomeScreenMachine.typegen.ts index 91dcdb4f5a..55f8848801 100644 --- a/screens/Home/HomeScreenMachine.typegen.ts +++ b/screens/Home/HomeScreenMachine.typegen.ts @@ -1,65 +1,40 @@ -// This file was automatically generated. Edits will be overwritten -export interface Typegen0 { - '@@xstate/typegen': true; - internalEvents: { - 'done.invoke.HomeScreen.tabs.checkStorage:invocation[0]': { - type: 'done.invoke.HomeScreen.tabs.checkStorage:invocation[0]'; - data: unknown; - __tip: 'See the XState TS docs to learn how to strongly type this.'; - }; - 'xstate.after(100)#HomeScreen.tabs.init': { - type: 'xstate.after(100)#HomeScreen.tabs.init'; - }; - 'xstate.init': {type: 'xstate.init'}; - }; - invokeSrcNameMap: { - checkStorageAvailability: 'done.invoke.HomeScreen.tabs.checkStorage:invocation[0]'; - }; - missingImplementations: { - actions: never; - delays: never; - guards: never; - services: never; - }; - eventsCausingActions: { - resetSelectedVc: 'DISMISS_MODAL' | 'xstate.init'; - sendAddEvent: 'DOWNLOAD_ID'; - setSelectedVc: 'VIEW_VC'; - spawnTabActors: 'xstate.init'; - }; - eventsCausingDelays: {}; - eventsCausingGuards: { - isMinimumStorageLimitReached: 'done.invoke.HomeScreen.tabs.checkStorage:invocation[0]'; - }; - eventsCausingServices: { - checkStorageAvailability: 'GOTO_ISSUERS'; - issuersMachine: 'done.invoke.HomeScreen.tabs.checkStorage:invocation[0]'; - }; - matchesStates: - | 'modals' - | 'modals.none' - | 'modals.viewingVc' - | 'tabs' - | 'tabs.checkStorage' - | 'tabs.gotoIssuers' - | 'tabs.history' - | 'tabs.idle' - | 'tabs.init' - | 'tabs.myVcs' - | 'tabs.receivedVcs' - | 'tabs.storageLimitReached' - | { - modals?: 'none' | 'viewingVc'; - tabs?: - | 'checkStorage' - | 'gotoIssuers' - | 'history' - | 'idle' - | 'init' - | 'myVcs' - | 'receivedVcs' - | 'storageLimitReached'; - }; - tags: never; -} + // This file was automatically generated. Edits will be overwritten + + export interface Typegen0 { + '@@xstate/typegen': true; + internalEvents: { + "done.invoke.HomeScreen.tabs.checkStorage:invocation[0]": { type: "done.invoke.HomeScreen.tabs.checkStorage:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; +"xstate.after(100)#HomeScreen.tabs.init": { type: "xstate.after(100)#HomeScreen.tabs.init" }; +"xstate.init": { type: "xstate.init" }; + }; + invokeSrcNameMap: { + "checkStorageAvailability": "done.invoke.HomeScreen.tabs.checkStorage:invocation[0]"; + }; + missingImplementations: { + actions: never; + delays: never; + guards: never; + services: never; + }; + eventsCausingActions: { + "resetSelectedVc": "DISMISS_MODAL" | "xstate.init"; +"sendAddEvent": "DOWNLOAD_ID"; +"setSelectedVc": "VIEW_VC"; +"spawnTabActors": "xstate.init"; + }; + eventsCausingDelays: { + + }; + eventsCausingGuards: { + "isMinimumStorageLimitReached": "done.invoke.HomeScreen.tabs.checkStorage:invocation[0]"; + }; + eventsCausingServices: { + "checkStorageAvailability": "GOTO_ISSUERS"; +"issuersMachine": "done.invoke.HomeScreen.tabs.checkStorage:invocation[0]"; + }; + matchesStates: "modals" | "modals.none" | "modals.viewingVc" | "tabs" | "tabs.checkStorage" | "tabs.gotoIssuers" | "tabs.history" | "tabs.idle" | "tabs.init" | "tabs.myVcs" | "tabs.receivedVcs" | "tabs.storageLimitReached" | { "modals"?: "none" | "viewingVc"; +"tabs"?: "checkStorage" | "gotoIssuers" | "history" | "idle" | "init" | "myVcs" | "receivedVcs" | "storageLimitReached"; }; + tags: never; + } + \ No newline at end of file diff --git a/screens/QrLogin/MyBindedVcs.tsx b/screens/QrLogin/MyBindedVcs.tsx index 1b6a486678..0f73924504 100644 --- a/screens/QrLogin/MyBindedVcs.tsx +++ b/screens/QrLogin/MyBindedVcs.tsx @@ -3,7 +3,7 @@ import {Button, Centered, Column, Text} from '../../components/ui'; import {Theme} from '../../components/ui/styleUtils'; import {useTranslation} from 'react-i18next'; import {useQrLogin} from './QrLoginController'; -import {QrLoginRef} from '../../machines/QrLoginMachine'; +import {QrLoginRef} from '../../machines/QrLogin/QrLoginMachine'; import {Icon} from 'react-native-elements'; import {Modal} from '../../components/ui/Modal'; import {VcItemContainer} from '../../components/VC/VcItemContainer'; diff --git a/screens/QrLogin/QrConsent.tsx b/screens/QrLogin/QrConsent.tsx index 66563a0125..d7f923f369 100644 --- a/screens/QrLogin/QrConsent.tsx +++ b/screens/QrLogin/QrConsent.tsx @@ -6,7 +6,7 @@ import {useQrLogin} from './QrLoginController'; import {Image, View} from 'react-native'; import {Icon, ListItem, Switch} from 'react-native-elements'; import {Modal} from '../../components/ui/Modal'; -import {QrLoginRef} from '../../machines/QrLoginMachine'; +import {QrLoginRef} from '../../machines/QrLogin/QrLoginMachine'; import {ScrollView} from 'react-native'; import {getClientNameForCurrentLanguage} from '../../i18n'; diff --git a/screens/QrLogin/QrLogin.tsx b/screens/QrLogin/QrLogin.tsx index e639755801..e42618c9fc 100644 --- a/screens/QrLogin/QrLogin.tsx +++ b/screens/QrLogin/QrLogin.tsx @@ -7,7 +7,7 @@ import {MessageOverlay} from '../../components/MessageOverlay'; import {MyBindedVcs} from './MyBindedVcs'; import {QrLoginSuccess} from './QrLoginSuccessMessage'; import {QrConsent} from './QrConsent'; -import {QrLoginRef} from '../../machines/QrLoginMachine'; +import {QrLoginRef} from '../../machines/QrLogin/QrLoginMachine'; import {Icon} from 'react-native-elements'; import {View} from 'react-native'; import {FaceVerificationAlertOverlay} from '../Scan/FaceVerificationAlertOverlay'; diff --git a/screens/QrLogin/QrLoginController.ts b/screens/QrLogin/QrLoginController.ts index d2f852d0ce..fcabc159b6 100644 --- a/screens/QrLogin/QrLoginController.ts +++ b/screens/QrLogin/QrLoginController.ts @@ -1,8 +1,8 @@ import {useSelector} from '@xstate/react'; import {useContext, useState} from 'react'; import {ActorRefFrom} from 'xstate'; +import { QrLoginEvents } from '../../machines/QrLogin/QrLoginMachine'; import { - QrLoginEvents, selectClientName, selectErrorMessage, selectEssentialClaims, @@ -25,7 +25,7 @@ import { selectVoluntaryClaims, selectCredential, selectVerifiableCredentialData, -} from '../../machines/QrLoginMachine'; +} from '../../machines/QrLogin/QrLoginSelectors'; import {selectBindedVcsMetadata} from '../../machines/VerifiableCredential/VCMetaMachine/VCMetaSelectors'; import {GlobalContext} from '../../shared/GlobalContext'; import {QrLoginProps} from './QrLogin'; @@ -85,8 +85,8 @@ export function useQrLogin({service}: QrLoginProps) { const vcData = vcRef.getSnapshot().context; service.send(QrLoginEvents.SELECT_VC(vcData)); }, - FACE_VERIFICATION_CONSENT: (isConsentGiven: boolean) => - service.send(QrLoginEvents.FACE_VERIFICATION_CONSENT(isConsentGiven)), + FACE_VERIFICATION_CONSENT: (isDoNotAskAgainChecked: boolean) => + service.send(QrLoginEvents.FACE_VERIFICATION_CONSENT(isDoNotAskAgainChecked)), DISMISS: () => service.send(QrLoginEvents.DISMISS()), SCANNING_DONE: (qrCode: string) => service.send(QrLoginEvents.SCANNING_DONE(qrCode)), diff --git a/screens/QrLogin/QrLoginSuccessMessage.tsx b/screens/QrLogin/QrLoginSuccessMessage.tsx index 43c6c360b5..1e6859396a 100644 --- a/screens/QrLogin/QrLoginSuccessMessage.tsx +++ b/screens/QrLogin/QrLoginSuccessMessage.tsx @@ -6,7 +6,7 @@ import {Modal} from '../../components/ui/Modal'; import {Centered, Button, Text, Column} from '../../components/ui'; import {Theme} from '../../components/ui/styleUtils'; import {useQrLogin} from './QrLoginController'; -import {QrLoginRef} from '../../machines/QrLoginMachine'; +import {QrLoginRef} from '../../machines/QrLogin/QrLoginMachine'; import {getClientNameForCurrentLanguage} from '../../i18n'; export const QrLoginSuccess: React.FC = props => { diff --git a/screens/Scan/FaceVerificationAlertOverlay.tsx b/screens/Scan/FaceVerificationAlertOverlay.tsx index 757d5a89d3..2cd5a784c7 100644 --- a/screens/Scan/FaceVerificationAlertOverlay.tsx +++ b/screens/Scan/FaceVerificationAlertOverlay.tsx @@ -90,7 +90,7 @@ export const FaceVerificationAlertOverlay: React.FC< interface FaceVerificationAlertProps { isVisible: boolean; - onConfirm: (isConsentGiven: boolean) => void; + onConfirm: (isDoNotAskAgainChecked: boolean) => void; close: () => void; isQrLogin?: boolean; } diff --git a/screens/Scan/ScanLayoutController.ts b/screens/Scan/ScanLayoutController.ts index ed710cdfc9..879754fdfc 100644 --- a/screens/Scan/ScanLayoutController.ts +++ b/screens/Scan/ScanLayoutController.ts @@ -24,7 +24,7 @@ import { selectIsFaceIdentityVerified, selectCredential, selectVerifiableCredentialData, -} from '../../machines/bleShare/scan/selectors'; +} from '../../machines/bleShare/scan/scanSelectors'; import { selectBleError, selectIsAccepted, diff --git a/screens/Scan/ScanScreen.tsx b/screens/Scan/ScanScreen.tsx index 127aae764c..fb438bcc31 100644 --- a/screens/Scan/ScanScreen.tsx +++ b/screens/Scan/ScanScreen.tsx @@ -16,10 +16,13 @@ import {BannerNotificationContainer} from '../../components/BannerNotificationCo import {SharingStatusModal} from './SharingStatusModal'; import {SvgImage} from '../../components/ui/svg'; import {LocationPermissionRational} from './LocationPermissionRational'; +import { FaceVerificationAlertOverlay } from './FaceVerificationAlertOverlay'; +import { useSendVcScreen } from './SendVcScreenController'; export const ScanScreen: React.FC = () => { const {t} = useTranslation('ScanScreen'); - const controller = useScanScreen(); + const scanScreenController = useScanScreen(); + const sendVcScreenController = useSendVcScreen(); const [isBluetoothOn, setIsBluetoothOn] = useState(false); useEffect(() => { @@ -36,13 +39,13 @@ export const ScanScreen: React.FC = () => { // TODO(kludge): skip running this hook on every render useEffect(() => { - if (controller.isStartPermissionCheck && !controller.isEmpty) - controller.START_PERMISSION_CHECK(); + if (scanScreenController.isStartPermissionCheck && !scanScreenController.isEmpty) + scanScreenController.START_PERMISSION_CHECK(); }); useEffect(() => { - if (controller.isQuickShareDone) controller.GOTO_HOME(); - }, [controller.isQuickShareDone]); + if (scanScreenController.isQuickShareDone) scanScreenController.GOTO_HOME(); + }, [scanScreenController.isQuickShareDone]); const openSettings = () => { Linking.openSettings(); @@ -123,14 +126,14 @@ export const ScanScreen: React.FC = () => { testID="enableLocationServicesMessage" align="center" color={Theme.Colors.errorMessage}> - {controller.locationError.message} + {scanScreenController.locationError.message}