From 0b11e0a8126365978d08cc19aa970d5b3b23999c Mon Sep 17 00:00:00 2001 From: abhip2565 <74866247+abhip2565@users.noreply.github.com> Date: Wed, 10 Jul 2024 22:19:01 +0530 Subject: [PATCH] Inji tuvali release (#1557) * Revert "[INJIMOB-891] add tuvali native" This reverts commit d4a4e89bd64f2c753e22576aeff4840fcb1eb0ae. * [INJIMOB-891]: add a wrapper for tuvali to use native artifacts Signed-off-by: Alka Prasad * [INJIMOB-891]: add a wrapper for tuvali in ios to consume ios native artifact Signed-off-by: Alka Prasad * [INJIMOB-891]: add tuvali native dependency Signed-off-by: Alka Prasad --------- Signed-off-by: Alka Prasad Co-authored-by: Alka Prasad --- android/app/build.gradle | 12 +++ .../io/mosip/residentapp/IRNEventEmitter.java | 9 ++ .../io/mosip/residentapp/InjiPackage.java | 7 +- .../io/mosip/residentapp/RNEventEmitter.java | 24 ++++++ .../io/mosip/residentapp/RNEventMapper.java | 74 +++++++++++++++++ .../mosip/residentapp/RNVerifierModule.java | 42 ++++++++++ .../io/mosip/residentapp/RNVersionModule.java | 25 ++++++ .../io/mosip/residentapp/RNWalletModule.java | 82 +++++++++++++++++++ android/build.gradle | 5 +- ios/Inji.xcodeproj/project.pbxproj | 81 +++++++++++++----- .../xcshareddata/swiftpm/Package.resolved | 29 ++++++- ios/Inji/RNEventEmitter.swift | 27 ++++++ ios/Inji/RNEventEmitterProtocol.swift | 5 ++ ios/Inji/RNEventMapper.swift | 47 +++++++++++ ios/Inji/RNVersionModule.m | 11 +++ ios/Inji/RNVersionModule.swift | 34 ++++++++ ios/Inji/RNWalletModule.m | 19 +++++ ios/Inji/RNWalletModule.swift | 65 +++++++++++++++ ios/Podfile.lock | 14 ---- machines/bleShare/request/requestMachine.ts | 5 +- machines/bleShare/scan/scanActions.ts | 4 +- machines/bleShare/scan/scanServices.ts | 5 +- package-lock.json | 16 ---- package.json | 15 ++-- shared/GlobalVariables.ts | 20 ++--- shared/openIdBLE/verifierEventHandler.ts | 6 +- shared/openIdBLE/walletEventHandler.ts | 5 +- shared/tuvali/index.ts | 58 +++++++++++++ shared/tuvali/types/events.ts | 64 +++++++++++++++ shared/tuvali/types/interface.ts | 28 +++++++ 30 files changed, 746 insertions(+), 92 deletions(-) create mode 100644 android/app/src/main/java/io/mosip/residentapp/IRNEventEmitter.java create mode 100644 android/app/src/main/java/io/mosip/residentapp/RNEventEmitter.java create mode 100644 android/app/src/main/java/io/mosip/residentapp/RNEventMapper.java create mode 100644 android/app/src/main/java/io/mosip/residentapp/RNVerifierModule.java create mode 100644 android/app/src/main/java/io/mosip/residentapp/RNVersionModule.java create mode 100644 android/app/src/main/java/io/mosip/residentapp/RNWalletModule.java create mode 100644 ios/Inji/RNEventEmitter.swift create mode 100644 ios/Inji/RNEventEmitterProtocol.swift create mode 100644 ios/Inji/RNEventMapper.swift create mode 100644 ios/Inji/RNVersionModule.m create mode 100644 ios/Inji/RNVersionModule.swift create mode 100644 ios/Inji/RNWalletModule.m create mode 100644 ios/Inji/RNWalletModule.swift create mode 100644 shared/tuvali/index.ts create mode 100644 shared/tuvali/types/events.ts create mode 100644 shared/tuvali/types/interface.ts diff --git a/android/app/build.gradle b/android/app/build.gradle index a25ba4db58..a031eae6fe 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -258,6 +258,7 @@ dependencies { implementation 'com.facebook.soloader:soloader:0.10.1+' implementation("io.mosip:pixelpass:0.2.0-SNAPSHOT") implementation("io.mosip:secure-keystore:0.2.0-SNAPSHOT") + implementation("io.mosip:tuvali:0.5.0-SNAPSHOT") def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true"; def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true"; @@ -304,6 +305,17 @@ dependencies { implementation 'com.jakewharton.timber:timber:4.7.1' } +task CaptureLibraryVersion { + def libDef = project.configurations.getByName('implementation').allDependencies.matching { + it.group.equals("io.mosip") && it.name.equals("tuvali") + } + if (libDef.size() > 0) { + android.buildTypes.each { + it.buildConfigField 'String', 'TUVALI_LIB_VERSION', "\"${libDef[0].version}\"" + } + } +} + apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) // https://github.com/oblador/react-native-vector-icons?tab=readme-ov-file#android-setup diff --git a/android/app/src/main/java/io/mosip/residentapp/IRNEventEmitter.java b/android/app/src/main/java/io/mosip/residentapp/IRNEventEmitter.java new file mode 100644 index 0000000000..b6e08f2782 --- /dev/null +++ b/android/app/src/main/java/io/mosip/residentapp/IRNEventEmitter.java @@ -0,0 +1,9 @@ +package io.mosip.residentapp; + +import com.facebook.react.bridge.WritableMap; + +import kotlin.Unit; + +public interface IRNEventEmitter { + Unit emitEvent(WritableMap eventMap); +} \ No newline at end of file diff --git a/android/app/src/main/java/io/mosip/residentapp/InjiPackage.java b/android/app/src/main/java/io/mosip/residentapp/InjiPackage.java index 2f5498dbd2..24addbcc52 100644 --- a/android/app/src/main/java/io/mosip/residentapp/InjiPackage.java +++ b/android/app/src/main/java/io/mosip/residentapp/InjiPackage.java @@ -10,7 +10,9 @@ import java.util.Collections; import java.util.List; - +import io.mosip.tuvali.verifier.Verifier; +import io.mosip.tuvali.wallet.Wallet; + public class InjiPackage implements ReactPackage { @NonNull @Override @@ -20,6 +22,9 @@ public List createNativeModules(@NonNull ReactApplicationContext r modules.add(new InjiVciClientModule(reactApplicationContext)); modules.add(new RNPixelpassModule(reactApplicationContext)); modules.add(new RNSecureKeystoreModule(reactApplicationContext)); + modules.add(new RNVersionModule()); + modules.add(new RNWalletModule(new RNEventEmitter(reactApplicationContext), new Wallet(reactApplicationContext), reactApplicationContext)); + modules.add(new RNVerifierModule(new RNEventEmitter(reactApplicationContext), new Verifier(reactApplicationContext), reactApplicationContext)); return modules; } diff --git a/android/app/src/main/java/io/mosip/residentapp/RNEventEmitter.java b/android/app/src/main/java/io/mosip/residentapp/RNEventEmitter.java new file mode 100644 index 0000000000..d06cb1f053 --- /dev/null +++ b/android/app/src/main/java/io/mosip/residentapp/RNEventEmitter.java @@ -0,0 +1,24 @@ +package io.mosip.residentapp; + +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.modules.core.DeviceEventManagerModule; + +import kotlin.Unit; +import kotlin.jvm.functions.Function1; + +public class RNEventEmitter implements IRNEventEmitter { + + private static final String EVENT_NAME = "DATA_EVENT"; + private final ReactApplicationContext reactContext; + + public RNEventEmitter(ReactApplicationContext reactContext) { + this.reactContext = reactContext; + } + + @Override + public Unit emitEvent(WritableMap eventMap) { + reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(EVENT_NAME, eventMap); + return null; + } +} diff --git a/android/app/src/main/java/io/mosip/residentapp/RNEventMapper.java b/android/app/src/main/java/io/mosip/residentapp/RNEventMapper.java new file mode 100644 index 0000000000..0bd540296b --- /dev/null +++ b/android/app/src/main/java/io/mosip/residentapp/RNEventMapper.java @@ -0,0 +1,74 @@ +package io.mosip.residentapp; + +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.WritableMap; +import io.mosip.tuvali.common.events.*; + +import java.lang.reflect.Field; +import java.util.Map; +import java.util.HashMap; + +public class RNEventMapper { + + public static WritableMap toMap(Event event) { + WritableMap writableMap = Arguments.createMap(); + writableMap.putString("type", getEventType(event)); + populateProperties(event, writableMap); + return writableMap; + } + + private static String getEventType(Event event) { + if (event instanceof DataReceivedEvent) { + return "onDataReceived"; + } else if (event instanceof ErrorEvent) { + return "onError"; + } else if (event instanceof VerificationStatusEvent) { + return "onVerificationStatusReceived"; + } else if (event instanceof ConnectedEvent) { + return "onConnected"; + } else if (event instanceof DataSentEvent) { + return "onDataSent"; + } else if (event instanceof DisconnectedEvent) { + return "onDisconnected"; + } else if (event instanceof SecureChannelEstablishedEvent) { + return "onSecureChannelEstablished"; + } else { + System.out.println("Invalid event type"); + return ""; + } + } + + private static void populateProperties(Event event, WritableMap writableMap) { + for (Field field : event.getClass().getDeclaredFields()) { + try { + field.setAccessible(true); + populateProperty(field, event, writableMap); + field.setAccessible(false); + } catch (Exception e) { + System.out.println("Unable to populate RN event " + field.getName()); + } + } + } + + private static void populateProperty(Field field, Event event, WritableMap writableMap) throws IllegalAccessException { + Object propertyValue = field.get(event); + if (propertyValue instanceof Enum) { + propertyValue = readEnumValue((Enum) propertyValue); + } + if (propertyValue instanceof Integer) { + writableMap.putInt(field.getName(), (Integer) propertyValue); + } else { + writableMap.putString(field.getName(), propertyValue.toString()); + } + } + + private static Object readEnumValue(Enum enumValue) { + try { + Field valueField = enumValue.getClass().getDeclaredField("value"); + valueField.setAccessible(true); + return valueField.get(enumValue); + } catch (Exception e) { + return enumValue.ordinal(); + } + } +} diff --git a/android/app/src/main/java/io/mosip/residentapp/RNVerifierModule.java b/android/app/src/main/java/io/mosip/residentapp/RNVerifierModule.java new file mode 100644 index 0000000000..d8944ef2a5 --- /dev/null +++ b/android/app/src/main/java/io/mosip/residentapp/RNVerifierModule.java @@ -0,0 +1,42 @@ +package io.mosip.residentapp; + +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; + +import io.mosip.tuvali.verifier.Verifier; + +public class RNVerifierModule extends ReactContextBaseJavaModule { + + private static final String NAME = "VerifierModule"; + private final RNEventEmitter eventEmitter; + private final Verifier verifier; + + + public RNVerifierModule(RNEventEmitter eventEmitter, Verifier verifier, ReactApplicationContext reactContext) { + super(reactContext); + this.eventEmitter = eventEmitter; + this.verifier = verifier; + verifier.subscribe(event -> eventEmitter.emitEvent(RNEventMapper.toMap(event))); + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public String startAdvertisement(String advIdentifier) { + return verifier.startAdvertisement(advIdentifier); + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public void disconnect() { + verifier.disconnect(); + } + + @ReactMethod + public void sendVerificationStatus(int status) { + verifier.sendVerificationStatus(status); + } + + @Override + public String getName() { + return NAME; + } +} diff --git a/android/app/src/main/java/io/mosip/residentapp/RNVersionModule.java b/android/app/src/main/java/io/mosip/residentapp/RNVersionModule.java new file mode 100644 index 0000000000..3dfcb1b8fc --- /dev/null +++ b/android/app/src/main/java/io/mosip/residentapp/RNVersionModule.java @@ -0,0 +1,25 @@ + +package io.mosip.residentapp; + +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import io.mosip.residentapp.BuildConfig; + + + +public class RNVersionModule extends ReactContextBaseJavaModule { + + private static final String NAME = "VersionModule"; + + @ReactMethod(isBlockingSynchronousMethod = true) + public String getVersion() { + return BuildConfig.TUVALI_LIB_VERSION; + } + + @Override + public String getName() { + return NAME; + } +} + + diff --git a/android/app/src/main/java/io/mosip/residentapp/RNWalletModule.java b/android/app/src/main/java/io/mosip/residentapp/RNWalletModule.java new file mode 100644 index 0000000000..23b01c9211 --- /dev/null +++ b/android/app/src/main/java/io/mosip/residentapp/RNWalletModule.java @@ -0,0 +1,82 @@ +package io.mosip.residentapp; + +import android.bluetooth.BluetoothAdapter; +import android.content.IntentFilter; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.WritableMap; + +import io.mosip.residentapp.RNEventEmitter; +import io.mosip.tuvali.common.BluetoothStateChangeReceiver; +import io.mosip.tuvali.wallet.Wallet; +import kotlin.Unit; +import kotlin.jvm.functions.Function1; +import kotlin.jvm.functions.Function2; + +public class RNWalletModule extends ReactContextBaseJavaModule { + + private static final String NAME = "WalletModule"; + private final RNEventEmitter eventEmitter; + private final Wallet wallet; + private final IntentFilter bluetoothStateChangeIntentFilter; + private final BluetoothStateChangeReceiver bluetoothStateChangeReceiver; + + public RNWalletModule(RNEventEmitter eventEmitter, Wallet wallet, ReactApplicationContext reactContext) { + super(reactContext); + this.eventEmitter = eventEmitter; + this.wallet = wallet; + + this.bluetoothStateChangeIntentFilter = new IntentFilter(); + bluetoothStateChangeIntentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); + + this.bluetoothStateChangeReceiver = new BluetoothStateChangeReceiver(handleDisconnect); + reactContext.registerReceiver(bluetoothStateChangeReceiver, bluetoothStateChangeIntentFilter); + wallet.subscribe(event -> eventEmitter.emitEvent(RNEventMapper.toMap(event))); + } + + Function2 handleDisconnect = new Function2() { + @Override + public Unit invoke(Integer status, Integer state) { + wallet.handleDisconnect(status, state); + return Unit.INSTANCE; + } + }; + + public Function1 emitEventHandler = new Function1() { + @Override + public Unit invoke(WritableMap eventMap) { + eventEmitter.emitEvent(eventMap); + return Unit.INSTANCE; + } + }; + + @ReactMethod(isBlockingSynchronousMethod = true) + public void startConnection(String uri) { + wallet.startConnection(uri); + } + + @ReactMethod + public void sendData(String payload) { + wallet.sendData(payload); + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public void disconnect() { + wallet.disconnect(); + } + + @Override + public String getName() { + return NAME; + } + + @Override + protected void finalize() throws Throwable { + try { + getReactApplicationContext().unregisterReceiver(bluetoothStateChangeReceiver); + } finally { + super.finalize(); + } + } +} diff --git a/android/build.gradle b/android/build.gradle index 474a7735f7..7582a65596 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -14,7 +14,6 @@ buildscript { google() jcenter() mavenCentral() - } dependencies { classpath("com.android.tools.build:gradle:7.3.1") @@ -28,5 +27,7 @@ buildscript { def expoCameraMavenPath = new File(["node", "--print", "require.resolve('expo-camera/package.json')"].execute(null, rootDir).text.trim(), "../android/maven") allprojects { repositories { maven{url("https://oss.sonatype.org/content/repositories/snapshots/")} - maven { url(expoCameraMavenPath) } } } + maven { url(expoCameraMavenPath) } + mavenCentral() +} } // @generated end expo-camera-import \ No newline at end of file diff --git a/ios/Inji.xcodeproj/project.pbxproj b/ios/Inji.xcodeproj/project.pbxproj index 0c7bd9195a..7ecad1cfae 100644 --- a/ios/Inji.xcodeproj/project.pbxproj +++ b/ios/Inji.xcodeproj/project.pbxproj @@ -15,8 +15,16 @@ 96905EF65AED1B983A6B3ABC /* libPods-Inji.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58EEBF8E8E6FB1BC6CAF49B5 /* libPods-Inji.a */; }; 9C0E86B52BEE357A00E9F9F6 /* RNPixelpassModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C0E86B42BEE357A00E9F9F6 /* RNPixelpassModule.swift */; }; 9C0E86BB2BEE36C300E9F9F6 /* RNPixelpassModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C0E86BA2BEE36C300E9F9F6 /* RNPixelpassModule.m */; }; - 9C7A2FA02C3129D2009C68D4 /* pixelpass in Frameworks */ = {isa = PBXBuildFile; productRef = 9C7A2F9F2C3129D2009C68D4 /* pixelpass */; }; - 9C7A2FA32C3129FC009C68D4 /* VCIClient in Frameworks */ = {isa = PBXBuildFile; productRef = 9C7A2FA22C3129FC009C68D4 /* VCIClient */; }; + 9C48504B2C3E59B5002ECBD5 /* RNWalletModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C4850442C3E59B5002ECBD5 /* RNWalletModule.swift */; }; + 9C48504D2C3E59B5002ECBD5 /* RNWalletModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C4850462C3E59B5002ECBD5 /* RNWalletModule.m */; }; + 9C48504E2C3E59B5002ECBD5 /* RNEventEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C4850472C3E59B5002ECBD5 /* RNEventEmitter.swift */; }; + 9C48504F2C3E59B5002ECBD5 /* RNVersionModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C4850482C3E59B5002ECBD5 /* RNVersionModule.swift */; }; + 9C4850502C3E59B5002ECBD5 /* RNEventMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C4850492C3E59B5002ECBD5 /* RNEventMapper.swift */; }; + 9C4850512C3E59B5002ECBD5 /* RNVersionModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C48504A2C3E59B5002ECBD5 /* RNVersionModule.m */; }; + 9C4850532C3E59E2002ECBD5 /* RNEventEmitterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C4850522C3E59E2002ECBD5 /* RNEventEmitterProtocol.swift */; }; + 9CD4F7D42C3EE417004B7DE6 /* pixelpass in Frameworks */ = {isa = PBXBuildFile; productRef = 9CD4F7D32C3EE417004B7DE6 /* pixelpass */; }; + 9CD4F7D72C3EE427004B7DE6 /* VCIClient in Frameworks */ = {isa = PBXBuildFile; productRef = 9CD4F7D62C3EE427004B7DE6 /* VCIClient */; }; + 9CD4F7DA2C3EE440004B7DE6 /* ios-tuvali-library in Frameworks */ = {isa = PBXBuildFile; productRef = 9CD4F7D92C3EE440004B7DE6 /* ios-tuvali-library */; }; B18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */; }; BB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; }; E86208152C0335C5007C3E24 /* RNVCIClientModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E86208142C0335C5007C3E24 /* RNVCIClientModule.swift */; }; @@ -50,12 +58,18 @@ 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Inji/Images.xcassets; sourceTree = ""; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Inji/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Inji/main.m; sourceTree = ""; }; - 182671E22C11BFD0007B2B46 /* InjiRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = InjiRelease.entitlements; path = Inji/InjiRelease.entitlements; sourceTree = ""; }; 58EEBF8E8E6FB1BC6CAF49B5 /* libPods-Inji.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Inji.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 6C2E3173556A471DD304B334 /* Pods-Inji.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Inji.debug.xcconfig"; path = "Target Support Files/Pods-Inji/Pods-Inji.debug.xcconfig"; sourceTree = ""; }; 7A4D352CD337FB3A3BF06240 /* Pods-Inji.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Inji.release.xcconfig"; path = "Target Support Files/Pods-Inji/Pods-Inji.release.xcconfig"; sourceTree = ""; }; 9C0E86B42BEE357A00E9F9F6 /* RNPixelpassModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNPixelpassModule.swift; sourceTree = ""; }; 9C0E86BA2BEE36C300E9F9F6 /* RNPixelpassModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNPixelpassModule.m; sourceTree = ""; }; + 9C4850442C3E59B5002ECBD5 /* RNWalletModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RNWalletModule.swift; path = Inji/RNWalletModule.swift; sourceTree = ""; }; + 9C4850462C3E59B5002ECBD5 /* RNWalletModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNWalletModule.m; path = Inji/RNWalletModule.m; sourceTree = ""; }; + 9C4850472C3E59B5002ECBD5 /* RNEventEmitter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RNEventEmitter.swift; path = Inji/RNEventEmitter.swift; sourceTree = ""; }; + 9C4850482C3E59B5002ECBD5 /* RNVersionModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RNVersionModule.swift; path = Inji/RNVersionModule.swift; sourceTree = ""; }; + 9C4850492C3E59B5002ECBD5 /* RNEventMapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RNEventMapper.swift; path = Inji/RNEventMapper.swift; sourceTree = ""; }; + 9C48504A2C3E59B5002ECBD5 /* RNVersionModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNVersionModule.m; path = Inji/RNVersionModule.m; sourceTree = ""; }; + 9C4850522C3E59E2002ECBD5 /* RNEventEmitterProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RNEventEmitterProtocol.swift; path = Inji/RNEventEmitterProtocol.swift; sourceTree = ""; }; AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = Inji/SplashScreen.storyboard; sourceTree = ""; }; BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = ""; }; D98B96A488E54CBDB286B26F /* noop-file.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = "noop-file.swift"; path = "Inji/noop-file.swift"; sourceTree = ""; }; @@ -89,8 +103,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9C7A2FA32C3129FC009C68D4 /* VCIClient in Frameworks */, - 9C7A2FA02C3129D2009C68D4 /* pixelpass in Frameworks */, + 9CD4F7D72C3EE427004B7DE6 /* VCIClient in Frameworks */, + 9CD4F7DA2C3EE440004B7DE6 /* ios-tuvali-library in Frameworks */, + 9CD4F7D42C3EE417004B7DE6 /* pixelpass in Frameworks */, 96905EF65AED1B983A6B3ABC /* libPods-Inji.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -101,12 +116,18 @@ 13B07FAE1A68108700A75B9A /* Inji */ = { isa = PBXGroup; children = ( - 182671E22C11BFD0007B2B46 /* InjiRelease.entitlements */, BB2F792B24A3F905000567C9 /* Supporting */, 008F07F21AC5B25A0029DE68 /* main.jsbundle */, 13B07FAF1A68108700A75B9A /* AppDelegate.h */, 13B07FB01A68108700A75B9A /* AppDelegate.mm */, 9C0E86B42BEE357A00E9F9F6 /* RNPixelpassModule.swift */, + 9C4850472C3E59B5002ECBD5 /* RNEventEmitter.swift */, + 9C4850522C3E59E2002ECBD5 /* RNEventEmitterProtocol.swift */, + 9C4850492C3E59B5002ECBD5 /* RNEventMapper.swift */, + 9C48504A2C3E59B5002ECBD5 /* RNVersionModule.m */, + 9C4850482C3E59B5002ECBD5 /* RNVersionModule.swift */, + 9C4850462C3E59B5002ECBD5 /* RNWalletModule.m */, + 9C4850442C3E59B5002ECBD5 /* RNWalletModule.swift */, 9C0E86BA2BEE36C300E9F9F6 /* RNPixelpassModule.m */, 13B07FB51A68108700A75B9A /* Images.xcassets */, 13B07FB61A68108700A75B9A /* Info.plist */, @@ -243,8 +264,9 @@ ); name = Inji; packageProductDependencies = ( - 9C7A2F9F2C3129D2009C68D4 /* pixelpass */, - 9C7A2FA22C3129FC009C68D4 /* VCIClient */, + 9CD4F7D32C3EE417004B7DE6 /* pixelpass */, + 9CD4F7D62C3EE427004B7DE6 /* VCIClient */, + 9CD4F7D92C3EE440004B7DE6 /* ios-tuvali-library */, ); productName = Inji; productReference = 13B07F961A680F5B00A75B9A /* Inji.app */; @@ -273,8 +295,9 @@ ); mainGroup = 83CBB9F61A601CBA00E9B192; packageReferences = ( - 9C7A2F9E2C3129D2009C68D4 /* XCRemoteSwiftPackageReference "pixelpass-ios-swift" */, - 9C7A2FA12C3129FC009C68D4 /* XCRemoteSwiftPackageReference "inji-vci-client-ios-swift" */, + 9CD4F7D22C3EE417004B7DE6 /* XCRemoteSwiftPackageReference "pixelpass-ios-swift" */, + 9CD4F7D52C3EE427004B7DE6 /* XCRemoteSwiftPackageReference "inji-vci-client-ios-swift" */, + 9CD4F7D82C3EE440004B7DE6 /* XCRemoteSwiftPackageReference "tuvali-ios-swift" */, ); productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; projectDirPath = ""; @@ -453,13 +476,20 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9C48504F2C3E59B5002ECBD5 /* RNVersionModule.swift in Sources */, 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */, 9C0E86BB2BEE36C300E9F9F6 /* RNPixelpassModule.m in Sources */, E86208152C0335C5007C3E24 /* RNVCIClientModule.swift in Sources */, 9C0E86B52BEE357A00E9F9F6 /* RNPixelpassModule.swift in Sources */, + 9C4850532C3E59E2002ECBD5 /* RNEventEmitterProtocol.swift in Sources */, 13B07FC11A68108700A75B9A /* main.m in Sources */, + 9C4850502C3E59B5002ECBD5 /* RNEventMapper.swift in Sources */, E86208172C0335EC007C3E24 /* RNVCIClientModule.m in Sources */, + 9C48504E2C3E59B5002ECBD5 /* RNEventEmitter.swift in Sources */, + 9C48504B2C3E59B5002ECBD5 /* RNWalletModule.swift in Sources */, + 9C48504D2C3E59B5002ECBD5 /* RNWalletModule.m in Sources */, B18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */, + 9C4850512C3E59B5002ECBD5 /* RNVersionModule.m in Sources */, 73295844242A4AD3AA52D0BE /* noop-file.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -475,10 +505,9 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Inji/Inji.entitlements; CODE_SIGN_IDENTITY = "Apple Distribution"; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 8; - DEVELOPMENT_TEAM = V2ABX7953Z; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = V2ABX7953Z; + DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -501,7 +530,6 @@ PRODUCT_BUNDLE_IDENTIFIER = io.mosip.inji.wallet.mobileid; PRODUCT_NAME = Inji; PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = ""; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -690,7 +718,7 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 9C7A2F9E2C3129D2009C68D4 /* XCRemoteSwiftPackageReference "pixelpass-ios-swift" */ = { + 9CD4F7D22C3EE417004B7DE6 /* XCRemoteSwiftPackageReference "pixelpass-ios-swift" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/mosip/pixelpass-ios-swift/"; requirement = { @@ -698,7 +726,7 @@ kind = branch; }; }; - 9C7A2FA12C3129FC009C68D4 /* XCRemoteSwiftPackageReference "inji-vci-client-ios-swift" */ = { + 9CD4F7D52C3EE427004B7DE6 /* XCRemoteSwiftPackageReference "inji-vci-client-ios-swift" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/mosip/inji-vci-client-ios-swift/"; requirement = { @@ -706,19 +734,32 @@ kind = branch; }; }; + 9CD4F7D82C3EE440004B7DE6 /* XCRemoteSwiftPackageReference "tuvali-ios-swift" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/mosip/tuvali-ios-swift/"; + requirement = { + branch = "release-0.5.x"; + kind = branch; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 9C7A2F9F2C3129D2009C68D4 /* pixelpass */ = { + 9CD4F7D32C3EE417004B7DE6 /* pixelpass */ = { isa = XCSwiftPackageProductDependency; - package = 9C7A2F9E2C3129D2009C68D4 /* XCRemoteSwiftPackageReference "pixelpass-ios-swift" */; + package = 9CD4F7D22C3EE417004B7DE6 /* XCRemoteSwiftPackageReference "pixelpass-ios-swift" */; productName = pixelpass; }; - 9C7A2FA22C3129FC009C68D4 /* VCIClient */ = { + 9CD4F7D62C3EE427004B7DE6 /* VCIClient */ = { isa = XCSwiftPackageProductDependency; - package = 9C7A2FA12C3129FC009C68D4 /* XCRemoteSwiftPackageReference "inji-vci-client-ios-swift" */; + package = 9CD4F7D52C3EE427004B7DE6 /* XCRemoteSwiftPackageReference "inji-vci-client-ios-swift" */; productName = VCIClient; }; + 9CD4F7D92C3EE440004B7DE6 /* ios-tuvali-library */ = { + isa = XCSwiftPackageProductDependency; + package = 9CD4F7D82C3EE440004B7DE6 /* XCRemoteSwiftPackageReference "tuvali-ios-swift" */; + productName = "ios-tuvali-library"; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; diff --git a/ios/Inji.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ios/Inji.xcworkspace/xcshareddata/swiftpm/Package.resolved index 1b26602bc4..9613e4957d 100644 --- a/ios/Inji.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ios/Inji.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "3de43a9fdcd5ea826d64a486680e1152ae01e34f4f25e98d41ee2667da7f9ac9", + "originHash" : "a6543a04f734b9c7569cf659b2ca72978ddd4cb37e1d3cb84167ecd1d06d1d7e", "pins" : [ { "identity" : "base45-swift", @@ -10,6 +10,24 @@ "version" : "1.1.0" } }, + { + "identity" : "crcswift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ivanesik/CrcSwift.git", + "state" : { + "revision" : "bb2fff7fb79815fad0528da71c9168d570bfc76c", + "version" : "0.0.3" + } + }, + { + "identity" : "gzipswift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/1024jp/GzipSwift", + "state" : { + "revision" : "7a7f17761c76a932662ab77028a4329f67d645a4", + "version" : "5.2.0" + } + }, { "identity" : "inji-vci-client-ios-swift", "kind" : "remoteSourceControl", @@ -27,6 +45,15 @@ "branch" : "release-0.2.x", "revision" : "0b716d5f6545b10de84c69edbf59565e66776ccd" } + }, + { + "identity" : "tuvali-ios-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/mosip/tuvali-ios-swift/", + "state" : { + "branch" : "release-0.5.x", + "revision" : "96bc662cd07df051cf2357691469bba57b0217e8" + } } ], "version" : 2 diff --git a/ios/Inji/RNEventEmitter.swift b/ios/Inji/RNEventEmitter.swift new file mode 100644 index 0000000000..9a4c384014 --- /dev/null +++ b/ios/Inji/RNEventEmitter.swift @@ -0,0 +1,27 @@ +import Foundation + +class RNEventEmitter: RNEventEmitterProtocol { + public static var sharedInstance = RNEventEmitter() + private var EVENT_NAME = "DATA_EVENT" + static var producer: WalletModule! + + private init() {} + + func emitEvent(eventMap: NSMutableDictionary) { + dispatch(name: EVENT_NAME, body: eventMap) + } + + func registerEventEmitter(producer: WalletModule) { + RNEventEmitter.producer = producer + } + + fileprivate func dispatch(name: String, body: Any?) { + RNEventEmitter.producer.sendEvent(withName: name, body: body) + } + + lazy var allEvents: [String] = { + return [ + EVENT_NAME + ] + }() +} diff --git a/ios/Inji/RNEventEmitterProtocol.swift b/ios/Inji/RNEventEmitterProtocol.swift new file mode 100644 index 0000000000..e37b11b972 --- /dev/null +++ b/ios/Inji/RNEventEmitterProtocol.swift @@ -0,0 +1,5 @@ +import Foundation + +protocol RNEventEmitterProtocol { + func emitEvent(eventMap: NSMutableDictionary) +} diff --git a/ios/Inji/RNEventMapper.swift b/ios/Inji/RNEventMapper.swift new file mode 100644 index 0000000000..650d1caed6 --- /dev/null +++ b/ios/Inji/RNEventMapper.swift @@ -0,0 +1,47 @@ +import Foundation +import ios_tuvali_library +import os.log + +class RNEventMapper { + + static func toMap(_ event: Event) -> NSMutableDictionary { + let writableMap = NSMutableDictionary() + + writableMap["type"] = getEventType(event) + populateWithArgs(event, writableMap) + + return writableMap + } + + fileprivate static func getEventType(_ event: Event) -> String { + switch event { + case is ConnectedEvent: return "onConnected" + case is SecureChannelEstablishedEvent: return "onSecureChannelEstablished" + case is DataSentEvent: return "onDataSent" + case is VerificationStatusEvent: return "onVerificationStatusReceived" + case is ErrorEvent: return "onError" + case is DisconnectedEvent: return "onDisconnected" + default: + os_log(.error, "Invalid event type") + return "" + } + } + + fileprivate static func populateWithArgs(_ event: Event, _ writableMap: NSMutableDictionary) { + let eventMirror = Mirror(reflecting: event) + + for child in eventMirror.children { + var value = child.value + + if(child.label != nil && (value is String || value is Int)) { + writableMap[child.label!] = value + continue + } + } + + //TODO: Find a way to convert enum to arg in a generic way + if let event = event as? VerificationStatusEvent { + writableMap["status"] = event.status.rawValue + } + } +} diff --git a/ios/Inji/RNVersionModule.m b/ios/Inji/RNVersionModule.m new file mode 100644 index 0000000000..aed51fe6da --- /dev/null +++ b/ios/Inji/RNVersionModule.m @@ -0,0 +1,11 @@ +#import +#import + +@interface RCT_EXTERN_MODULE(VersionModule, RCTEventEmitter) + +RCT_EXTERN_METHOD(setTuvaliVersion:(NSString *)version + resolver:(RCTPromiseResolveBlock)resolver + rejecter:(RCTPromiseRejectBlock)rejecter) + + +@end diff --git a/ios/Inji/RNVersionModule.swift b/ios/Inji/RNVersionModule.swift new file mode 100644 index 0000000000..b3355b4b83 --- /dev/null +++ b/ios/Inji/RNVersionModule.swift @@ -0,0 +1,34 @@ +import Foundation +import React +import os.log + + +@objc(VersionModule) +class VersionModule: RCTEventEmitter { + private var tuvaliVersion: String = "unknown" + + @objc + func setTuvaliVersion(_ version: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) { + do { + tuvaliVersion = version + os_log("Tuvali version - %{public}@", tuvaliVersion) + resolver(tuvaliVersion) + } catch let error { + rejecter("SET_VERSION_ERROR", "Failed to set Tuvali version", error) + } + } + + @objc + override func supportedEvents() -> [String]! { + return [] + } + + override static func requiresMainQueueSetup() -> Bool { + return true + } + + @objc + override static func moduleName() -> String { + return "VersionModule" + } +} diff --git a/ios/Inji/RNWalletModule.m b/ios/Inji/RNWalletModule.m new file mode 100644 index 0000000000..856d8e19d9 --- /dev/null +++ b/ios/Inji/RNWalletModule.m @@ -0,0 +1,19 @@ +#import +#import + +@interface RCT_EXTERN_MODULE(WalletModule, RCTEventEmitter) + +RCT_EXTERN_METHOD(noop) + +RCT_EXTERN_METHOD(startConnection:(NSString *)uri + resolver:(RCTPromiseResolveBlock)resolver + rejecter:(RCTPromiseRejectBlock)rejecter) + +RCT_EXTERN_METHOD(disconnect:(RCTPromiseResolveBlock)resolver + rejecter:(RCTPromiseRejectBlock)rejecter) + +RCT_EXTERN_METHOD(sendData:(NSString *)payload + resolver:(RCTPromiseResolveBlock)resolver + rejecter:(RCTPromiseRejectBlock)rejecter) + +@end diff --git a/ios/Inji/RNWalletModule.swift b/ios/Inji/RNWalletModule.swift new file mode 100644 index 0000000000..4d288fd542 --- /dev/null +++ b/ios/Inji/RNWalletModule.swift @@ -0,0 +1,65 @@ +import Foundation +import React +import ios_tuvali_library + +@objc(WalletModule) +class WalletModule: RCTEventEmitter { + var wallet: WalletProtocol = Wallet() + var tuvaliVersion: String = "unknown" + + override init() { + super.init() + RNEventEmitter.sharedInstance.registerEventEmitter(producer: self) + wallet.subscribe { event in + RNEventEmitter.sharedInstance.emitEvent(eventMap: RNEventMapper.toMap(event)) + } + } + + @objc func noop() { + // No operation method + } + + @objc + func startConnection(_ uri: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) { + do { + wallet.startConnection(uri) + resolver(nil) + } catch let error { + rejecter("START_CONNECTION_ERROR", "Failed to start connection", error) + } + } + + @objc + func disconnect(_ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) { + do { + wallet.disconnect() + resolver(nil) + } catch let error { + rejecter("DISCONNECT_ERROR", "Failed to disconnect", error) + } + } + + @objc + func sendData(_ payload: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) { + do { + wallet.send(payload) + resolver(nil) + } catch let error { + rejecter("SEND_DATA_ERROR", "Failed to send data", error) + } + } + + @objc override func supportedEvents() -> [String]! { + return RNEventEmitter.sharedInstance.allEvents + } + + + override static func requiresMainQueueSetup() -> Bool { + return false + } + + @objc + override static func moduleName() -> String { + return "WalletModule" + } +} diff --git a/ios/Podfile.lock b/ios/Podfile.lock index fd678683fb..67ad367888 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -15,7 +15,6 @@ PODS: - BVLinearGradient (2.8.3): - React-Core - CatCrypto (0.3.2) - - CrcSwift (0.0.3) - DoubleConversion (1.1.6) - EASClient (0.6.0): - ExpoModulesCore @@ -130,7 +129,6 @@ PODS: - AppAuth/Core (~> 1.6) - GTMSessionFetcher/Core (< 4.0, >= 1.5) - GTMSessionFetcher/Core (1.7.2) - - GzipSwift (5.1.1) - hermes-engine (0.71.8): - hermes-engine/Pre-built (= 0.71.8) - hermes-engine/Pre-built (0.71.8) @@ -592,10 +590,6 @@ PODS: - TensorFlowLiteObjC/Core (= 2.12.0) - TensorFlowLiteObjC/Core (2.12.0): - TensorFlowLiteC (= 2.12.0) - - tuvali (0.4.9): - - CrcSwift (~> 0.0.3) - - GzipSwift - - React-Core - Yoga (1.14.0) - ZXingObjC/Core (3.6.5) - ZXingObjC/OneD (3.6.5): @@ -696,7 +690,6 @@ DEPENDENCIES: - RNShare (from `../node_modules/react-native-share`) - RNSVG (from `../node_modules/react-native-svg`) - RNZipArchive (from `../node_modules/react-native-zip-archive`) - - "tuvali (from `../node_modules/@mosip/tuvali`)" - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) SPEC REPOS: @@ -705,7 +698,6 @@ SPEC REPOS: - ASN1Decoder - BiometricSdk - CatCrypto - - CrcSwift - fmt - GoogleDataTransport - GoogleMLKit @@ -715,7 +707,6 @@ SPEC REPOS: - GoogleUtilitiesComponents - GTMAppAuth - GTMSessionFetcher - - GzipSwift - libevent - MLImage - MLKitCommon @@ -913,8 +904,6 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-svg" RNZipArchive: :path: "../node_modules/react-native-zip-archive" - tuvali: - :path: "../node_modules/@mosip/tuvali" Yoga: :path: "../node_modules/react-native/ReactCommon/yoga" @@ -926,7 +915,6 @@ SPEC CHECKSUMS: boost: 57d2868c099736d80fcd648bf211b4431e51a558 BVLinearGradient: 880f91a7854faff2df62518f0281afb1c60d49a3 CatCrypto: a477899b6be4954e75be4897e732da098cc0a5a8 - CrcSwift: f85dea6b41dddb5f98bb3743fd777ce58b77bc2e DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 EASClient: 49f8ea858204eb4844d9fb386e5fb7920aee2e30 EXApplication: 042aa2e3f05258a16962ea1a9914bf288db9c9a1 @@ -962,7 +950,6 @@ SPEC CHECKSUMS: GoogleUtilitiesComponents: 679b2c881db3b615a2777504623df6122dd20afe GTMAppAuth: 99fb010047ba3973b7026e45393f51f27ab965ae GTMSessionFetcher: 5595ec75acf5be50814f81e9189490412bad82ba - GzipSwift: 893f3e48e597a1a4f62fafcb6514220fcf8287fa hermes-engine: 47986d26692ae75ee7a17ab049caee8864f855de ImageColors: 88be684570585c07ae2750bff34eb7b78bfc53b4 libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 @@ -1038,7 +1025,6 @@ SPEC CHECKSUMS: SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef TensorFlowLiteC: 20785a69299185a379ba9852b6625f00afd7984a TensorFlowLiteObjC: 9a46a29a76661c513172cfffd3bf712b11ef25c3 - tuvali: 9c3aad61844f6fcbd48ec7967cd6805418c3f8da Yoga: 065f0b74dba4832d6e328238de46eb72c5de9556 ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb diff --git a/machines/bleShare/request/requestMachine.ts b/machines/bleShare/request/requestMachine.ts index 79a7178a50..74481a33f9 100644 --- a/machines/bleShare/request/requestMachine.ts +++ b/machines/bleShare/request/requestMachine.ts @@ -1,4 +1,3 @@ -import tuvali from '@mosip/tuvali'; import BluetoothStateManager from 'react-native-bluetooth-state-manager'; import {EmitterSubscription, Linking} from 'react-native'; import { @@ -22,7 +21,7 @@ import { import {ActivityLogEvents, ActivityLogType} from '../../activityLog'; import {VcMetaEvents} from '../../VerifiableCredential/VCMetaMachine/VCMetaMachine'; import {subscribe} from '../../../shared/openIdBLE/verifierEventHandler'; -import {VerifierDataEvent} from '@mosip/tuvali/src/types/events'; +import {VerifierDataEvent} from '../../../shared/tuvali/types/events'; import {BLEError} from '../types'; import Storage from '../../../shared/storage'; import {VCMetadata} from '../../../shared/VCMetadata'; @@ -39,7 +38,7 @@ import { import {TelemetryConstants} from '../../../shared/telemetry/TelemetryConstants'; import {getCredentialTypes} from '../../../components/VC/common/VCUtils'; -const {verifier, EventTypes, VerificationStatus} = tuvali; +import {EventTypes, VerificationStatus, verifier} from '../../../shared/tuvali'; const model = createModel( { diff --git a/machines/bleShare/scan/scanActions.ts b/machines/bleShare/scan/scanActions.ts index 2281a500fe..b6e83c5bf6 100644 --- a/machines/bleShare/scan/scanActions.ts +++ b/machines/bleShare/scan/scanActions.ts @@ -26,12 +26,12 @@ import {createQrLoginMachine} from '../../QrLogin/QrLoginMachine'; import {VcMetaEvents} from '../../VerifiableCredential/VCMetaMachine/VCMetaEvents'; import {ActivityLogEvents} from '../../activityLog'; import {StoreEvents} from '../../store'; -import tuvali from '@mosip/tuvali'; import BluetoothStateManager from 'react-native-bluetooth-state-manager'; import {NativeModules} from 'react-native'; import {getCredentialTypes} from '../../../components/VC/common/VCUtils'; -const {wallet, EventTypes, VerificationStatus} = tuvali; +import {wallet} from '../../../shared/tuvali'; + export const ScanActions = (model: any, QR_LOGIN_REF_ID: any) => { const {RNPixelpassModule} = NativeModules; return { diff --git a/machines/bleShare/scan/scanServices.ts b/machines/bleShare/scan/scanServices.ts index dcfcdc6641..ba0bb3856f 100644 --- a/machines/bleShare/scan/scanServices.ts +++ b/machines/bleShare/scan/scanServices.ts @@ -1,8 +1,6 @@ -import {WalletDataEvent} from '@mosip/tuvali/lib/typescript/types/events'; import {isLocationEnabled} from 'react-native-device-info'; import Storage from '../../../shared/storage'; import BluetoothStateManager from 'react-native-bluetooth-state-manager'; -import tuvali from '@mosip/tuvali'; import { check, checkMultiple, @@ -18,7 +16,8 @@ import { } from '../../../shared/location'; import {isIOS} from '../../../shared/constants'; -const {wallet, EventTypes, VerificationStatus} = tuvali; +import {wallet, EventTypes, VerificationStatus} from '../../../shared/tuvali'; +import {WalletDataEvent} from '../../../shared/tuvali/types/events'; export const ScanServices = (model: any) => { return { diff --git a/package-lock.json b/package-lock.json index 1445659d21..5610807448 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,6 @@ "@expo/metro-config": "~0.10.0", "@invertase/react-native-apple-authentication": "^2.3.0", "@iriscan/biometric-sdk-react-native": "0.2.6", - "@mosip/tuvali": "0.4.9", "@react-native-clipboard/clipboard": "^1.10.0", "@react-native-community/image-editor": "^4.2.0", "@react-native-community/netinfo": "9.3.7", @@ -5843,15 +5842,6 @@ "node": ">= 4.0.0" } }, - "node_modules/@mosip/tuvali": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/@mosip/tuvali/-/tuvali-0.4.9.tgz", - "integrity": "sha512-WnpnM9EAJKEBdZ71DPSeh2va5LDy01iWFI3Ngtc4KfJ4XHWyQbRQA/1T4QPDgofMTP8wy9wehD7w4m8K8YJdhw==", - "peerDependencies": { - "react": "*", - "react-native": "*" - } - }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -34070,12 +34060,6 @@ } } }, - "@mosip/tuvali": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/@mosip/tuvali/-/tuvali-0.4.9.tgz", - "integrity": "sha512-WnpnM9EAJKEBdZ71DPSeh2va5LDy01iWFI3Ngtc4KfJ4XHWyQbRQA/1T4QPDgofMTP8wy9wehD7w4m8K8YJdhw==", - "requires": {} - }, "@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", diff --git a/package.json b/package.json index 33a11891c7..6de2182e34 100644 --- a/package.json +++ b/package.json @@ -21,11 +21,10 @@ "@expo/metro-config": "~0.10.0", "@invertase/react-native-apple-authentication": "^2.3.0", "@iriscan/biometric-sdk-react-native": "0.2.6", - "@mosip/tuvali": "0.4.9", "@react-native-clipboard/clipboard": "^1.10.0", + "@react-native-community/image-editor": "^4.2.0", "@react-native-community/netinfo": "9.3.7", "@react-native-google-signin/google-signin": "^10.1.1", - "@react-native-community/image-editor": "^4.2.0", "@react-native-picker/picker": "2.4.8", "@react-navigation/bottom-tabs": "^6.0.7", "@react-navigation/native": "^6.0.8", @@ -35,22 +34,22 @@ "base45-web": "^1.0.2", "base64url-universal": "^1.1.0", "buffer": "^6.0.3", + "color-diff": "^1.4.0", "date-fns": "^2.26.0", "expo": "~49.0.23", - "hex-rgb": "^5.0.0", "expo-auth-session": "^5.2.0", "expo-barcode-scanner": "~12.3.2", "expo-camera": "^13.6.0", "expo-constants": "^14.4.2", + "expo-face-detector": "12.4.0", "expo-font": "~11.1.1", "expo-local-authentication": "~13.3.0", "expo-localization": "~14.1.1", "expo-modules-autolinking": "~1.5.0", "expo-updates": "^0.18.17", - "expo-face-detector": "12.4.0", "expo-web-browser": "^12.5.0", + "hex-rgb": "^5.0.0", "i18next": "^21.6.16", - "color-diff": "^1.4.0", "iso-639-3": "^3.0.1", "jwt-decode": "^3.1.2", "node-forge": "^1.3.1", @@ -74,11 +73,11 @@ "react-native-elements": "3.4.3", "react-native-fs": "^2.18.0", "react-native-gesture-handler": "~2.9.0", + "react-native-image-colors": "^2.4.0", "react-native-keychain": "^8.0.0", "react-native-linear-gradient": "^2.8.0", "react-native-localize": "^3.0.2", "react-native-location": "^2.5.0", - "react-native-image-colors": "^2.4.0", "react-native-mmkv-storage": "^0.9.1", "react-native-permissions": "^3.8.0", "react-native-popable": "^0.4.3", @@ -135,12 +134,12 @@ "prettier": "^2.6.1", "react-native-flipper": "^0.212.0", "react-native-flipper-xstate": "^1.0.5", + "react-native-share": "^10.2.1", "react-native-svg-transformer": "^1.1.0", "react-native-url-polyfill": "^2.0.0", "rn-mmkv-storage-flipper": "^1.1.1", "ts-jest": "^29.1.1", - "typescript": "^4.9.5", - "react-native-share": "^10.2.1" + "typescript": "^4.9.5" }, "private": true, "name": "mosip-resident-app", diff --git a/shared/GlobalVariables.ts b/shared/GlobalVariables.ts index 2063cd82dc..16f2573800 100644 --- a/shared/GlobalVariables.ts +++ b/shared/GlobalVariables.ts @@ -1,20 +1,10 @@ import {getVersion} from 'react-native-device-info'; import ShortUniqueId from 'short-unique-id'; -import {APP_ID_LENGTH} from './constants'; -/* eslint-disable @typescript-eslint/no-var-requires */ -const dependencies = require('../package-lock.json').dependencies; +import {APP_ID_LENGTH, isIOS} from './constants'; +import {NativeModules} from 'react-native'; function getTuvaliPackageDetails() { - let packageVersion; - Object.keys(dependencies).forEach(dependencyName => { - const dependencyData = dependencies[dependencyName]; - if (dependencyName == '@mosip/tuvali') { - packageVersion = dependencyData?.version - ? dependencyData.version - : 'unknown'; - } - }); - return {packageVersion}; + return isIOS() ? 'unknown' : NativeModules.VersionModule.getVersion(); } export class __AppId { private static value: string; @@ -31,7 +21,7 @@ export class __TuvaliVersion { private static packageDetails = getTuvaliPackageDetails(); public static getpackageVersion(): string { - return __TuvaliVersion.packageDetails.packageVersion; + return __TuvaliVersion.packageDetails; } public static getValue(): string { @@ -58,4 +48,4 @@ function generateSessionId() { length: APP_ID_LENGTH, }); return shortUUID.randomUUID() + Date.now(); -} +} \ No newline at end of file diff --git a/shared/openIdBLE/verifierEventHandler.ts b/shared/openIdBLE/verifierEventHandler.ts index c10a8b38b1..493d5391a5 100644 --- a/shared/openIdBLE/verifierEventHandler.ts +++ b/shared/openIdBLE/verifierEventHandler.ts @@ -1,7 +1,5 @@ -import tuvali from '@mosip/tuvali'; -import {VerifierDataEvent} from '@mosip/tuvali/src/types/events'; - -const {verifier} = tuvali; +import {VerifierDataEvent} from '../tuvali/types/events'; +import {verifier} from '../tuvali'; export function subscribe(callback: (event: VerifierDataEvent) => void) { return verifier.handleDataEvents(e => { callback(e); diff --git a/shared/openIdBLE/walletEventHandler.ts b/shared/openIdBLE/walletEventHandler.ts index a2ab862eae..29276f441e 100644 --- a/shared/openIdBLE/walletEventHandler.ts +++ b/shared/openIdBLE/walletEventHandler.ts @@ -1,7 +1,6 @@ -import tuvali from '@mosip/tuvali'; -import {WalletDataEvent} from '@mosip/tuvali/src/types/events'; +import {WalletDataEvent} from '../tuvali/types/events'; -const {wallet} = tuvali; +import {wallet} from '../tuvali'; export function subscribe(callback: (event: WalletDataEvent) => void) { return wallet.handleDataEvents(e => { diff --git a/shared/tuvali/index.ts b/shared/tuvali/index.ts new file mode 100644 index 0000000000..420cfa10a7 --- /dev/null +++ b/shared/tuvali/index.ts @@ -0,0 +1,58 @@ +import {NativeEventEmitter, NativeModules, Platform} from 'react-native'; +import type {Verifier, VersionModule, Wallet} from './types/interface'; +import {EventTypes, VerificationStatus} from './types/events'; +import {isAndroid, isIOS} from '../constants'; + +const LINKING_ERROR = + `The package 'tuvali' doesn't seem to be linked. Make sure: \n\n` + + Platform.select({ios: "- You have run 'pod install'\n", default: ''}) + + '- You rebuilt the app after installing the package\n' + + '- You are not using Expo Go\n'; + +const VERIFIER_NOT_IMPLEMENTATED_ERROR = `Verifier is not yet implemented on IOS. Please remove Verifier usage on IOS Platform`; + +const wallet: Wallet = NativeModules.WalletModule + ? NativeModules.WalletModule + : new Proxy( + {}, + { + get() { + throw new Error(LINKING_ERROR); + }, + }, + ); + +// TODO: Use Actual Verifier module on IOS once Verifier is implemented +let verifier: Verifier = NativeModules.VerifierModule; + +if (!isIOS()) { + if (verifier) setupModule(verifier); + else + new Proxy( + {}, + { + get() { + throw new Error(VERIFIER_NOT_IMPLEMENTATED_ERROR); + }, + }, + ); +} + +setupModule(wallet); + + +function setupModule(module: any) { + if (isAndroid()) { + const eventEmitter = new NativeEventEmitter(); + module.handleDataEvents = (callback: (event: any) => void) => + eventEmitter.addListener('DATA_EVENT', callback); + } + + if (isIOS()) { + const eventEmitter = new NativeEventEmitter(module); + module.handleDataEvents = (callback: (event: any) => void) => + eventEmitter.addListener('DATA_EVENT', callback); + } +} + +export {verifier, wallet, EventTypes, VerificationStatus}; diff --git a/shared/tuvali/types/events.ts b/shared/tuvali/types/events.ts new file mode 100644 index 0000000000..07db3d5b1f --- /dev/null +++ b/shared/tuvali/types/events.ts @@ -0,0 +1,64 @@ +/* This file redefines the types from Native Modules to allow auto complete to the consumer applications, + However this means, if the native module type definition changes, such changes needs to be applied here as well + to avoid mismatch of type information +*/ + +export type CommonDataEvent = + | ConnectedEvent + | DisconnectedEvent + | ErrorEvent + | SecureChannelEstablished; + +export type WalletDataEvent = + | CommonDataEvent + | VerificationStatusReceivedEvent + | DataSentEvent; + +export type VerifierDataEvent = CommonDataEvent | DataReceivedEvent; + +export type ConnectedEvent = {type: EventTypes.onConnected}; + +export type SecureChannelEstablished = { + type: EventTypes.onSecureChannelEstablished; +}; + +export type DataReceivedEvent = { + type: EventTypes.onDataReceived; + data: string; + crcFailureCount: number; + totalChunkCount: number; +}; + +export type DataSentEvent = { + type: EventTypes.onDataSent; +}; + +export type VerificationStatusReceivedEvent = { + type: EventTypes.onVerificationStatusReceived; + status: VerificationStatus; +}; + +export type DisconnectedEvent = { + type: EventTypes.onDisconnected; +}; + +export type ErrorEvent = { + type: EventTypes.onError; + message: string; + code: string; +}; + +export enum EventTypes { + onConnected = 'onConnected', + onSecureChannelEstablished = 'onSecureChannelEstablished', + onDataSent = 'onDataSent', + onDataReceived = 'onDataReceived', + onVerificationStatusReceived = 'onVerificationStatusReceived', + onError = 'onError', + onDisconnected = 'onDisconnected', +} + +export enum VerificationStatus { + ACCEPTED = 0, + REJECTED = 1, +} diff --git a/shared/tuvali/types/interface.ts b/shared/tuvali/types/interface.ts new file mode 100644 index 0000000000..c695e91b1d --- /dev/null +++ b/shared/tuvali/types/interface.ts @@ -0,0 +1,28 @@ +import type {EmitterSubscription} from 'react-native'; +import type {VerifierDataEvent, WalletDataEvent} from './events'; +import type {VerificationStatus} from './events'; + +interface TuvaliModule { + noop: () => void; + disconnect: () => void; +} + +export interface Verifier extends TuvaliModule { + startAdvertisement: (advIdentifier: String) => string; + sendVerificationStatus: (status: VerificationStatus) => void; + handleDataEvents: ( + callback: (events: VerifierDataEvent) => void, + ) => EmitterSubscription; +} + +export interface Wallet extends TuvaliModule { + startConnection: (uri: String) => void; + sendData: (data: string) => void; + handleDataEvents: ( + callback: (events: WalletDataEvent) => void, + ) => EmitterSubscription; +} + +export interface VersionModule { + setTuvaliVersion: (version: string) => void; +}