From da125f0942beda50263638ebe1c2f0436c52633a Mon Sep 17 00:00:00 2001 From: Tilak Puli Date: Thu, 11 May 2023 15:09:37 +0530 Subject: [PATCH] feat(#84): [Pooja|Tilak] remove old nearby state machines and refactor selectors --- machines/app.ts | 32 +- machines/openIdBle/commonSelectors.ts | 58 + .../{request.ts => request/machine.ts} | 129 +- .../machine.typegen.ts} | 3 + machines/openIdBle/request/selectors.ts | 60 + .../openIdBle/{scan.ts => scan/machine.ts} | 128 +- .../machine.typegen.ts} | 0 machines/openIdBle/scan/selectors.ts | 76 ++ machines/request.ts | 1005 -------------- machines/scan.ts | 1181 ----------------- screens/Request/ReceiveVcScreenController.ts | 20 +- screens/Request/RequestLayoutController.ts | 20 +- screens/Request/RequestScreenController.ts | 30 +- screens/Scan/ScanLayoutController.ts | 40 +- screens/Scan/ScanScreenController.ts | 16 +- screens/Scan/SendVcScreenController.ts | 22 +- shared/GlobalContext.ts | 11 +- 17 files changed, 321 insertions(+), 2510 deletions(-) create mode 100644 machines/openIdBle/commonSelectors.ts rename machines/openIdBle/{request.ts => request/machine.ts} (88%) rename machines/openIdBle/{request.typegen.ts => request/machine.typegen.ts} (98%) create mode 100644 machines/openIdBle/request/selectors.ts rename machines/openIdBle/{scan.ts => scan/machine.ts} (90%) rename machines/openIdBle/{scan.typegen.ts => scan/machine.typegen.ts} (100%) create mode 100644 machines/openIdBle/scan/selectors.ts delete mode 100644 machines/request.ts delete mode 100644 machines/scan.ts diff --git a/machines/app.ts b/machines/app.ts index bdd9c881a9..e62a20d83b 100644 --- a/machines/app.ts +++ b/machines/app.ts @@ -12,16 +12,15 @@ import { createSettingsMachine, settingsMachine } from './settings'; import { storeMachine } from './store'; import { createVcMachine, vcMachine } from './vc'; import { createActivityLogMachine, activityLogMachine } from './activityLog'; -import { createRequestMachine, requestMachine } from './request'; -import * as BLERequest from './openIdBle/request'; -import * as BLEScan from './openIdBle/scan'; -import { createScanMachine, scanMachine } from './scan'; +import { + createRequestMachine, + requestMachine, +} from './openIdBle/request/machine'; +import { createScanMachine, scanMachine } from './openIdBle/scan/machine'; import { createRevokeMachine, revokeVidsMachine } from './revoke'; import { pure, respond } from 'xstate/lib/actions'; import { AppServices } from '../shared/GlobalContext'; -import { request } from '../shared/request'; -import { isBLEEnabled } from '../lib/smartshare'; const model = createModel( { @@ -197,19 +196,15 @@ export const appMachine = model.createMachine( activityLogMachine.id ); - serviceRefs.scan = isBLEEnabled - ? spawn( - BLEScan.createScanMachine(serviceRefs), - BLEScan.scanMachine.id - ) - : spawn(createScanMachine(serviceRefs), scanMachine.id); + serviceRefs.scan = spawn( + createScanMachine(serviceRefs), + scanMachine.id + ); - serviceRefs.request = isBLEEnabled - ? spawn( - BLERequest.createRequestMachine(serviceRefs), - BLERequest.requestMachine.id - ) - : spawn(createRequestMachine(serviceRefs), requestMachine.id); + serviceRefs.request = spawn( + createRequestMachine(serviceRefs), + requestMachine.id + ); serviceRefs.revoke = spawn( createRevokeMachine(serviceRefs), @@ -318,6 +313,7 @@ interface AppInfo { deviceId: string; deviceName: string; } + interface BackendInfo { application: { name: string; diff --git a/machines/openIdBle/commonSelectors.ts b/machines/openIdBle/commonSelectors.ts new file mode 100644 index 0000000000..c19efd66ca --- /dev/null +++ b/machines/openIdBle/commonSelectors.ts @@ -0,0 +1,58 @@ +import { StateFrom } from 'xstate'; +import { scanMachine } from './scan/machine'; +import { requestMachine } from './request/machine'; + +type State = StateFrom; + +export function selectIsCancelling(state: State) { + return state.matches('cancelling'); +} + +export function selectIsReviewing(state: State) { + return state.matches('reviewing'); +} + +export function selectIsAccepted(state: State) { + return state.matches('reviewing.accepted'); +} + +export function selectIsRejected(state: State) { + return state.matches('reviewing.rejected'); +} + +export function selectIsVerifyingIdentity(state: State) { + return state.matches('reviewing.verifyingIdentity'); +} + +export function selectIsInvalidIdentity(state: State) { + return state.matches('reviewing.invalidIdentity'); +} + +export function selectIsDisconnected(state: State) { + return state.matches('disconnected'); +} + +export function selectIsBluetoothDenied(state: State) { + return state.matches('bluetoothDenied'); +} + +// TODO: Remove these selectors and respective UI code once discussed with team +export function selectIsExchangingDeviceInfo() { + return false; +} + +export function selectIsExchangingDeviceInfoTimeout() { + return false; +} + +export function selectIsDone(state: State) { + return state.matches('reviewing.navigatingToHome'); +} + +export function selectIsOffline() { + return false; +} + +export function selectIsHandlingBleError(state: State) { + return state.matches('handlingBleError'); +} diff --git a/machines/openIdBle/request.ts b/machines/openIdBle/request/machine.ts similarity index 88% rename from machines/openIdBle/request.ts rename to machines/openIdBle/request/machine.ts index d5235a27b4..e3a3fa97c8 100644 --- a/machines/openIdBle/request.ts +++ b/machines/openIdBle/request/machine.ts @@ -1,20 +1,20 @@ import openIdBLE from 'react-native-openid4vp-ble'; import BluetoothStateManager from 'react-native-bluetooth-state-manager'; import { EmitterSubscription, Linking, Platform } from 'react-native'; -import { assign, EventFrom, send, StateFrom } from 'xstate'; +import { assign, EventFrom, send } from 'xstate'; import { createModel } from 'xstate/lib/model'; -import { DeviceInfo } from '../../components/DeviceInfoList'; +import { DeviceInfo } from '../../../components/DeviceInfoList'; import { getDeviceNameSync } from 'react-native-device-info'; -import { StoreEvents } from '../store'; -import { VC } from '../../types/vc'; -import { AppServices } from '../../shared/GlobalContext'; +import { StoreEvents } from '../../store'; +import { VC } from '../../../types/vc'; +import { AppServices } from '../../../shared/GlobalContext'; import { RECEIVED_VCS_STORE_KEY, VC_ITEM_STORE_KEY, -} from '../../shared/constants'; -import { ActivityLogEvents, ActivityLogType } from '../activityLog'; -import { VcEvents } from '../vc'; -import { offlineSubscribe } from '../../shared/openIdBLE/verifierEventHandler'; +} from '../../../shared/constants'; +import { ActivityLogEvents, ActivityLogType } from '../../activityLog'; +import { VcEvents } from '../../vc'; +import { offlineSubscribe } from '../../../shared/openIdBLE/verifierEventHandler'; import { log } from 'xstate/lib/actions'; import { VerifierDataEvent } from 'react-native-openid4vp-ble/lib/typescript/types/bleshare'; // import { verifyPresentation } from '../shared/vcjs/verifyPresentation'; @@ -70,6 +70,7 @@ const model = createModel( }, } ); +export const RequestEvents = model.events; export const requestMachine = /** @xstate-layout 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-TVAYfRqda4a23LS5QDcM-ZwTQQNWwT5dcwlNEbzYNfk1-IiHkKAVqYUYWYYUnMADajmI9XYESw0dKGynKisbZAZOHRCHEEqvTFa9-GRL-U4u6tJFwLYXpS0dYAtS7IbDEbUHYAoFHFEYNc6zGli7fXfHGgQQ-UeRgiG-GucLEBso6F+EhZGd3R6tKXRZoYKhmudLGlm-fNmyAHVJmoa2Skav3ImrEEmhyEocmjLbYQZa2Rqpw-iDGNAjAr6W65W+6i4rYAsQyFoaEk0c2VQAsH3YqZiZiOgiWRg6osAVglTX06wYdXko2UQ60PECQ3wXwIAA */ @@ -77,7 +78,7 @@ export const requestMachine = { predictableActionArguments: true, preserveActionOrder: true, - tsTypes: {} as import('./request.typegen').Typegen0, + tsTypes: {} as import('./machine.typegen').Typegen0, schema: { context: model.initialContext, events: {} as EventFrom, @@ -185,7 +186,7 @@ export const requestMachine = }, on: { ADV_STARTED: { - actions: ['setOpenID4VpUri'], + actions: 'setOpenID4VpUri', }, CONNECTED: { target: 'waitingForVc', @@ -695,109 +696,3 @@ export function createRequestMachine(serviceRefs: AppServices) { serviceRefs, }); } - -type State = StateFrom; - -export function selectSenderInfo(state: State) { - return state.context.senderInfo; -} - -export function selectOpenId4VpUri(state: State) { - return state.context.openId4VpUri; -} - -export function selectIncomingVc(state: State) { - return state.context.incomingVc; -} - -export function selectSharingProtocol(state: State) { - return state.context.sharingProtocol; -} - -export function selectIsIncomingVp(state: State) { - return state.context.incomingVc?.verifiablePresentation != null; -} - -export function selectIsCancelling(state: State) { - return state.matches('cancelling'); -} - -export function selectIsReviewing(state: State) { - return state.matches('reviewing'); -} - -export function selectIsAccepted(state: State) { - return state.matches('reviewing.accepted'); -} - -export function selectIsAccepting(state: State) { - return state.matches('reviewing.accepting'); -} - -export function selectIsSavingFailedInIdle(state: State) { - return state.matches('reviewing.savingFailed.idle'); -} - -export function selectIsSavingFailedInViewingVc(state: State) { - return state.matches('reviewing.savingFailed.viewingVc'); -} - -export function selectStoreError(state: State) { - return state.context.storeError; -} - -export function selectIsRejected(state: State) { - return state.matches('reviewing.rejected'); -} - -export function selectIsVerifyingIdentity(state: State) { - return state.matches('reviewing.verifyingIdentity'); -} - -export function selectIsVerifyingVp(state: State) { - return state.matches('reviewing.verifyingVp'); -} - -export function selectIsInvalidIdentity(state: State) { - return state.matches('reviewing.invalidIdentity'); -} - -export function selectIsDisconnected(state: State) { - return state.matches('disconnected'); -} - -export function selectIsWaitingForConnection(state: State) { - return state.matches('waitingForConnection'); -} - -export function selectIsBluetoothDenied(state: State) { - return state.matches('bluetoothDenied'); -} - -export function selectIsCheckingBluetoothService(state: State) { - return state.matches('checkingBluetoothService'); -} -//TODO: post discussion with team remove the selectIsExchangingDeviceInfo & selectIsExchangingDeviceInfoTimeOut functions -export function selectIsExchangingDeviceInfo() { - return true; -} - -export function selectIsExchangingDeviceInfoTimeout() { - return true; -} - -export function selectIsWaitingForVc(state: State) { - return state.matches('waitingForVc.inProgress'); -} - -export function selectIsWaitingForVcTimeout(state: State) { - return state.matches('waitingForVc.timeout'); -} - -export function selectIsDone(state: State) { - return state.matches('reviewing.navigatingToHome'); -} - -export function selectIsHandlingBleError(state: State) { - return state.matches('handlingBleError'); -} diff --git a/machines/openIdBle/request.typegen.ts b/machines/openIdBle/request/machine.typegen.ts similarity index 98% rename from machines/openIdBle/request.typegen.ts rename to machines/openIdBle/request/machine.typegen.ts index 7bdc1708e4..2b2f756caf 100644 --- a/machines/openIdBle/request.typegen.ts +++ b/machines/openIdBle/request/machine.typegen.ts @@ -75,10 +75,13 @@ export interface Typegen0 { | 'done.invoke.request.reviewing.verifyingVp:invocation[0]'; sendVcReceived: 'STORE_RESPONSE'; setIncomingVc: 'VC_RECEIVED'; + setOpenID4VpUri: 'ADV_STARTED'; setReceiveLogTypeDiscarded: 'CANCEL' | 'REJECT' | 'STORE_ERROR'; setReceiveLogTypeRegular: 'ACCEPT' | 'STORE_RESPONSE'; setReceiveLogTypeUnverified: 'FACE_INVALID'; setReceiveLogTypeVerified: 'FACE_VALID'; + setReceiverInfo: 'CONNECTED'; + setSenderInfo: 'CONNECTED'; setStoringError: 'STORE_ERROR'; storeVc: 'STORE_RESPONSE'; switchProtocol: 'SWITCH_PROTOCOL'; diff --git a/machines/openIdBle/request/selectors.ts b/machines/openIdBle/request/selectors.ts new file mode 100644 index 0000000000..dc38b9eb55 --- /dev/null +++ b/machines/openIdBle/request/selectors.ts @@ -0,0 +1,60 @@ +import { StateFrom } from 'xstate'; +import { requestMachine } from './machine'; + +type State = StateFrom; + +export function selectSenderInfo(state: State) { + return state.context.senderInfo; +} + +export function selectIncomingVc(state: State) { + return state.context.incomingVc; +} + +export function selectSharingProtocol(state: State) { + return state.context.sharingProtocol; +} + +export function selectIsIncomingVp(state: State) { + return state.context.incomingVc?.verifiablePresentation != null; +} + +export function selectIsReviewingInIdle(state: State) { + return state.matches('reviewing.idle'); +} + +export function selectIsWaitingForConnection(state: State) { + return state.matches('waitingForConnection'); +} + +export function selectIsCheckingBluetoothService(state: State) { + return state.matches('checkingBluetoothService'); +} + +export function selectIsWaitingForVc(state: State) { + return state.matches('waitingForVc.inProgress'); +} + +export function selectIsWaitingForVcTimeout(state: State) { + return state.matches('waitingForVc.timeout'); +} + +export function selectOpenId4VpUri(state: State) { + return state.context.openId4VpUri; +} + +export function selectIsAccepting(state: State) { + return state.matches('reviewing.accepting'); +} + +export function selectIsSavingFailedInIdle(state: State) { + return state.matches('reviewing.savingFailed.idle'); +} + +export function selectIsSavingFailedInViewingVc(state: State) { + return state.matches('reviewing.savingFailed.viewingVc'); +} + +export function selectStoreError(state: State) { + return state.context.storeError; +} diff --git a/machines/openIdBle/scan.ts b/machines/openIdBle/scan/machine.ts similarity index 90% rename from machines/openIdBle/scan.ts rename to machines/openIdBle/scan/machine.ts index 7060c9ebba..2834d2900a 100644 --- a/machines/openIdBle/scan.ts +++ b/machines/openIdBle/scan/machine.ts @@ -9,29 +9,31 @@ import { EventFrom, send, spawn, - StateFrom, } from 'xstate'; import { createModel } from 'xstate/lib/model'; import { EmitterSubscription, Linking, Platform } from 'react-native'; -import { DeviceInfo } from '../../components/DeviceInfoList'; +import { DeviceInfo } from '../../../components/DeviceInfoList'; import { getDeviceNameSync } from 'react-native-device-info'; -import { VC, VerifiablePresentation } from '../../types/vc'; -import { AppServices } from '../../shared/GlobalContext'; -import { ActivityLogEvents, ActivityLogType } from '../activityLog'; -import { MY_LOGIN_STORE_KEY, VC_ITEM_STORE_KEY } from '../../shared/constants'; -import { offlineSubscribe } from '../../shared/openIdBLE/walletEventHandler'; +import { VC, VerifiablePresentation } from '../../../types/vc'; +import { AppServices } from '../../../shared/GlobalContext'; +import { ActivityLogEvents, ActivityLogType } from '../../activityLog'; +import { + MY_LOGIN_STORE_KEY, + VC_ITEM_STORE_KEY, +} from '../../../shared/constants'; +import { offlineSubscribe } from '../../../shared/openIdBLE/walletEventHandler'; import { check, PERMISSIONS, PermissionStatus, RESULTS, } from 'react-native-permissions'; -import { checkLocation, requestLocation } from '../../shared/location'; +import { checkLocation, requestLocation } from '../../../shared/location'; import { CameraCapturedPicture } from 'expo-camera'; import { log } from 'xstate/lib/actions'; -import { isBLEEnabled } from '../../lib/smartshare'; -import { createQrLoginMachine, qrLoginMachine } from '../QrLoginMachine'; -import { StoreEvents } from '../store'; +import { isBLEEnabled } from '../../../lib/smartshare'; +import { createQrLoginMachine, qrLoginMachine } from '../../QrLoginMachine'; +import { StoreEvents } from '../../store'; import { WalletDataEvent } from 'react-native-openid4vp-ble/lib/typescript/types/bleshare'; const { wallet } = openIdBLE; @@ -84,7 +86,7 @@ const model = createModel( LOCATION_DISABLED: () => ({}), LOCATION_REQUEST: () => ({}), UPDATE_VC_NAME: (vcName: string) => ({ vcName }), - STORE_RESPONSE: (response: unknown) => ({ response }), + STORE_RESPONSE: (response: any) => ({ response }), APP_ACTIVE: () => ({}), FACE_VALID: () => ({}), FACE_INVALID: () => ({}), @@ -95,6 +97,7 @@ const model = createModel( } ); const QR_LOGIN_REF_ID = 'QrLogin'; +export const ScanEvents = model.events; export const scanMachine = /** @xstate-layout N4IgpgJg5mDOIC5SwMYEMB2BiAygYQCUBRIgOQH0AhAGQFUCBtABgF1FQAHAe1gEsAXXlwzsQAD0QAWAEwAaEAE9E0gOzSAdNICsTbaq0BOLdoAcAXzPzUmXIRIUAYgHk8tHMzZIQ3PoOGiJBBl5JQQTAwN1HSYARgMmADYDSS0TLS0LK3RsGiJyIgICJ0ZWUR8BIREvQODFRBjpEyimXSZJBNTdE2lpTJBrDHUUAAswFABrXgwoSgAbAFcwfi4ufmGcMAAnADdeFDAh0YmpqCwaWiIAFScnS4AJcgBBamonAHUiABEPMp4K-2qiC0kkiagSCQAzCYIZIVAkVLCQogjJJ1C1dNIYroIkwVH0BocxpNpnNFstVustrt9oTjtMznQrjd7uRPmQAJJfH5ecp+KqgQIGCEQ9RxLQQmIqcVQ1JyOphaQJZq6GRSmKSKH47K04kzBZLFZrDY7PYHTZgACOi1ggnp5yZtweZEeuW+pR5fz5ASBIPUYMh0Nh8MR8pUTC0fp02niMlSCRiWswOpOpINFON1LNlutttO9uujtZ7JwLuoXPdnE9lW9CCFIrFEqlwrS3SRQQ6ysV3RUJjUYYyln62pGRJT+vJRqppvUYAwaAARrNIFhuZXfNXAbXhaKjI3pS25aFeyo0S1MbEkuqYglE4NF2TDcNPrPeMvHgAFd9PPCXdkANSIVdvCrAEBWUOJ1GhQwYTaeIJSMNtJBiCN0QhFoTHjXQYVvdR7zTNZnwwV8ICwABxW4nHIHArl-UhSPcCtgPXUDxEQCFpFiTQYUaMMNVhHo23YppDDULRkJ0GFYRwlAlzQTYTjwYQMDGPksE+Ys8CcUhSCIH8gN5DcwIVQSTHDTRoRiBomHYrR4QhaTZPk6ZFIwZSUFUsQbTQfgDjQAAzHzNgACjZHBLiKABNchfwAWSIJxaEuABKLACRksA5IUpSVMqfSQP5Vja0PNipSYdR4wSSQmGSHQb0HAk-KmCAstcnLhFsR5SDy5iCsCcUIxiISEhMNIsRSLREJVcqWkkNIqq0FQYm6HDGowZrnOy9zKg6rqYk8Nd-l6n0BqGkaxLadJBIRMrewlUb42hSEVqalq3NU-BOoYaR9qYw6a2BE7GmG0aLom+UoWhP0NWkGEVGSAwEl6ertVgYYuAAdwARU2aguCgKYsAgYQDimbYuHGA5sdx-GMG6v7N26EVMRGxIhQMJaVBUK7OcgkFoXY6yxLqrIk1RjGqbxgn1JwGLiwYn6DJYvqIUBjCzrGy7waF9QVZaSVGjPNocLFrGcclwYbS4JzTjC4o8mIHB3y06i6a9TdLIiSCVaFcNrIhOGEiu8UdZUO6haWiEnuRpMUE23MsE07TdMucsFfymtEcE68yt1phukkAv43s6PBlj1qtumdQpnfTY8fNWBYCwTz+G83yAq2ILE50n92S06L2TihLktS4c45OKuMBruu4FgV3DMKgxFXUWb2mBAw1A1UPJo7btmfSRG4WksfK8EABbMAuHmfgE86vAiGoOelcQTPwfPSDoj5xHGxw81djAdHx6wDAEuCuUA-woCwLQd8nxHgp3IMQR4OAtKPyOggdUPQdZ2W6KoFI7RA7ynEhoZCSRMRxGGhxYuItBi-1fAAyuQCQG5nAWpDSWlu6XBQTWJaC1RSxCFhxW6ec2yqFMuVdo3YEaxlUD-MAf86FQHUAwnK0xmHUTLD+cgf48CcPdhqJUWJbLIVhD2RaXMCHjT9NZeEI0Ei4h7OYEu6gaH-0AcA5RYCIEAQIOyBwUVOqfG-Hfd8lx4FEExhcMKOijLDRPMCXisFpBIVsm2a88YdwwnZhqVIDQHFUKcbI2hrjGEnGYY8PAQSQnEHCUQSJjFFaoJiVEWEbQElJPwaEZC6pNBVUaNeboiRclDiTM4+Rii3GgOYXgW+98omFUGmY0IiSUg6wRqY2auJcTCyGdQgpLj6HjKYRA64pFSJlnIG4Ao5BE7UVIBwup6d3YQkXpBboERtDpAwmDDp3tNA6D0cYWEkcDAyLkePbI+xZizBOCue5PUuEmFhLwzpiM86hyEQQ6qN1hQLXPADGGILCn7LWiUiB0su7J1mYEJaiKsTIoEWikwwi0WinEbY4EHQV4Er2QooBxKVGeLwFRMgdy05ws3P7GI6gIjSvVLEaqGEFnKDhJEcIw0qpYjSItSh2z8mgqJetDxWAtGBKIME1OvwxVGUspHTQCMhRqG0M2Rl8pVD+xWcNdIlkKpbIJCM1xfLDXGuIAAKWTuaj0lq5kNCVNIO1-sej7mdYsiqYjwTDVsWCaRji-X6pJRPKeUB66N2bq3dQ-lApBRwHcR43i6L90HolFKvrdmjN5Qa8B+ba6FpnpSoEec-QmAaDoYdQovnKFGiysMyEOKtGsly1ts520oHUGfC+V8b6kDvg-WF9MrVettUkeNjqIbCNsvo9oU6lpGGgvO8eaAUD7A4D5Ei0tZY4Hlha3dcyQQniEteKdfylpMrdU8j1YlrypNvZXc0AArFSy5X1y17WghFJ5aX8NRWhJNygU2VRibK0O6ooMKO2FsXgfkFAnHZBAWcgh+AKCwA4MpeQ-zPHZG6UVX6qWSmERhes4iYaDoRPi7NLbx6kfkhRqjNGMB0YY0xu+5B2SkFY9QdjyHGlxJaSCRJxCUnxA0IelIZ0VaSmI+oCT5HKPTGo7RgQDGpmbpmTut20TexNPiTptpKTMLlVHYk2Ig7qqSHMygc03kSkcEJsTCeZMKaKO1DmhRYWMpMI4AgUmXB0B8g8MhhoiqEDaB7H54UEQEWQjEqF8LaWsBbFrpsdQHBZjeT8lbU+CXhlicriliLKj0uZey7lVgyHGgiiSP1BaecYY2RSekSIHQ7JGHjHDMzom9UKNJmgKFEBbOyfsywmWSGXPz0CKYcqiT14AtiBxAr15g6WQvCrIajRzObe27tuTWBiDhSil4nx7Ipm-mQcdp+hXhrnZ-Vdqyt2eySuSLDMShcOU4WaqgOOCHixvo-RGrj4FQ47mMAjcU7N-bAd-QjNI4HvU4WGJgCAUKSRLiIJserB2sfIcjqicEVVJHhl7LGsdaDGjKj1pq9e4IcJvd4C+zHR3OOucKmoRCDRJXhnjZzJCh9HEjjpFAXGg3hAZmnDr3UOAW78HmI3V4gPe4UGdK6PL7RIi7ksvzYzkg2w+y9hk2y6QuxIzySbk4+uIuG6nDSIP0wzfeUt1ga3sDbdFhLA7kHqD1RJCleKV3wp3dthMcvVI4o0hLdMgOQPRxdQh75Ebmk5orRwFzJcLgRA5yLjAHHlwCe+727LBxz9CuqUGBGsvf2OmOiJBhm2ILaIoIe3aEhSq0kK-B6y6HjANesz15tCcJvLeFxLg7zbvu0tSzhoOgP+oQ+mibzH7VSfoZDBRCggXYwvYclL9HNMKvlQN-JmmO+LYU+XgBubaePIHO3UgU-PvHHC-QrdeNDWaBETmIWReT3KEEOWqcICGR1D-XXb-MPE0CPZff-QA4AvgdqMAxPE-FPeXE7ZQMSEUCfDoR1aMdpRAQdJURGMSDCRGaVReXAyvVfavcPA4VHffZcSgvuKpCJEVfvOgtBCIOHWNMMFESyBaQXFQmfYUBECUaqBaELbXYgvXIQn-EQ9QGTYiLAD8L8MpX8ACEbBaJobnJCdieMKqDoPPcEUUPQOITEHoJbAQlfA3dfMwiwiQzvcA0JapWpWg0HVQWNHWbgvOVIBEL1PPJaUURaZIGQNmBaPEPoDALgGjeALwAYOQ0HAAWjYIQCqMlznC2lI3KNQVITEUp0qgwklEHWEV9G0EC0emBjPECMZwfHTBEKaJrA4iVCgiFCqhBGsjFDbGyVPFaCQg1CeXyPL0-z1BGMnEIIOEjygHGM3G0FRGmJgjmPgkF3ZiVFKn0FMhhEhADx1QONTAnEpD2PyS31zCOKMglElVh30HXhaThDbHBGEj1h7AqixDhiGO2PwneMzBnFbyXAgB+MVzSEgl6VxH9nXksmKlrERV6J6Dwy6HXhwjwjeMImIjRO43iCfyHwLmh3VEQjQjRCjHZjzkhBhDL2eMclejagKnqRrHYkSV4XXhSCxANghBSRVnKjBKhGlUWk12egDRcjenniFPFUSGXmZieTQkji9UFwlQGjKwdSHUGh9RRjRlNmpimBpMQGQM0CWlMkPXZmPEEg+V5jKyd05kSWNmtIlhpirnpzAHtLCB4Sv0jhZkMQRCugggyU+R7GySzTyRNkDKmEUWWGtjDKH0lSKzf25xGmvCDhFAySlGwWmIMNTIDLNiDLnF2CgF6ygCbzuC4HPjDMGk9lHyHyhEsjhgMG5imL5mJPPHDCrOeOPkOJgPkIRBuOsljULilClEEi91cNMnDGITSCPnLlzE7WngbjDLhlRDDHYmyPhHUO3lONUCxA6FDlDmBW10nJXV4HPkvn4A7L6UghyVWUXmxUvMxMWkSAWn9ieWIzDJBBSX1kjAvEXkSHcMtM63WzGWKX5XAqMCRQDkbEXnZh82DkwmvCeyBhezW0JWS0wAhQZynPP3kIaCQjZPEW6EqkslqEWRf0glWUlHWTDC1zySSzGQDXATDPYhFD4MyTlSH3hGESLlTUI3FySALnMzbTzWri7SLSEsWilT4NlSxAkoK0aB0BZSSHnMlHBH9kUsXTzVXTfJzI0qhEaHXlVThChF4wMvTzgkxDhEhA2J1T4qUv5X4vfOnNBx0CaABOHXDFHSZVmkMseL4kqgWnM3vUfWfQ7Kw2XkwneUJxJyZS6VAxlAaBhElB5ObSQtg3g1RKCrTwXKiCFAskjmGhVkF0VElBivTVxEVBTJ8q6wUXrN4EbMby4FbPbMqq4URg0HzMXh-XhHxNdRPFVQLiMGzgq3M0sykxsxkzkxzPXj9CBN9kYsWmqMlB5mqmEr+VG21RKtIqGGq0ixstmw1BeWbFSLiDJJIu5Viy22lw+3szuoIXZhPDhnOhf0YrzhR2ALLjekgDDI4g4lPE5m6CKpSOqNmvYrAy9Ug0cVpzWkormDAGZ3qw7PCGaEhLznVXsUOoSPRFFwWjkrqO2E+oquotBzhGPPnLPKXKNJGhVUVFVB-V7EGTSiMPwJCL2I-LSQoWqgXJnXv1CERklVSFKx7Pzgl0MK2OFt-wOOjwtxKKZqquqk0GskluSGlulPlCwKf0araEaHznHMFrVpMIIMRLrxzB32b2RNDJGvdkvG6Q8tjSwNDlNtCBZoL01VskNtsQQtLiFodpFsRIOIAM2CAJAJYk1KMh6H1v9EQLHJlCn2eVKjzivQBhVs2LwJjt-zELb0Zt+lgPTtBEVHaP7A1DSDz2BE7FSSKzGthPVtCJfChs9rTp7BFF7Cz38KskF0HXm20CWnBFjWlSRgsCAA */ @@ -102,7 +105,7 @@ export const scanMachine = { predictableActionArguments: true, preserveActionOrder: true, - tsTypes: {} as import('./scan.typegen').Typegen0, + tsTypes: {} as import('./machine.typegen').Typegen0, schema: { context: model.initialContext, events: {} as EventFrom, @@ -857,102 +860,3 @@ export function createScanMachine(serviceRefs: AppServices) { serviceRefs, }); } - -type State = StateFrom; - -export function selectReceiverInfo(state: State) { - return state.context.receiverInfo; -} - -export function selectReason(state: State) { - return state.context.reason; -} - -export function selectVcName(state: State) { - return state.context.vcName; -} - -export function selectSelectedVc(state: State) { - return state.context.selectedVc; -} - -export function selectIsScanning(state: State) { - return state.matches('findingConnection'); -} - -export function selectIsConnecting(state: State) { - return state.matches('connecting.inProgress'); -} - -export function selectIsConnectingTimeout(state: State) { - return state.matches('connecting.timeout'); -} - -//TODO: post discussion with team remove the selectIsExchangingDeviceInfo & selectIsExchangingDeviceInfoTimeOut functions -export function selectIsExchangingDeviceInfo() { - return true; -} - -export function selectIsExchangingDeviceInfoTimeout() { - return true; -} - -export function selectIsReviewing(state: State) { - return state.matches('reviewing'); -} - -export function selectIsSelectingVc(state: State) { - return state.matches('reviewing.selectingVc'); -} - -export function selectIsSendingVc(state: State) { - return state.matches('reviewing.sendingVc.inProgress'); -} - -export function selectIsSendingVcTimeout(state: State) { - return state.matches('reviewing.sendingVc.timeout'); -} - -export function selectIsAccepted(state: State) { - return state.matches('reviewing.accepted'); -} - -export function selectIsRejected(state: State) { - return state.matches('reviewing.rejected'); -} - -export function selectIsInvalid(state: State) { - return state.matches('invalid'); -} - -export function selectIsBluetoothDenied(state: State) { - return state.matches('bluetoothDenied'); -} - -export function selectIsLocationDenied(state: State) { - return state.matches('checkingLocationService.denied'); -} - -export function selectIsLocationDisabled(state: State) { - return state.matches('checkingLocationService.disabled'); -} - -export function selectIsDone(state: State) { - return state.matches('reviewing.navigatingToHome'); -} - -export function selectIsVerifyingIdentity(state: State) { - return state.matches('reviewing.verifyingIdentity'); -} - -export function selectIsInvalidIdentity(state: State) { - return state.matches('reviewing.invalidIdentity'); -} - -export function selectIsCancelling(state: State) { - return state.matches('reviewing.cancelling'); -} - -export function selectIsHandlingBleError(state: State) { - return state.matches('handlingBleError'); -} diff --git a/machines/openIdBle/scan.typegen.ts b/machines/openIdBle/scan/machine.typegen.ts similarity index 100% rename from machines/openIdBle/scan.typegen.ts rename to machines/openIdBle/scan/machine.typegen.ts diff --git a/machines/openIdBle/scan/selectors.ts b/machines/openIdBle/scan/selectors.ts new file mode 100644 index 0000000000..21c12f4f3d --- /dev/null +++ b/machines/openIdBle/scan/selectors.ts @@ -0,0 +1,76 @@ +import { StateFrom } from 'xstate'; +import { scanMachine } from './machine'; + +type State = StateFrom; + +export function selectReceiverInfo(state: State) { + return state.context.receiverInfo; +} + +export function selectReason(state: State) { + return state.context.reason; +} + +export function selectVcName(state: State) { + return state.context.vcName; +} + +export function selectSelectedVc(state: State) { + return state.context.selectedVc; +} + +export function selectQrLoginRef(state: State) { + return state.context.QrLoginRef; +} + +export function selectIsScanning(state: State) { + return state.matches('findingConnection'); +} + +export function selectIsConnecting(state: State) { + return state.matches('connecting.inProgress'); +} + +export function selectIsConnectingTimeout(state: State) { + return state.matches('connecting.timeout'); +} + +export function selectIsSelectingVc(state: State) { + return state.matches('reviewing.selectingVc'); +} + +export function selectIsSendingVc(state: State) { + return state.matches('reviewing.sendingVc.inProgress'); +} + +export function selectIsSendingVcTimeout(state: State) { + return state.matches('reviewing.sendingVc.timeout'); +} + +export function selectIsSent(state: State) { + return state.matches('reviewing.sendingVc.sent'); +} + +export function selectIsInvalid(state: State) { + return state.matches('invalid'); +} + +export function selectIsLocationDenied(state: State) { + return state.matches('checkingLocationService.denied'); +} + +export function selectIsLocationDisabled(state: State) { + return state.matches('checkingLocationService.disabled'); +} + +export function selectIsShowQrLogin(state: State) { + return state.matches('showQrLogin'); +} + +export function selectIsQrLoginDone(state: State) { + return state.matches('showQrLogin.navigatingToHome'); +} + +export function selectIsQrLoginStoring(state: State) { + return state.matches('showQrLogin.storing'); +} diff --git a/machines/request.ts b/machines/request.ts deleted file mode 100644 index 8b689ee1ca..0000000000 --- a/machines/request.ts +++ /dev/null @@ -1,1005 +0,0 @@ -/* eslint-disable sonarjs/no-duplicate-string */ -import SmartshareReactNative from '@idpass/smartshare-react-native'; -import uuid from 'react-native-uuid'; -import BluetoothStateManager from 'react-native-bluetooth-state-manager'; -import { EmitterSubscription, Linking, Platform } from 'react-native'; -import { assign, EventFrom, send, sendParent, StateFrom } from 'xstate'; -import { createModel } from 'xstate/lib/model'; -import { DeviceInfo } from '../components/DeviceInfoList'; -import { getDeviceNameSync } from 'react-native-device-info'; -import { StoreEvents } from './store'; -import { VC } from '../types/vc'; -import { AppServices } from '../shared/GlobalContext'; -import { - GNM_API_KEY, - RECEIVED_VCS_STORE_KEY, - VC_ITEM_STORE_KEY, -} from '../shared/constants'; -import { ActivityLogEvents, ActivityLogType } from './activityLog'; -import { VcEvents } from './vc'; -import { ConnectionParams } from '@idpass/smartshare-react-native/lib/typescript/IdpassSmartshare'; -import { - ExchangeReceiverInfoEvent, - onlineSubscribe, - offlineSubscribe, - PairingResponseEvent, - onlineSend, - offlineSend, - SendVcResponseEvent, -} from '../shared/smartshare'; -import { log } from 'xstate/lib/actions'; -import NetInfo from '@react-native-community/netinfo'; -// import { verifyPresentation } from '../shared/vcjs/verifyPresentation'; - -const { GoogleNearbyMessages, IdpassSmartshare } = SmartshareReactNative; - -type SharingProtocol = 'OFFLINE' | 'ONLINE'; - -const model = createModel( - { - serviceRefs: {} as AppServices, - senderInfo: {} as DeviceInfo, - receiverInfo: {} as DeviceInfo, - incomingVc: {} as VC, - openId4VpUri: '', - loggers: [] as EmitterSubscription[], - sharingProtocol: (Platform.OS === 'ios' - ? 'ONLINE' - : 'OFFLINE') as SharingProtocol, - receiveLogType: '' as ActivityLogType, - pairId: '', - }, - { - events: { - ACCEPT: () => ({}), - ACCEPT_AND_VERIFY: () => ({}), - REJECT: () => ({}), - GO_TO_RECEIVED_VC_TAB: () => ({}), - CANCEL: () => ({}), - DISMISS: () => ({}), - RESET: () => ({}), - VC_RECEIVED: (vc: VC) => ({ vc }), - CONNECTED: (pairId?: string) => ({ pairId: pairId || '' }), - DISCONNECT: () => ({}), - EXCHANGE_DONE: (senderInfo: DeviceInfo) => ({ senderInfo }), - SCREEN_FOCUS: () => ({}), - SCREEN_BLUR: () => ({}), - BLUETOOTH_ENABLED: () => ({}), - BLUETOOTH_DISABLED: () => ({}), - STORE_READY: () => ({}), - STORE_RESPONSE: (response: unknown) => ({ response }), - RECEIVE_DEVICE_INFO: (info: DeviceInfo) => ({ info }), - RECEIVED_VCS_UPDATED: () => ({}), - VC_RESPONSE: (response: unknown) => ({ response }), - SWITCH_PROTOCOL: (value: boolean) => ({ value }), - GOTO_SETTINGS: () => ({}), - FACE_VALID: () => ({}), - FACE_INVALID: () => ({}), - RETRY_VERIFICATION: () => ({}), - ONLINE: () => ({}), - OFFLINE: () => ({}), - APP_ACTIVE: () => ({}), - }, - } -); - -export const RequestEvents = model.events; - -export const requestMachine = - /** @xstate-layout N4IgpgJg5mDOIC5QCcwEcCucAuBiAygMIBKAoqQHID6AQgDICqxA2gAwC6ioADgPawBLbAN4A7LiAAeiAIwAmAMysAdKxkKA7AFY1ADgAsurQDYNAGhABPRAFoAnBrnK7RuVpm6NuuQY0BfPwtUTBwCEnJqADEAeUIGfDZOJBA+QWExCWkELS19ZW9jOTlC1mNjGTsZC2sEeztjZw19OXrvVl1jBTkAoPQsWDwiMkoqGLiEmSSefiERcWSs3SXlYv0NGQ1y9sMFats7OTycw-1WNbdchR6QYP7BgHUASQAVQgAJKgAFYmjn2Oi6IkJKlZhkFrItAplBoXDlmo4ZMZdKw5HtajI1E5mg5jJVkVoitdbqF8E9Xh9vr9-oDJsCZul5qAsoi8qxWDklnIZOctHY0TZeVCZIjNFpvF5ITIiX0cMoAMYACzAcoA1gJRFAaAAbLDYXi8bAK-BgZAANwEcrAuAAgp9PlRrYRno8AGqkIHJEEMzKIBT1VQdEwwppNFzmKy2XENQ5LRGmLTB7qBG4ygbypWq9WanVgPUGo0m82W9PKtUa3D0BikP6-D6Ua30UgAEQ90zScx9CE6DRR+jsOh2pSW-IUHWU7gOXQ2UbWWmlITTitLWe1uv1huNZotYBLmfLler0VrVCbj3wDbozdbKXpHfBCHxyn0xjOwpc3kqxn5facuLsdlYdZuXqdp-GTYlFwzMtszXfNNyLHcIOEfdGEPY960bFsODpdswSZWQZHcFYFH0eR9EhToNG0b9PGUJEqMMHJjHcXQpXA1NsF3aDV1zdcCy3YskKzCtUJrZ4PlPc9MOvL073whBuQULR8gUbk1EcBRVK-CNak6FRFFKORWH-GFcXnO4uJXHM8w3Qtt2UMBRAAQwAIy1SBcBk288KkWQUTsZRuRyQVSkMcMahsQ4ZDozSOn7MoDGaOd2IXTi3Ngw0m0cgQPIAcSpKh8GrZ0KFyhJsM9bzGV8hTyg0ZxNAOXwznWGioVxLlSORZ8tmS3pUvldynOQLNCDEURlQZXBJAGJzsB3JyADN5uQAAKQhL2tYgT1IOhrQATQASlwJDBrAYbRvGya5i83DqqyBxdGUEijBcADdDsfR+ScNlEQ8DRAIS0c+pTAaAHcnNmDVIl4ZAxtECa5SmwhogoChSCdK8KrbUF7r8lEn2YppNPUJTSLRLohUpoxhX0Z9zNlCGoagGG4aupG5lwSSUbRjHnlu3HO3UQ4VmY047CUYVeS0NEWgaLoiYJOmDkKK4Uos7hUG4C6NWeXhSEkRUnI1MBHlERbeFwMhCFIV1SB2l1HhtqhHgoGIBe9e96mU-tgzFBQyhacLEATFRNnaAOCX-Ps7AZtMwENhVjagLMsoQs2LdwUgAA13mtUr7abVH3Wxm87s7FwoWKYoqJ0QUEzRYUCdYzZyIDozPrjziE6NjVU7AdPzd4ZR1U+ZBeCgVBYFgabZvm5QlpW9bUfRp1HlRqhnQAWVIaIGGeY7Tp7pO+41NPtwz4fR-Hye4FgD25JqjEPBWVgSPI1ZWp0pYnufLl+0Auyeoxgu4OUTsnfug8LbKGEAAWzALwDAeBCD5xtoCUuskfJZBfMpToqk3DsjZJpbSNQJbKQ-mLdYpQlKx3VozSGyEWawxdHKLmZ4ear35hgqqQs-QBWYi+JKMcOi6Ebj4ZScgGJrA8FyEwat+oWSZow1mLDcAukIFQa2ts3RYSmGXQWXsXBPg8B0TYJF-q7B0hsHwKlCIoh0OyIw+hQFKKzCouUI9RBjwnlPGeM1sBzQWstE0q18BvC2q7XKm9Hg7z3gfE6HFlCuOhswjx18fF3wflgvySh8gbAlgHbw7glKNzpvVUOYoExGSqS4hhbjUkwIEPAxByDUG7SyXjLsbJVB-ybkpAwuJG46GisiTQH0DinB-KAuUxtLRai1MJfxgSF7BLWigigaDomxP3ofRJMzRBzIWRqDpnYWgqCViRXEAMzFuApppFYEtEQMSoj-UBqBzRgDBsJR0NtPhcL0ZgzpJEnD1DIUxYyn1ISy3ZHkCUhhCiGCAW8geOUvnlh+aQP5DoKBNioG6YgjxIj7ROfeF8IyKjaEhC0KWfIdJGSotCEofZALFHUMij5aKoBW1IAAKT5iS+SGJWKBTWJUGEhSerQoZZsIyzLHDlGKOy1Fwl1loIFTVPE+QALaFDAYHwqI6WAXqjKs42rWWKroWmd5yqNTKFNCaAQi1LBZkeBARywhsCWFwJER09sXTWjoI8XROEDHyVFdCXIGglKQlyJ9A1NRDg6GcOpPsngdDeHkaDCy1rPlZjtQ6p1Lq3WiA9V6n1ztXb+sDcGyq5d7xUOhABAkQZ+y6FHLLciKgAIbFTdodoiglW5ttfakahaNSuvdUIL1qr2ncLrYK6hgULkBxIkxWWigoQAXFu0QoUsQanRzZyzxponILIgBOktU62H4C3mecqAKeH1qaE+D6IZeS1w8LLJEeQPBDmYkYHItCFGykPXm9UJ6z0XtLdy54xB9p4tIASyITtrTOlRuqxYRgGqnCuUpNQn1Zb9OcDkLwn0NgA2cZazioHh0FudRqF03BcAQDEDucDvAVSIUSTRqA+bR30agIxhA7GZkMkSBhiEuTThFEMD4QCaxg4IGrgFNt6wujNE0IBQdR6R2OoE4x3AJpx7IGUNwLUc0LbIFgcoA9KKh28d02OwT3BhOiFNLwUTN0OASYUpKFYRReTCi8KOURdLNL1VFSRfskigrabzU5OUlpuCMJsxxLMxBlRgAEPaiALCZ7qM0aQfAnxUZFR89oX8CZXqmQ8A3Olb0nxUVAhRf9+7uN2aPQlpLKWhIagy5abLkA8tqI0WQYrpX3S0lraGp+8h6qESbvINQFKvr1Y+o1gGaaA6tbi7arrYBkt5t61AA2AgBhZlUfgP4ZBCvjYoGVudM3FilCfJG7bTROgEZ0pTFQ8gAFNVIp9MCwGrUdfi4lg7KX4HIBTuOg5vBYEXdYVd6IN2xslfuyXB986arIgaORNY7I-SnE8KFmoSl1CBX7NyUMGk2Ig+o2DvbEPDu2s1gdxyEB0uZcG7l5H137bo4mz54UuI6Jimi0AnQtLycGUCi0aXPhAdrF27x-brPeMDFhkjggAvbsY4e9jp7BExf-oOLySc3hVvk+KVT9waw+x09VwvFn80IDXtvfge9IbPbyQMFCTYjg2RIhyJpGXvpWJPTftoZEnhNgxud6gAAVpNDyklPfe+m77p+wZAr9PkOoVityrHRfyD4cooKfC11AVz2Acp2Zu493ekXxxiNdBMOyEwki0TwmcLiFEbIJafXaNMqCWYKC5jBrDFUuBUaBvRj5sWqgZVIlZWR-kXgGheF8I4LdFRR-Lg1BP7AU-kAz+iJESI8+sc+8ftgpNBhWiQjOPodv-IOhhwTII-sq6B1UeULwItItEclaHPq7DflnnfogDCE9JUn6PKi0KOPGrYJvtCEsApmcoDqAoAcAeqFaLaPaI6M6G6IvkpOOG4M+OoPkmsGTvsCLMcHTC1BcK-gEMmKILwG6vAMkEhLftkgpOyI2gBvCFyEiCiPyLTA0AcA4NoLVmLG1gNOqAlsIParwZ0kttFIcPYqYEKm4OHrUJ4NFPhs0HNoGORAfnuDBLxHBHZJaKoZ2CYHkKOHTJph9uRHoTYI4PVLoe3hyMUJmqdEuBYTxDZPxAhJZBqHYaSvIM9IlC4c+G4fyJ9hGhLEiEYP3sKOYdxNZHxPBPZMdpEfJJCmXgQgSI4DoEUIkX6MkYUmkQBMZJkVZBlKEfZI5K5O5BAAUU-APtCBUMtkFBsF0N+GoKoEiLTPHmcvTlmrKOlFYZlNlJAJ0cyM+O1GcHFIUEYOKvyDkCoGoLsVyGcEUBsNMkNCNBqPDIjNnoChXMiPkMZGKBCoPpsOIURGLKpEsNoMYHTGULUszKzOcddD5FcV7LksZIBE2nTF1MgQgAcNCOyG4FGoiv2JCKAuztrKcVAHrAbL3DAJfIsYgP2D+uUM-JGgYDLDpM0CCiiFRJoORFGu4KAsfBAmfCipaLiZAXwW2pSaUYxBUPCWiOsE9CyKREHqUGKLoAyeAqfFAOfKyUPJ4t4rfNPHiQ+DcU2pIjyebopq4HRJ8e-B-gYB4BKdiZAhfHKXAggkgsqR9E9DGBThpgmHoRLHkBQpIu8TCJ3P-skkwsgCwlaZoMRLUfhm4JpGIuUKoKHo7mUK-l4D8cog0ukoqVwTjNnphhIsDOkebiGVYn6MpMFJIk0MULurGfUj6R4uaS0laf6IiKxKvp0BiAcEMt0qMm2k8uoPTP-vsoclmMqQHAFM-I4GFCIn2I3B4PLBuh8WcArKrsqS0HkKCtGh3tHFClYh9HkOIoYOoKUG-H2M7gIBAO5MqeoDkE+IYI9PWRHOul0MmqRNyDIpoAHM7o5gJlBlOsqaHFqjmZcsiF4NbogEUMZOLiTgMocJsLuW5qenuS+Z6sqR8SKh3E0AYaLrLLyE9KSbkHLLGMxI+XRhdtwIeQSFvlRJIvYhyBsB2l4OOOYlua-kpP4e1hyuDt1t2eyZ0hRuLhKA4PULVoppIp0PkAinLG-KYEmAzqlgxczkxbasdv1lljlnljBdKtGVRHGvmXoeItFO3CyubooPIdmkzmrq7kdmlhqKdudgxnKDBVhkoAipSp4C0LQQgEoOtiTP9G4byJRqJTxi7pJbxtDrDlAGbPXojuZZZRIt4N+f+EYBsXckZMmkUlcvIISP-l5erilqiZztzgNnJRZSxULNyE4AttWdIiROyBTO0AFC5Z4G5R6Z5fpd5ZDnmlruib6blfeMKMKm3HVMZKYCujFV2v2iYA4IlSJVMaDuJQZd1gsa1fJBKOGYUAWc0H2DkBTCUM4DRQiG4G4IUInmACnkjFNcmVAQpK6dCFRMKJpH6CmtCmLiyh9K6QDJIs7s5OaFAHNFmHrG8AjmAFae0LcYUIUGKG4N4FUN9pUE4JcAOV4HoE0DXmdvXgjKnh0dNU-MsdCC0ErsHpcGiIHOQdTkZKuv2EBqNZxIEdBMfqfiqD2WGcBG-J4JpC1L+foeRKoKpAcIRO9KTNgUASAT9WmaOAcF4AiO0O-i+BGuHEtb-mrAEEAA */ - model.createMachine( - { - predictableActionArguments: true, - preserveActionOrder: true, - tsTypes: {} as import('./request.typegen').Typegen0, - schema: { - context: model.initialContext, - events: {} as EventFrom, - services: {} as { - verifyVp: { - data: VC; - }; - }, - }, - invoke: { - src: 'monitorConnection', - }, - id: 'request', - initial: 'inactive', - on: { - SCREEN_BLUR: { - target: '.inactive', - }, - - SCREEN_FOCUS: [ - { - target: '.checkingNetwork', - cond: 'isModeOnline', - }, - '.checkingBluetoothService', - ], - - SWITCH_PROTOCOL: [ - { - target: '.checkingNetwork', - actions: 'switchProtocol', - cond: 'isModeOnline', - description: `Check internet connection for online protocol`, - }, - { - target: '.checkingBluetoothService', - actions: 'switchProtocol', - }, - ], - }, - states: { - inactive: { - entry: 'removeLoggers', - }, - - checkingBluetoothService: { - initial: 'checking', - - states: { - checking: { - invoke: { - src: 'checkBluetoothService', - }, - on: { - BLUETOOTH_ENABLED: { - target: 'enabled', - }, - BLUETOOTH_DISABLED: { - target: 'requesting', - }, - }, - }, - - requesting: { - invoke: { - src: 'requestBluetooth', - }, - on: { - BLUETOOTH_ENABLED: { - target: 'enabled', - }, - BLUETOOTH_DISABLED: { - target: '#request.bluetoothDenied', - }, - }, - }, - - enabled: { - always: { - target: '#request.clearingConnection', - }, - }, - }, - - on: { - APP_ACTIVE: 'checkingNetwork', - }, - }, - - bluetoothDenied: { - on: { - GOTO_SETTINGS: { - actions: 'openSettings', - }, - }, - }, - - clearingConnection: { - entry: 'disconnect', - after: { - CLEAR_DELAY: { - target: '#request.waitingForConnection', - actions: [], - internal: false, - }, - }, - }, - - waitingForConnection: { - entry: [ - 'removeLoggers', - 'registerLoggers', - 'generateConnectionParams', - ], - invoke: { - src: 'advertiseDevice', - }, - on: { - CONNECTED: { - actions: ['setPairId'], - target: 'preparingToExchangeInfo', - }, - DISCONNECT: { - target: 'disconnected', - }, - }, - }, - - preparingToExchangeInfo: { - entry: 'requestReceiverInfo', - on: { - RECEIVE_DEVICE_INFO: { - target: 'exchangingDeviceInfo', - actions: 'setReceiverInfo', - }, - }, - }, - - exchangingDeviceInfo: { - invoke: { - src: 'exchangeDeviceInfo', - }, - initial: 'inProgress', - states: { - inProgress: { - after: { - CONNECTION_TIMEOUT: { - target: '#request.exchangingDeviceInfo.timeout', - actions: [], - internal: false, - }, - }, - }, - timeout: { - on: { - CANCEL: { - target: '#request.cancelling', - }, - }, - }, - }, - on: { - EXCHANGE_DONE: { - target: 'waitingForVc', - actions: 'setSenderInfo', - }, - }, - }, - - waitingForVc: { - invoke: { - src: 'receiveVc', - }, - initial: 'inProgress', - states: { - inProgress: { - after: { - SHARING_TIMEOUT: { - target: '#request.waitingForVc.timeout', - actions: [], - internal: false, - }, - }, - }, - timeout: { - on: { - CANCEL: { - target: '#request.cancelling', - }, - }, - }, - }, - on: { - DISCONNECT: { - target: 'disconnected', - }, - VC_RECEIVED: { - target: 'reviewing', - actions: 'setIncomingVc', - }, - }, - }, - - cancelling: { - invoke: { - src: 'sendDisconnect', - }, - after: { - CANCEL_TIMEOUT: { - target: '#request.checkingBluetoothService', - actions: ['disconnect'], - internal: false, - }, - }, - }, - - reviewing: { - exit: 'disconnect', - initial: 'idle', - states: { - idle: {}, - verifyingIdentity: { - exit: 'clearShouldVerifyPresence', - on: { - FACE_VALID: { - target: 'accepting', - actions: 'setReceiveLogTypeVerified', - }, - FACE_INVALID: { - target: 'invalidIdentity', - actions: 'setReceiveLogTypeUnverified', - }, - CANCEL: { - target: 'idle', - }, - }, - }, - invalidIdentity: { - on: { - DISMISS: { - target: 'accepting', - }, - RETRY_VERIFICATION: { - target: 'verifyingIdentity', - }, - }, - }, - verifyingVp: { - invoke: { - src: 'verifyVp', - onDone: [ - { - target: 'accepting', - }, - ], - onError: [ - { - target: 'idle', - actions: log('Failed to verify Verifiable Presentation'), - }, - ], - }, - }, - accepting: { - initial: 'requestingReceivedVcs', - states: { - requestingReceivedVcs: { - entry: 'requestReceivedVcs', - on: { - VC_RESPONSE: [ - { - target: 'requestingExistingVc', - cond: 'hasExistingVc', - }, - { - target: 'prependingReceivedVc', - }, - ], - }, - }, - requestingExistingVc: { - entry: 'requestExistingVc', - on: { - STORE_RESPONSE: { - target: 'mergingIncomingVc', - }, - }, - }, - mergingIncomingVc: { - entry: 'mergeIncomingVc', - on: { - STORE_RESPONSE: { - target: '#request.reviewing.accepted', - }, - }, - }, - prependingReceivedVc: { - entry: 'prependReceivedVc', - on: { - STORE_RESPONSE: { - target: 'storingVc', - }, - }, - }, - storingVc: { - entry: 'storeVc', - on: { - STORE_RESPONSE: { - target: '#request.reviewing.accepted', - }, - }, - }, - }, - }, - accepted: { - entry: ['updateReceivedVcs', 'logReceived'], - invoke: { - src: 'sendVcResponse', - data: { - status: 'ACCEPTED', - }, - }, - on: { - DISMISS: { - target: 'navigatingToHome', - }, - }, - }, - rejected: { - entry: ['setReceiveLogTypeDiscarded', 'logReceived'], - invoke: { - src: 'sendVcResponse', - data: { - status: 'REJECTED', - }, - }, - on: { - DISMISS: { - target: '#request.waitingForConnection', - }, - }, - }, - navigatingToHome: {}, - }, - on: { - ACCEPT: { - target: '.accepting', - actions: 'setReceiveLogTypeRegular', - }, - ACCEPT_AND_VERIFY: { - target: '.verifyingIdentity', - }, - REJECT: { - target: '.rejected', - }, - CANCEL: { - target: '.rejected', - }, - }, - }, - - disconnected: { - entry: 'disconnect', - on: { - DISMISS: { - target: 'waitingForConnection', - }, - }, - }, - - checkingNetwork: { - invoke: { - src: 'checkNetwork', - }, - - on: { - ONLINE: 'checkingBluetoothService', - OFFLINE: 'offline', - }, - }, - - offline: { - on: { - ONLINE: 'checkingBluetoothService', - APP_ACTIVE: 'checkingNetwork', - }, - }, - }, - }, - { - actions: { - setPairId: assign({ - pairId: (_context, event) => event.pairId, - }), - - openSettings: () => { - Platform.OS === 'android' - ? BluetoothStateManager.openSettings().catch() - : Linking.openURL('App-Prefs:Bluetooth'); - }, - - switchProtocol: assign({ - sharingProtocol: (_context, event) => - event.value ? 'ONLINE' : 'OFFLINE', - }), - - requestReceivedVcs: send(VcEvents.GET_RECEIVED_VCS(), { - to: (context) => context.serviceRefs.vc, - }), - - requestReceiverInfo: sendParent('REQUEST_DEVICE_INFO'), - - setReceiverInfo: model.assign({ - receiverInfo: (_context, event) => event.info, - }), - - disconnect: (context) => { - try { - if (context.sharingProtocol === 'OFFLINE') { - IdpassSmartshare.destroyConnection(); - } else { - GoogleNearbyMessages.disconnect(); - } - } catch (e) { - // pass - } - }, - - generateConnectionParams: assign({ - openId4VpUri: (context) => { - if (context.sharingProtocol === 'OFFLINE') { - return IdpassSmartshare.getConnectionParameters(); - } else { - const cid = uuid.v4(); - return JSON.stringify({ - pk: '', - cid, - }); - } - }, - }), - - setSenderInfo: model.assign({ - senderInfo: (_context, event) => event.senderInfo, - }), - - setIncomingVc: assign({ - incomingVc: (_context, event) => { - const vp = event.vc.verifiablePresentation; - return vp != null - ? { - ...event.vc, - verifiableCredential: vp.verifiableCredential[0], - } - : event.vc; - }, - }), - - registerLoggers: assign({ - loggers: () => { - if (__DEV__) { - return [ - IdpassSmartshare.handleNearbyEvents((event) => { - console.log( - getDeviceNameSync(), - '', - JSON.stringify(event).slice(0, 100) - ); - }), - IdpassSmartshare.handleLogEvents((event) => { - console.log( - getDeviceNameSync(), - '', - JSON.stringify(event).slice(0, 100) - ); - }), - ]; - } else { - return []; - } - }, - }), - - removeLoggers: assign({ - loggers: ({ loggers }) => { - loggers?.forEach((logger) => logger.remove()); - return null; - }, - }), - - prependReceivedVc: send( - (context) => - StoreEvents.PREPEND( - RECEIVED_VCS_STORE_KEY, - VC_ITEM_STORE_KEY(context.incomingVc) - ), - { to: (context) => context.serviceRefs.store } - ), - - requestExistingVc: send( - (context) => StoreEvents.GET(VC_ITEM_STORE_KEY(context.incomingVc)), - { to: (context) => context.serviceRefs.store } - ), - - mergeIncomingVc: send( - (context, event) => { - const existing = event.response as VC; - const updated: VC = { - ...existing, - reason: existing.reason.concat(context.incomingVc.reason), - }; - return StoreEvents.SET(VC_ITEM_STORE_KEY(updated), updated); - }, - { to: (context) => context.serviceRefs.store } - ), - - storeVc: send( - (context) => - StoreEvents.SET( - VC_ITEM_STORE_KEY(context.incomingVc), - context.incomingVc - ), - { to: (context) => context.serviceRefs.store } - ), - - setReceiveLogTypeRegular: model.assign({ - receiveLogType: 'VC_RECEIVED', - }), - - setReceiveLogTypeVerified: model.assign({ - receiveLogType: 'VC_RECEIVED_WITH_PRESENCE_VERIFIED', - }), - - setReceiveLogTypeUnverified: model.assign({ - receiveLogType: 'VC_RECEIVED_BUT_PRESENCE_VERIFICATION_FAILED', - }), - - setReceiveLogTypeDiscarded: model.assign({ - receiveLogType: 'VC_RECEIVED_NOT_SAVED', - }), - - logReceived: send( - (context) => - ActivityLogEvents.LOG_ACTIVITY({ - _vcKey: VC_ITEM_STORE_KEY(context.incomingVc), - type: context.receiveLogType, - timestamp: Date.now(), - deviceName: - context.senderInfo.name || context.senderInfo.deviceName, - vcLabel: context.incomingVc.tag || context.incomingVc.id, - }), - { to: (context) => context.serviceRefs.activityLog } - ), - - updateReceivedVcs: send( - (context) => { - return VcEvents.VC_RECEIVED(VC_ITEM_STORE_KEY(context.incomingVc)); - }, - { to: (context) => context.serviceRefs.vc } - ), - - clearShouldVerifyPresence: assign({ - incomingVc: (context) => ({ - ...context.incomingVc, - shouldVerifyPresence: false, - }), - }), - }, - - services: { - sendDisconnect: (context) => () => { - if (context.sharingProtocol === 'ONLINE') { - onlineSend( - { - type: 'disconnect', - data: 'rejected', - }, - context.pairId - ); - } - }, - - checkBluetoothService: () => (callback) => { - const subscription = BluetoothStateManager.onStateChange((state) => { - if (state === 'PoweredOn') { - callback(model.events.BLUETOOTH_ENABLED()); - } else { - callback(model.events.BLUETOOTH_DISABLED()); - } - }, true); - return () => subscription.remove(); - }, - - checkNetwork: () => async (callback) => { - const state = await NetInfo.fetch(); - callback({ - type: state.isInternetReachable ? 'ONLINE' : 'OFFLINE', - }); - }, - - requestBluetooth: () => (callback) => { - BluetoothStateManager.requestToEnable() - .then(() => callback(model.events.BLUETOOTH_ENABLED())) - .catch(() => callback(model.events.BLUETOOTH_DISABLED())); - }, - - advertiseDevice: (context) => (callback) => { - if (context.sharingProtocol === 'OFFLINE') { - GoogleNearbyMessages.disconnect(); - IdpassSmartshare.createConnection('advertiser', () => { - callback({ type: 'CONNECTED', pairId: '' }); - }); - } else { - (async function () { - GoogleNearbyMessages.addOnErrorListener((kind, message) => - console.log('\n\n[request] GNM_ERROR\n\n', kind, message) - ); - - try { - IdpassSmartshare.destroyConnection(); - } catch (e) { - /*pass*/ - } - await GoogleNearbyMessages.connect( - Platform.select({ - ios: { - apiKey: GNM_API_KEY, - }, - default: {}, - }) - ); - console.log('[request] GNM connected!'); - - const generatedParams = JSON.parse( - context.openId4VpUri - ) as ConnectionParams; - - await onlineSubscribe( - 'pairing', - async (scannedQrParams) => { - try { - if (scannedQrParams.cid === generatedParams.cid) { - const event: PairingResponseEvent = { - type: 'pairing:response', - data: scannedQrParams.cid, - }; - await onlineSend(event, scannedQrParams.cid); - callback({ - type: 'CONNECTED', - pairId: scannedQrParams.cid, - }); - } - } catch (e) { - console.error('Could not parse message.', e); - } - }, - null, - { pairId: generatedParams.cid } - ); - })(); - } - }, - - monitorConnection: (context) => (callback) => { - if (context.sharingProtocol === 'OFFLINE') { - const subscription = IdpassSmartshare.handleNearbyEvents( - (event) => { - if (event.type === 'onDisconnected') { - callback({ type: 'DISCONNECT' }); - } - } - ); - - return () => subscription.remove(); - } - }, - - exchangeDeviceInfo: (context) => (callback) => { - const event: ExchangeReceiverInfoEvent = { - type: 'exchange-receiver-info', - data: context.receiverInfo, - }; - - if (context.sharingProtocol === 'OFFLINE') { - const subscription = offlineSubscribe( - 'exchange-sender-info', - (senderInfo) => { - offlineSend(event, () => { - callback({ type: 'EXCHANGE_DONE', senderInfo }); - }); - } - ); - - return () => subscription.remove(); - } else { - onlineSubscribe( - 'exchange-sender-info', - async (senderInfo) => { - await GoogleNearbyMessages.unpublish(); - await onlineSend(event, context.pairId); - callback({ type: 'EXCHANGE_DONE', senderInfo }); - }, - null, - { pairId: context.pairId } - ); - } - }, - - receiveVc: (context) => (callback) => { - if (context.sharingProtocol === 'OFFLINE') { - const subscription = offlineSubscribe('send-vc', ({ vc }) => { - callback({ type: 'VC_RECEIVED', vc }); - }); - - return () => subscription.remove(); - } else { - let rawData = ''; - onlineSubscribe( - 'send-vc', - async ({ isChunked, vc, vcChunk }) => { - await GoogleNearbyMessages.unpublish(); - const VcReceivedEvent: SendVcResponseEvent = { - type: 'send-vc:response', - data: 'RECEIVED', - }; - if (isChunked) { - rawData += vcChunk.rawData; - if (vcChunk.chunk === vcChunk.total - 1) { - const vc = JSON.parse(rawData) as VC; - GoogleNearbyMessages.unsubscribe(); - await onlineSend(VcReceivedEvent, context.pairId); - callback({ type: 'VC_RECEIVED', vc }); - } else { - await onlineSend( - { - type: 'send-vc:response', - data: vcChunk.chunk, - }, - context.pairId - ); - } - } else { - await onlineSend(VcReceivedEvent, context.pairId); - callback({ type: 'VC_RECEIVED', vc }); - } - }, - () => callback({ type: 'DISCONNECT' }), - { keepAlive: true, pairId: context.pairId } - ); - } - }, - - sendVcResponse: (context, _event, meta) => async () => { - const event: SendVcResponseEvent = { - type: 'send-vc:response', - data: meta.data.status, - }; - - if (context.sharingProtocol === 'OFFLINE') { - offlineSend(event, () => { - // pass - }); - } else { - await GoogleNearbyMessages.unpublish(); - await onlineSend(event, context.pairId); - } - }, - - verifyVp: (context) => async () => { - const vp = context.incomingVc.verifiablePresentation; - - // TODO - // const challenge = ? - // await verifyPresentation(vp, challenge); - - const vc: VC = { - ...context.incomingVc, - verifiablePresentation: null, - verifiableCredential: vp.verifiableCredential[0], - }; - - return Promise.resolve(vc); - }, - }, - - guards: { - hasExistingVc: (context, event) => { - const receivedVcs = event.response as string[]; - const vcKey = VC_ITEM_STORE_KEY(context.incomingVc); - return receivedVcs.includes(vcKey); - }, - - isModeOnline: (context, event) => - event.type === 'SCREEN_FOCUS' - ? context.sharingProtocol === 'ONLINE' - : event.value, - }, - - delays: { - CLEAR_DELAY: 250, - CANCEL_TIMEOUT: 5000, - CONNECTION_TIMEOUT: (context) => { - return (context.sharingProtocol === 'ONLINE' ? 15 : 5) * 1000; - }, - SHARING_TIMEOUT: (context) => { - return (context.sharingProtocol === 'ONLINE' ? 45 : 15) * 1000; - }, - }, - } - ); - -export function createRequestMachine(serviceRefs: AppServices) { - return requestMachine.withContext({ - ...requestMachine.context, - serviceRefs, - }); -} - -type State = StateFrom; - -export function selectSenderInfo(state: State) { - return state.context.senderInfo; -} - -export function selectOpenIdVpUri(state: State) { - return state.context.openId4VpUri; -} - -export function selectIncomingVc(state: State) { - return state.context.incomingVc; -} - -export function selectSharingProtocol(state: State) { - return state.context.sharingProtocol; -} - -export function selectIsIncomingVp(state: State) { - return state.context.incomingVc?.verifiablePresentation != null; -} - -export function selectIsCancelling(state: State) { - return state.matches('cancelling'); -} - -export function selectIsReviewing(state: State) { - return state.matches('reviewing'); -} - -export function selectIsReviewingInIdle(state: State) { - return state.matches('reviewing.idle'); -} - -export function selectIsAccepted(state: State) { - return state.matches('reviewing.accepted'); -} - -export function selectIsRejected(state: State) { - return state.matches('reviewing.rejected'); -} - -export function selectIsVerifyingIdentity(state: State) { - return state.matches('reviewing.verifyingIdentity'); -} - -export function selectIsVerifyingVp(state: State) { - return state.matches('reviewing.verifyingVp'); -} - -export function selectIsInvalidIdentity(state: State) { - return state.matches('reviewing.invalidIdentity'); -} - -export function selectIsDisconnected(state: State) { - return state.matches('disconnected'); -} - -export function selectIsWaitingForConnection(state: State) { - return state.matches('waitingForConnection'); -} - -export function selectIsBluetoothDenied(state: State) { - return state.matches('bluetoothDenied'); -} - -export function selectIsCheckingBluetoothService(state: State) { - return state.matches('checkingBluetoothService'); -} - -export function selectIsExchangingDeviceInfo(state: State) { - return state.matches('exchangingDeviceInfo.inProgress'); -} - -export function selectIsExchangingDeviceInfoTimeout(state: State) { - return state.matches('exchangingDeviceInfo.timeout'); -} - -export function selectIsWaitingForVc(state: State) { - return state.matches('waitingForVc.inProgress'); -} - -export function selectIsWaitingForVcTimeout(state: State) { - return state.matches('waitingForVc.timeout'); -} - -export function selectIsDone(state: State) { - return state.matches('reviewing.navigatingToHome'); -} - -export function selectIsOffline(state: State) { - return state.matches('offline'); -} diff --git a/machines/scan.ts b/machines/scan.ts deleted file mode 100644 index cd263ac984..0000000000 --- a/machines/scan.ts +++ /dev/null @@ -1,1181 +0,0 @@ -/* eslint-disable sonarjs/no-duplicate-string */ -import SmartshareReactNative from '@idpass/smartshare-react-native'; -import { ConnectionParams } from '@idpass/smartshare-react-native/lib/typescript/IdpassSmartshare'; - -import { - ActorRefFrom, - assign, - DoneInvokeEvent, - EventFrom, - send, - sendParent, - spawn, - StateFrom, -} from 'xstate'; -import { createModel } from 'xstate/lib/model'; -import { EmitterSubscription, Linking, Platform } from 'react-native'; -import { DeviceInfo } from '../components/DeviceInfoList'; -import { getDeviceNameSync } from 'react-native-device-info'; -import { VC, VerifiablePresentation } from '../types/vc'; -import { AppServices } from '../shared/GlobalContext'; -import { ActivityLogEvents, ActivityLogType } from './activityLog'; -import { - GNM_API_KEY, - GNM_MESSAGE_LIMIT, - MY_LOGIN_STORE_KEY, - VC_ITEM_STORE_KEY, -} from '../shared/constants'; -import { - onlineSubscribe, - offlineSubscribe, - offlineSend, - onlineSend, - ExchangeSenderInfoEvent, - PairingEvent, - SendVcEvent, - SendVcStatus, -} from '../shared/smartshare'; -import { check, PERMISSIONS, PermissionStatus } from 'react-native-permissions'; -import { checkLocation, requestLocation } from '../shared/location'; -import { CameraCapturedPicture } from 'expo-camera'; -import { log } from 'xstate/lib/actions'; - -const { GoogleNearbyMessages, IdpassSmartshare } = SmartshareReactNative; -import NetInfo from '@react-native-community/netinfo'; -import { createQrLoginMachine, qrLoginMachine } from './QrLoginMachine'; -import { StoreEvents } from './store'; - -type SharingProtocol = 'OFFLINE' | 'ONLINE'; - -const SendVcResponseType = 'send-vc:response'; - -const model = createModel( - { - serviceRefs: {} as AppServices, - senderInfo: {} as DeviceInfo, - receiverInfo: {} as DeviceInfo, - selectedVc: {} as VC, - createdVp: null as VC, - reason: '', - loggers: [] as EmitterSubscription[], - vcName: '', - verificationImage: {} as CameraCapturedPicture, - sharingProtocol: 'OFFLINE' as SharingProtocol, - scannedQrParams: {} as ConnectionParams, - shareLogType: '' as ActivityLogType, - QrLoginRef: {} as ActorRefFrom, - linkCode: '', - }, - { - events: { - EXCHANGE_DONE: (receiverInfo: DeviceInfo) => ({ receiverInfo }), - RECEIVE_DEVICE_INFO: (info: DeviceInfo) => ({ info }), - SELECT_VC: (vc: VC) => ({ vc }), - SCAN: (params: string) => ({ params }), - ACCEPT_REQUEST: () => ({}), - VERIFY_AND_ACCEPT_REQUEST: () => ({}), - VC_ACCEPTED: () => ({}), - VC_REJECTED: () => ({}), - VC_SENT: () => ({}), - CANCEL: () => ({}), - DISMISS: () => ({}), - CONNECTED: () => ({}), - DISCONNECT: () => ({}), - SCREEN_BLUR: () => ({}), - SCREEN_FOCUS: () => ({}), - UPDATE_REASON: (reason: string) => ({ reason }), - LOCATION_ENABLED: () => ({}), - LOCATION_DISABLED: () => ({}), - LOCATION_REQUEST: () => ({}), - UPDATE_VC_NAME: (vcName: string) => ({ vcName }), - STORE_RESPONSE: (response: unknown) => ({ response }), - APP_ACTIVE: () => ({}), - FACE_VALID: () => ({}), - FACE_INVALID: () => ({}), - RETRY_VERIFICATION: () => ({}), - VP_CREATED: (vp: VerifiablePresentation) => ({ vp }), - TOGGLE_USER_CONSENT: () => ({}), - ONLINE: () => ({}), - OFFLINE: () => ({}), - }, - } -); -const QR_LOGIN_REF_ID = 'QrLogin'; - -export const ScanEvents = model.events; - -export const scanMachine = - /** @xstate-layout N4IgpgJg5mDOIC5SwMYEMB2BiAygYQCUBRIgOQH0AhAGQFUCBtABgF1FQAHAe1gEsAXXlwzsQAD0QBmSQDoAjAqYA2AJwAmABxMVAFgDsAViY6ANCACeUgwfkrrWg2oN79SyQF93Z1JlyESFABiAPJ4tDjMbEgg3HyCwqISCAC0TmoyKipKOmp6GvlacnZmlgiS1rb2TI7Orh5eID4YMigANmBoAE68GFB4whhgKPHYYrD8aPxgMmgAZlOdABR41EQAggTkACJE1GsAmgCUWE0t7V09fQNDI5GisQJCItFJcgZyGUpyGkpfakr-NIlRBvFRMDKZXJyST6Jj-eredDNWY9CCXfoYQbDJ5+NakO7RB4jRKIZLldKSNRyKEaMEqPR6NSmCwg2k2AwaIxMbk1JQGJSeRGYGQojBo3oYrEjXH4uRRTg8R4JF6k9QyWrvPSSAGGPTfYEIb52dWc7k8px8gUNU6i8VXTE3HH4PEMNTymKK4kqw1aDI6TkGSS0+lBg1Fb7qr61f3QnIqQWNJEyDidMAcC69AAqXElNywxDwRAAkgA1IjbIglouF8hF0ghAkKuJPEkIXKyZSGJnUpQaf3M0pqId6GQaINFLnkrIJ04oa7Y3pYPDBUikIh4TNELaNj3N5WgV56JQyJhdvtfHKMzQG-4GHTyKk6NxvLQIxPCucOhdQGQ9AAKnRcFAqawLAWBjBMUwzPMYBLMuq7rpmRYruQSEALJEMEtCZscs7zoIvS-hgAFASBsA7kSLbetSHxGPkkjGHIR5vO8N7vOCMLSL22hjuoM5Jp+UqXDIggALZgFwACu-BLnihbUBRnpUQeiDOOkGh6r2ALZNYrEsm27y0SoMI6GCchMEUxj8cKYBiCgAAWmBQJcWxgAAbrwKBgEWGCzFwWBbEW+ArmuG6KXuzwqQg1iyHo9KmT8cIMsYN6ZPeT5qMY1R2Gy1nNLZDlOS57med5vn+UQAAaeAABJ4gA4uWWwrkQ4VKpF4gghUDK6Go5T5MZcgAgaDG6DIDEaeoOj6DGeUyAVjm9MVHleT5fngeMkzTHMCzLCFiHIRQ6GYdhuFJgtRW9K5K1lX5bVelFFRfBoTj6N8vbqD8qVPjI-rZFS6gAq9c0XUtV0lat5Uibw4lSTJeBybs93KZ1CA6NyMiGOZegWVkfKZCNCgjkw5RBkwGn-Co0JzamHlgAA7sJsBgO034ligWC0H+WxrJu5DEGsOArsj+6o8kNHjSotJauoDJONqI18ho6oGFLTG-JyJk0yVDNMyzjq9OzAVBfBoWZiLHVJMk03pMY-zTW8ALqHIhNMSepP8nyzgMQY2t04zhHM6zBFQEbOC7Ih5AlngFutuLp4yJaeRKOTR5xUxI3WB8JNaurqiglaQrNLTvC64H+tsxzZYEEWgT7OQeJbA3eCFn+mb80QACKtBEDg5usPcSmi1bbiY3FaX+keVOciNfbgs4WhaDkfZS37pcBz+QcG6HHNrC3RBtx33e9-37qUcPiD6Cov3Tfy5l2-6Bo6Ex4LGU4gbaNykh6GvZebxXIcjYI1IPJWO1ExyJyHP9FOWQ5A6H5IrDQHw8hjiUHqVWSC1C-w3jILelcsCZmCPVeqqxyDhCIJseC4dSCn0HhFOObxwT0WkPoQwd44F6BGjob+ic0HGSPAxAGvtrRJhLn-FomAvKtFaJcDakFtowTgojagqEiwYSwjhE4oidY4KRFImRvQwFRXMk4dUZpVbmUkJ9DQXCijqm4Zlb+mQU46GwXrMUlwjaBWCghMKA9CRD0tiCDKKs4r-CSgyGET8owyFyGaJ8Kc3BuPLh4w2Vc8DN1bpubc-imztVbGoMa01TLQiyFYlwkholUjMa4Z2qhqjJP-qkneWBo4dwAFKIS3EY1GtIPhuDNN2Kx0IlBP1MiOfk-VtRFEyI03BYBmnsyIiRYCcAwIQS2tBXaOA6o11IPVVR6jTpaOFGInBzNFkoGWYBVZoEelJEBJjZ+fYiZxUDF9fSt9lYuOUFSXGug5kXLtEssSElpKyRAUjXJu58neiprIKW2RnmaB5AYMZbxxp3lPNURkCg3ynDOcJNAKAvIcCmBAY2OA0JBQiNC8+QSygRl+dUSm+Qc5Px+B2aaxg3BalPD-ERpydHCVTAAKxuJASl1KcC0rPoE1s1IwS-WyHkKxzzTw2P0iZWQ7zKQF2MNIOZblYK8FmOYS4RYIALMEPwcwWBAh73LCWNY1Aiw5LlfQ70Pt5CUmfkDLIug0WfKKPeRwnJVCFNPPGQVxdhWEWNd0M1FqrUYBtXah1NY6zOtde6uhsLjFHnVGCKk0JHCBs4cGoaJ4uxggDJlLBMaZCEvjSapNvRLXWoEHa4BoC6Xyu9LkEckgFCcjgSTRw38g2lCDIyDIFlpqUicFTLUcyUCpkmJ4jgWAIDCGmD0NyXAADW0wCVxp-GujogCOAIH3VwdAtxWD3MQFeWJZlybsPfmoJ+cDr5BjsL8RxfJV3rqvVgWCgFOjJlaJMPynRRK4O0f7YSF6N2G2vbe+9TxIhPoQIyWQIyARPmfpoBks8q1aFyACb+TFAzCKLk2s9RE3JoBkRADtqau1SppTh1IbtoRFC0NirUfVZ5KtxlSL4YIiNzP3Sx3gbGU1pvzEQTMBB67V1rtWXmh0cO9hPJyF6Ybn6q0ME-aooahy6ABKOow+KkxolQPhSV3jpWyrzQ9VGfIRz+mLUybhL1jI3jQeCEmKrMgkyYnYOasnWNcZlTh5+19zHwMZEePklT9LfAZL9OeONTLf2HQK+jDkhiHsuNQO9G7hA4FgjdFo9lSuXBwJBSSYFqChG0yhMgawaDdL7Z6qKvGRzqGxaZSzVmK2lHMjkItkSNIhv0HZj8DWUBld6BVzD1XaulXq413ozXJitawO1hGSEULeJ66sXNASBti39H6bh99l1HgsgaKmtsmT-CnlJ1xjaSurfK5VkYNXOh1dTAAR0knAEO2YiAYDQAAI3aMdjrZ2KDdd69dvJHnXg-TQb2DKLzvjkze84eQTErG9lVjCL4c1-tragBtqrGAQdg7AJD6HlxYfw6R2AFHp3DrbCCpdvrHr82oxyLIF6-ntDjPfgORAPx0h6hJsZVWYI9RLeaPTwHm2Wfba8rtgHvQ-ywVErwUCOITudfR6QEXWOYU4+CcefH55NDP2J5qqb2opfDr7IYLQiTC7vm1ythnTPgcG+mDrk3ZuLd8GEPzm3QucD24S9SDIgY7BMj5PoRwYZMohc-qoFOX9fvFbD7r5nrOdsOcR+0Cl1u0dHx7n3BLpivi6lUHqOKeQDR5HBNw9hnsGRwIbRXvbjOgdPBr4blNpcKVrD-H+ZuSEywJfgZjO8uo7Bqz0lNjV8gjDmU1IxbUdPK-ren1t0HteFkL6T834gx82-9fF0kNLJ4SPZAp24QLmXqgbA0F+o0EkEdItcjcGdSAwB+B6YuBOhD0sBghAhAhXU1wcNClr5Ch8h8dUtrx9JMoU5fo4F3gkEpYacICY8oBoDYD4DECVw0DWo38ncUhTFwwtJNRpBh0XYCDQRE5EsNIepi05ouBZhZgDE+cXNuNmCUYkh+RwRDBi1F5wkFcfRst+xyZVAshlAmJPAGgMAuArV4Bogmh3NZDSRTIQscgkVHZCkqQbxMpE47A74sgyCAxot4dsRjUzCL40Zxpv5tJOxNByhfgxkbAGIGIewnwxxn46dzhugJR8IUZ6UFU7xfp-gNIJorExx8CpsUtYlHB0s+Q4QNI5pbR0QkjRYUjqI+M+xVYhx0YzQ9QwwcZjxchaRh1HB-h8c5oUw0wMwoBsxcxhgfCGVkh8hE4mInxSZnoYoHCfo8hPcSCqR+Q6ckjehRi44ORYlGRiNoQnA4RQwCDJ1RxuEYQ7B0Y+xKD1ifx-wbkyJNjvR44djuwqRKQjA+oXo2JzJTiuItByC+I-sbjoZYZpJHiop0YgDGRs8hppimRvimEzjuIATx8Q95o7JFpnJwYbo1ouBwTUYRxnpXo9QfhaRNBRkCCsYMgfhEs+poiGQQYMTLooBrpSpcTrlSI1l8TXhClxptBsgGJuEpY1cbwcCcsBSeohxtQNBGTCowYWSIZbouAQSwV+BuSpArFMYXpNBAxYxITvpjxEUcgihARgZG1m0oB1TWC+QfUBNuQcZhMMtp0hwbAhoB9XAU4JNAUAFPEUArSq1AQXASYnxuR-gRpkp9NlBR0eoIjV1JEWYDFLSbt39EBdARxWijxaQXFqRFZ+QnlGQNVyZPty80SLT5lLkrSARE4c4qNqhEonTL5fV5Asoh9il4FvTLkOTbljDsdzDDQfiU4Ai+o6zBywjvksoARzIZkSzT0kMUlgUrlQU4YrTaN1RtQo0BN-ceDSgvlqz0ZJz-kZzEN14iUSU0xyUrTgii0WEJp8hIsKSdycZr4FBCl4ENJHAaM5kxUJUIB-TCkdVh0cUhomQ7xEEFCANTRBNPS5l4cPIoBUNBiuAaouBxJLyIET9Txewp5ikp1L5YEMgyZTxFVAYjVW1zV21FMu1LzTJMYXFshMg1I4pVC1V+kOR3cXoKN2zzTGMUMr0rS9QkttRkoUsBlmKpZ0gjB9ADjuR5s6NSzGMYt5N2M00rTxZn5fogxVBCt34vgHypB6RjwGIBk3ljAGQis0SHNBIfzKz0ZiCmJSSrxoQvdEBB10yKcElMpvgjzhRFLfzkyWDl4NKkFtA7w9UrEwwylmza1DjpAwRg9ZxL8p89dZ8wBVLbwMhMo8t1BMD9ADQNZ3YhpyhrBLQAQL9J8I8Z8o9ICmsWsezHc+yhtMVlBuEep6L9R9I2E1zCrqQ-MQqyrjckrq8qqIcodxgucuA4d69Ur-K+zsgx5KQLJsZuEdJ+8KhdTnwGj0YAU-tEqKqb86sqDTc4N49kj+1jFyYcs35w1OVcYwxqgEUzRtChSZ1+rw9r99db858Lcpq-LezfCcZ0hdBEoXBPogxVCepeEPyrFPK9RXqq9I9Prph59IBKy8zqR3hhTXwrFcL+zMgCji1nA7xaRuE4begaC4CEDVK8hE5x5jSXT0ZSMCDQsMgSCZKBlZlG1RDxCehpq-qGVnB544ogwQiGKxwbxlBB8SDvgBMKC9D3AgA */ - model.createMachine( - { - predictableActionArguments: true, - preserveActionOrder: true, - tsTypes: {} as import('./scan.typegen').Typegen0, - schema: { - context: model.initialContext, - events: {} as EventFrom, - services: {} as { - createVp: { - data: VC; - }; - }, - }, - invoke: { - src: 'monitorConnection', - }, - id: 'scan', - initial: 'inactive', - on: { - SCREEN_BLUR: { - target: '.inactive', - }, - SCREEN_FOCUS: { - target: '.checkingLocationService', - }, - }, - states: { - inactive: { - entry: 'removeLoggers', - }, - clearingConnection: { - entry: 'disconnect', - after: { - CLEAR_DELAY: { - target: '#scan.findingConnection', - actions: [], - internal: false, - }, - }, - }, - - findingConnection: { - entry: [ - 'removeLoggers', - 'registerLoggers', - 'clearScannedQrParams', - 'setChildRef', - ], - on: { - SCAN: [ - { - target: 'preparingToConnect', - cond: 'isQrOffline', - actions: 'setConnectionParams', - }, - { - target: 'checkingNetwork', - cond: 'isQrOnline', - actions: 'setScannedQrParams', - }, - { - target: 'showQrLogin', - cond: 'isQrLogin', - actions: 'setLinkCode', - }, - { - target: 'invalid', - }, - ], - }, - }, - showQrLogin: { - invoke: { - id: 'QrLogin', - src: qrLoginMachine, - onDone: '.storing', - }, - on: { - DISMISS: 'findingConnection', - }, - initial: 'idle', - states: { - idle: {}, - storing: { - entry: ['storeLoginItem'], - on: { - STORE_RESPONSE: { - target: 'navigatingToHome', - actions: ['storingActivityLog'], - }, - }, - }, - navigatingToHome: {}, - }, - entry: 'sendScanData', - }, - preparingToConnect: { - entry: 'requestSenderInfo', - on: { - RECEIVE_DEVICE_INFO: { - target: 'connecting', - actions: 'setSenderInfo', - }, - }, - }, - - connecting: { - invoke: { - src: 'discoverDevice', - }, - initial: 'inProgress', - states: { - inProgress: { - after: { - CONNECTION_TIMEOUT: { - target: '#scan.connecting.timeout', - actions: [], - internal: false, - }, - }, - }, - timeout: { - on: { - CANCEL: { - target: '#scan.reviewing.cancelling', - }, - }, - }, - }, - on: { - CONNECTED: { - target: 'exchangingDeviceInfo', - }, - }, - }, - - exchangingDeviceInfo: { - invoke: { - src: 'exchangeDeviceInfo', - }, - initial: 'inProgress', - after: { - CONNECTION_TIMEOUT: { - target: '#scan.exchangingDeviceInfo.timeout', - actions: [], - internal: false, - }, - }, - states: { - inProgress: {}, - timeout: { - on: { - CANCEL: { - target: '#scan.reviewing.cancelling', - }, - }, - }, - }, - on: { - DISCONNECT: { - target: 'disconnected', - }, - EXCHANGE_DONE: { - target: 'reviewing', - actions: 'setReceiverInfo', - }, - }, - }, - - reviewing: { - entry: ['resetShouldVerifyPresence'], - exit: ['disconnect', 'clearReason', 'clearCreatedVp'], - initial: 'selectingVc', - states: { - selectingVc: { - invoke: { - src: 'monitorCancellation', - }, - on: { - UPDATE_REASON: { - actions: 'setReason', - }, - DISCONNECT: { - target: '#scan.disconnected', - }, - SELECT_VC: { - actions: 'setSelectedVc', - }, - VERIFY_AND_ACCEPT_REQUEST: { - target: 'verifyingIdentity', - }, - ACCEPT_REQUEST: { - target: 'sendingVc', - actions: 'setShareLogTypeUnverified', - }, - CANCEL: { - target: 'cancelling', - }, - TOGGLE_USER_CONSENT: { - actions: 'toggleShouldVerifyPresence', - }, - }, - exit: ['onlineUnsubscribe'], - }, - cancelling: { - invoke: { - src: 'sendDisconnect', - }, - after: { - CANCEL_TIMEOUT: { - target: '#scan.findingConnection', - actions: ['disconnect'], - internal: false, - }, - }, - }, - sendingVc: { - invoke: { - src: 'sendVc', - }, - initial: 'inProgress', - states: { - inProgress: { - after: { - SHARING_TIMEOUT: { - target: '#scan.reviewing.sendingVc.timeout', - actions: [], - internal: false, - }, - }, - }, - timeout: { - on: { - CANCEL: { - target: '#scan.reviewing.cancelling', - }, - }, - }, - sent: { - description: - 'VC data has been shared and the receiver should now be viewing it', - }, - }, - on: { - DISCONNECT: { - target: '#scan.findingConnection', - }, - VC_SENT: { - target: '.sent', - }, - VC_ACCEPTED: { - target: '#scan.reviewing.accepted', - }, - VC_REJECTED: { - target: '#scan.reviewing.rejected', - }, - }, - }, - accepted: { - entry: 'logShared', - on: { - DISMISS: { - target: 'navigatingToHome', - }, - }, - }, - rejected: { - on: { - DISMISS: { - target: '#scan.findingConnection', - }, - }, - }, - navigatingToHome: {}, - verifyingIdentity: { - on: { - FACE_VALID: { - target: 'sendingVc', - actions: 'setShareLogTypeVerified', - }, - FACE_INVALID: { - target: 'invalidIdentity', - actions: 'logFailedVerification', - }, - CANCEL: { - target: 'selectingVc', - }, - }, - }, - creatingVp: { - invoke: { - src: 'createVp', - onDone: [ - { - target: 'sendingVc', - actions: 'setCreatedVp', - }, - ], - onError: [ - { - target: 'selectingVc', - actions: log('Could not create Verifiable Presentation'), - }, - ], - }, - }, - invalidIdentity: { - on: { - DISMISS: { - target: 'selectingVc', - }, - RETRY_VERIFICATION: { - target: 'verifyingIdentity', - }, - }, - }, - }, - }, - - disconnected: { - on: { - DISMISS: { - target: 'findingConnection', - }, - }, - }, - - invalid: { - on: { - DISMISS: { - target: 'findingConnection', - }, - }, - }, - - checkingLocationService: { - initial: 'checkingStatus', - states: { - checkingStatus: { - invoke: { - src: 'checkLocationStatus', - }, - on: { - LOCATION_ENABLED: { - target: 'checkingPermission', - }, - LOCATION_DISABLED: { - target: 'requestingToEnable', - }, - }, - }, - requestingToEnable: { - entry: 'requestToEnableLocation', - on: { - LOCATION_ENABLED: { - target: 'checkingPermission', - }, - LOCATION_DISABLED: { - target: 'disabled', - }, - }, - }, - checkingPermission: { - invoke: { - src: 'checkLocationPermission', - }, - on: { - LOCATION_ENABLED: { - target: '#scan.clearingConnection', - }, - LOCATION_DISABLED: { - target: 'denied', - }, - }, - }, - disabled: { - on: { - LOCATION_REQUEST: { - target: 'requestingToEnable', - }, - }, - }, - denied: { - on: { - APP_ACTIVE: { - target: 'checkingPermission', - }, - LOCATION_REQUEST: { - actions: 'openSettings', - }, - }, - }, - }, - }, - - checkingNetwork: { - invoke: { - src: 'checkNetwork', - }, - - on: { - OFFLINE: 'offline', - ONLINE: 'preparingToConnect', - }, - }, - - offline: { - on: { - DISMISS: 'findingConnection', - }, - }, - }, - }, - { - actions: { - setChildRef: assign({ - QrLoginRef: (context) => - spawn(createQrLoginMachine(context.serviceRefs), QR_LOGIN_REF_ID), - }), - - sendScanData: (context) => - context.QrLoginRef.send({ - type: 'GET', - value: context.linkCode, - }), - - requestSenderInfo: sendParent('REQUEST_DEVICE_INFO'), - - setSenderInfo: model.assign({ - senderInfo: (_context, event) => event.info, - }), - - requestToEnableLocation: () => requestLocation(), - - disconnect: (context) => { - try { - if (context.sharingProtocol === 'OFFLINE') { - IdpassSmartshare.destroyConnection(); - } else { - GoogleNearbyMessages.disconnect(); - } - } catch (e) { - // - } - }, - - setConnectionParams: (_context, event) => { - IdpassSmartshare.setConnectionParameters(event.params); - }, - - setScannedQrParams: model.assign({ - scannedQrParams: (_context, event) => - JSON.parse(event.params) as ConnectionParams, - sharingProtocol: 'ONLINE', - }), - - clearScannedQrParams: assign({ - scannedQrParams: {} as ConnectionParams, - }), - - setReceiverInfo: model.assign({ - receiverInfo: (_context, event) => event.receiverInfo, - }), - - setReason: model.assign({ - reason: (_context, event) => event.reason, - }), - - clearReason: assign({ reason: '' }), - - setSelectedVc: assign({ - selectedVc: (context, event) => { - const reason = []; - if (context.reason.trim() !== '') { - reason.push({ message: context.reason, timestamp: Date.now() }); - } - return { - ...event.vc, - reason, - shouldVerifyPresence: context.selectedVc.shouldVerifyPresence, - }; - }, - }), - - setCreatedVp: assign({ - createdVp: (_context, event) => event.data, - }), - - clearCreatedVp: assign({ - createdVp: () => null, - }), - - registerLoggers: assign({ - loggers: (context) => { - if (context.sharingProtocol === 'OFFLINE' && __DEV__) { - return [ - IdpassSmartshare.handleNearbyEvents((event) => { - console.log( - getDeviceNameSync(), - '', - JSON.stringify(event).slice(0, 100) - ); - }), - IdpassSmartshare.handleLogEvents((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', - }), - - logShared: send( - (context) => - ActivityLogEvents.LOG_ACTIVITY({ - _vcKey: VC_ITEM_STORE_KEY(context.selectedVc), - type: context.selectedVc.shouldVerifyPresence - ? 'VC_SHARED_WITH_VERIFICATION_CONSENT' - : context.shareLogType, - timestamp: Date.now(), - deviceName: - context.receiverInfo.name || context.receiverInfo.deviceName, - vcLabel: context.selectedVc.tag || context.selectedVc.id, - }), - { to: (context) => context.serviceRefs.activityLog } - ), - - logFailedVerification: send( - (context) => - ActivityLogEvents.LOG_ACTIVITY({ - _vcKey: VC_ITEM_STORE_KEY(context.selectedVc), - type: 'PRESENCE_VERIFICATION_FAILED', - timestamp: Date.now(), - deviceName: - context.receiverInfo.name || context.receiverInfo.deviceName, - vcLabel: context.selectedVc.tag || context.selectedVc.id, - }), - { to: (context) => context.serviceRefs.activityLog } - ), - - openSettings: () => Linking.openSettings(), - - toggleShouldVerifyPresence: assign({ - selectedVc: (context) => ({ - ...context.selectedVc, - shouldVerifyPresence: !context.selectedVc.shouldVerifyPresence, - }), - }), - - setLinkCode: assign({ - linkCode: (_context, event) => - event.params.substring( - event.params.indexOf('linkCode=') + 9, - event.params.indexOf('&') - ), - }), - - resetShouldVerifyPresence: assign({ - selectedVc: (context) => ({ - ...context.selectedVc, - shouldVerifyPresence: false, - }), - }), - - onlineUnsubscribe: () => { - GoogleNearbyMessages.unsubscribe(); - }, - - 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: '', - type: 'QRLOGIN_SUCCESFULL', - timestamp: Date.now(), - deviceName: '', - vcLabel: String(event.response.selectedVc.id), - }), - { - to: (context) => context.serviceRefs.activityLog, - } - ), - }, - - services: { - checkLocationPermission: () => async (callback) => { - try { - // wait a bit for animation to finish when app becomes active - await new Promise((resolve) => setTimeout(resolve, 250)); - - let response: PermissionStatus; - if (Platform.OS === 'android') { - response = await check(PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION); - } else if (Platform.OS === 'ios') { - return callback(model.events.LOCATION_ENABLED()); - } - - if (response === 'granted') { - callback(model.events.LOCATION_ENABLED()); - } else { - callback(model.events.LOCATION_DISABLED()); - } - } catch (e) { - console.error(e); - } - }, - - monitorConnection: (context) => (callback) => { - if (context.sharingProtocol === 'OFFLINE') { - const subscription = IdpassSmartshare.handleNearbyEvents( - (event) => { - if (event.type === 'onDisconnected') { - callback({ type: 'DISCONNECT' }); - } - } - ); - - return () => subscription.remove(); - } - }, - - monitorCancellation: (context) => async (callback) => { - if (context.sharingProtocol === 'ONLINE') { - await onlineSubscribe( - 'disconnect', - null, - () => callback({ type: 'DISCONNECT' }), - { pairId: context.scannedQrParams.cid } - ); - } - }, - - checkLocationStatus: () => (callback) => { - checkLocation( - () => callback(model.events.LOCATION_ENABLED()), - () => callback(model.events.LOCATION_DISABLED()) - ); - }, - - checkNetwork: () => async (callback) => { - const state = await NetInfo.fetch(); - callback({ type: state.isInternetReachable ? 'ONLINE' : 'OFFLINE' }); - }, - - discoverDevice: (context) => (callback) => { - if (context.sharingProtocol === 'OFFLINE') { - GoogleNearbyMessages.disconnect(); - IdpassSmartshare.createConnection('discoverer', () => { - callback({ type: 'CONNECTED' }); - }); - } else { - (async function () { - GoogleNearbyMessages.addOnErrorListener((kind, message) => - console.log('\n\n[scan] GNM_ERROR\n\n', kind, message) - ); - - try { - IdpassSmartshare.destroyConnection(); - } catch (e) { - /*pass*/ - } - await GoogleNearbyMessages.connect( - Platform.select({ - ios: { - apiKey: GNM_API_KEY, - }, - default: {}, - }) - ); - console.log('[scan] GNM connected!'); - - await onlineSubscribe( - 'pairing:response', - async (response) => { - await GoogleNearbyMessages.unpublish(); - if (response === context.scannedQrParams.cid) { - callback({ type: 'CONNECTED' }); - } - }, - null, - { pairId: context.scannedQrParams.cid } - ); - - const pairingEvent: PairingEvent = { - type: 'pairing', - data: context.scannedQrParams, - }; - - await onlineSend(pairingEvent, context.scannedQrParams.cid); - })(); - } - }, - - exchangeDeviceInfo: (context) => (callback) => { - const event: ExchangeSenderInfoEvent = { - type: 'exchange-sender-info', - data: context.senderInfo, - }; - - if (context.sharingProtocol === 'OFFLINE') { - let subscription: EmitterSubscription; - offlineSend(event, () => { - subscription = offlineSubscribe( - 'exchange-receiver-info', - (receiverInfo) => { - callback({ type: 'EXCHANGE_DONE', receiverInfo }); - } - ); - }); - return () => subscription?.remove(); - } else { - (async function () { - await onlineSubscribe( - 'exchange-receiver-info', - async (receiverInfo) => { - await GoogleNearbyMessages.unpublish(); - callback({ type: 'EXCHANGE_DONE', receiverInfo }); - }, - null, - { pairId: context.scannedQrParams.cid } - ); - - await onlineSend(event, context.scannedQrParams.cid); - })(); - } - }, - - sendVc: (context) => (callback) => { - let subscription: EmitterSubscription; - const vp = context.createdVp; - const vc = { - ...(vp != null ? vp : context.selectedVc), - tag: '', - }; - - const statusCallback = (status: SendVcStatus) => { - console.log('[scan] statusCallback', status); - if (typeof status === 'number') return; - if (status === 'RECEIVED') { - callback({ type: 'VC_SENT' }); - } else { - callback({ - type: status === 'ACCEPTED' ? 'VC_ACCEPTED' : 'VC_REJECTED', - }); - } - }; - - if (context.sharingProtocol === 'OFFLINE') { - const event: SendVcEvent = { - type: 'send-vc', - data: { isChunked: false, vc }, - }; - offlineSend(event, () => { - subscription = offlineSubscribe( - SendVcResponseType, - statusCallback - ); - }); - return () => subscription?.remove(); - } else { - sendVc( - vc, - statusCallback, - () => callback({ type: 'DISCONNECT' }), - context.scannedQrParams.cid - ); - } - }, - - sendDisconnect: (context) => () => { - if (context.sharingProtocol === 'ONLINE') { - onlineSend( - { - type: 'disconnect', - data: 'rejected', - }, - context.scannedQrParams.cid - ); - } - }, - - createVp: (context) => async () => { - // TODO - // const verifiablePresentation = await createVerifiablePresentation(...); - - const verifiablePresentation: VerifiablePresentation = { - '@context': [''], - 'proof': null, - 'type': 'VerifiablePresentation', - 'verifiableCredential': [context.selectedVc.verifiableCredential], - }; - - const vc: VC = { - ...context.selectedVc, - verifiableCredential: null, - verifiablePresentation, - }; - - return Promise.resolve(vc); - }, - }, - - guards: { - isQrOffline: (_context, event) => { - if (Platform.OS === 'ios') return false; - - const param: ConnectionParams = Object.create(null); - try { - Object.assign(param, JSON.parse(event.params)); - return 'cid' in param && 'pk' in param && param.pk !== ''; - } catch (e) { - return false; - } - }, - - isQrOnline: (_context, event) => { - const param: ConnectionParams = Object.create(null); - try { - Object.assign(param, JSON.parse(event.params)); - return 'cid' in param && 'pk' in param && param.pk === ''; - } catch (e) { - return false; - } - }, - - isQrLogin: (_context, event) => { - let linkCode = ''; - try { - linkCode = event.params.substring( - event.params.indexOf('linkCode=') + 9, - event.params.indexOf('&') - ); - return linkCode !== null; - } catch (e) { - return false; - } - }, - }, - - delays: { - CLEAR_DELAY: 250, - CANCEL_TIMEOUT: 5000, - CONNECTION_TIMEOUT: (context) => { - return (context.sharingProtocol === 'ONLINE' ? 15 : 5) * 1000; - }, - SHARING_TIMEOUT: (context) => { - return (context.sharingProtocol === 'ONLINE' ? 45 : 15) * 1000; - }, - }, - } - ); - -export function createScanMachine(serviceRefs: AppServices) { - return scanMachine.withContext({ - ...scanMachine.context, - serviceRefs, - }); -} - -type State = StateFrom; - -export function selectReceiverInfo(state: State) { - return state.context.receiverInfo; -} - -export function selectReason(state: State) { - return state.context.reason; -} - -export function selectVcName(state: State) { - return state.context.vcName; -} - -export function selectSelectedVc(state: State) { - return state.context.selectedVc; -} -export function selectQrLoginRef(state: State) { - return state.context.QrLoginRef; -} - -export function selectIsScanning(state: State) { - return state.matches('findingConnection'); -} - -export function selectIsConnecting(state: State) { - return state.matches('connecting.inProgress'); -} - -export function selectIsConnectingTimeout(state: State) { - return state.matches('connecting.timeout'); -} - -export function selectIsExchangingDeviceInfo(state: State) { - return state.matches('exchangingDeviceInfo.inProgress'); -} - -export function selectIsExchangingDeviceInfoTimeout(state: State) { - return state.matches('exchangingDeviceInfo.timeout'); -} - -export function selectIsReviewing(state: State) { - return state.matches('reviewing'); -} - -export function selectIsSelectingVc(state: State) { - return state.matches('reviewing.selectingVc'); -} - -export function selectIsSendingVc(state: State) { - return state.matches('reviewing.sendingVc.inProgress'); -} - -export function selectIsSendingVcTimeout(state: State) { - return state.matches('reviewing.sendingVc.timeout'); -} - -export function selectIsAccepted(state: State) { - return state.matches('reviewing.accepted'); -} - -export function selectIsRejected(state: State) { - return state.matches('reviewing.rejected'); -} - -export function selectIsSent(state: State) { - return state.matches('reviewing.sendingVc.sent'); -} - -export function selectIsInvalid(state: State) { - return state.matches('invalid'); -} - -export function selectIsLocationDenied(state: State) { - return state.matches('checkingLocationService.denied'); -} - -export function selectIsLocationDisabled(state: State) { - return state.matches('checkingLocationService.disabled'); -} - -export function selectIsDone(state: State) { - return state.matches('reviewing.navigatingToHome'); -} - -export function selectIsVerifyingIdentity(state: State) { - return state.matches('reviewing.verifyingIdentity'); -} - -export function selectIsInvalidIdentity(state: State) { - return state.matches('reviewing.invalidIdentity'); -} - -export function selectIsCancelling(state: State) { - return state.matches('reviewing.cancelling'); -} - -export function selectIsShowQrLogin(state: State) { - return state.matches('showQrLogin'); -} - -export function selectIsQrLoginDone(state: State) { - return state.matches('showQrLogin.navigatingToHome'); -} - -export function selectIsQrLoginStoring(state: State) { - return state.matches('showQrLogin.storing'); -} - -export function selectIsOffline(state: State) { - return state.matches('offline'); -} - -export function selectIsDisconnected(state: State) { - return state.matches('disconnected'); -} - -async function sendVc( - vc: VC, - callback: (status: SendVcStatus) => void, - disconnectCallback: () => void, - pairId: string -) { - const rawData = JSON.stringify(vc); - const chunks = chunkString(rawData, GNM_MESSAGE_LIMIT); - if (chunks.length > 1) { - let chunk = 0; - const vcChunk = { - total: chunks.length, - chunk, - rawData: chunks[chunk], - }; - const event: SendVcEvent = { - type: 'send-vc', - data: { - isChunked: true, - vcChunk, - }, - }; - - await onlineSubscribe( - SendVcResponseType, - async (status) => { - if (typeof status === 'number' && chunk < event.data.vcChunk.total) { - chunk += 1; - await GoogleNearbyMessages.unpublish(); - await onlineSend( - { - type: 'send-vc', - data: { - isChunked: true, - vcChunk: { - total: chunks.length, - chunk, - rawData: chunks[chunk], - }, - }, - }, - pairId - ); - } else if (typeof status === 'string') { - if (status === 'ACCEPTED' || status === 'REJECTED') { - GoogleNearbyMessages.unsubscribe(); - } - callback(status); - } - }, - disconnectCallback, - { keepAlive: true, pairId } - ); - await onlineSend(event, pairId); - } else { - const event: SendVcEvent = { - type: 'send-vc', - data: { isChunked: false, vc }, - }; - await onlineSubscribe(SendVcResponseType, callback, null, { pairId }); - await onlineSend(event, pairId); - } -} - -function chunkString(str: string, length: number) { - return str.match(new RegExp('.{1,' + length + '}', 'g')); -} diff --git a/screens/Request/ReceiveVcScreenController.ts b/screens/Request/ReceiveVcScreenController.ts index 50151f911e..af17ecd913 100644 --- a/screens/Request/ReceiveVcScreenController.ts +++ b/screens/Request/ReceiveVcScreenController.ts @@ -1,21 +1,21 @@ import { useSelector } from '@xstate/react'; import { useContext } from 'react'; -import { - RequestEvents, - selectIncomingVc, - selectIsIncomingVp, - selectIsInvalidIdentity, - selectIsReviewingInIdle, - selectIsVerifyingIdentity, - selectSenderInfo, -} from '../../machines/request'; import { selectVcLabel } from '../../machines/settings'; import { GlobalContext } from '../../shared/GlobalContext'; import { + selectIncomingVc, selectIsAccepting, + selectIsIncomingVp, + selectIsReviewingInIdle, selectIsSavingFailedInIdle, + selectSenderInfo, selectStoreError, -} from '../../machines/openIdBle/request'; +} from '../../machines/openIdBle/request/selectors'; +import { + selectIsInvalidIdentity, + selectIsVerifyingIdentity, +} from '../../machines/openIdBle/commonSelectors'; +import { RequestEvents } from '../../machines/openIdBle/request/machine'; export function useReceiveVcScreen() { const { appService } = useContext(GlobalContext); diff --git a/screens/Request/RequestLayoutController.ts b/screens/Request/RequestLayoutController.ts index 83e6466cf5..02a6346f8c 100644 --- a/screens/Request/RequestLayoutController.ts +++ b/screens/Request/RequestLayoutController.ts @@ -1,21 +1,23 @@ import { NavigationProp, useNavigation } from '@react-navigation/native'; import { useSelector } from '@xstate/react'; import { useContext, useEffect } from 'react'; +import { selectVcLabel } from '../../machines/settings'; +import { MainBottomTabParamList } from '../../routes/main'; +import { GlobalContext } from '../../shared/GlobalContext'; +import { + selectIsSavingFailedInViewingVc, + selectIsWaitingForConnection, + selectSenderInfo, +} from '../../machines/openIdBle/request/selectors'; import { - RequestEvents, selectIsAccepted, selectIsDisconnected, selectIsDone, + selectIsHandlingBleError, selectIsRejected, selectIsReviewing, - selectIsWaitingForConnection, - selectSenderInfo, -} from '../../machines/request'; -import { selectVcLabel } from '../../machines/settings'; -import { MainBottomTabParamList } from '../../routes/main'; -import { GlobalContext } from '../../shared/GlobalContext'; -import { selectIsHandlingBleError } from '../../machines/openIdBle/scan'; -import { selectIsSavingFailedInViewingVc } from '../../machines/openIdBle/request'; +} from '../../machines/openIdBle/commonSelectors'; +import { RequestEvents } from '../../machines/openIdBle/request/machine'; type RequestStackParamList = { RequestScreen: undefined; diff --git a/screens/Request/RequestScreenController.ts b/screens/Request/RequestScreenController.ts index 0e5d31c190..7052be1aa6 100644 --- a/screens/Request/RequestScreenController.ts +++ b/screens/Request/RequestScreenController.ts @@ -1,26 +1,28 @@ import { useSelector } from '@xstate/react'; import { useContext, useEffect } from 'react'; import { selectIsActive, selectIsFocused } from '../../machines/app'; +import { selectVcLabel } from '../../machines/settings'; +import { GlobalContext } from '../../shared/GlobalContext'; +import BluetoothStateManager from 'react-native-bluetooth-state-manager'; +import { useTranslation } from 'react-i18next'; import { - RequestEvents, - selectIsBluetoothDenied, - selectIsReviewing, - selectSenderInfo, + selectIsCheckingBluetoothService, selectIsWaitingForConnection, - selectIsExchangingDeviceInfo, selectIsWaitingForVc, - selectSharingProtocol, - selectIsExchangingDeviceInfoTimeout, selectIsWaitingForVcTimeout, - selectIsCheckingBluetoothService, + selectOpenId4VpUri, + selectSenderInfo, + selectSharingProtocol, +} from '../../machines/openIdBle/request/selectors'; +import { + selectIsBluetoothDenied, selectIsCancelling, + selectIsExchangingDeviceInfo, + selectIsExchangingDeviceInfoTimeout, selectIsOffline, -} from '../../machines/request'; -import { selectVcLabel } from '../../machines/settings'; -import { GlobalContext } from '../../shared/GlobalContext'; -import BluetoothStateManager from 'react-native-bluetooth-state-manager'; -import { useTranslation } from 'react-i18next'; -import { selectOpenId4VpUri } from '../../machines/openIdBle/request'; + selectIsReviewing, +} from '../../machines/openIdBle/commonSelectors'; +import { RequestEvents } from '../../machines/openIdBle/request/machine'; export function useRequestScreen() { const { t } = useTranslation('RequestScreen'); diff --git a/screens/Scan/ScanLayoutController.ts b/screens/Scan/ScanLayoutController.ts index c6c21778d4..e70406db49 100644 --- a/screens/Scan/ScanLayoutController.ts +++ b/screens/Scan/ScanLayoutController.ts @@ -3,32 +3,34 @@ import { useSelector } from '@xstate/react'; import { useContext, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { MessageOverlayProps } from '../../components/MessageOverlay'; +import { selectVcLabel } from '../../machines/settings'; +import { MainBottomTabParamList } from '../../routes/main'; +import { GlobalContext } from '../../shared/GlobalContext'; import { - ScanEvents, - selectIsInvalid, - selectIsLocationDisabled, - selectIsLocationDenied, selectIsConnecting, - selectIsExchangingDeviceInfo, selectIsConnectingTimeout, - selectIsExchangingDeviceInfoTimeout, - selectIsDone, - selectIsReviewing, - selectIsScanning, + selectIsInvalid, + selectIsLocationDenied, + selectIsLocationDisabled, selectIsQrLoginDone, - selectIsOffline, - selectIsSent, - selectIsDisconnected, - selectIsRejected, - selectIsAccepted, + selectIsScanning, selectIsSendingVc, selectIsSendingVcTimeout, + selectIsSent, selectReceiverInfo, -} from '../../machines/scan'; -import { selectVcLabel } from '../../machines/settings'; -import { MainBottomTabParamList } from '../../routes/main'; -import { GlobalContext } from '../../shared/GlobalContext'; -import { selectIsHandlingBleError } from '../../machines/openIdBle/scan'; +} from '../../machines/openIdBle/scan/selectors'; +import { + selectIsAccepted, + selectIsDisconnected, + selectIsDone, + selectIsExchangingDeviceInfo, + selectIsExchangingDeviceInfoTimeout, + selectIsHandlingBleError, + selectIsOffline, + selectIsRejected, + selectIsReviewing, +} from '../../machines/openIdBle/commonSelectors'; +import { ScanEvents } from '../../machines/openIdBle/scan/machine'; type ScanStackParamList = { ScanScreen: undefined; diff --git a/screens/Scan/ScanScreenController.ts b/screens/Scan/ScanScreenController.ts index d27e89d4b8..ae012e0a5e 100644 --- a/screens/Scan/ScanScreenController.ts +++ b/screens/Scan/ScanScreenController.ts @@ -2,19 +2,19 @@ import { useSelector } from '@xstate/react'; import { useContext } from 'react'; import { useTranslation } from 'react-i18next'; +import { selectVcLabel } from '../../machines/settings'; +import { selectShareableVcs } from '../../machines/vc'; +import { GlobalContext } from '../../shared/GlobalContext'; import { - ScanEvents, - selectIsLocationDisabled, selectIsLocationDenied, + selectIsLocationDisabled, + selectIsQrLoginStoring, selectIsScanning, selectIsShowQrLogin, selectQrLoginRef, - selectIsQrLoginStoring, -} from '../../machines/scan'; -import { selectVcLabel } from '../../machines/settings'; -import { selectShareableVcs } from '../../machines/vc'; -import { GlobalContext } from '../../shared/GlobalContext'; -import { selectIsBluetoothDenied } from '../../machines/openIdBle/scan'; +} from '../../machines/openIdBle/scan/selectors'; +import { selectIsBluetoothDenied } from '../../machines/openIdBle/commonSelectors'; +import { ScanEvents } from '../../machines/openIdBle/scan/machine'; export function useScanScreen() { const { t } = useTranslation('ScanScreen'); diff --git a/screens/Scan/SendVcScreenController.ts b/screens/Scan/SendVcScreenController.ts index 2704626ba6..2f772241af 100644 --- a/screens/Scan/SendVcScreenController.ts +++ b/screens/Scan/SendVcScreenController.ts @@ -1,21 +1,23 @@ import { useSelector } from '@xstate/react'; import { useContext, useState } from 'react'; import { ActorRefFrom } from 'xstate'; +import { selectVcLabel } from '../../machines/settings'; +import { selectShareableVcs } from '../../machines/vc'; +import { vcItemMachine } from '../../machines/vcItem'; +import { GlobalContext } from '../../shared/GlobalContext'; import { - ScanEvents, + selectIsSelectingVc, selectReason, selectReceiverInfo, - selectIsSelectingVc, - selectVcName, - selectIsVerifyingIdentity, - selectIsInvalidIdentity, selectSelectedVc, + selectVcName, +} from '../../machines/openIdBle/scan/selectors'; +import { selectIsCancelling, -} from '../../machines/scan'; -import { selectVcLabel } from '../../machines/settings'; -import { selectShareableVcs } from '../../machines/vc'; -import { vcItemMachine } from '../../machines/vcItem'; -import { GlobalContext } from '../../shared/GlobalContext'; + selectIsInvalidIdentity, + selectIsVerifyingIdentity, +} from '../../machines/openIdBle/commonSelectors'; +import { ScanEvents } from '../../machines/openIdBle/scan/machine'; export function useSendVcScreen() { const { appService } = useContext(GlobalContext); diff --git a/shared/GlobalContext.ts b/shared/GlobalContext.ts index e02bc71aaf..c729f96946 100644 --- a/shared/GlobalContext.ts +++ b/shared/GlobalContext.ts @@ -3,15 +3,12 @@ import { ActorRefFrom, InterpreterFrom } from 'xstate'; import { activityLogMachine } from '../machines/activityLog'; import { appMachine } from '../machines/app'; import { authMachine } from '../machines/auth'; -import { requestMachine } from '../machines/request'; -import { requestMachine as bleRequestMachine } from '../machines/openIdBle/request'; -import { scanMachine as bleScanMachine } from '../machines/openIdBle/scan'; -import { scanMachine } from '../machines/scan'; +import { requestMachine } from '../machines/openIdBle/request/machine'; +import { scanMachine } from '../machines/openIdBle/scan/machine'; import { settingsMachine } from '../machines/settings'; import { storeMachine } from '../machines/store'; import { vcMachine } from '../machines/vc'; import { revokeVidsMachine } from '../machines/revoke'; -import { qrLoginMachine } from '../machines/QrLoginMachine'; export const GlobalContext = createContext({} as GlobalServices); @@ -25,7 +22,7 @@ export interface AppServices { vc: ActorRefFrom; settings: ActorRefFrom; activityLog: ActorRefFrom; - request: ActorRefFrom; - scan: ActorRefFrom; + request: ActorRefFrom; + scan: ActorRefFrom; revoke: ActorRefFrom; }