mirror of
https://github.com/selfxyz/self.git
synced 2026-04-27 03:01:15 -04:00
@@ -10,6 +10,7 @@ import { AMPLITUDE_KEY } from '@env';
|
||||
import * as amplitude from '@amplitude/analytics-react-native';
|
||||
import useUserStore from './src/stores/userStore';
|
||||
import { bgWhite } from './src/utils/colors';
|
||||
import { setupUniversalLinkListener } from './src/utils/qrCode'; // Adjust the import path as needed
|
||||
global.Buffer = Buffer;
|
||||
|
||||
function App(): React.JSX.Element {
|
||||
@@ -29,13 +30,18 @@ function App(): React.JSX.Element {
|
||||
useEffect(() => {
|
||||
setSelectedTab('splash');
|
||||
}, [setSelectedTab]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (AMPLITUDE_KEY) {
|
||||
amplitude.init(AMPLITUDE_KEY);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const cleanup = setupUniversalLinkListener();
|
||||
return cleanup;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<YStack f={1} bc={bgWhite} h="100%" w="100%">
|
||||
<YStack h="100%" w="100%">
|
||||
|
||||
@@ -107,6 +107,7 @@
|
||||
1686F0DB2C500F3800841CDE /* QRScannerBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRScannerBridge.swift; sourceTree = "<group>"; };
|
||||
1686F0DD2C500F4F00841CDE /* QRScannerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRScannerViewController.swift; sourceTree = "<group>"; };
|
||||
1686F0DF2C500FBD00841CDE /* QRScannerBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QRScannerBridge.m; sourceTree = "<group>"; };
|
||||
169349842CC694DA00166F21 /* OpenPassportDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = OpenPassportDebug.entitlements; path = OpenPassport/OpenPassportDebug.entitlements; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
7C737C07B2C3788F9AB02DE4 /* 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>"; };
|
||||
@@ -180,6 +181,7 @@
|
||||
13B07FAE1A68108700A75B9A /* OpenPassport */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
169349842CC694DA00166F21 /* OpenPassportDebug.entitlements */,
|
||||
16E884A42C5BD764003B7125 /* passport.json */,
|
||||
05EDEDC42B52D25D00AA51AD /* Prover.m */,
|
||||
05EDEDC52B52D25D00AA51AD /* Prover.swift */,
|
||||
@@ -491,7 +493,7 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = OpenPassport/OpenPassport.entitlements;
|
||||
CODE_SIGN_ENTITLEMENTS = OpenPassport/OpenPassportDebug.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 63;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import <React/RCTBundleURLProvider.h>
|
||||
#import <React/RCTRootView.h>
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTLinkingManager.h>
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
@@ -30,4 +30,13 @@
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
- (BOOL)application:(UIApplication *)application
|
||||
continueUserActivity:(NSUserActivity *)userActivity
|
||||
restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
|
||||
{
|
||||
return [RCTLinkingManager application:application
|
||||
continueUserActivity:userActivity
|
||||
restorationHandler:restorationHandler];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -70,5 +70,14 @@
|
||||
<string>A0000002472001</string>
|
||||
<string>00000000000000</string>
|
||||
</array>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>proofofpassport</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<string>appclips:openpassport.app</string>
|
||||
<string>appclips:staging.openpassport.app</string>
|
||||
<string>appclips:appclip.openpassport.app</string>
|
||||
<string>applinks:proofofpassport-merkle-tree.xyz</string>
|
||||
</array>
|
||||
<key>com.apple.developer.nfc.readersession.formats</key>
|
||||
<array>
|
||||
|
||||
23
app/ios/OpenPassport/OpenPassportDebug.entitlements
Normal file
23
app/ios/OpenPassport/OpenPassportDebug.entitlements
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.developer.associated-appclip-app-identifiers</key>
|
||||
<array>
|
||||
<string>5B29R5LYHQ.com.warroom.proofofpassport.Clip</string>
|
||||
</array>
|
||||
<key>com.apple.developer.associated-domains</key>
|
||||
<array>
|
||||
<string>appclips:openpassport.app</string>
|
||||
<string>appclips:staging.openpassport.app</string>
|
||||
<string>appclips:appclip.openpassport.app</string>
|
||||
<string>applinks:proofofpassport-merkle-tree.xyz</string>
|
||||
</array>
|
||||
<key>com.apple.developer.nfc.readersession.formats</key>
|
||||
<array>
|
||||
<string>TAG</string>
|
||||
</array>
|
||||
<key>com.apple.security.device.camera</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -25,7 +25,6 @@ import ProveScreen from './ProveScreen';
|
||||
import NfcScreen from './NfcScreen';
|
||||
import CameraScreen from './CameraScreen';
|
||||
import NextScreen from './NextScreen';
|
||||
import RegisterScreen from './RegisterScreen';
|
||||
import AppScreen from './AppScreen';
|
||||
// import constants
|
||||
import { RPC_URL, SignatureAlgorithmIndex } from '../../../common/src/constants/constants';
|
||||
@@ -336,14 +335,6 @@ const MainScreen: React.FC = () => {
|
||||
<Eraser color={textColor2} />
|
||||
</Button>
|
||||
</Fieldset>
|
||||
<Fieldset gap="$4" mt="$1" horizontal>
|
||||
<Label color={textBlack} width={200} justifyContent="flex-end" htmlFor="skip" >
|
||||
go to register
|
||||
</Label>
|
||||
<Button bg="white" jc="center" borderColor={borderColor} borderWidth={1.2} size="$3.5" ml="$2" onPress={() => setSelectedTab('register')}>
|
||||
<ArrowRight color={textColor2} />
|
||||
</Button>
|
||||
</Fieldset>
|
||||
<Fieldset gap="$4" mt="$1" horizontal>
|
||||
<Label color={textBlack} width={200} justifyContent="flex-end" htmlFor="skip" >
|
||||
registered = (!registered)
|
||||
@@ -689,9 +680,6 @@ const MainScreen: React.FC = () => {
|
||||
<Tabs.Content value="next" f={1}>
|
||||
<NextScreen />
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="register" f={1}>
|
||||
<RegisterScreen />
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="app" f={1}>
|
||||
<AppScreen
|
||||
setSheetAppListOpen={setSheetAppListOpen}
|
||||
|
||||
@@ -5,11 +5,11 @@ import { countryCodes, DEVELOPMENT_MODE, max_cert_bytes, } from '../../../common
|
||||
import { bgGreen, bgGreen2, greenColorLight, separatorColor, textBlack } from '../utils/colors';
|
||||
import useUserStore from '../stores/userStore';
|
||||
import useNavigationStore from '../stores/navigationStore';
|
||||
import { ArgumentsDisclose, DisclosureOptions, OpenPassportApp } from '../../../common/src/utils/appType';
|
||||
import { DisclosureOptions, OpenPassportApp } from '../../../common/src/utils/appType';
|
||||
import CustomButton from '../components/CustomButton';
|
||||
import { formatProof, generateProof } from '../utils/prover';
|
||||
import { generateProof } from '../utils/prover';
|
||||
import io, { Socket } from 'socket.io-client';
|
||||
import { getCircuitName, parseCertificate, parseDSC } from '../../../common/src/utils/certificates/handleCertificate';
|
||||
import { getCircuitName, parseCertificate } from '../../../common/src/utils/certificates/handleCertificate';
|
||||
import { CircuitName } from '../utils/zkeyDownload';
|
||||
import { generateCircuitInputsInApp } from '../utils/generateInputsInApp';
|
||||
import { buildAttestation } from '../../../common/src/utils/openPassportAttestation';
|
||||
@@ -41,7 +41,7 @@ const ProveScreen: React.FC<ProveScreenProps> = ({ setSheetRegisterIsOpen }) =>
|
||||
const [isConnecting, setIsConnecting] = useState(false);
|
||||
const { signatureAlgorithm, hashFunction, authorityKeyIdentifier } = parseCertificate(passportData.dsc);
|
||||
const { secret, dscSecret } = useUserStore.getState();
|
||||
const circuitName = getCircuitName("prove", signatureAlgorithm, hashFunction);
|
||||
const circuitName = getCircuitName(selectedApp.mode, signatureAlgorithm, hashFunction);
|
||||
|
||||
const waitForSocketConnection = (socket: Socket): Promise<void> => {
|
||||
return new Promise((resolve) => {
|
||||
@@ -88,7 +88,7 @@ const ProveScreen: React.FC<ProveScreenProps> = ({ setSheetRegisterIsOpen }) =>
|
||||
console.log("result", result);
|
||||
if (JSON.parse(result).valid) {
|
||||
toast.show("✅", {
|
||||
message: "Proof verified",
|
||||
message: "Identity verified",
|
||||
customData: {
|
||||
type: "success",
|
||||
},
|
||||
@@ -98,7 +98,7 @@ const ProveScreen: React.FC<ProveScreenProps> = ({ setSheetRegisterIsOpen }) =>
|
||||
}, 700);
|
||||
} else {
|
||||
toast.show("❌", {
|
||||
message: "Wrong proof",
|
||||
message: "Verification failed",
|
||||
customData: {
|
||||
type: "info",
|
||||
},
|
||||
@@ -142,28 +142,16 @@ const ProveScreen: React.FC<ProveScreenProps> = ({ setSheetRegisterIsOpen }) =>
|
||||
|
||||
socket.emit('proof_generation_start', { sessionId: selectedApp.sessionId });
|
||||
|
||||
console.log("selectedApp.mode", selectedApp.mode);
|
||||
const inputs = await generateCircuitInputsInApp(passportData, selectedApp);
|
||||
let attestation;
|
||||
let proof;
|
||||
let dscProof;
|
||||
|
||||
switch (selectedApp.mode) {
|
||||
case 'vc_and_disclose':
|
||||
const inputs_disclose = await generateCircuitInputsInApp(passportData, selectedApp);
|
||||
const proof_disclose = await generateProof('vc_and_disclose', inputs_disclose);
|
||||
const formattedProof_disclose = formatProof(proof_disclose);
|
||||
console.log(formattedProof_disclose);
|
||||
const attestation_disclose = buildAttestation({
|
||||
userIdType: selectedApp.userIdType,
|
||||
mode: selectedApp.mode,
|
||||
proof: formattedProof_disclose.proof,
|
||||
publicSignals: formattedProof_disclose.publicSignals,
|
||||
signatureAlgorithm: signatureAlgorithm,
|
||||
hashFunction: hashFunction,
|
||||
});
|
||||
socket.emit('proof_generated', { sessionId: selectedApp.sessionId, proof: attestation_disclose });
|
||||
break;
|
||||
case 'prove_onchain':
|
||||
case 'register':
|
||||
const inputs = await generateCircuitInputsInApp(passportData, selectedApp);
|
||||
const cscaInputs = generateCircuitInputsDSC(dscSecret as string, passportData.dsc, max_cert_bytes, true);
|
||||
const [modalResponse, proof] = await Promise.all([
|
||||
const cscaInputs = generateCircuitInputsDSC(dscSecret as string, passportData.dsc, max_cert_bytes, selectedApp.devMode);
|
||||
[dscProof, proof] = await Promise.all([
|
||||
sendCSCARequest(
|
||||
cscaInputs
|
||||
),
|
||||
@@ -172,17 +160,12 @@ const ProveScreen: React.FC<ProveScreenProps> = ({ setSheetRegisterIsOpen }) =>
|
||||
inputs,
|
||||
)
|
||||
]);
|
||||
const dscProof = JSON.parse(JSON.stringify(modalResponse));
|
||||
const cscaPem = getCSCAFromSKI(authorityKeyIdentifier, DEVELOPMENT_MODE);
|
||||
if (!cscaPem) {
|
||||
throw new Error(`CSCA not found, devMode: ${DEVELOPMENT_MODE}, authorityKeyIdentifier: ${authorityKeyIdentifier}`);
|
||||
}
|
||||
const { signatureAlgorithm: signatureAlgorithmDsc } = parseCertificate(cscaPem);
|
||||
const formattedProof = formatProof(proof);
|
||||
const attestation = buildAttestation({
|
||||
attestation = buildAttestation({
|
||||
mode: selectedApp.mode,
|
||||
proof: formattedProof.proof,
|
||||
publicSignals: formattedProof.publicSignals,
|
||||
proof: proof.proof,
|
||||
publicSignals: proof.publicSignals,
|
||||
signatureAlgorithm: signatureAlgorithm,
|
||||
hashFunction: hashFunction,
|
||||
userIdType: selectedApp.userIdType,
|
||||
@@ -191,30 +174,25 @@ const ProveScreen: React.FC<ProveScreenProps> = ({ setSheetRegisterIsOpen }) =>
|
||||
signatureAlgorithmDsc: signatureAlgorithmDsc,
|
||||
hashFunctionDsc: hashFunction,
|
||||
});
|
||||
console.log("\x1b[90mattestation\x1b[0m", attestation);
|
||||
socket.emit('proof_generated', { sessionId: selectedApp.sessionId, proof: attestation });
|
||||
break;
|
||||
case 'prove_offchain':
|
||||
const inputs_prove = await generateCircuitInputsInApp(passportData, selectedApp);
|
||||
const proof_prove = await generateProof(
|
||||
default:
|
||||
proof = await generateProof(
|
||||
circuitName,
|
||||
inputs_prove,
|
||||
);
|
||||
const formattedProof_prove = formatProof(proof_prove);
|
||||
const attestation_prove = buildAttestation({
|
||||
inputs,
|
||||
)
|
||||
attestation = buildAttestation({
|
||||
userIdType: selectedApp.userIdType,
|
||||
mode: selectedApp.mode,
|
||||
proof: formattedProof_prove.proof,
|
||||
publicSignals: formattedProof_prove.publicSignals,
|
||||
proof: proof.proof,
|
||||
publicSignals: proof.publicSignals,
|
||||
signatureAlgorithm: signatureAlgorithm,
|
||||
hashFunction: hashFunction,
|
||||
dsc: passportData.dsc,
|
||||
});
|
||||
console.log("\x1b[90mattestation\x1b[0m", attestation_prove);
|
||||
|
||||
socket.emit('proof_generated', { sessionId: selectedApp.sessionId, proof: attestation_prove });
|
||||
break;
|
||||
}
|
||||
console.log("\x1b[90mattestation\x1b[0m", attestation);
|
||||
socket.emit('proof_generated', { sessionId: selectedApp.sessionId, proof: attestation });
|
||||
|
||||
} catch (error) {
|
||||
toast.show("Error", {
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import { YStack, XStack, Text, Button, Spinner } from 'tamagui';
|
||||
import { LockKeyhole, UserPlus } from '@tamagui/lucide-icons';
|
||||
import { bgGreen, borderColor, componentBgColor, componentBgColor2, textBlack } from '../utils/colors';
|
||||
import { Platform } from 'react-native';
|
||||
import useUserStore from '../stores/userStore';
|
||||
import useNavigationStore from '../stores/navigationStore';
|
||||
import CustomButton from '../components/CustomButton';
|
||||
|
||||
const RegisterScreen: React.FC = () => {
|
||||
|
||||
const [registering, setRegistering] = useState(false);
|
||||
const [registerStep, setRegisterStep] = useState<string | null>(null);
|
||||
|
||||
const { isZkeyDownloading } = useNavigationStore.getState();
|
||||
|
||||
const handleRegister = async () => {
|
||||
setRegistering(true);
|
||||
useUserStore.getState().registerCommitment();
|
||||
|
||||
setRegisterStep("Generating witness...");
|
||||
setTimeout(() => {
|
||||
setRegisterStep("Generating proof...");
|
||||
setTimeout(() => {
|
||||
setRegisterStep("DSC verification...");
|
||||
setTimeout(() => {
|
||||
setRegisterStep("Registering...");
|
||||
}, 4000);
|
||||
}, 4000);
|
||||
}, 4000);
|
||||
}
|
||||
|
||||
return (
|
||||
<YStack p="$3" f={1} mb={Platform.OS === 'ios' ? "$5" : "$0"}>
|
||||
<YStack flex={1} mx="$2" gap="$2">
|
||||
<Text mt="$7" fontSize="$9" color={textBlack}>Join OpenPassport to start sharing your identity<Text style={{
|
||||
textDecorationLine: "underline", textDecorationColor: bgGreen
|
||||
}}> securely. </Text></Text>
|
||||
<Text mt="$0" color={textBlack} fontSize="$8">Easily verify your nationality, humanity, or age and share<Text style={{
|
||||
textDecorationLine: "underline", textDecorationColor: bgGreen
|
||||
}}> only </Text>what you want to reveal.</Text>
|
||||
<XStack f={1} />
|
||||
|
||||
<XStack mt="$5" bg="white" borderRadius={100} mb="$12" py="$2.5" px="$3">
|
||||
<XStack p="$2" >
|
||||
<LockKeyhole alignSelf='center' size={24} color={textBlack} />
|
||||
</XStack>
|
||||
<Text alignSelf='center' ml="$3" pr="$5" fontSize="$3" color={textBlack}>Registration does not leak any personal information</Text>
|
||||
</XStack>
|
||||
|
||||
<CustomButton
|
||||
isDisabled={isZkeyDownloading.register_sha256WithRSAEncryption_65537 || registering}
|
||||
onPress={handleRegister}
|
||||
text={isZkeyDownloading.register_sha256WithRSAEncryption_65537 ? "Downloading zkey..." : (registerStep || "Register")}
|
||||
Icon={isZkeyDownloading.register_sha256WithRSAEncryption_65537 || registering ? <Spinner color={textBlack} /> : <UserPlus color={textBlack} />}
|
||||
/>
|
||||
{/* <Button
|
||||
disabled={isZkeyDownloading.register_sha256WithRSAEncryption_65537}
|
||||
mt="$8"
|
||||
alignSelf='center'
|
||||
onPress={handleRegister}
|
||||
borderWidth={1.3} borderColor={borderColor} borderRadius="$10" bg={isZkeyDownloading.register_sha256WithRSAEncryption_65537 ? "gray" : "#3185FC"}
|
||||
mb="$6"
|
||||
w="100%"
|
||||
>
|
||||
<XStack gap="$3">
|
||||
{(registering || isZkeyDownloading.register_sha256WithRSAEncryption_65537) && <Spinner color="white" size="small" />}
|
||||
<Text color={textBlack} fontSize="$5" >
|
||||
{isZkeyDownloading.register_sha256WithRSAEncryption_65537 ? "Downloading zkey..." : (registerStep || "Register")}
|
||||
</Text>
|
||||
</XStack>
|
||||
</Button> */}
|
||||
</YStack >
|
||||
</YStack >
|
||||
);
|
||||
};
|
||||
|
||||
export default RegisterScreen;
|
||||
@@ -37,15 +37,15 @@ export const generateProof = async (
|
||||
if (Platform.OS === 'android') {
|
||||
const parsedResponse = parseProofAndroid(response);
|
||||
console.log('parsedResponse', parsedResponse);
|
||||
return parsedResponse
|
||||
return formatProof(parsedResponse)
|
||||
} else {
|
||||
const parsedResponse = JSON.parse(response);
|
||||
console.log('parsedResponse', parsedResponse);
|
||||
|
||||
return {
|
||||
return formatProof({
|
||||
proof: parsedResponse.proof,
|
||||
pub_signals: parsedResponse.inputs,
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.log('err', err);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { NativeModules, Platform } from "react-native";
|
||||
import { NativeModules, Platform, Linking } from "react-native";
|
||||
// import { AppType, reconstructAppType } from "../../../common/src/utils/appType";
|
||||
import useNavigationStore from '../stores/navigationStore';
|
||||
import { getCircuitName, parseDSC } from "../../../common/src/utils/certificates/handleCertificate";
|
||||
@@ -6,89 +6,147 @@ import useUserStore from "../stores/userStore";
|
||||
import { downloadZkey } from "./zkeyDownload";
|
||||
import msgpack from "msgpack-lite";
|
||||
import pako from "pako";
|
||||
import { OpenPassportApp } from "../../../common/src/utils/appType";
|
||||
import { Mode, OpenPassportApp } from "../../../common/src/utils/appType";
|
||||
|
||||
const parseUrlParams = (url: string): Map<string, string> => {
|
||||
const [, queryString] = url.split('?');
|
||||
const params = new Map<string, string>();
|
||||
if (queryString) {
|
||||
queryString.split('&').forEach(pair => {
|
||||
const [key, value] = pair.split('=');
|
||||
params.set(key, decodeURIComponent(value));
|
||||
});
|
||||
}
|
||||
return params;
|
||||
};
|
||||
|
||||
export const scanQRCode = () => {
|
||||
const { toast, setSelectedApp, setSelectedTab } = useNavigationStore.getState();
|
||||
|
||||
if (Platform.OS === 'ios') {
|
||||
if (NativeModules.QRScannerBridge && NativeModules.QRScannerBridge.scanQRCode) {
|
||||
NativeModules.QRScannerBridge.scanQRCode()
|
||||
.then((result: string) => {
|
||||
handleQRCodeScan(result, toast, setSelectedApp, setSelectedTab);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.error('QR Scanner Error:', error);
|
||||
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: 'Failed to scan QR code',
|
||||
message: 'QR Scanner not available',
|
||||
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') {
|
||||
if (NativeModules.QRCodeScanner && NativeModules.QRCodeScanner.scanQRCode) {
|
||||
NativeModules.QRCodeScanner.scanQRCode()
|
||||
.then((result: string) => {
|
||||
handleQRCodeScan(result, toast, setSelectedApp, setSelectedTab);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.error('QR Scanner Error:', error);
|
||||
}
|
||||
} else if (Platform.OS === 'android') {
|
||||
const qrScanner = NativeModules.QRCodeScanner;
|
||||
if (qrScanner && qrScanner.scanQRCode) {
|
||||
qrScanner.scanQRCode()
|
||||
.then((result: string) => {
|
||||
handleQRCodeScan(result, 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: 'Failed to scan QR code',
|
||||
message: 'QR Scanner not available',
|
||||
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);
|
||||
toast.show('Error', {
|
||||
message: 'Failed to process initial link',
|
||||
type: 'error',
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const handleQRCodeScan = (result: string, toast: any, setSelectedApp: any, setSelectedTab: any) => {
|
||||
try {
|
||||
console.log(result);
|
||||
const decodedResult = atob(result);
|
||||
const uint8Array = new Uint8Array(decodedResult.split('').map(char => char.charCodeAt(0)));
|
||||
const decompressedData = pako.inflate(uint8Array);
|
||||
const unpackedData = msgpack.decode(decompressedData);
|
||||
console.log(unpackedData);
|
||||
const openPassportApp: OpenPassportApp = unpackedData;
|
||||
setSelectedApp(openPassportApp);
|
||||
|
||||
const dsc = useUserStore.getState().passportData.dsc;
|
||||
const sigAlgName = parseDSC(dsc!);
|
||||
if (openPassportApp.mode == 'vc_and_disclose') {
|
||||
downloadZkey('vc_and_disclose');
|
||||
}
|
||||
else {
|
||||
const circuitName = getCircuitName("prove", sigAlgName.signatureAlgorithm, sigAlgName.hashFunction);
|
||||
downloadZkey(circuitName as any);
|
||||
}
|
||||
|
||||
const circuitName = openPassportApp.mode === 'vc_and_disclose'
|
||||
? 'vc_and_disclose'
|
||||
: getCircuitName("prove" as Mode, sigAlgName.signatureAlgorithm, sigAlgName.hashFunction);
|
||||
downloadZkey(circuitName as any);
|
||||
|
||||
setSelectedTab("prove");
|
||||
toast.show('✅', {
|
||||
message: "QR code scanned",
|
||||
customData: {
|
||||
type: "success",
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error parsing QR code result:', error);
|
||||
toast.show('Try again', {
|
||||
message: "Error reading QR code",
|
||||
message: "Error reading QR code: " + (error as Error).message,
|
||||
customData: {
|
||||
type: "info",
|
||||
type: "error",
|
||||
},
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const handleUniversalLink = (url: string) => {
|
||||
const { toast, setSelectedApp, setSelectedTab } = useNavigationStore.getState();
|
||||
const params = parseUrlParams(url);
|
||||
const encodedData = params.get('data');
|
||||
console.log("Encoded data:", encodedData);
|
||||
if (encodedData) {
|
||||
handleQRCodeScan(encodedData, toast, setSelectedApp, setSelectedTab);
|
||||
} else {
|
||||
console.error('No data found in the Universal Link');
|
||||
toast.show('Error', {
|
||||
message: 'Invalid link',
|
||||
type: 'error',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const setupUniversalLinkListener = () => {
|
||||
Linking.getInitialURL().then((url) => {
|
||||
if (url) {
|
||||
handleUniversalLink(url);
|
||||
}
|
||||
});
|
||||
|
||||
const linkingEventListener = Linking.addEventListener('url', ({ url }) => {
|
||||
handleUniversalLink(url);
|
||||
});
|
||||
|
||||
return () => {
|
||||
linkingEventListener.remove();
|
||||
};
|
||||
};
|
||||
|
||||
@@ -50,10 +50,12 @@ export const ECDSA_K_LENGTH_FACTOR = 2;
|
||||
// possible values because of sha1 constaints: 192,320,384, 448, 576, 640
|
||||
|
||||
export const circuitNameFromMode = {
|
||||
prove: 'prove',
|
||||
prove_onchain: 'prove',
|
||||
prove_offchain: 'prove',
|
||||
register: 'prove',
|
||||
vc_and_disclose: 'vc_and_disclose',
|
||||
dsc: 'dsc',
|
||||
}
|
||||
|
||||
export enum SignatureAlgorithmIndex {
|
||||
|
||||
@@ -14,6 +14,7 @@ export interface OpenPassportAppPartial {
|
||||
sessionId: string;
|
||||
userId: string;
|
||||
userIdType: UserIdType;
|
||||
devMode: boolean;
|
||||
}
|
||||
|
||||
export interface OpenPassportApp extends OpenPassportAppPartial {
|
||||
|
||||
@@ -5,6 +5,8 @@ import elliptic from 'elliptic';
|
||||
import { parseRsaPublicKey, parseRsaPssPublicKey, parseECParameters } from './publicKeyDetails';
|
||||
import { PublicKeyDetailsRSAPSS } from './dataStructure';
|
||||
import { getNamedCurve } from './curves';
|
||||
import { circuitNameFromMode } from '../../constants/constants';
|
||||
import { Mode } from '../appType';
|
||||
|
||||
if (typeof global.Buffer === 'undefined') {
|
||||
global.Buffer = require('buffer').Buffer;
|
||||
@@ -48,12 +50,16 @@ export function parseCertificate(pem: string) {
|
||||
|
||||
}
|
||||
|
||||
export const getCircuitName = (circuitType: string, signatureAlgorithm: string, hashFunction: string) => {
|
||||
if (signatureAlgorithm === 'ecdsa') {
|
||||
return circuitType + "_" + signatureAlgorithm + "_secp256r1_" + hashFunction;
|
||||
export const getCircuitName = (circuitMode: Mode, signatureAlgorithm: string, hashFunction: string) => {
|
||||
const circuit = circuitNameFromMode[circuitMode];
|
||||
if (circuit == 'vc_and_disclose') {
|
||||
return 'vc_and_disclose';
|
||||
}
|
||||
else if (signatureAlgorithm === 'ecdsa') {
|
||||
return circuit + "_" + signatureAlgorithm + "_secp256r1_" + hashFunction;
|
||||
}
|
||||
else {
|
||||
return circuitType + "_" + signatureAlgorithm + "_65537_" + hashFunction;
|
||||
return circuit + "_" + signatureAlgorithm + "_65537_" + hashFunction;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { sha1Pad, sha256Pad } from "./shaPad";
|
||||
import { shaPad } from "./shaPad";
|
||||
import * as forge from "node-forge";
|
||||
import { bytesToBigDecimal, extractRSFromSignature, getNAndK, getNAndKCSCA, hexToDecimal, splitToWords } from "./utils";
|
||||
import { CSCA_TREE_DEPTH, MODAL_SERVER_ADDRESS } from "../constants/constants";
|
||||
@@ -9,13 +9,16 @@ import axios from "axios";
|
||||
import { parseCertificate } from "./certificates/handleCertificate";
|
||||
import { getLeafCSCA } from "./pubkeyTree";
|
||||
import { SKI_PEM, SKI_PEM_DEV } from "../constants/skiPem";
|
||||
|
||||
export function findStartIndex(modulus: string, messagePadded: Uint8Array): number {
|
||||
console.log('messagePadded', messagePadded);
|
||||
const modulusNumArray = [];
|
||||
for (let i = 0; i < modulus.length; i += 2) {
|
||||
const hexPair = modulus.slice(i, i + 2);
|
||||
const number = parseInt(hexPair, 16);
|
||||
modulusNumArray.push(number);
|
||||
}
|
||||
console.log('modulusNumArray', modulusNumArray);
|
||||
const messagePaddedNumber = [];
|
||||
for (let i = 0; i < messagePadded.length; i += 1) {
|
||||
const number = Number(messagePadded[i]);
|
||||
@@ -26,17 +29,18 @@ export function findStartIndex(modulus: string, messagePadded: Uint8Array): numb
|
||||
if (modulusNumArray[0] === messagePaddedNumber[i]) {
|
||||
for (let j = 0; j < modulusNumArray.length; j++) {
|
||||
if (modulusNumArray[j] !== messagePaddedNumber[i + j]) {
|
||||
//console.log("NO MODULUS FOUND IN CERTIFICATE");
|
||||
break;
|
||||
}
|
||||
else if (j === modulusNumArray.length - 1) {
|
||||
//console.log("MODULUS FOUND IN CERTIFICATE");
|
||||
startIndex = i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (startIndex === -1) {
|
||||
throw new Error('DSC Pubkey not found in CSCA certificate');
|
||||
}
|
||||
return startIndex;
|
||||
}
|
||||
|
||||
@@ -52,18 +56,7 @@ export function generateCircuitInputsDSC(dscSecret: string, dscCertificate: any,
|
||||
const { signatureAlgorithm, hashFunction, publicKeyDetails, x, y, modulus, curve, exponent, bits, subjectKeyIdentifier, authorityKeyIdentifier } = parseCertificate(dscCertificate);
|
||||
let dsc_message_padded;
|
||||
let dsc_messagePaddedLen;
|
||||
switch (hashFunction) {
|
||||
case 'sha1':
|
||||
[dsc_message_padded, dsc_messagePaddedLen] = sha1Pad(dscTbsCertUint8Array, max_cert_bytes);
|
||||
break;
|
||||
case 'sha256':
|
||||
[dsc_message_padded, dsc_messagePaddedLen] = sha256Pad(dscTbsCertUint8Array, max_cert_bytes);
|
||||
break;
|
||||
default:
|
||||
console.log("Signature algorithm not recognized", signatureAlgorithm);
|
||||
[dsc_message_padded, dsc_messagePaddedLen] = sha256Pad(dscTbsCertUint8Array, max_cert_bytes);
|
||||
break;
|
||||
}
|
||||
[dsc_message_padded, dsc_messagePaddedLen] = shaPad(dscTbsCertUint8Array, max_cert_bytes);
|
||||
|
||||
const { n, k } = getNAndK(signatureAlgorithm);
|
||||
// Extract the signature from the DSC certificate
|
||||
@@ -78,6 +71,7 @@ export function generateCircuitInputsDSC(dscSecret: string, dscCertificate: any,
|
||||
const dsc_messagePaddedLen_formatted = BigInt(dsc_messagePaddedLen).toString()
|
||||
|
||||
const cscaPem = getCSCAFromSKI(authorityKeyIdentifier, devMode);
|
||||
console.log('cscaPem', cscaPem);
|
||||
|
||||
const { x: csca_x, y: csca_y, modulus: csca_modulus, signature_algorithm: csca_signature_algorithm } = parseCertificate(cscaPem);
|
||||
const { n: n_csca, k: k_csca } = getNAndKCSCA(csca_signature_algorithm);
|
||||
@@ -139,12 +133,13 @@ export function generateCircuitInputsDSC(dscSecret: string, dscCertificate: any,
|
||||
|
||||
}
|
||||
|
||||
export function getCSCAFromSKI(ski: string, devMode: boolean): string | null {
|
||||
export function getCSCAFromSKI(ski: string, devMode: boolean): string {
|
||||
const cscaPemPROD = (SKI_PEM as any)[ski];
|
||||
const cscaPemDEV = (SKI_PEM_DEV as any)[ski];
|
||||
const cscaPem = devMode ? cscaPemDEV || cscaPemPROD : cscaPemPROD;
|
||||
if (!cscaPem) {
|
||||
console.log('\x1b[31m%s\x1b[0m', `CSCA with SKI ${ski} not found`, 'devMode: ', devMode);
|
||||
throw new Error(`CSCA not found, authorityKeyIdentifier: ${ski}, areMockPassportsAllowed: ${devMode},`);
|
||||
}
|
||||
return cscaPem;
|
||||
}
|
||||
|
||||
@@ -218,12 +218,10 @@ export function generateCircuitInputsProve(
|
||||
}
|
||||
|
||||
const [eContentPadded, eContentLen] = shaPad(
|
||||
signatureAlgorithm,
|
||||
new Uint8Array(eContent),
|
||||
MAX_PADDED_ECONTENT_LEN[signatureAlgorithmFullName]
|
||||
);
|
||||
const [signedAttrPadded, signedAttrPaddedLen] = shaPad(
|
||||
signatureAlgorithm,
|
||||
new Uint8Array(signedAttr),
|
||||
MAX_PADDED_SIGNED_ATTR_LEN[signatureAlgorithmFullName]
|
||||
);
|
||||
|
||||
@@ -1,37 +1,7 @@
|
||||
// Copied from zk-email cuz it uses crypto so can't import it here.
|
||||
|
||||
export function shaPad(signatureAlgorithm: string, prehash_prepad_m: Uint8Array, maxShaBytes: number): [Uint8Array, number] {
|
||||
if (signatureAlgorithm == 'sha1WithRSAEncryption') {
|
||||
return sha1Pad(prehash_prepad_m, maxShaBytes);
|
||||
} else {
|
||||
return sha256Pad(prehash_prepad_m, maxShaBytes);
|
||||
}
|
||||
}
|
||||
|
||||
// Puts an end selector, a bunch of 0s, then the length, then fill the rest with 0s.
|
||||
export function sha1Pad(prehash_prepad_m: Uint8Array, maxShaBytes: number): [Uint8Array, number] {
|
||||
let length_bits = prehash_prepad_m.length * 8; // bytes to bits
|
||||
let length_in_bytes = int64toBytes(length_bits);
|
||||
prehash_prepad_m = mergeUInt8Arrays(prehash_prepad_m, int8toBytes(2 ** 7)); // Add the 1 on the end, length 505
|
||||
while ((prehash_prepad_m.length * 8 + length_in_bytes.length * 8) % 512 !== 0) {
|
||||
prehash_prepad_m = mergeUInt8Arrays(prehash_prepad_m, int8toBytes(0));
|
||||
}
|
||||
prehash_prepad_m = mergeUInt8Arrays(prehash_prepad_m, length_in_bytes);
|
||||
assert((prehash_prepad_m.length * 8) % 512 === 0, "Padding did not complete properly!");
|
||||
let messageLen = prehash_prepad_m.length;
|
||||
while (prehash_prepad_m.length < maxShaBytes) {
|
||||
prehash_prepad_m = mergeUInt8Arrays(prehash_prepad_m, int64toBytes(0));
|
||||
}
|
||||
assert(
|
||||
prehash_prepad_m.length === maxShaBytes,
|
||||
`Padding to max length did not complete properly! Your padded message is ${prehash_prepad_m.length} long but max is ${maxShaBytes}!`
|
||||
);
|
||||
return [prehash_prepad_m, messageLen];
|
||||
}
|
||||
|
||||
|
||||
// Puts an end selector, a bunch of 0s, then the length, then fill the rest with 0s.
|
||||
export function sha256Pad(prehash_prepad_m: Uint8Array, maxShaBytes: number): [Uint8Array, number] {
|
||||
export function shaPad(prehash_prepad_m: Uint8Array, maxShaBytes: number): [Uint8Array, number] {
|
||||
let length_bits = prehash_prepad_m.length * 8; // bytes to bits
|
||||
let length_in_bytes = int64toBytes(length_bits);
|
||||
prehash_prepad_m = mergeUInt8Arrays(prehash_prepad_m, int8toBytes(2 ** 7)); // Add the 1 on the end, length 505
|
||||
|
||||
@@ -260,8 +260,7 @@ export class AttestationVerifier {
|
||||
signatureAlgorithm: string,
|
||||
hashFunction: string
|
||||
): Promise<void> {
|
||||
const circuitName = circuitNameFromMode[mode];
|
||||
const vkey = getVkeyFromArtifacts(circuitName, signatureAlgorithm, hashFunction);
|
||||
const vkey = getVkeyFromArtifacts(mode, signatureAlgorithm, hashFunction);
|
||||
const isVerified = await groth16.verify(vkey, publicSignals, proof as any);
|
||||
this.verifyAttribute('proof', isVerified.toString(), 'true');
|
||||
}
|
||||
|
||||
@@ -95,6 +95,7 @@ export class OpenPassportVerifier extends AttestationVerifier {
|
||||
sessionId: sessionId,
|
||||
userId: userId,
|
||||
userIdType: userIdType,
|
||||
devMode: this.devMode,
|
||||
};
|
||||
|
||||
let openPassportArguments: ArgumentsProveOffChain | ArgumentsRegister;
|
||||
|
||||
@@ -51,6 +51,13 @@ const OpenPassportQRcode: React.FC<OpenPassportQRcodeProps> = ({
|
||||
);
|
||||
}, [sessionId, websocketUrl]);
|
||||
|
||||
const generateUniversalLink = () => {
|
||||
const baseUrl = 'https://proofofpassport-merkle-tree.xyz';
|
||||
const path = '/open-passport';
|
||||
const data = openPassportVerifier.getIntent(appName, userId, userIdType, sessionId);
|
||||
return `${baseUrl}${path}?data=${data}`;
|
||||
};
|
||||
|
||||
const renderProofStatus = () => (
|
||||
<div style={containerStyle}>
|
||||
<div style={ledContainerStyle}>
|
||||
@@ -89,7 +96,7 @@ const OpenPassportQRcode: React.FC<OpenPassportQRcodeProps> = ({
|
||||
default:
|
||||
return (
|
||||
<QRCodeSVG
|
||||
value={openPassportVerifier.getIntent(appName, userId, userIdType, sessionId)}
|
||||
value={generateUniversalLink()}
|
||||
size={size}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -12,8 +12,7 @@ export default function Prove() {
|
||||
.setCommitmentMerkleTreeUrl(COMMITMENT_TREE_TRACKER_URL)
|
||||
.excludeCountries('Albania')
|
||||
.setMinimumAge(20)
|
||||
.enableOFACCheck()
|
||||
.setNationality('Germany');
|
||||
.enableOFACCheck();
|
||||
return (
|
||||
<div className="h-screen w-full bg-white flex flex-col items-center justify-center gap-4">
|
||||
<OpenPassportQRcode
|
||||
@@ -21,7 +20,7 @@ export default function Prove() {
|
||||
userId={userId}
|
||||
userIdType={'uuid'}
|
||||
openPassportVerifier={openPassportVerifierDisclose}
|
||||
onSuccess={(attestation) => {}}
|
||||
onSuccess={(attestation) => { }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -11,7 +11,7 @@ export default function Prove() {
|
||||
const openPassportVerifier = new OpenPassportVerifier(
|
||||
'register',
|
||||
scope
|
||||
).setCommitmentMerkleTreeUrl(COMMITMENT_TREE_TRACKER_URL);
|
||||
).setCommitmentMerkleTreeUrl(COMMITMENT_TREE_TRACKER_URL).allowMockPassports();
|
||||
return (
|
||||
<div className="h-screen w-full bg-white flex flex-col items-center justify-center gap-4">
|
||||
<OpenPassportQRcode
|
||||
|
||||
@@ -2,6 +2,7 @@ import { ethers } from 'ethers';
|
||||
import { getCurrentDateYYMMDD } from '../../common/src/utils/utils';
|
||||
import {
|
||||
attributeToPosition,
|
||||
circuitNameFromMode,
|
||||
REGISTER_ABI,
|
||||
REGISTER_CONTRACT_ADDRESS,
|
||||
} from '../../common/src/constants/constants';
|
||||
@@ -18,20 +19,24 @@ import {
|
||||
vkey_vc_and_disclose,
|
||||
} from '../../common/src/constants/vkey';
|
||||
import { getCircuitName } from '../../common/src/utils/certificates/handleCertificate';
|
||||
import { Mode } from 'fs';
|
||||
|
||||
export function getCurrentDateFormatted() {
|
||||
return getCurrentDateYYMMDD().map((datePart) => BigInt(datePart).toString());
|
||||
}
|
||||
|
||||
export function getVkeyFromArtifacts(
|
||||
circuit: string,
|
||||
circuitMode: Mode,
|
||||
signatureAlgorithm: string,
|
||||
hashFunction: string
|
||||
) {
|
||||
const circuitName =
|
||||
circuit === 'vc_and_disclose'
|
||||
? circuit
|
||||
: getCircuitName(circuit, signatureAlgorithm, hashFunction);
|
||||
const circuit = circuitNameFromMode[circuitMode];
|
||||
let circuitName = '';
|
||||
if (circuit === 'vc_and_disclose') {
|
||||
circuitName = circuit;
|
||||
} else {
|
||||
circuitName = getCircuitName(circuit, signatureAlgorithm, hashFunction);
|
||||
}
|
||||
// console.log('\x1b[90m%s\x1b[0m', 'circuit name:', circuitName);
|
||||
switch (circuitName) {
|
||||
case 'vc_and_disclose':
|
||||
|
||||
Reference in New Issue
Block a user