Bringing openpassport/main (#19)

Co-authored-by: seshanthS <seshanth@protonmail.com>
Co-authored-by: turnoffthiscomputer <colin.remi07@gmail.com>
Co-authored-by: thomas-senechal <thomas.senechal@pm.me>
Co-authored-by: motemotech <i.am.nicoshark@gmail.com>
Co-authored-by: turnoffthiscomputer <98749896+remicolin@users.noreply.github.com>
Co-authored-by: ayman <aymanshaik1015@gmail.com>
This commit is contained in:
turboblitz
2025-02-05 02:13:52 -08:00
committed by GitHub
parent 3775790736
commit 629dfdad1a
484 changed files with 23040 additions and 18896 deletions

View File

@@ -1,8 +1,13 @@
import React, { useEffect } from 'react';
import 'react-native-get-random-values';
import * as amplitude from '@amplitude/analytics-react-native';
import { AMPLITUDE_KEY } from '@env';
import { SEGMENT_KEY } from '@env';
import {
EventPlugin,
PluginType,
SegmentEvent,
createClient,
} from '@segment/analytics-react-native';
import '@ethersproject/shims';
import { Buffer } from 'buffer';
import { YStack } from 'tamagui';
@@ -15,6 +20,57 @@ import { setupUniversalLinkListener } from './src/utils/qrCode';
global.Buffer = Buffer;
// Adjust the import path as needed
export class DisableTrackingPlugin extends EventPlugin {
type = PluginType.before;
execute(event: SegmentEvent): SegmentEvent {
// Ensure context exists
if (!event.context) {
event.context = {};
}
// Ensure device context exists
if (!event.context.device) {
event.context.device = {};
}
// Force tracking related fields to be disabled
event.context.device.adTrackingEnabled = false;
event.context.device.advertisingId = undefined;
event.context.device.trackingStatus = 'not-authorized';
event.context.device.id = undefined;
return event;
}
}
export const createSegmentClient = () => {
if (!SEGMENT_KEY) return null;
const client = createClient({
writeKey: SEGMENT_KEY,
trackAppLifecycleEvents: true,
debug: true,
collectDeviceId: false,
defaultSettings: {
integrations: {
'Segment.io': {
apiKey: SEGMENT_KEY,
},
},
},
});
client.add({ plugin: new DisableTrackingPlugin() });
return client;
};
// Export the client variable (will be initialized later)
export let segmentClient: ReturnType<typeof createClient> | null = null;
function App(): React.JSX.Element {
// const toast = useToastController();
// const setToast = useNavigationStore(state => state.setToast);
@@ -34,14 +90,13 @@ function App(): React.JSX.Element {
// }, [setSelectedTab]);
useEffect(() => {
if (AMPLITUDE_KEY) {
amplitude.init(AMPLITUDE_KEY);
}
const cleanup = setupUniversalLinkListener();
return cleanup;
}, []);
useEffect(() => {
const cleanup = setupUniversalLinkListener();
return cleanup;
// Initialize segment directly without any tracking checks
segmentClient = createSegmentClient();
}, []);
return (

View File

@@ -85,8 +85,8 @@ android {
applicationId "com.proofofpassportapp"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 16
versionName "1.5"
versionCode 19
versionName "1.8"
externalNativeBuild {
cmake {
cppFlags += "-fexceptions -frtti -std=c++11"

View File

@@ -362,11 +362,13 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
}
}
eventMessageEmitter("Reading DG1.....")
val dg1In = service.getInputStream(PassportService.EF_DG1)
dg1File = DG1File(dg1In)
val dg2In = service.getInputStream(PassportService.EF_DG2)
dg2File = DG2File(dg2In)
dg1File = DG1File(dg1In)
// eventMessageEmitter("Reading DG2.....")
// val dg2In = service.getInputStream(PassportService.EF_DG2)
// dg2File = DG2File(dg2In)
eventMessageEmitter("Reading SOD.....")
val sodIn = service.getInputStream(PassportService.EF_SOD)
sodFile = SODFile(sodIn)
@@ -406,20 +408,20 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
// sendDataToJS(PassportData(dg1File, dg2File, sodFile))
// Log.d(TAG, "============DATA SENT TO JS=============")
val allFaceImageInfo: MutableList<FaceImageInfo> = ArrayList()
dg2File.faceInfos.forEach {
allFaceImageInfo.addAll(it.faceImageInfos)
}
if (allFaceImageInfo.isNotEmpty()) {
val faceImageInfo = allFaceImageInfo.first()
val imageLength = faceImageInfo.imageLength
val dataInputStream = DataInputStream(faceImageInfo.imageInputStream)
val buffer = ByteArray(imageLength)
dataInputStream.readFully(buffer, 0, imageLength)
val inputStream: InputStream = ByteArrayInputStream(buffer, 0, imageLength)
bitmap = decodeImage(reactContext, faceImageInfo.mimeType, inputStream)
imageBase64 = Base64.encodeToString(buffer, Base64.DEFAULT)
}
// val allFaceImageInfo: MutableList<FaceImageInfo> = ArrayList()
// dg2File.faceInfos.forEach {
// allFaceImageInfo.addAll(it.faceImageInfos)
// }
// if (allFaceImageInfo.isNotEmpty()) {
// val faceImageInfo = allFaceImageInfo.first()
// val imageLength = faceImageInfo.imageLength
// val dataInputStream = DataInputStream(faceImageInfo.imageInputStream)
// val buffer = ByteArray(imageLength)
// dataInputStream.readFully(buffer, 0, imageLength)
// val inputStream: InputStream = ByteArrayInputStream(buffer, 0, imageLength)
// bitmap = decodeImage(reactContext, faceImageInfo.mimeType, inputStream)
// imageBase64 = Base64.encodeToString(buffer, Base64.DEFAULT)
// }
} catch (e: Exception) {
eventMessageEmitter(Messages.RESET)
return e
@@ -429,6 +431,7 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
private fun doChipAuth(service: PassportService) {
try {
eventMessageEmitter("Reading DG14.....")
val dg14In = service.getInputStream(PassportService.EF_DG14)
dg14Encoded = IOUtils.toByteArray(dg14In)
val dg14InByte = ByteArrayInputStream(dg14Encoded)
@@ -459,11 +462,8 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
val dataHashes = sodFile.dataGroupHashes
eventMessageEmitter("Reading DG14.....")
val dg14Hash = if (chipAuthSucceeded) digest.digest(dg14Encoded) else ByteArray(0)
eventMessageEmitter("Reading DG1.....")
val dg1Hash = digest.digest(dg1File.encoded)
eventMessageEmitter("Reading DG2.....")
val dg2Hash = digest.digest(dg2File.encoded)
// val gson = Gson()
@@ -486,7 +486,8 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
Log.d(TAG, "Comparing data group hashes...")
eventMessageEmitter(Messages.COMPARING)
if (Arrays.equals(dg1Hash, dataHashes[1]) && Arrays.equals(dg2Hash, dataHashes[2])
// if (Arrays.equals(dg1Hash, dataHashes[1]) && Arrays.equals(dg2Hash, dataHashes[2])
if (Arrays.equals(dg1Hash, dataHashes[1])
&& (!chipAuthSucceeded || Arrays.equals(dg14Hash, dataHashes[14]))) {
Log.d(TAG, "Data group hashes match.")
@@ -660,13 +661,13 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
// Log.d(TAG, "signedData.signerInfos: ${gson.toJson(signedData.signerInfos)}")
// Log.d(TAG, "signedData.certificates: ${gson.toJson(signedData.certificates)}")
var quality = 100
val base64 = bitmap?.let { toBase64(it, quality) }
val photo = Arguments.createMap()
photo.putString("base64", base64 ?: "")
photo.putInt("width", bitmap?.width ?: 0)
photo.putInt("height", bitmap?.height ?: 0)
passport.putMap("photo", photo)
// var quality = 100
// val base64 = bitmap?.let { toBase64(it, quality) }
// val photo = Arguments.createMap()
// photo.putString("base64", base64 ?: "")
// photo.putInt("width", bitmap?.width ?: 0)
// photo.putInt("height", bitmap?.height ?: 0)
// passport.putMap("photo", photo)
// passport.putString("dg2File", gson.toJson(dg2File))
eventMessageEmitter(Messages.COMPLETED)

View File

@@ -34,7 +34,6 @@
1686F0E02C500FBD00841CDE /* QRScannerBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 1686F0DF2C500FBD00841CDE /* QRScannerBridge.m */; };
16E6646E2B8D292500FDD6A0 /* QKMRZScannerViewRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16E6646D2B8D292500FDD6A0 /* QKMRZScannerViewRepresentable.swift */; };
16E884A52C5BD764003B7125 /* passport.json in Resources */ = {isa = PBXBuildFile; fileRef = 16E884A42C5BD764003B7125 /* passport.json */; };
1B904271B8E1DB8434EF0613 /* Pods_OpenPassport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3435ED6D988B5E2DE0DE8101 /* Pods_OpenPassport.framework */; };
4A1791A6108347E5A635DB1C /* Inter-ThinItalic.otf in Resources */ = {isa = PBXBuildFile; fileRef = EEA2A4D24A8F4B10A5ECA607 /* Inter-ThinItalic.otf */; };
5008C8140A304ED79DB817C5 /* slkscrb.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B4E7218406B64A95BCE0DFE4 /* slkscrb.ttf */; };
5C66B65890614C638590DC8A /* Inter-ExtraBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 8CE3CC4CFFC24314A22F1391 /* Inter-ExtraBold.otf */; };
@@ -61,6 +60,7 @@
EBECCA4983EC6929A7722578 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = E56E082698598B41447667BB /* PrivacyInfo.xcprivacy */; };
EEF3331B93C24D6482021BA2 /* Inter-ExtraLightItalic.otf in Resources */ = {isa = PBXBuildFile; fileRef = 090474A3F07B4FFA82C9A751 /* Inter-ExtraLightItalic.otf */; };
F1961109CC004035884F79D9 /* Inter-ExtraBoldItalic.otf in Resources */ = {isa = PBXBuildFile; fileRef = 37A4DECF3A824D5BAA8863FD /* Inter-ExtraBoldItalic.otf */; };
F2B6CAF95CEE1D3F94541B0F /* Pods_OpenPassport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF34842C3AD0E76B7A7D5C5E /* Pods_OpenPassport.framework */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -142,12 +142,12 @@
16E6646D2B8D292500FDD6A0 /* QKMRZScannerViewRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QKMRZScannerViewRepresentable.swift; sourceTree = "<group>"; };
16E884A42C5BD764003B7125 /* passport.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = passport.json; sourceTree = "<group>"; };
276287D0D37B4E8EBD7A1ABD /* Inter-SemiBold.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-SemiBold.otf"; path = "../node_modules/@tamagui/font-inter/otf/Inter-SemiBold.otf"; sourceTree = "<group>"; };
3435ED6D988B5E2DE0DE8101 /* Pods_OpenPassport.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OpenPassport.framework; sourceTree = BUILT_PRODUCTS_DIR; };
37A4DECF3A824D5BAA8863FD /* Inter-ExtraBoldItalic.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-ExtraBoldItalic.otf"; path = "../node_modules/@tamagui/font-inter/otf/Inter-ExtraBoldItalic.otf"; sourceTree = "<group>"; };
3BF771EA645241D9A28A3AE9 /* Inter-Bold.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-Bold.otf"; path = "../node_modules/@tamagui/font-inter/otf/Inter-Bold.otf"; sourceTree = "<group>"; };
4B261C28061D47B7B3BB3E37 /* Inter-Black.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-Black.otf"; path = "../node_modules/@tamagui/font-inter/otf/Inter-Black.otf"; sourceTree = "<group>"; };
64F386964AAE4C1E8F2DF789 /* Inter-ExtraLight.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-ExtraLight.otf"; path = "../node_modules/@tamagui/font-inter/otf/Inter-ExtraLight.otf"; sourceTree = "<group>"; };
6CF8D6DF98634423ACD5D630 /* Inter-Regular.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-Regular.otf"; path = "../node_modules/@tamagui/font-inter/otf/Inter-Regular.otf"; sourceTree = "<group>"; };
73A8B182B1187BFE180CBB44 /* Pods-OpenPassport.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OpenPassport.release.xcconfig"; path = "Target Support Files/Pods-OpenPassport/Pods-OpenPassport.release.xcconfig"; sourceTree = "<group>"; };
7CCB5F83F57540E88D54B34A /* slkscr.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = slkscr.ttf; path = "../node_modules/@tamagui/font-silkscreen/files/slkscr.ttf"; sourceTree = "<group>"; };
7E5C3CEF7EDA4871B3D0EBE1 /* Advercase-Regular.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Advercase-Regular.otf"; path = "../src/assets/fonts/Advercase-Regular.otf"; sourceTree = "<group>"; };
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = OpenPassport/LaunchScreen.storyboard; sourceTree = "<group>"; };
@@ -158,10 +158,10 @@
905B70062A72774000AFA232 /* PassportReader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PassportReader.m; sourceTree = "<group>"; };
905B70082A729CD400AFA232 /* OpenPassport.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = OpenPassport.entitlements; path = OpenPassport/OpenPassport.entitlements; sourceTree = "<group>"; };
9BF744D9A73A4BAC96EC569A /* DINOT-Medium.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "DINOT-Medium.otf"; path = "../src/assets/fonts/DINOT-Medium.otf"; sourceTree = "<group>"; };
A239B1BBD7EF208EB51EF7DE /* Pods-OpenPassport.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OpenPassport.release.xcconfig"; path = "Target Support Files/Pods-OpenPassport/Pods-OpenPassport.release.xcconfig"; sourceTree = "<group>"; };
AF34842C3AD0E76B7A7D5C5E /* Pods_OpenPassport.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OpenPassport.framework; sourceTree = BUILT_PRODUCTS_DIR; };
B4E7218406B64A95BCE0DFE4 /* slkscrb.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = slkscrb.ttf; path = "../node_modules/@tamagui/font-silkscreen/files/slkscrb.ttf"; sourceTree = "<group>"; };
BB9316819FB038104D42933E /* Pods-OpenPassport.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OpenPassport.debug.xcconfig"; path = "Target Support Files/Pods-OpenPassport/Pods-OpenPassport.debug.xcconfig"; sourceTree = "<group>"; };
C56F122245594D6DA9B7570A /* slkscr.woff */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = slkscr.woff; path = "../node_modules/@tamagui/font-silkscreen/files/slkscr.woff"; sourceTree = "<group>"; };
CA67A75B161A05334E3E9402 /* Pods-OpenPassport.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OpenPassport.debug.xcconfig"; path = "Target Support Files/Pods-OpenPassport/Pods-OpenPassport.debug.xcconfig"; sourceTree = "<group>"; };
D58C0CED91AE4265A5A406A0 /* Inter-BlackItalic.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-BlackItalic.otf"; path = "../node_modules/@tamagui/font-inter/otf/Inter-BlackItalic.otf"; sourceTree = "<group>"; };
DD642F4F3A114B43A22296D7 /* Inter-Thin.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-Thin.otf"; path = "../node_modules/@tamagui/font-inter/otf/Inter-Thin.otf"; sourceTree = "<group>"; };
E56E082698598B41447667BB /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = OpenPassport/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
@@ -186,7 +186,7 @@
05D985F62BB331AB00F58EEA /* libfr.a in Frameworks */,
167D934A2C91D2EA00530E6B /* libwitnesscalc_prove_rsa_65537_sha256.a in Frameworks */,
167D93462C91B1E100530E6B /* libwitnesscalc_register_rsa_65537_sha1.a in Frameworks */,
1B904271B8E1DB8434EF0613 /* Pods_OpenPassport.framework in Frameworks */,
F2B6CAF95CEE1D3F94541B0F /* Pods_OpenPassport.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -273,7 +273,7 @@
0569F35E2BBC98C9006670BD /* libfq.a */,
0569F35A2BBC900D006670BD /* librapidsnark.a */,
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
3435ED6D988B5E2DE0DE8101 /* Pods_OpenPassport.framework */,
AF34842C3AD0E76B7A7D5C5E /* Pods_OpenPassport.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -343,8 +343,8 @@
BBD78D7AC51CEA395F1C20DB /* Pods */ = {
isa = PBXGroup;
children = (
BB9316819FB038104D42933E /* Pods-OpenPassport.debug.xcconfig */,
A239B1BBD7EF208EB51EF7DE /* Pods-OpenPassport.release.xcconfig */,
CA67A75B161A05334E3E9402 /* Pods-OpenPassport.debug.xcconfig */,
73A8B182B1187BFE180CBB44 /* Pods-OpenPassport.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@@ -356,15 +356,15 @@
isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "OpenPassport" */;
buildPhases = (
62212FE980074600640A3F2F /* [CP] Check Pods Manifest.lock */,
1C3B778186C749AEAB10A0B1 /* [CP] Check Pods Manifest.lock */,
FD10A7F022414F080027D42C /* Start Packager */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
054340D12C71B2980014B445 /* Embed App Clips */,
19B6B230BF58128B7603B834 /* [CP] Embed Pods Frameworks */,
CCF107224BF9CF7E8A4F57B7 /* [CP] Copy Pods Resources */,
0C6411FE06C61E7F495D9204 /* [CP] Embed Pods Frameworks */,
DAB2FFB78D69B620A585FF8C /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -461,7 +461,7 @@
shellPath = /bin/sh;
shellScript = "set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n";
};
19B6B230BF58128B7603B834 /* [CP] Embed Pods Frameworks */ = {
0C6411FE06C61E7F495D9204 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -478,7 +478,7 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-OpenPassport/Pods-OpenPassport-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
62212FE980074600640A3F2F /* [CP] Check Pods Manifest.lock */ = {
1C3B778186C749AEAB10A0B1 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -500,7 +500,7 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
CCF107224BF9CF7E8A4F57B7 /* [CP] Copy Pods Resources */ = {
DAB2FFB78D69B620A585FF8C /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -584,7 +584,7 @@
/* Begin XCBuildConfiguration section */
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = BB9316819FB038104D42933E /* Pods-OpenPassport.debug.xcconfig */;
baseConfigurationReference = CA67A75B161A05334E3E9402 /* Pods-OpenPassport.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
@@ -592,7 +592,7 @@
CODE_SIGN_ENTITLEMENTS = OpenPassport/OpenPassportDebug.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 67;
CURRENT_PROJECT_VERSION = 72;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 5B29R5LYHQ;
ENABLE_BITCODE = NO;
@@ -707,7 +707,7 @@
"$(PROJECT_DIR)",
"$(PROJECT_DIR)/MoproKit/Libs",
);
MARKETING_VERSION = 2.0.0;
MARKETING_VERSION = 2.0.6;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -725,13 +725,13 @@
};
13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = A239B1BBD7EF208EB51EF7DE /* Pods-OpenPassport.release.xcconfig */;
baseConfigurationReference = 73A8B182B1187BFE180CBB44 /* Pods-OpenPassport.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = OpenPassport/OpenPassport.entitlements;
CURRENT_PROJECT_VERSION = 67;
CURRENT_PROJECT_VERSION = 72;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 5B29R5LYHQ;
FRAMEWORK_SEARCH_PATHS = (
@@ -845,7 +845,7 @@
"$(PROJECT_DIR)",
"$(PROJECT_DIR)/MoproKit/Libs",
);
MARKETING_VERSION = 2.0.0;
MARKETING_VERSION = 2.0.6;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",

View File

@@ -97,7 +97,7 @@ class PassportReader: NSObject{
// let masterListURL = Bundle.main.url(forResource: "masterList", withExtension: ".pem")
// passportReader.setMasterListURL( masterListURL! )
let passport = try await passportReader.readPassport( mrzKey: mrzKey, customDisplayMessage: customMessageHandler)
let passport = try await passportReader.readPassport( mrzKey: mrzKey, tags: [.COM, .DG1, .SOD], customDisplayMessage: customMessageHandler)
var ret = [String:String]()
print("documentType", passport.documentType)
@@ -118,13 +118,13 @@ class PassportReader: NSObject{
ret["phoneNumber"] = passport.phoneNumber
ret["personalNumber"] = passport.personalNumber
let passportPhotoData = passport.passportPhoto // [UInt8]
if let passportPhotoData = passport.passportPhoto {
let data = Data(passportPhotoData)
let base64String = data.base64EncodedString()
// let passportPhotoData = passport.passportPhoto // [UInt8]
// if let passportPhotoData = passport.passportPhoto {
// let data = Data(passportPhotoData)
// let base64String = data.base64EncodedString()
ret["passportPhoto"] = base64String
}
// ret["passportPhoto"] = base64String
// }
// documentSigningCertificate
// countrySigningCertificate

View File

@@ -24,7 +24,7 @@ target 'OpenPassport' do
config = use_native_modules!
use_frameworks!
pod 'NFCPassportReader', git: 'https://github.com/0xturboblitz/NFCPassportReader.git', commit: '0a8e26d56f5f85f698b67c5df5ea9ecbb53cbc45'
pod 'NFCPassportReader', git: 'https://github.com/zk-passport/NFCPassportReader', commit: '8e72f0a2d3ca3bede00304bd22ed10829535dd53'
pod 'QKMRZScanner'
pod 'RNFS', :path => '../node_modules/react-native-fs'
pod 'lottie-ios'

View File

@@ -7,9 +7,9 @@ PODS:
- fmt (9.1.0)
- glog (0.3.5)
- lottie-ios (4.5.0)
- NFCPassportReader (2.0.3):
- OpenSSL-Universal (= 1.1.1100)
- OpenSSL-Universal (1.1.1100)
- NFCPassportReader (2.1.1):
- OpenSSL-Universal (= 1.1.1900)
- OpenSSL-Universal (1.1.1900)
- QKMRZParser (2.0.0)
- QKMRZScanner (3.0.0):
- QKMRZParser (~> 2.0.0)
@@ -1227,6 +1227,10 @@ PODS:
- React-Core
- react-native-nfc-manager (3.16.1):
- React-Core
- react-native-safe-area-context (5.1.0):
- React-Core
- react-native-tracking-transparency (0.1.2):
- React
- React-nativeconfig (0.75.4)
- React-NativeModulesApple (0.75.4):
- glog
@@ -1474,6 +1478,27 @@ PODS:
- React-Core
- RNFS (2.20.0):
- React-Core
- RNGestureHandler (2.22.1):
- DoubleConversion
- glog
- RCT-Folly (= 2024.01.01.00)
- RCTRequired
- RCTTypeSafety
- React-Core
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- RNKeychain (8.2.0):
- React-Core
- RNSVG (13.4.0):
@@ -1485,7 +1510,12 @@ PODS:
- RNZipArchive/Core (6.1.2):
- React-Core
- SSZipArchive (~> 2.2)
- segment-analytics-react-native (2.20.3):
- React-Core
- sovran-react-native
- SocketRocket (0.7.0)
- sovran-react-native (1.1.3):
- React-Core
- SSZipArchive (2.4.3)
- SwiftQRScanner (1.1.6)
- SwiftyTesseract (3.1.3)
@@ -1499,7 +1529,7 @@ DEPENDENCIES:
- fmt (from `../node_modules/react-native/third-party-podspecs/fmt.podspec`)
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
- lottie-ios
- NFCPassportReader (from `https://github.com/0xturboblitz/NFCPassportReader.git`, commit `0a8e26d56f5f85f698b67c5df5ea9ecbb53cbc45`)
- NFCPassportReader (from `https://github.com/zk-passport/NFCPassportReader`, commit `8e72f0a2d3ca3bede00304bd22ed10829535dd53`)
- QKMRZScanner
- RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
- RCT-Folly/Fabric (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
@@ -1536,6 +1566,8 @@ DEPENDENCIES:
- react-native-get-random-values (from `../node_modules/react-native-get-random-values`)
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
- react-native-nfc-manager (from `../node_modules/react-native-nfc-manager`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- react-native-tracking-transparency (from `../node_modules/react-native-tracking-transparency`)
- React-nativeconfig (from `../node_modules/react-native/ReactCommon`)
- React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
- React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`)
@@ -1563,9 +1595,12 @@ DEPENDENCIES:
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
- RNFS (from `../node_modules/react-native-fs`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- RNKeychain (from `../node_modules/react-native-keychain`)
- RNSVG (from `../node_modules/react-native-svg`)
- RNZipArchive (from `../node_modules/react-native-zip-archive`)
- "segment-analytics-react-native (from `../node_modules/@segment/analytics-react-native`)"
- "sovran-react-native (from `../node_modules/@segment/sovran-react-native`)"
- SwiftQRScanner (from `https://github.com/vinodiOS/SwiftQRScanner`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
@@ -1593,8 +1628,8 @@ EXTERNAL SOURCES:
glog:
:podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec"
NFCPassportReader:
:commit: 0a8e26d56f5f85f698b67c5df5ea9ecbb53cbc45
:git: https://github.com/0xturboblitz/NFCPassportReader.git
:commit: 8e72f0a2d3ca3bede00304bd22ed10829535dd53
:git: https://github.com/zk-passport/NFCPassportReader
RCT-Folly:
:podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec"
RCTDeprecation:
@@ -1661,6 +1696,10 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-community/netinfo"
react-native-nfc-manager:
:path: "../node_modules/react-native-nfc-manager"
react-native-safe-area-context:
:path: "../node_modules/react-native-safe-area-context"
react-native-tracking-transparency:
:path: "../node_modules/react-native-tracking-transparency"
React-nativeconfig:
:path: "../node_modules/react-native/ReactCommon"
React-NativeModulesApple:
@@ -1715,12 +1754,18 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-async-storage/async-storage"
RNFS:
:path: "../node_modules/react-native-fs"
RNGestureHandler:
:path: "../node_modules/react-native-gesture-handler"
RNKeychain:
:path: "../node_modules/react-native-keychain"
RNSVG:
:path: "../node_modules/react-native-svg"
RNZipArchive:
:path: "../node_modules/react-native-zip-archive"
segment-analytics-react-native:
:path: "../node_modules/@segment/analytics-react-native"
sovran-react-native:
:path: "../node_modules/@segment/sovran-react-native"
SwiftQRScanner:
:git: https://github.com/vinodiOS/SwiftQRScanner
Yoga:
@@ -1728,8 +1773,8 @@ EXTERNAL SOURCES:
CHECKOUT OPTIONS:
NFCPassportReader:
:commit: 0a8e26d56f5f85f698b67c5df5ea9ecbb53cbc45
:git: https://github.com/0xturboblitz/NFCPassportReader.git
:commit: 8e72f0a2d3ca3bede00304bd22ed10829535dd53
:git: https://github.com/zk-passport/NFCPassportReader
SwiftQRScanner:
:commit: fddcabcb431cd6110cea0394660082661dbafa7e
:git: https://github.com/vinodiOS/SwiftQRScanner
@@ -1742,8 +1787,8 @@ SPEC CHECKSUMS:
fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120
glog: 69ef571f3de08433d766d614c73a9838a06bf7eb
lottie-ios: a881093fab623c467d3bce374367755c272bdd59
NFCPassportReader: a160b80e3df3b5325c13902f90405f5eef7520b3
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
NFCPassportReader: e931c61c189e08a4b4afa0ed4014af19eab2f129
OpenSSL-Universal: 84efb8a29841f2764ac5403e0c4119a28b713346
QKMRZParser: 6b419b6f07d6bff6b50429b97de10846dc902c29
QKMRZScanner: cf2348fd6ce441e758328da4adf231ef2b51d769
RCT-Folly: 4464f4d875961fce86008d45f4ecf6cef6de0740
@@ -1779,6 +1824,8 @@ SPEC CHECKSUMS:
react-native-get-random-values: 21325b2244dfa6b58878f51f9aa42821e7ba3d06
react-native-netinfo: f0a9899081c185db1de5bb2fdc1c88c202a059ac
react-native-nfc-manager: 5213321cf6c18d879c8092c0bf56806b771ec5ac
react-native-safe-area-context: 04803a01f39f31cc6605a5531280b477b48f8a88
react-native-tracking-transparency: 25ff1ff866e338c137c818bdec20526bb05ffcc1
React-nativeconfig: 31072ab0146e643594f6959c7f970a04b6c9ddd0
React-NativeModulesApple: 5df767d9a2197ac25f4d8dd2d4ae1af3624022e2
React-perflogger: 59e1a3182dca2cee7b9f1f7aab204018d46d1914
@@ -1806,15 +1853,18 @@ SPEC CHECKSUMS:
ReactCommon: 03d2d48fcd1329fe3bc4e428a78a0181b68068c2
RNCAsyncStorage: ec53e44dc3e75b44aa2a9f37618a49c3bc080a7a
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
RNGestureHandler: e705387b01bba53f4643bdff381ee08c7b9679a1
RNKeychain: bfe3d12bf4620fe488771c414530bf16e88f3678
RNSVG: 07dbd870b0dcdecc99b3a202fa37c8ca163caec2
RNZipArchive: 6d736ee4e286dbbd9d81206b7a4da355596ca04a
segment-analytics-react-native: d57ed4971cbb995706babf29215ebdbf242ecdab
SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d
sovran-react-native: eec37f82e4429f0e3661f46aaf4fcd85d1b54f60
SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
SwiftQRScanner: e85a25f9b843e9231dab89a96e441472fe54a724
SwiftyTesseract: 1f3d96668ae92dc2208d9842c8a59bea9fad2cbb
Yoga: b05994d1933f507b0a28ceaa4fdb968dc18da178
PODFILE CHECKSUM: cc6778e0dcd4c510b705f4dc458411547dc1d00c
PODFILE CHECKSUM: a5761927116120f511f409f5249a18a8c626545c
COCOAPODS: 1.16.2
COCOAPODS: 1.15.2

View File

@@ -27,6 +27,8 @@
"@react-navigation/elements": "^2.2.5",
"@react-navigation/native": "^7.0.14",
"@react-navigation/stack": "^7.1.1",
"@segment/analytics-react-native": "^2.20.3",
"@segment/sovran-react-native": "^1.1.3",
"@tamagui/colors": "1.110.0",
"@tamagui/config": "1.110.0",
"@tamagui/core": "1.110.0",
@@ -57,6 +59,7 @@
"react-native-passport-reader": "^1.0.3",
"react-native-safe-area-context": "^5.1.0",
"react-native-svg": "13.4.0",
"react-native-tracking-transparency": "^0.1.2",
"react-native-zip-archive": "^6.1.0",
"socket.io-client": "^4.7.5",
"tamagui": "1.110.0",

View File

@@ -19,7 +19,8 @@ import {
} from 'tamagui';
import { countryCodes } from '../../../common/src/constants/constants';
import { genMockPassportData } from '../../../common/src/utils/genMockPassportData';
import { genMockPassportData } from '../../../common/src/utils/passports/genMockPassportData';
import { parsePassportData } from '../../../common/src/utils/passports/passport_parsing/parsePassportData';
import CustomButton from '../components/CustomButton';
import useUserStore from '../stores/userStore';
import {
@@ -77,20 +78,38 @@ const MockDataScreen: React.FC<MockDataScreenProps> = ({}) => {
.toUpperCase();
await new Promise(resolve =>
setTimeout(() => {
let mockPassportData;
const hashAlgo = selectedAlgorithm === 'rsa sha1' ? 'sha1' : 'sha256';
const mockPassportData = genMockPassportData(
hashAlgo,
hashAlgo,
signatureAlgorithmToStrictSignatureAlgorithm[
selectedAlgorithm as keyof typeof signatureAlgorithmToStrictSignatureAlgorithm
],
selectedCountry as keyof typeof countryCodes,
castDate(-age),
castDate(expiryYears),
randomPassportNumber,
...(isInOfacList ? ['HENAO MONTOYA', 'ARCANGEL DE JESUS'] : []),
);
if (isInOfacList) {
mockPassportData = genMockPassportData(
hashAlgo,
hashAlgo,
signatureAlgorithmToStrictSignatureAlgorithm[
selectedAlgorithm as keyof typeof signatureAlgorithmToStrictSignatureAlgorithm
],
selectedCountry as keyof typeof countryCodes,
castDate(-age),
castDate(expiryYears),
randomPassportNumber,
'HENAO MONTOYA', // this name is the OFAC list
'ARCANGEL DE JESUS',
);
} else {
mockPassportData = genMockPassportData(
hashAlgo,
hashAlgo,
signatureAlgorithmToStrictSignatureAlgorithm[
selectedAlgorithm as keyof typeof signatureAlgorithmToStrictSignatureAlgorithm
],
selectedCountry as keyof typeof countryCodes,
castDate(-age),
castDate(expiryYears),
randomPassportNumber,
);
}
useUserStore.getState().registerPassportData(mockPassportData);
const parsedPassportData = parsePassportData(mockPassportData);
useUserStore.getState().setPassportMetadata(parsedPassportData);
useUserStore.getState().setRegistered(true);
resolve(null);
}, 0),

View File

@@ -50,9 +50,10 @@ const NextScreen: React.FC = () => {
h={height > 750 ? 190 : 130}
borderRadius={height > 750 ? '$7' : '$6'}
source={{
uri: passportData.mockUser
? USER_PROFILE
: passportData.photoBase64 ?? USER_PROFILE,
uri:
passportData?.mockUser || !!!passportData?.photoBase64
? USER_PROFILE
: passportData?.photoBase64 ?? USER_PROFILE,
}}
/>
)}
@@ -78,16 +79,34 @@ const NextScreen: React.FC = () => {
const key_ = key;
const indexes =
attributeToPosition[key_ as keyof typeof attributeToPosition];
if (!passportData?.mrz || !indexes) {
return null;
}
const keyFormatted = key_
.replace(/_/g, ' ')
.split(' ')
.map((word: string) => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');
if (
indexes[0] >= passportData.mrz.length ||
indexes[1] >= passportData.mrz.length
) {
console.warn(
`Invalid indexes for key ${key_}: [${indexes[0]}, ${indexes[1]}]`,
);
return null;
}
const mrzAttribute = passportData.mrz.slice(
indexes[0],
indexes[1] + 1,
);
const mrzAttributeFormatted = formatAttribute(key_, mrzAttribute);
const mrzAttributeFormatted = formatAttribute(
key_,
mrzAttribute ?? '',
);
return (
<Fieldset horizontal key={key} gap="$3" alignItems="center">

View File

@@ -1,12 +1,10 @@
import React, { useEffect, useState } from 'react';
import { useNavigation } from '@react-navigation/native';
import io, { Socket } from 'socket.io-client';
import { Text, YStack } from 'tamagui';
import {
DEVELOPMENT_MODE,
max_cert_bytes,
MAX_CERT_BYTES,
} from '../../../../common/src/constants/constants';
import {
ArgumentsProveOffChain,
@@ -16,13 +14,15 @@ import {
getCircuitNameOld,
parseCertificateSimple,
} from '../../../../common/src/utils/certificate_parsing/parseCertificateSimple';
// import {
// getCSCAFromSKI,
// sendCSCARequest,
// } from '../../../../common/src/utils/csca';
import {
generateCircuitInputsDSC,
getCSCAFromSKI,
sendCSCARequest,
} from '../../../../common/src/utils/csca';
} from '../../../../common/src/utils/circuits/generateInputs';
import { buildAttestation } from '../../../../common/src/utils/openPassportAttestation';
import { parsePassportData } from '../../../../common/src/utils/parsePassportData';
import { parsePassportData } from '../../../../common/src/utils/passports/passport_parsing/parsePassportData';
import Disclosures from '../../components/Disclosures';
import { PrimaryButton } from '../../components/buttons/PrimaryButton';
import { BodyText } from '../../components/typography/BodyText';
@@ -31,7 +31,7 @@ import { ExpandableBottomLayout } from '../../layouts/ExpandableBottomLayout';
import useNavigationStore from '../../stores/navigationStore';
import useUserStore from '../../stores/userStore';
import { black, slate300, white } from '../../utils/colors';
import { generateCircuitInputsInApp } from '../../utils/generateInputsInApp';
// import { generateCircuitInputsInApp } from '../../utils/generateInputsInApp';
import { generateProof } from '../../utils/prover';
import { CircuitName } from '../../utils/zkeyDownload';
@@ -188,34 +188,34 @@ const ProveScreen: React.FC = () => {
switch (selectedApp.mode) {
case 'prove_onchain':
case 'register':
const cscaInputs = generateCircuitInputsDSC(
dscSecret as string,
passportData.dsc,
max_cert_bytes,
selectedApp.devMode,
);
[dscProof, proof] = await Promise.all([
sendCSCARequest(cscaInputs),
generateProof(circuitName, inputs),
]);
const cscaPem = getCSCAFromSKI(
authorityKeyIdentifier,
DEVELOPMENT_MODE,
);
const { signatureAlgorithm: signatureAlgorithmDsc } =
parseCertificateSimple(cscaPem);
attestation = buildAttestation({
mode: selectedApp.mode,
proof: proof.proof,
publicSignals: proof.publicSignals,
signatureAlgorithm: signatureAlgorithm,
hashFunction: parsedPassportData.signedAttrHashFunction,
userIdType: selectedApp.userIdType,
dscProof: (dscProof as any).proof,
dscPublicSignals: (dscProof as any).pub_signals,
signatureAlgorithmDsc: signatureAlgorithmDsc,
hashFunctionDsc: parsedPassportData.signedAttrHashFunction,
});
// const cscaInputs = generateCircuitInputsDSC(
// dscSecret as string,
// passportData.dsc,
// MAX_CERT_BYTES,
// selectedApp.devMode,
// );
// [dscProof, proof] = await Promise.all([
// sendCSCARequest(cscaInputs),
// generateProof(circuitName, inputs),
// ]);
// const cscaPem = getCSCAFromSKI(
// authorityKeyIdentifier,
// DEVELOPMENT_MODE,
// );
// const { signatureAlgorithm: signatureAlgorithmDsc } =
// parseCertificateSimple(cscaPem);
// attestation = buildAttestation({
// mode: selectedApp.mode,
// proof: proof.proof,
// publicSignals: proof.publicSignals,
// signatureAlgorithm: signatureAlgorithm,
// hashFunction: parsedPassportData.signedAttrHashFunction,
// userIdType: selectedApp.userIdType,
// dscProof: (dscProof as any).proof,
// dscPublicSignals: (dscProof as any).pub_signals,
// signatureAlgorithmDsc: signatureAlgorithmDsc,
// hashFunctionDsc: parsedPassportData.signedAttrHashFunction,
// });
break;
default:
proof = await generateProof(circuitName, inputs);

View File

@@ -2,7 +2,7 @@ import React from 'react';
import { ScrollView, Separator, Text, XStack, YStack } from 'tamagui';
import { parsePassportData } from '../../../common/src/utils/parsePassportData';
import { parsePassportData } from '../../../common/src/utils/passports/passport_parsing/parsePassportData';
import useUserStore from '../stores/userStore';
import { separatorColor, textBlack } from '../utils/colors';
@@ -126,7 +126,7 @@ const UserInfo: React.FC = () => {
<InfoRow
label="CSCA Signature Algorithm"
value={passportMetaData?.cscaSignature || 'None'}
value={passportMetaData?.cscaSignatureAlgorithm || 'None'}
/>
<Separator borderColor={separatorColor} />

View File

@@ -2,6 +2,7 @@ import { useToastController } from '@tamagui/toast';
import { create } from 'zustand';
import { OpenPassportApp } from '../../../common/src/utils/appType';
import { segmentClient } from '../../App';
import {
IsZkeyDownloading,
ShowWarningModalProps,
@@ -24,10 +25,12 @@ interface NavigationState {
setNfcSheetIsOpen: (isOpen: boolean) => void;
zkeyDownloadedPercentage: number;
setZkeyDownloadedPercentage: (percentage: number) => void;
trackEvent: (eventName: string, properties?: Record<string, any>) => void;
trackNavigation: (tab: string) => void;
}
const useNavigationStore = create<NavigationState>((set, get) => ({
zkeyDownloadedPercentage: 100,
zkeyDownloadedPercentage: 0,
setZkeyDownloadedPercentage: (percentage: number) =>
set({ zkeyDownloadedPercentage: percentage }),
isZkeyDownloading: {
@@ -54,7 +57,10 @@ const useNavigationStore = create<NavigationState>((set, get) => ({
setToast: toast => set({ toast }),
setSelectedApp: app => set({ selectedApp: app }),
setSelectedTab: tab => set({ selectedTab: tab }),
setSelectedTab: (tab: string) => {
const { trackNavigation } = get();
trackNavigation(tab);
},
update: patch => {
set({
@@ -64,6 +70,21 @@ const useNavigationStore = create<NavigationState>((set, get) => ({
},
nfcSheetIsOpen: false,
setNfcSheetIsOpen: isOpen => set({ nfcSheetIsOpen: isOpen }),
trackEvent: (eventName: string, properties?: Record<string, any>) => {
if (segmentClient) {
segmentClient.track(eventName, properties);
}
},
trackNavigation: (tab: string) => {
if (segmentClient) {
segmentClient.track('Navigation Change', {
tab,
});
}
set({ selectedTab: tab });
},
}));
export default useNavigationStore;

View File

@@ -3,12 +3,15 @@ import { resetGenericPassword } from 'react-native-keychain';
import { DEFAULT_DOB, DEFAULT_DOE, DEFAULT_PNUMBER } from '@env';
import { create } from 'zustand';
import { generateDscSecret } from '../../../common/src/utils/csca';
// import { generateDscSecret } from '../../../common/src/utils/csca';
import { PassportMetadata } from '../../../common/src/utils/passports/passport_parsing/parsePassportData';
import { PassportData, Proof } from '../../../common/src/utils/types';
import {
loadPassportData,
loadPassportMetadata,
loadSecretOrCreateIt,
storePassportData,
storePassportMetadata,
} from '../utils/keychain';
interface UserState {
@@ -18,6 +21,7 @@ interface UserState {
countryCode: string;
registered: boolean;
passportData: PassportData | null;
passportMetadata: PassportMetadata | null;
secret: string;
cscaProof: Proof | null;
localProof: Proof | null;
@@ -35,6 +39,8 @@ interface UserState {
setUserLoaded: (userLoaded: boolean) => void;
proofVerificationResult: string;
setProofVerificationResult: (proofVerificationResult: string) => void;
setPassportMetadata: (metadata: PassportMetadata) => void;
clearPassportMetadataFromStorage: () => void;
}
const useUserStore = create<UserState>((set, get) => ({
@@ -46,6 +52,7 @@ const useUserStore = create<UserState>((set, get) => ({
dscSecret: null,
registered: false,
passportData: null,
passportMetadata: null,
secret: '',
cscaProof: null,
localProof: null,
@@ -58,6 +65,10 @@ const useUserStore = create<UserState>((set, get) => ({
setUserLoaded: (userLoaded: boolean) => {
set({ userLoaded });
},
setPassportMetadata: async (metadata: PassportMetadata) => {
await storePassportMetadata(metadata);
set({ passportMetadata: metadata });
},
proofVerificationResult: 'null',
setProofVerificationResult: (proofVerificationResult: string) => {
set({ proofVerificationResult });
@@ -68,16 +79,18 @@ const useUserStore = create<UserState>((set, get) => ({
// - If the commitment is present in the tree, proceed to main screen
// - If the commitment is not present in the tree, proceed to main screen AND try registering it in the background
initUserStore: async () => {
// download zkeys if they are not already downloaded
const secret = await loadSecretOrCreateIt();
set({ secret });
const dscSecret = await generateDscSecret();
set({ dscSecret });
// const dscSecret = await generateDscSecret();
// set({ dscSecret });
const passportDataString = await loadPassportData();
if (!passportDataString) {
console.log('No passport data found, starting onboarding flow');
const passportMetadataString = await loadPassportMetadata();
if (!passportDataString || !passportMetadataString) {
console.log(
'No passport data or metadata found, starting onboarding flow',
);
set({
userLoaded: true,
});
@@ -87,6 +100,9 @@ const useUserStore = create<UserState>((set, get) => ({
// const isAlreadyRegistered = await isCommitmentRegistered(secret, JSON.parse(passportData));
const isAlreadyRegistered = true;
const passportData: PassportData = JSON.parse(passportDataString);
const passportMetadata: PassportMetadata = JSON.parse(
passportMetadataString,
);
if (!isAlreadyRegistered) {
console.log(
@@ -94,9 +110,9 @@ const useUserStore = create<UserState>((set, get) => ({
);
set({
passportData: passportData,
passportMetadata: passportMetadata,
userLoaded: true,
});
return;
}
@@ -105,9 +121,10 @@ const useUserStore = create<UserState>((set, get) => ({
);
set({
passportData: passportData,
passportMetadata: passportMetadata,
registered: true,
userLoaded: true,
});
set({ userLoaded: true });
},
// When reading passport for the first time:
@@ -152,6 +169,11 @@ const useUserStore = create<UserState>((set, get) => ({
dateOfBirth: '',
dateOfExpiry: '',
}),
clearPassportMetadataFromStorage: async () => {
await resetGenericPassword({ service: 'passportMetadata' });
set({ passportMetadata: null });
},
}));
export default useUserStore;

View File

@@ -15,11 +15,11 @@ import {
OpenPassportApp,
} from '../../../common/src/utils/appType';
import {
generateCircuitInputsDisclose,
generateCircuitInputsProve,
} from '../../../common/src/utils/generateInputs';
import { fetchTreeFromUrl } from '../../../common/src/utils/pubkeyTree';
import { revealBitmapFromAttributes } from '../../../common/src/utils/revealBitmap';
generateCircuitInputsRegister,
generateCircuitInputsVCandDisclose,
} from '../../../common/src/utils/circuits/generateInputs';
import { fetchTreeFromUrl } from '../../../common/src/utils/trees';
import { revealBitmapFromAttributes } from '../../../common/src/utils/circuits/formatOutputs';
import { PassportData } from '../../../common/src/utils/types';
import useUserStore from '../stores/userStore';
@@ -99,7 +99,7 @@ export const generateCircuitInputsInApp = async (
disclosureOptionsDisclose.excludedCountries.value.map(country =>
getCountryCode(country),
);
return generateCircuitInputsDisclose(
return generateCircuitInputsVCandDisclose(
secret,
PASSPORT_ATTESTATION_ID,
passportData,

View File

@@ -2,6 +2,7 @@ import * as Keychain from 'react-native-keychain';
import { ethers } from 'ethers';
import { PassportMetadata } from '../../../common/src/utils/passports/passport_parsing/parsePassportData';
import { PassportData } from '../../../common/src/utils/types';
export async function loadSecretOrCreateIt() {
@@ -36,3 +37,18 @@ export async function storePassportData(passportData: PassportData) {
{ service: 'passportData' },
);
}
export async function loadPassportMetadata() {
const metadataCreds = await Keychain.getGenericPassword({
service: 'passportMetadata',
});
return metadataCreds === false ? false : metadataCreds.password;
}
export async function storePassportMetadata(metadata: PassportMetadata) {
await Keychain.setGenericPassword(
'passportMetadata',
JSON.stringify(metadata),
{ service: 'passportMetadata' },
);
}

View File

@@ -2,10 +2,9 @@ import { NativeModules, Platform } from 'react-native';
import PassportReader from 'react-native-passport-reader';
// @ts-ignore
import * as amplitude from '@amplitude/analytics-react-native';
import { Buffer } from 'buffer';
import { parsePassportData } from '../../../common/src/utils/parsePassportData';
import { parsePassportData } from '../../../common/src/utils/passports/passport_parsing/parsePassportData';
import { PassportData } from '../../../common/src/utils/types';
import useNavigationStore from '../stores/navigationStore';
import useUserStore from '../stores/userStore';
@@ -16,12 +15,15 @@ export const scan = async (
) => {
const { passportNumber, dateOfBirth, dateOfExpiry } = useUserStore.getState();
const { toast } = useNavigationStore.getState();
const { toast, trackEvent } = useNavigationStore.getState();
const check = checkInputs(passportNumber, dateOfBirth, dateOfExpiry);
if (!check.success) {
amplitude.track('inputs_invalid', { error: check.message });
trackEvent('Inputs Failed', {
success: false,
error: check.message,
});
toast.show('Unvailable', {
message: check.message,
customData: {
@@ -31,20 +33,26 @@ export const scan = async (
return;
}
trackEvent('NFC Started', {
success: true,
});
console.log('scanning...');
if (Platform.OS === 'android') {
scanAndroid(setModalProofStep);
scanAndroid(setModalProofStep, Date.now());
} else {
scanIOS(setModalProofStep);
scanIOS(setModalProofStep, Date.now());
}
};
const scanAndroid = async (
setModalProofStep: (modalProofStep: number) => void,
startTime: number,
) => {
const { passportNumber, dateOfBirth, dateOfExpiry } = useUserStore.getState();
const { toast, setNfcSheetIsOpen } = useNavigationStore.getState();
const { toast, setNfcSheetIsOpen, trackEvent } =
useNavigationStore.getState();
setNfcSheetIsOpen(true);
try {
@@ -55,12 +63,15 @@ const scanAndroid = async (
});
console.log('scanned');
setNfcSheetIsOpen(false);
amplitude.track('nfc_scan_successful');
handleResponseAndroid(response, setModalProofStep);
trackEvent('NFC Success', {
success: true,
duration_ms: Date.now() - startTime,
});
} catch (e: any) {
console.log('error during scan:', e);
setNfcSheetIsOpen(false);
amplitude.track('nfc_scan_unsuccessful', { error: e.message });
if (e.message.includes('InvalidMRZKey')) {
toast.show('Error', {
message:
@@ -70,6 +81,10 @@ const scanAndroid = async (
},
timeout: 5000,
});
trackEvent('Invalid Key', {
success: false,
error: e.message,
});
useNavigationStore.getState().setSelectedTab('scan');
} else {
toast.show('Error', {
@@ -78,13 +93,21 @@ const scanAndroid = async (
type: 'error',
},
});
trackEvent('NFC Failed', {
success: false,
error: e.message,
duration_ms: Date.now() - startTime,
});
}
}
};
const scanIOS = async (setModalProofStep: (modalProofStep: number) => void) => {
const scanIOS = async (
setModalProofStep: (modalProofStep: number) => void,
startTime: number,
) => {
const { passportNumber, dateOfBirth, dateOfExpiry } = useUserStore.getState();
const { toast } = useNavigationStore.getState();
const { toast, trackEvent } = useNavigationStore.getState();
console.log('passportNumber', passportNumber);
console.log('dateOfBirth', dateOfBirth);
@@ -98,18 +121,13 @@ const scanIOS = async (setModalProofStep: (modalProofStep: number) => void) => {
);
console.log('scanned');
handleResponseIOS(response, setModalProofStep);
amplitude.track('nfc_scan_successful');
trackEvent('NFC Success', {
success: true,
duration_ms: Date.now() - startTime,
});
} catch (e: any) {
console.log('error during scan:', e);
amplitude.track('nfc_scan_unsuccessful', { error: e.message });
// if (!e.message.includes("UserCanceled")) {
// toast.show('Failed to read passport', {
// message: e.message,
// customData: {
// type: "error",
// },
// })
// }
if (e.message.includes('InvalidMRZKey')) {
toast.show('Error', {
message:
@@ -120,6 +138,10 @@ const scanIOS = async (setModalProofStep: (modalProofStep: number) => void) => {
timeout: 5000,
});
useNavigationStore.getState().setSelectedTab('scan');
trackEvent('Invalid Key', {
success: false,
error: e.message,
});
} else {
toast.show('Error', {
message: e.message,
@@ -127,6 +149,10 @@ const scanIOS = async (setModalProofStep: (modalProofStep: number) => void) => {
type: 'error',
},
});
trackEvent('NFC Failed', {
success: false,
error: e.message,
});
}
}
};
@@ -135,7 +161,7 @@ const handleResponseIOS = async (
response: any,
_setModalProofStep: (modalProofStep: number) => void,
) => {
const { toast } = useNavigationStore.getState();
const { toast, trackEvent } = useNavigationStore.getState();
const parsed = JSON.parse(response);
@@ -149,21 +175,16 @@ const handleResponseIOS = async (
const signedAttributes = parsed?.signedAttributes; // this is what we call eContent in android world
const mrz = parsed?.passportMRZ;
const signatureBase64 = parsed?.signatureBase64;
console.log('dataGroupsPresent', parsed?.dataGroupsPresent);
console.log('placeOfBirth', parsed?.placeOfBirth);
console.log('activeAuthenticationPassed', parsed?.activeAuthenticationPassed);
console.log('isPACESupported', parsed?.isPACESupported);
console.log(
'isChipAuthenticationSupported',
parsed?.isChipAuthenticationSupported,
);
console.log('residenceAddress', parsed?.residenceAddress);
console.log('passportPhoto', parsed?.passportPhoto.substring(0, 100) + '...');
console.log(
'encapsulatedContentDigestAlgorithm',
parsed?.encapsulatedContentDigestAlgorithm,
);
console.log('documentSigningCertificate', parsed?.documentSigningCertificate);
const pem = JSON.parse(parsed?.documentSigningCertificate).PEM.replace(
/\n/g,
'',
@@ -186,18 +207,6 @@ const handleResponseIOS = async (
Buffer.from(signatureBase64, 'base64'),
).map(byte => (byte > 127 ? byte - 256 : byte));
// amplitude.track('nfc_response_parsed', {
// dataGroupsPresent: parsed?.dataGroupsPresent,
// eContentLength: signedEContentArray?.length,
// concatenatedDataHashesLength: concatenatedDataHashesArraySigned?.length,
// encryptedDigestLength: encryptedDigestArray?.length,
// activeAuthenticationPassed: parsed?.activeAuthenticationPassed,
// isPACESupported: parsed?.isPACESupported,
// isChipAuthenticationSupported: parsed?.isChipAuthenticationSupported,
// encapsulatedContentDigestAlgorithm: parsed?.encapsulatedContentDigestAlgorithm,
// dsc: pem,
// });
const passportData = {
mrz,
dsc: pem,
@@ -207,24 +216,28 @@ const handleResponseIOS = async (
eContent: concatenatedDataHashesArraySigned,
signedAttr: signedEContentArray,
encryptedDigest: encryptedDigestArray,
photoBase64: 'data:image/jpeg;base64,' + parsed.passportPhoto,
photoBase64: parsed?.passportPhoto
? 'data:image/jpeg;base64,' + parsed?.passportPhoto
: '',
mockUser: false,
parsed: false,
};
const parsedPassportData = parsePassportData(passportData);
amplitude.track('nfc_response_parsed', parsedPassportData);
try {
useUserStore.getState().registerPassportData(passportData);
useNavigationStore.getState().setSelectedTab('next');
parsePassportDataAsync(passportData);
} catch (e: any) {
console.log('error during parsing:', e);
amplitude.track('error_parsing_nfc_response', { error: e.message });
toast.show('Error', {
toast.show('Error during passport data parsing', {
message: e.message,
customData: {
type: 'error',
},
});
trackEvent('Passport ParseFailed', {
success: false,
error: e.message,
});
}
};
@@ -232,18 +245,18 @@ const handleResponseAndroid = async (
response: any,
_setModalProofStep: (modalProofStep: number) => void,
) => {
const { toast } = useNavigationStore.getState();
const { toast, trackEvent } = useNavigationStore.getState();
const {
mrz,
eContent,
encryptedDigest,
photo,
digestAlgorithm,
signerInfoDigestAlgorithm,
digestEncryptionAlgorithm,
LDSVersion,
unicodeVersion,
// digestAlgorithm,
// signerInfoDigestAlgorithm,
// digestEncryptionAlgorithm,
// LDSVersion,
// unicodeVersion,
encapContent,
documentSigningCertificate,
dataGroupHashes,
@@ -272,8 +285,9 @@ const handleResponseAndroid = async (
eContent: JSON.parse(encapContent),
signedAttr: JSON.parse(eContent),
encryptedDigest: JSON.parse(encryptedDigest),
photoBase64: photo.base64,
photoBase64: photo?.base64 ?? '',
mockUser: false,
parsed: false,
};
console.log(
@@ -287,7 +301,7 @@ const handleResponseAndroid = async (
2,
),
);
/***
console.log('mrz', passportData?.mrz);
console.log('dataGroupHashes', passportData?.eContent);
console.log('eContent', passportData?.eContent);
@@ -303,31 +317,56 @@ const handleResponseAndroid = async (
console.log('unicodeVersion', unicodeVersion);
console.log('encapContent', encapContent);
console.log('documentSigningCertificate', documentSigningCertificate);
const parsedPassportData = parsePassportData(passportData);
amplitude.track('nfc_response_parsed', parsedPassportData);
// amplitude.track('nfc_response_parsed', {
// dataGroupHashesLength: passportData?.eContent?.length,
// eContentLength: passportData?.eContent?.length,
// encryptedDigestLength: passportData?.encryptedDigest?.length,
// digestAlgorithm: digestAlgorithm,
// signerInfoDigestAlgorithm: signerInfoDigestAlgorithm,
// digestEncryptionAlgorithm: digestEncryptionAlgorithm,
// dsc: pem,
// mockUser: false
// });
***/
try {
await useUserStore.getState().registerPassportData(passportData);
useNavigationStore.getState().setSelectedTab('next');
parsePassportDataAsync(passportData);
} catch (e: any) {
console.log('error during parsing:', e);
amplitude.track('error_parsing_nfc_response', { error: e.message });
toast.show('Error', {
message: e.message,
customData: {
type: 'error',
},
});
trackEvent('Passport ParseFailed', {
success: false,
error: e.message,
});
}
};
async function parsePassportDataAsync(passportData: PassportData) {
const { trackEvent } = useNavigationStore.getState();
const parsedPassportData = parsePassportData(passportData);
useUserStore.getState().setPassportMetadata(parsedPassportData);
await useUserStore.getState().registerPassportData(passportData);
trackEvent('Passport Parsed', {
success: true,
data_groups: parsedPassportData.dataGroups,
dg1_hash_function: parsedPassportData.dg1HashFunction,
dg1_hash_offset: parsedPassportData.dg1HashOffset,
dg_padding_bytes: parsedPassportData.dgPaddingBytes,
e_content_size: parsedPassportData.eContentSize,
e_content_hash_function: parsedPassportData.eContentHashFunction,
e_content_hash_offset: parsedPassportData.eContentHashOffset,
signed_attr_size: parsedPassportData.signedAttrSize,
signed_attr_hash_function: parsedPassportData.signedAttrHashFunction,
signature_algorithm: parsedPassportData.signatureAlgorithm,
salt_length: parsedPassportData.saltLength,
curve_or_exponent: parsedPassportData.curveOrExponent,
signature_algorithm_bits: parsedPassportData.signatureAlgorithmBits,
country_code: parsedPassportData.countryCode,
csca_found: parsedPassportData.cscaFound,
csca_hash_function: parsedPassportData.cscaHashFunction,
csca_signature_algorithm: parsedPassportData.cscaSignatureAlgorithm,
csca_salt_length: parsedPassportData.cscaSaltLength,
csca_curve_or_exponent: parsedPassportData.cscaCurveOrExponent,
csca_signature_algorithm_bits:
parsedPassportData.cscaSignatureAlgorithmBits,
dsc: parsedPassportData.dsc,
});
useNavigationStore.getState().setSelectedTab('next');
}

View File

@@ -6,7 +6,7 @@ import * as amplitude from '@amplitude/analytics-react-native';
import '@react-navigation/native';
import { Buffer } from 'buffer';
import { parsePassportData } from '../../../common/src/utils/parsePassportData';
import { parsePassportData } from '../../../common/src/utils/passports/passport_parsing/parsePassportData';
import { PassportData } from '../../../common/src/utils/types';
import useNavigationStore from '../stores/navigationStore';
import useUserStore from '../stores/userStore';
@@ -179,6 +179,7 @@ const handleResponseIOS = async (response: any) => {
encryptedDigest: encryptedDigestArray,
photoBase64: 'data:image/jpeg;base64,' + parsed.passportPhoto,
mockUser: false,
parsed: false,
};
const parsedPassportData = parsePassportData(passportData);
amplitude.track('nfc_response_parsed', parsedPassportData);
@@ -238,6 +239,7 @@ const handleResponseAndroid = async (response: any) => {
encryptedDigest: JSON.parse(encryptedDigest),
photoBase64: photo.base64,
mockUser: false,
parsed: false,
};
console.log(

View File

@@ -1,27 +1,30 @@
import { NativeModules, Platform } from 'react-native';
import RNFS from 'react-native-fs';
import * as amplitude from '@amplitude/analytics-react-native';
import useNavigationStore from '../stores/navigationStore';
import { parseProofAndroid } from './utils';
export const generateProof = async (circuit: string, inputs: any) => {
console.log('launching generateProof function');
console.log('inputs in prover.ts', inputs);
console.log('circuit', circuit);
const startTime = Date.now();
const { trackEvent } = useNavigationStore.getState();
trackEvent('Proof Started', {
success: true,
circuit: circuit,
});
// Example: "/data/user/0/com.proofofpassportapp/files/register_sha256WithRSAEncryption_65537.zkey" on android
const zkey_path = `${RNFS.DocumentDirectoryPath}/${circuit}.zkey`;
const dat_path = `${RNFS.DocumentDirectoryPath}/${circuit}.dat`;
const witness_calculator = circuit;
if (!zkey_path || !witness_calculator || !dat_path) {
trackEvent('Proof Failed', {
success: false,
error: 'Required parameters are missing',
circuit: circuit,
});
throw new Error('Required parameters are missing');
}
console.log('zkey_path', zkey_path);
console.log('witness_calculator', witness_calculator);
console.log('dat_path', dat_path);
try {
const response = await NativeModules.Prover.runProveAction(
@@ -31,15 +34,24 @@ export const generateProof = async (circuit: string, inputs: any) => {
inputs,
);
// console.log('local proof:', response);
if (Platform.OS === 'android') {
const parsedResponse = parseProofAndroid(response);
console.log('parsedResponse', parsedResponse);
trackEvent('Proof Generated', {
success: true,
duration_ms: Date.now() - startTime,
circuit: circuit,
});
return formatProof(parsedResponse);
} else {
const parsedResponse = JSON.parse(response);
console.log('parsedResponse', parsedResponse);
trackEvent('Proof Generated', {
success: true,
duration_ms: Date.now() - startTime,
circuit: circuit,
});
return formatProof({
proof: parsedResponse.proof,
@@ -47,31 +59,47 @@ export const generateProof = async (circuit: string, inputs: any) => {
});
}
} catch (err: any) {
console.log('err', err);
amplitude.track('error_generating_proof', {
trackEvent('Proof Failed', {
success: false,
error: err.message,
duration_ms: Date.now() - startTime,
circuit: circuit,
zkey_path: zkey_path,
witness_calculator: witness_calculator,
dat_path: dat_path,
});
throw new Error(err);
}
};
export const formatProof = (rawProof: any): any => {
return {
proof: {
pi_a: [rawProof.proof.a[0], rawProof.proof.a[1], '1'],
pi_b: [
[rawProof.proof.b[0][0], rawProof.proof.b[0][1]],
[rawProof.proof.b[1][0], rawProof.proof.b[1][1]],
['1', '0'],
],
pi_c: [rawProof.proof.c[0], rawProof.proof.c[1], '1'],
protocol: 'groth16',
curve: 'bn128',
},
publicSignals: (rawProof as any).pub_signals,
};
const { trackEvent } = useNavigationStore.getState();
try {
const formattedProof = {
proof: {
pi_a: [rawProof.proof.a[0], rawProof.proof.a[1], '1'],
pi_b: [
[rawProof.proof.b[0][0], rawProof.proof.b[0][1]],
[rawProof.proof.b[1][0], rawProof.proof.b[1][1]],
['1', '0'],
],
pi_c: [rawProof.proof.c[0], rawProof.proof.c[1], '1'],
protocol: 'groth16',
curve: 'bn128',
},
publicSignals: (rawProof as any).pub_signals,
};
trackEvent('Proof Formatted', {
success: true,
});
return formattedProof;
} catch (err: any) {
trackEvent('Proof FormatFailed', {
success: false,
error: err.message,
});
throw err;
}
};

View File

@@ -5,7 +5,6 @@ import pako from 'pako';
import { Mode, OpenPassportApp } from '../../../common/src/utils/appType';
import { getCircuitNameOld } from '../../../common/src/utils/certificate_parsing/parseCertificateSimple';
import { parsePassportData } from '../../../common/src/utils/parsePassportData';
import useNavigationStore from '../stores/navigationStore';
import useUserStore from '../stores/userStore';
import { downloadZkey } from './zkeyDownload';
@@ -26,81 +25,66 @@ export const scanQRCode = () => {
const { toast, setSelectedApp, setSelectedTab } =
useNavigationStore.getState();
Linking.getInitialURL()
.then(url => {
if (url) {
handleUniversalLink(url);
} else {
if (Platform.OS === 'ios') {
console.log('Scanning QR code on iOS without Universal Link');
const qrScanner = NativeModules.QRScannerBridge;
if (qrScanner && qrScanner.scanQRCode) {
qrScanner
.scanQRCode()
.then((result: string) => {
const params = parseUrlParams(result);
const encodedData = params.get('data');
handleQRCodeScan(
encodedData as string,
toast,
setSelectedApp,
setSelectedTab,
);
})
.catch((error: any) => {
console.error('QR Scanner Error:', error);
toast.show('Error', {
message: 'Failed to scan QR code',
type: 'error',
});
});
} else {
console.error('QR Scanner module not found for iOS');
toast.show('Error', {
message: 'QR Scanner not available',
type: 'error',
});
}
} else if (Platform.OS === 'android') {
const qrScanner = NativeModules.QRCodeScanner;
if (qrScanner && qrScanner.scanQRCode) {
qrScanner
.scanQRCode()
.then((result: string) => {
const params = parseUrlParams(result);
const encodedData = params.get('data');
handleQRCodeScan(
encodedData as string,
toast,
setSelectedApp,
setSelectedTab,
);
})
.catch((error: any) => {
console.error('QR Scanner Error:', error);
toast.show('Error', {
message: 'Failed to scan QR code',
type: 'error',
});
});
} else {
console.error('QR Scanner module not found for Android');
toast.show('Error', {
message: 'QR Scanner not available',
type: 'error',
});
}
}
}
})
.catch(err => {
console.error('An error occurred while getting initial URL', err);
if (Platform.OS === 'ios') {
console.log('Scanning QR code on iOS');
const qrScanner = NativeModules.QRScannerBridge;
if (qrScanner && qrScanner.scanQRCode) {
qrScanner
.scanQRCode()
.then((result: string) => {
const params = parseUrlParams(result);
const encodedData = params.get('data');
handleQRCodeScan(
encodedData as string,
toast,
setSelectedApp,
setSelectedTab,
);
})
.catch((error: any) => {
console.error('QR Scanner Error:', error);
toast.show('Error', {
message: 'Failed to scan QR code',
type: 'error',
});
});
} else {
console.error('QR Scanner module not found for iOS');
toast.show('Error', {
message: 'Failed to process initial link',
message: 'QR Scanner not available',
type: 'error',
});
});
}
} else if (Platform.OS === 'android') {
const qrScanner = NativeModules.QRCodeScanner;
if (qrScanner && qrScanner.scanQRCode) {
qrScanner
.scanQRCode()
.then((result: string) => {
const params = parseUrlParams(result);
const encodedData = params.get('data');
handleQRCodeScan(
encodedData as string,
toast,
setSelectedApp,
setSelectedTab,
);
})
.catch((error: any) => {
console.error('QR Scanner Error:', error);
toast.show('Error', {
message: 'Failed to scan QR code',
type: 'error',
});
});
} else {
console.error('QR Scanner module not found for Android');
toast.show('Error', {
message: 'QR Scanner not available',
type: 'error',
});
}
}
};
const handleQRCodeScan = (
@@ -110,8 +94,8 @@ const handleQRCodeScan = (
setSelectedTab: any,
) => {
try {
const passportData = useUserStore.getState().passportData;
if (passportData) {
const { passportData, passportMetadata } = useUserStore.getState();
if (passportData && passportMetadata) {
const decodedResult = atob(result);
const uint8Array = new Uint8Array(
decodedResult.split('').map(char => char.charCodeAt(0)),
@@ -120,7 +104,6 @@ const handleQRCodeScan = (
const unpackedData = msgpack.decode(decompressedData);
const openPassportApp: OpenPassportApp = unpackedData;
setSelectedApp(openPassportApp);
const passportMetadata = parsePassportData(passportData);
const circuitName =
openPassportApp.mode === 'vc_and_disclose'

View File

@@ -5,7 +5,7 @@ import pako from 'pako';
import { Mode, OpenPassportApp } from '../../../common/src/utils/appType';
import { getCircuitNameOld } from '../../../common/src/utils/certificate_parsing/parseCertificateSimple';
import { parsePassportData } from '../../../common/src/utils/parsePassportData';
import { parsePassportData } from '../../../common/src/utils/passports/passport_parsing/parsePassportData';
import useNavigationStore from '../stores/navigationStore';
import useUserStore from '../stores/userStore';
import { downloadZkey } from './zkeyDownload';

View File

@@ -1,56 +0,0 @@
import { LeanIMT, LeanIMTHashFunction } from '@openpassport/zk-kit-lean-imt';
import axios from 'axios';
import { poseidon2 } from 'poseidon-lite';
import {
COMMITMENT_TREE_TRACKER_URL,
PASSPORT_ATTESTATION_ID,
} from '../../../common/src/constants/constants';
import { findIndexInTree } from '../../../common/src/utils/generateInputs';
import {
generateCommitment,
getLeaf,
} from '../../../common/src/utils/pubkeyTree';
import { PassportData } from '../../../common/src/utils/types';
import { formatMrz, packBytes } from '../../../common/src/utils/utils';
export async function isCommitmentRegistered(
secret: string,
passportData: PassportData,
) {
let response;
console.log(COMMITMENT_TREE_TRACKER_URL);
try {
response = await axios.get(COMMITMENT_TREE_TRACKER_URL);
} catch (error) {
console.error('Error fetching commitment tree:', error);
throw error; // rethrow the error after logging
}
console.log('response.data:', response.data);
const hashFunction: LeanIMTHashFunction = (a: bigint, b: bigint) =>
poseidon2([a, b]);
const imt = LeanIMT.import(hashFunction, response.data);
const pubkey_leaf = getLeaf(passportData.dsc);
const formattedMrz = formatMrz(passportData.mrz);
const mrz_bytes = packBytes(formattedMrz);
const commitment = generateCommitment(
secret,
PASSPORT_ATTESTATION_ID,
pubkey_leaf,
mrz_bytes,
passportData.dg2Hash?.map(x => x.toString()) || [],
);
console.log('commitment', commitment.toString());
try {
findIndexInTree(imt as any, commitment); // this will throw if not found
return true;
} catch (err) {
return false;
}
}

View File

@@ -1,148 +0,0 @@
import axios from 'axios';
import { ethers } from 'ethers';
import {
CHAIN_NAME,
RELAYER_URL,
RPC_URL,
SignatureAlgorithmIndex,
} from '../../../common/src/constants/constants';
import {
formatCallData_disclose,
formatCallData_dsc,
formatCallData_register,
} from '../../../common/src/utils/formatCallData';
import { Proof } from '../../../common/src/utils/types';
import registerArtefacts from '../../deployments/artifacts/Deploy_Registry#OpenPassportRegister.json';
import sbtArtefacts from '../../deployments/artifacts/Deploy_Registry#SBT.json';
import contractAddresses from '../../deployments/deployed_addresses.json';
import groth16ExportSolidityCallData from './snarkjs';
export const sendRegisterTransaction = async (
proof: Proof,
cscaProof: Proof,
sigAlgIndex: SignatureAlgorithmIndex,
) => {
const provider = new ethers.JsonRpcProvider(RPC_URL);
if (
!contractAddresses['Deploy_Registry#OpenPassportRegister'] ||
!registerArtefacts.abi
) {
console.log('contracts addresses or abi not found');
return;
}
// Format the proof and publicInputs as calldata for the verifier contract
//console.log("exporting local proof:", proof, proof.proof, proof.pub_signals);
const cd = groth16ExportSolidityCallData(proof.proof, proof.pub_signals);
const callData = JSON.parse(`[${cd}]`);
//console.log('callData', callData);
const formattedCallData_register = formatCallData_register(callData);
console.log('formattedCallData_register', formattedCallData_register);
//console.log("exporting csca proof", cscaProof, cscaProof.proof, cscaProof.pub_signals)
const cd_csca = groth16ExportSolidityCallData(
cscaProof.proof,
cscaProof.pub_signals,
);
const callData_csca = JSON.parse(`[${cd_csca}]`);
//console.log('callData_csca', callData_csca);
const formattedCallData_csca = formatCallData_dsc(callData_csca);
console.log('formattedCallData_csca', formattedCallData_csca);
try {
const registerContract = new ethers.Contract(
contractAddresses['Deploy_Registry#OpenPassportRegister'],
registerArtefacts.abi,
provider,
);
const transactionRequest =
await registerContract.validateProof.populateTransaction(
formattedCallData_register,
formattedCallData_csca,
sigAlgIndex,
sigAlgIndex,
);
console.log('transactionRequest', transactionRequest);
const response = await axios.post(RELAYER_URL, {
chain: CHAIN_NAME,
tx_data: transactionRequest,
});
console.log('response status', response.status);
console.log('response data', response.data);
return response;
} catch (err: any) {
console.log('err', err);
if (err.isAxiosError && err.response) {
const errorMessage = err.response.data.error;
console.log('Server error message:', errorMessage);
// parse blockchain error and show it
const match = errorMessage.match(/execution reverted: "([^"]*)"/);
if (match && match[1]) {
console.log('Parsed blockchain error:', match[1]);
throw new Error(match[1]);
} else {
throw new Error(errorMessage);
}
}
}
};
export const mintSBT = async (proof: Proof) => {
const provider = new ethers.JsonRpcProvider(RPC_URL);
if (!contractAddresses['Deploy_Registry#SBT'] || !sbtArtefacts.abi) {
console.log('contracts addresses or abi not found');
return;
}
// Format the proof and publicInputs as calldata for the verifier contract
const cd = groth16ExportSolidityCallData(proof.proof, proof.pub_signals);
const parsedCallData_disclose = JSON.parse(`[${cd}]`);
console.log('parsedCallData_disclose', parsedCallData_disclose);
const formattedCallData_disclose = formatCallData_disclose(
parsedCallData_disclose,
);
try {
const proofOfPassportContract = new ethers.Contract(
contractAddresses['Deploy_Registry#SBT'],
sbtArtefacts.abi,
provider,
);
const transactionRequest =
await proofOfPassportContract.mint.populateTransaction(
formattedCallData_disclose,
);
console.log('transactionRequest', transactionRequest);
const response = await axios.post(RELAYER_URL, {
chain: CHAIN_NAME,
tx_data: transactionRequest,
});
console.log('response status', response.status);
console.log('response data', response.data);
return response;
} catch (err: any) {
console.log('err', err);
if (err.isAxiosError && err.response) {
const errorMessage = err.response.data.error;
console.log('Server error message:', errorMessage);
// parse blockchain error and show it
const match = errorMessage.match(/execution reverted: "([^"]*)"/);
if (match && match[1]) {
console.log('Parsed blockchain error:', match[1]);
throw new Error(match[1]);
} else {
throw new Error(errorMessage);
}
}
}
};

View File

@@ -85,10 +85,14 @@ export const parseProofAndroid = (response: string) => {
};
export function getFirstName(mrz: string): string {
const names = mrz.split('<<');
const firstName = names[1].split('<')[0].trim();
const capitalized = firstName.charAt(0) + firstName.slice(1).toLowerCase();
return capitalized || 'Unknown';
try {
const names = mrz.split('<<');
const firstName = names[1].split('<')[0].trim();
const capitalized = firstName.charAt(0) + firstName.slice(1).toLowerCase();
return capitalized || 'Unknown';
} catch (error) {
return '';
}
}
export function checkInputs(

View File

@@ -1,7 +1,6 @@
import RNFS from 'react-native-fs';
import { unzip } from 'react-native-zip-archive';
import * as amplitude from '@amplitude/analytics-react-native';
import NetInfo from '@react-native-community/netinfo';
import axios from 'axios';
@@ -54,33 +53,59 @@ export type IsZkeyDownloading = {
// => this should be fine is the function is never called after the commitment is registered.
export async function downloadZkey(circuit: CircuitName) {
const { isZkeyDownloading, update } = useNavigationStore.getState();
const { isZkeyDownloading, update, trackEvent } =
useNavigationStore.getState();
const startTime = Date.now();
trackEvent('Download Started', {
success: true,
circuit: circuit,
});
const downloadRequired = await isDownloadRequired(circuit, isZkeyDownloading);
if (!downloadRequired) {
console.log(`zkey and dat for ${circuit} already downloaded`);
amplitude.track('zkey_already_downloaded', { circuit: circuit });
trackEvent('Download Skipped', {
success: true,
circuit: circuit,
reason: 'already_downloaded',
});
return;
}
const networkInfo = await NetInfo.fetch();
console.log('Network type:', networkInfo.type);
if (networkInfo.type === 'wifi') {
fetchZkeyAndDat(circuit);
} else {
const zkeyResponse = await axios.head(zkeyZipUrls[circuit]);
const datResponse = await axios.head(datZipUrls[circuit]);
const expectedSize =
parseInt(zkeyResponse.headers['content-length'], 10) +
parseInt(datResponse.headers['content-length'], 10);
try {
const networkInfo = await NetInfo.fetch();
if (networkInfo.type === 'wifi') {
fetchZkeyAndDat(circuit);
} else {
const zkeyResponse = await axios.head(zkeyZipUrls[circuit]);
const datResponse = await axios.head(datZipUrls[circuit]);
const expectedSize =
parseInt(zkeyResponse.headers['content-length'], 10) +
parseInt(datResponse.headers['content-length'], 10);
update({
showWarningModal: {
show: true,
update({
showWarningModal: {
show: true,
circuit: circuit,
size: expectedSize,
},
});
trackEvent('Download Paused', {
success: true,
circuit: circuit,
size: expectedSize,
},
reason: 'no_wifi',
expected_size: expectedSize,
});
}
} catch (error: any) {
trackEvent('Download Failed', {
success: false,
error: error.message,
circuit: circuit,
duration_ms: Date.now() - startTime,
});
throw error;
}
}
@@ -136,11 +161,19 @@ export async function isDownloadRequired(
}
export async function fetchZkeyAndDat(circuit: CircuitName) {
console.log(`fetching zkey and dat for ${circuit} ...`);
amplitude.track('fetching_zkey_and_dat', { circuit: circuit });
const startTime = Date.now();
const {
isZkeyDownloading,
toast,
update,
setZkeyDownloadedPercentage,
trackEvent,
} = useNavigationStore.getState();
const { isZkeyDownloading, toast, update, setZkeyDownloadedPercentage } =
useNavigationStore.getState();
trackEvent('Files Download Started', {
success: true,
circuit: circuit,
});
update({
isZkeyDownloading: {
@@ -149,7 +182,6 @@ export async function fetchZkeyAndDat(circuit: CircuitName) {
},
});
const startTime = Date.now();
let previousPercentComplete = -1;
const downloadFile = async (url: string, fileName: string) => {
@@ -158,7 +190,11 @@ export async function fetchZkeyAndDat(circuit: CircuitName) {
toFile: `${RNFS.DocumentDirectoryPath}/${fileName}`,
background: false,
begin: () => {
console.log(`Download of ${fileName} has begun`);
trackEvent('File Download Started', {
success: true,
circuit: circuit,
file_type: fileName.includes('zkey') ? 'zkey' : 'dat',
});
},
progress: (res: any) => {
if (fileName.endsWith('.zkey.zip')) {
@@ -169,7 +205,6 @@ export async function fetchZkeyAndDat(circuit: CircuitName) {
percentComplete % 5 === 0 &&
percentComplete !== previousPercentComplete
) {
console.log(`${percentComplete}%`);
previousPercentComplete = percentComplete;
setZkeyDownloadedPercentage(percentComplete);
}
@@ -178,9 +213,11 @@ export async function fetchZkeyAndDat(circuit: CircuitName) {
};
await RNFS.downloadFile(options).promise;
console.log(`Download of ${fileName} complete`);
RNFS.readDir(RNFS.DocumentDirectoryPath).then(result => {
console.log('Directory contents before unzipping:', result);
trackEvent('File Download Completed', {
success: true,
circuit: circuit,
file_type: fileName.includes('zkey') ? 'zkey' : 'dat',
});
};
@@ -198,60 +235,88 @@ export async function fetchZkeyAndDat(circuit: CircuitName) {
},
});
console.log(
'zkey and dat download succeeded, took ' +
(Date.now() - startTime) / 1000 +
' seconds',
);
await saveFileSize(circuit, 'zkey');
await saveFileSize(circuit, 'dat');
await RNFS.unlink(`${RNFS.DocumentDirectoryPath}/${circuit}.zkey.zip`);
await RNFS.unlink(`${RNFS.DocumentDirectoryPath}/${circuit}.dat.zip`);
console.log('zip files deleted');
const result = await RNFS.readDir(RNFS.DocumentDirectoryPath);
console.log('Directory contents at the end:', result);
trackEvent('Files Download Completed', {
success: true,
circuit: circuit,
duration_ms: Date.now() - startTime,
});
} catch (error: any) {
console.error(error);
update({
isZkeyDownloading: {
...isZkeyDownloading,
[circuit]: false,
},
});
trackEvent('Files Download Failed', {
success: false,
error: error.message,
circuit: circuit,
duration_ms: Date.now() - startTime,
});
toast.show('Error', {
message: `Error: ${error.message}`,
customData: {
type: 'error',
},
customData: { type: 'error' },
});
}
}
async function unzipFile(circuit: CircuitName, fileType: 'zkey' | 'dat') {
const unzipPath = `${RNFS.DocumentDirectoryPath}/${circuit}_temp`;
await unzip(
`${RNFS.DocumentDirectoryPath}/${circuit}.${fileType}.zip`,
unzipPath,
);
const files = await RNFS.readDir(unzipPath);
const targetFile = files.find(file => file.name.endsWith(`.${fileType}`));
if (targetFile) {
const destinationPath = `${RNFS.DocumentDirectoryPath}/${circuit}.${fileType}`;
if (await RNFS.exists(destinationPath)) {
await RNFS.unlink(destinationPath);
console.log(`Old ${fileType} file deleted`);
}
await RNFS.moveFile(targetFile.path, destinationPath);
console.log(`File moved to ${circuit}.${fileType}`);
} else {
throw new Error(
`${fileType.toUpperCase()} file not found in the unzipped directory`,
const { trackEvent } = useNavigationStore.getState();
const startTime = Date.now();
trackEvent('File Unzip Started', {
success: true,
circuit: circuit,
file_type: fileType,
});
try {
const unzipPath = `${RNFS.DocumentDirectoryPath}/${circuit}_temp`;
await unzip(
`${RNFS.DocumentDirectoryPath}/${circuit}.${fileType}.zip`,
unzipPath,
);
const files = await RNFS.readDir(unzipPath);
const targetFile = files.find(file => file.name.endsWith(`.${fileType}`));
if (targetFile) {
const destinationPath = `${RNFS.DocumentDirectoryPath}/${circuit}.${fileType}`;
if (await RNFS.exists(destinationPath)) {
await RNFS.unlink(destinationPath);
console.log(`Old ${fileType} file deleted`);
}
await RNFS.moveFile(targetFile.path, destinationPath);
console.log(`File moved to ${circuit}.${fileType}`);
} else {
throw new Error(
`${fileType.toUpperCase()} file not found in the unzipped directory`,
);
}
await RNFS.unlink(unzipPath);
trackEvent('File Unzip Completed', {
success: true,
circuit: circuit,
file_type: fileType,
duration_ms: Date.now() - startTime,
});
} catch (error: any) {
trackEvent('File Unzip Failed', {
success: false,
error: error.message,
circuit: circuit,
file_type: fileType,
duration_ms: Date.now() - startTime,
});
throw error;
}
await RNFS.unlink(unzipPath);
}
async function saveFileSize(circuit: CircuitName, fileType: 'zkey' | 'dat') {

File diff suppressed because it is too large Load Diff