This commit is contained in:
turnoffthiscomputer
2024-09-08 16:03:58 +02:00
23 changed files with 335 additions and 278 deletions

View File

@@ -1,7 +1,7 @@
import React, { useState, useEffect } from 'react';
import { YStack, XStack, Text, Spinner, Progress } from 'tamagui';
import { CheckCircle } from '@tamagui/lucide-icons';
import { DEFAULT_MAJORITY, WEBSOCKET_URL, } from '../../../common/src/constants/constants';
import { DEFAULT_MAJORITY, } from '../../../common/src/constants/constants';
import { bgGreen, bgGreen2, greenColorLight, separatorColor, textBlack } from '../utils/colors';
import useUserStore from '../stores/userStore';
import useNavigationStore from '../stores/navigationStore';
@@ -13,7 +13,6 @@ import { formatProof, generateProof } from '../utils/prover';
import io, { Socket } from 'socket.io-client';
import { getCircuitName, getSignatureAlgorithm } from '../../../common/src/utils/handleCertificate';
import { CircuitName } from '../utils/zkeyDownload';
interface ProveScreenProps {
setSheetRegisterIsOpen: (value: boolean) => void;
}
@@ -56,7 +55,7 @@ const ProveScreen: React.FC<ProveScreenProps> = ({ setSheetRegisterIsOpen }) =>
let newSocket: Socket | null = null;
try {
newSocket = io(WEBSOCKET_URL, {
newSocket = io(selectedApp.websocketUrl, {
path: '/websocket',
transports: ['websocket'],
query: { sessionId: selectedApp.sessionId, clientType: 'mobile' }
@@ -139,31 +138,35 @@ const ProveScreen: React.FC<ProveScreenProps> = ({ setSheetRegisterIsOpen }) =>
setIsConnecting(false);
socket.emit('proof_generation_start', { sessionId: selectedApp.sessionId });
console.log("selectedApp.userIdType", selectedApp.userIdType);
const inputs = generateCircuitInputsProve(
passportData,
64, 32,
selectedApp.scope,
revealBitmapFromAttributes(disclosureOptions as any),
disclosureOptions?.older_than ?? DEFAULT_MAJORITY,
selectedApp.userId
selectedApp.userId,
selectedApp.userIdType
);
const rawDscProof = await generateProof(
circuitName,
inputs,
);
const dscProof = formatProof(rawDscProof);
const response = { dsc: passportData.dsc, dscProof: dscProof, circuit: selectedApp.circuit }
console.log("response", response);
const response = { dsc: passportData.dsc, dscProof: dscProof, circuit: selectedApp.circuit, userIdType: selectedApp.userIdType };
socket.emit('proof_generated', { sessionId: selectedApp.sessionId, proof: response });
} catch (error) {
toast.show("Error", {
message: "Proof generation failed",
message: String(error),
customData: {
type: "error",
},
});
console.error('Error in handleProve:', error);
if (socket) {
socket.emit('proof_generation_failed', { sessionId: selectedApp.sessionId });
}
} finally {
setGeneratingProof(false);
setIsConnecting(false);

View File

@@ -63,10 +63,10 @@ const handleQRCodeScan = (result: string, toast: any, setSelectedApp: any, setSe
})
} catch (error) {
console.error('Error parsing QR code result:', error);
toast.show('Error', {
message: "QR code parsing failed",
toast.show('Try again', {
message: "Error reading QR code",
customData: {
type: "error",
type: "info",
},
})
}

View File

@@ -5,6 +5,7 @@ export const WEBSOCKET_URL = "https://proofofpassport-merkle-tree.xyz"
export const PUBKEY_TREE_DEPTH = 16
export const CSCA_TREE_DEPTH = 12
export const COMMITMENT_TREE_DEPTH = 16
export const DEFAULT_USER_ID_TYPE = 'uuid'
export const MODAL_SERVER_ADDRESS = "https://zk-passport--dsc-prover-generate-dsc-proof.modal.run"

View File

@@ -1,9 +1,14 @@
import { DEFAULT_USER_ID_TYPE, WEBSOCKET_URL } from "../constants/constants";
import { UserIdType } from "./utils";
export type CircuitName = "prove" | "register" | "disclose";
export interface AppType {
name: string,
scope: string,
userId: string,
userIdType: UserIdType,
websocketUrl: string,
sessionId: string,
circuit: CircuitName,
arguments: ArgumentsProve | ArgumentsRegister | ArgumentsDisclose,
@@ -100,9 +105,11 @@ export function reconstructAppType(json: any): AppType {
name: json.name,
scope: json.scope,
userId: json.userId,
userIdType: json.userIdType || DEFAULT_USER_ID_TYPE,
sessionId: json.sessionId,
circuit: json.circuit as CircuitName,
arguments: circuitArgs,
websocketUrl: json.websocketUrl || WEBSOCKET_URL,
getDisclosureOptions: function () {
if (this.circuit === 'prove' || this.circuit === 'disclose') {
return Object.fromEntries(

View File

@@ -1,4 +1,4 @@
import { MAX_DATAHASHES_LEN, PUBKEY_TREE_DEPTH, DEVELOPMENT_MODE } from '../constants/constants';
import { MAX_DATAHASHES_LEN, PUBKEY_TREE_DEPTH, DEVELOPMENT_MODE, DEFAULT_USER_ID_TYPE } from '../constants/constants';
import { assert, shaPad } from './shaPad';
import { PassportData } from './types';
import {
@@ -18,6 +18,7 @@ import {
extractRSFromSignature,
castFromUUID,
castFromScope,
parseUIDToBigInt,
} from './utils';
import { LeanIMT } from "@zk-kit/lean-imt";
import { getLeaf } from "./pubkeyTree";
@@ -267,8 +268,10 @@ export function generateCircuitInputsProve(
bitmap: string[],
majority: string,
user_identifier: string,
user_identifier_type: 'uuid' | 'hex' | 'ascii' = DEFAULT_USER_ID_TYPE
) {
const register_inputs = generateCircuitInputsRegister('0', '0', '0', passportData, n_dsc, k_dsc);
const current_date = getCurrentDateYYMMDD().map(datePart => BigInt(datePart).toString());
// Ensure majority is at least two digits
@@ -284,7 +287,7 @@ export function generateCircuitInputsProve(
current_date: current_date,
bitmap: bitmap,
majority: formattedMajority.split('').map(char => BigInt(char.charCodeAt(0)).toString()),
user_identifier: [castFromUUID(user_identifier)],
user_identifier: [parseUIDToBigInt(user_identifier, user_identifier_type)],
scope: [castFromScope(scope)]
};

View File

@@ -416,6 +416,12 @@ export function BigintToArray(n: number, k: number, x: bigint) {
}
/// UUID
function stringToHex(str: string): string {
return Buffer.from(str).toString('hex');
}
function hexToBigInt(hex: string): bigint {
return BigInt(`0x${hex}`);
}
@@ -454,8 +460,8 @@ export function castToUUID(bigInt: bigint): string {
/// scope
function checkStringLength(str: string) {
if (str.length > 30) {
throw new Error("Input string must not exceed 30 characters");
if (str.length > 25) {
throw new Error("Input string must not exceed 25 characters");
}
}
@@ -512,4 +518,51 @@ export function num2Bits(n: number, inValue: bigint): bigint[] {
throw new Error("Reconstructed value does not match the input.");
}
return out;
}
// custom user_identifier type validation
export type UserIdType = 'ascii' | 'hex' | 'uuid';
const validateUserId = (userId: string, type: UserIdType): boolean => {
switch (type) {
case 'ascii':
return /^[\x00-\xFF]+$/.test(userId);
case 'hex':
return /^[0-9A-Fa-f]+$/.test(userId);
case 'uuid':
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(userId);
default:
return false;
}
}
const getMaxLenght = (idType: UserIdType) => {
switch (idType) {
case 'ascii':
return 25;
default:
return 63;
}
}
export const parseUIDToBigInt = (user_identifier: string, user_identifier_type: UserIdType): string => {
if (!validateUserId(user_identifier, user_identifier_type)) {
throw new Error(`User identifier of type ${user_identifier_type} is not valid`);
}
const maxLength = getMaxLenght(user_identifier_type);
if (user_identifier.length > maxLength) {
throw new Error(`User identifier of type ${user_identifier_type} exceeds maximum length of ${maxLength} characters`);
}
switch (user_identifier_type) {
case 'ascii':
return stringToBigInt(user_identifier).toString();
case 'hex':
return hexToBigInt(user_identifier).toString();
case 'uuid':
return uuidToBigInt(user_identifier).toString();
}
}

11
mock_node_app/index.js Normal file
View File

@@ -0,0 +1,11 @@
const { OpenPassport2StepVerifier, OpenPassport1StepVerifier, OpenPassportQRcode } = require('@proofofpassport/sdk');
console.log('OpenPassport2StepVerifier:', typeof OpenPassport2StepVerifier);
console.log('OpenPassport1StepVerifier:', typeof OpenPassport1StepVerifier);
try {
const { OpenPassportQRcode } = require('@proofofpassport/sdk');
console.log('QRCodeComponent:', typeof OpenPassportQRcode);
} catch (error) {
console.log('QRCodeComponent is not available in Node.js environment.');
}

View File

@@ -0,0 +1,9 @@
{
"name": "mock_node_app",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"@proofofpassport/sdk": "^2.0.9"
}
}

View File

@@ -13,7 +13,7 @@ import { AppType } from '@openpassport/sdk';
const appName = '🤠 Cowboy App';
const scope = 'cowboyApp';
const userID = 'user1234';
const sessionID = crypto.randomUUID();
const sessionID = uuidv4():
const cowboyApp: AppType = {
name: appName,

View File

@@ -1,17 +1,19 @@
{
"name": "@proofofpassport/sdk",
"version": "1.8.1",
"main": "dist/sdk/src/index.js",
"name": "@openpassport/sdk",
"version": "0.1.8",
"main": "dist/bundle.node.js",
"browser": "dist/bundle.web.js",
"types": "dist/sdk/src/index.d.ts",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/zk-passport/proof-of-passport"
"url": "https://github.com/zk-passport/openpassport"
},
"author": "turnoffthiscomputer",
"dependencies": {
"@types/react": "^18.3.4",
"@types/react-dom": "^18.3.0",
"@types/uuid": "^10.0.0",
"@zk-kit/imt": "^2.0.0-beta.5",
"@zk-kit/lean-imt": "^2.0.1",
"asn1js": "^3.0.5",
@@ -23,6 +25,7 @@
"js-sha256": "^0.11.0",
"js-sha512": "^0.9.0",
"lottie-react": "^2.4.0",
"next": "^14.2.8",
"node-forge": "https://github.com/remicolin/forge",
"pkijs": "^3.2.4",
"poseidon-lite": "^0.2.0",
@@ -30,7 +33,8 @@
"react-dom": "^18.3.1",
"react-spinners": "^0.14.1",
"snarkjs": "^0.7.4",
"socket.io-client": "^4.7.5"
"socket.io-client": "^4.7.5",
"uuid": "^10.0.0"
},
"devDependencies": {
"@types/chai": "^4.3.6",
@@ -46,12 +50,18 @@
"dotenv": "^16.4.5",
"mocha": "^10.3.0",
"prettier": "^3.3.3",
"ts-loader": "^9.5.1",
"ts-mocha": "^10.0.0",
"ts-node": "^10.9.2",
"typescript": "^5.4.5"
"typescript": "^5.4.5",
"webpack": "^5.94.0",
"webpack-cli": "^5.1.4"
},
"scripts": {
"build": "tsc && tsc -p tsconfig.react.json",
"build:ts": "tsc && tsc -p tsconfig.react.json",
"build:web": "webpack --config webpack.web.config.js",
"build:node": "webpack --config webpack.node.config.js",
"build": "npm run build:ts && npm run build:web && npm run build:node",
"prepublishOnly": "npm run build",
"test": "yarn ts-mocha -p ./tsconfig.json tests/openPassport1Step.test.ts --exit",
"install-sdk": "cd ../common && yarn && cd ../sdk && yarn",
@@ -64,5 +74,13 @@
"common",
"circuits/**/*.json",
"src/QRcode"
]
],
"publishConfig": {
"access": "public"
},
"peerDependencies": {
"lottie-react": "^2.4.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}

0
sdk/rollup.config.ts Normal file
View File

View File

@@ -15,7 +15,9 @@ import {
castFromScope,
castToScope,
castToUUID,
hexToUUID,
splitToWords,
UserIdType,
} from '../../common/src/utils/utils';
import { getSignatureAlgorithm } from '../../common/src/utils/handleCertificate';
@@ -26,7 +28,6 @@ export class OpenPassport1StepVerifier {
rpcUrl: string;
report: OpenPassportVerifierReport;
dev_mode: boolean;
constructor(options: {
scope: string;
attestationId?: string;
@@ -100,9 +101,6 @@ export class OpenPassport1StepVerifier {
}
console.log('\x1b[32m%s\x1b[0m', `- proof verified`);
this.report.nullifier = bigIntToHex(BigInt(parsedPublicSignals.nullifier));
this.report.user_identifier = bigIntToHex(BigInt(parsedPublicSignals.user_identifier));
//7 Verify the dsc
const dscCertificate = forge.pki.certificateFromPem(openPassport1StepInputs.dsc);
const verified_certificate = verifyDSCValidity(dscCertificate, this.dev_mode);
@@ -129,7 +127,7 @@ export class OpenPassport1StepInputs {
};
dsc: string;
circuit: string;
userIdType?: UserIdType;
constructor(options: {
dscProof?: {
publicSignals: string[];
@@ -137,6 +135,7 @@ export class OpenPassport1StepInputs {
};
dsc?: string;
circuit?: string;
userIdType?: UserIdType;
}) {
this.dscProof = options.dscProof || {
publicSignals: [],
@@ -144,6 +143,27 @@ export class OpenPassport1StepInputs {
};
this.dsc = options.dsc || '';
this.circuit = options.circuit || '';
this.userIdType = options.userIdType || 'uuid';
}
getParsedPublicSignals() {
return parsePublicSignals1Step(this.dscProof.publicSignals);
}
getUserId() {
const rawUserId = this.getParsedPublicSignals().user_identifier;
switch (this.userIdType) {
case 'ascii':
return castToScope(BigInt(rawUserId));
case 'hex':
return bigIntToHex(BigInt(rawUserId));
case 'uuid':
return castToUUID(BigInt(rawUserId));
}
}
getNullifier() {
return bigIntToHex(BigInt(this.getParsedPublicSignals().nullifier));
}
}

View File

@@ -44,16 +44,4 @@ export class OpenPassportVerifierReport {
toString() {
return JSON.stringify(this);
}
getUUID() {
return hexToUUID(this.user_identifier);
}
getHexUUID() {
return this.user_identifier;
}
getNullifier() {
return this.nullifier;
}
}

View File

@@ -5,7 +5,7 @@ interface LEDProps {
connectionStatus?: 'disconnected' | 'web_connected' | 'mobile_connected';
}
const LED: React.FC<LEDProps> = ({ size = 10, connectionStatus = 'disconnected' }) => {
const LED: React.FC<LEDProps> = ({ size = 8, connectionStatus = 'disconnected' }) => {
const getColor = () => {
switch (connectionStatus) {
case 'web_connected':

View File

@@ -6,6 +6,7 @@ export interface OpenPassportQRcodeProps {
userId: string;
requirements: any[];
onSuccess: (result: any) => void;
size?: number;
devMode?: boolean;
}

View File

@@ -1,194 +0,0 @@
import React, { useEffect, useRef, useState } from 'react';
import { OpenPassport1StepVerifier } from '../index';
import { QRCodeGenerator } from './QRCodeGenerator';
import io from 'socket.io-client';
import { BounceLoader } from 'react-spinners';
import Lottie from 'lottie-react';
import CHECK_ANIMATION from '../../public/animations/check_animation.json';
import X_ANIMATION from '../../public/animations/x_animation.json';
import LED from './LED';
const ProofSteps = {
WAITING_FOR_MOBILE: 'WAITING_FOR_MOBILE',
MOBILE_CONNECTED: 'MOBILE_CONNECTED',
PROOF_GENERATION_STARTED: 'PROOF_GENERATION_STARTED',
PROOF_GENERATED: 'PROOF_GENERATED',
PROOF_VERIFIED: 'PROOF_VERIFIED',
};
const OpenPassportQRcode = ({
appName,
scope,
userId,
requirements,
onSuccess,
devMode = false,
}) => {
const [proofStep, setProofStep] = useState(ProofSteps.WAITING_FOR_MOBILE);
const [proofVerified, setProofVerified] = useState(null);
const [sessionId, setSessionId] = useState(crypto.randomUUID());
const [showAnimation, setShowAnimation] = useState(false);
const [connectionStatus, setConnectionStatus] = useState('disconnected');
const [qrElement, setQrElement] = useState(null);
const [animationKey, setAnimationKey] = useState(0);
const qrcodeRef = useRef(null);
const lottieRef = useRef(null);
const handleAnimationComplete = () => {
console.log('Animation completed');
setShowAnimation(false);
setProofStep(ProofSteps.WAITING_FOR_MOBILE);
const newSessionId = crypto.randomUUID();
setSessionId(newSessionId);
};
useEffect(() => {
const generateQR = async () => {
const showCaseApp = {
name: appName,
scope,
userId,
sessionId,
circuit: 'prove',
arguments: {
disclosureOptions: Object.fromEntries(requirements),
},
};
const qr = await QRCodeGenerator.generateQRCode(showCaseApp);
setQrElement(qr);
};
generateQR();
}, [appName, scope, userId, sessionId, requirements]);
useEffect(() => {
const newSocket = io('https://proofofpassport-merkle-tree.xyz', {
path: '/websocket',
query: { sessionId, clientType: 'web' },
});
const handleMobileStatus = async (data) => {
console.log('Received mobile status:', data.status);
switch (data.status) {
case 'mobile_connected':
setConnectionStatus('mobile_connected');
setProofStep(ProofSteps.MOBILE_CONNECTED);
break;
case 'mobile_disconnected':
setConnectionStatus('web_connected');
break;
case 'proof_generation_started':
setProofStep(ProofSteps.PROOF_GENERATION_STARTED);
break;
case 'proof_generated':
setProofStep(ProofSteps.PROOF_GENERATED);
break;
}
if (data.proof) {
const openPassport1StepVerifier = new OpenPassport1StepVerifier({
scope,
requirements,
dev_mode: devMode,
});
try {
const local_proofVerified = await openPassport1StepVerifier.verify(data.proof);
setProofVerified({ valid: local_proofVerified.valid });
setProofStep(ProofSteps.PROOF_VERIFIED);
newSocket.emit('proof_verified', {
sessionId,
proofVerified: local_proofVerified.toString(),
});
if (local_proofVerified.valid && onSuccess) {
onSuccess(local_proofVerified);
}
} catch (error) {
console.error('Error verifying proof:', error);
setProofVerified({ valid: false, error: error.message });
newSocket.emit('proof_verified', {
sessionId,
proofVerified: { valid: false, error: error.message },
});
}
}
};
newSocket.on('connect', () => setConnectionStatus('web_connected'));
newSocket.on('disconnect', () => {
setConnectionStatus('disconnected');
setProofStep(ProofSteps.WAITING_FOR_MOBILE);
});
newSocket.on('mobile_status', handleMobileStatus);
return () => {
newSocket.disconnect();
};
}, [sessionId, scope, requirements, devMode, onSuccess]);
useEffect(() => {
if (qrElement && qrcodeRef.current) {
qrcodeRef.current.innerHTML = '';
qrcodeRef.current.appendChild(qrElement);
}
}, [qrElement]);
useEffect(() => {
if (proofStep === ProofSteps.PROOF_VERIFIED && proofVerified?.valid === true) {
setShowAnimation(true);
setAnimationKey((prev) => prev + 1);
}
}, [proofStep, proofVerified]);
const renderProofStatus = () => (
<div className="flex flex-col items-center">
<LED connectionStatus={connectionStatus} />
<div className="w-[300px] h-[300px] flex items-center justify-center">
{(() => {
switch (proofStep) {
case ProofSteps.WAITING_FOR_MOBILE:
case ProofSteps.MOBILE_CONNECTED:
return qrElement ? <div ref={qrcodeRef}></div> : null;
case ProofSteps.PROOF_GENERATION_STARTED:
case ProofSteps.PROOF_GENERATED:
return <BounceLoader loading={true} size={200} color="#94FBAB" />;
case ProofSteps.PROOF_VERIFIED:
if (proofVerified?.valid === true) {
return showAnimation ? (
<Lottie
key={animationKey}
lottieRef={lottieRef}
animationData={CHECK_ANIMATION}
style={{ width: 200, height: 200 }}
loop={false}
autoplay={true}
onComplete={handleAnimationComplete}
/>
) : qrElement ? (
<div ref={qrcodeRef}></div>
) : null;
} else {
return (
<Lottie
key={animationKey}
lottieRef={lottieRef}
animationData={X_ANIMATION}
style={{ width: 200, height: 200 }}
loop={false}
autoplay={true}
onComplete={handleAnimationComplete}
/>
);
}
default:
return null;
}
})()}
</div>
</div>
);
return renderProofStatus();
};
export default OpenPassportQRcode;

View File

@@ -1,32 +1,59 @@
import React, { useEffect, useRef, useState } from 'react';
import { AppType, OpenPassport1StepVerifier } from '../index';
import {
AppType,
OpenPassport1StepInputs,
OpenPassport1StepVerifier,
OpenPassportVerifierReport,
} from '../index.web';
import { QRCodeGenerator } from './QRCodeGenerator';
import io from 'socket.io-client';
import { BounceLoader } from 'react-spinners';
import Lottie from 'lottie-react';
// import Lottie from 'lottie-react';
import CHECK_ANIMATION from './animations/check_animation.json';
import X_ANIMATION from './animations/x_animation.json';
import LED from './LED';
import { DEFAULT_USER_ID_TYPE, WEBSOCKET_URL } from '../../../common/src/constants/constants';
import { UserIdType } from '../../../common/src/utils/utils';
import { reconstructAppType } from '../../../common/src/utils/appType';
import { v4 as uuidv4 } from 'uuid';
import dynamic from 'next/dynamic';
const Lottie = dynamic(() => import('lottie-react'), { ssr: false });
const ProofSteps = {
WAITING_FOR_MOBILE: 'WAITING_FOR_MOBILE',
MOBILE_CONNECTED: 'MOBILE_CONNECTED',
PROOF_GENERATION_STARTED: 'PROOF_GENERATION_STARTED',
PROOF_GENERATED: 'PROOF_GENERATED',
PROOF_VERIFIED: 'PROOF_VERIFIED',
PROOF_VERIFIED: 'PROOF_VERIFIED'
};
const OpenPassportQRcode = ({
interface OpenPassportQRcodeProps {
appName: string;
scope: string;
userId: string;
userIdType?: UserIdType;
requirements?: string[][];
onSuccess: (proof: OpenPassport1StepInputs, report: OpenPassportVerifierReport) => void;
devMode?: boolean;
size?: number;
websocketUrl?: string;
}
const OpenPassportQRcode: React.FC<OpenPassportQRcodeProps> = ({
appName,
scope,
userId,
userIdType = DEFAULT_USER_ID_TYPE,
requirements,
onSuccess,
devMode = false,
size = 300,
websocketUrl = WEBSOCKET_URL,
}) => {
const [proofStep, setProofStep] = useState(ProofSteps.WAITING_FOR_MOBILE);
const [proofVerified, setProofVerified] = useState(null);
const [sessionId, setSessionId] = useState(crypto.randomUUID());
const [sessionId, setSessionId] = useState(uuidv4());
const [showAnimation, setShowAnimation] = useState(false);
const [connectionStatus, setConnectionStatus] = useState('disconnected');
const [qrElement, setQrElement] = useState(null);
@@ -39,30 +66,32 @@ const OpenPassportQRcode = ({
console.log('Animation completed');
setShowAnimation(false);
setProofStep(ProofSteps.WAITING_FOR_MOBILE);
const newSessionId = crypto.randomUUID();
const newSessionId = uuidv4()
setSessionId(newSessionId);
};
useEffect(() => {
const generateQR = async () => {
const showCaseApp = {
const showCaseApp = reconstructAppType({
name: appName,
scope,
userId,
userIdType,
sessionId,
circuit: 'prove',
arguments: {
disclosureOptions: Object.fromEntries(requirements),
},
};
const qr = await QRCodeGenerator.generateQRCode(showCaseApp as AppType);
websocketUrl,
});
const qr = await QRCodeGenerator.generateQRCode(showCaseApp as AppType, size);
setQrElement(qr);
};
generateQR();
}, [appName, scope, userId, sessionId, requirements]);
useEffect(() => {
const newSocket = io('https://proofofpassport-merkle-tree.xyz', {
const newSocket = io(websocketUrl, {
path: '/websocket',
query: { sessionId, clientType: 'web' },
});
@@ -83,6 +112,10 @@ const OpenPassportQRcode = ({
case 'proof_generated':
setProofStep(ProofSteps.PROOF_GENERATED);
break;
case 'proof_generation_failed':
setSessionId(uuidv4());
setProofStep(ProofSteps.WAITING_FOR_MOBILE);
break;
}
if (data.proof) {
@@ -93,7 +126,8 @@ const OpenPassportQRcode = ({
});
try {
const local_proofVerified = await openPassport1StepVerifier.verify(data.proof);
const local_proofVerified: OpenPassportVerifierReport =
await openPassport1StepVerifier.verify(data.proof);
setProofVerified({ valid: local_proofVerified.valid });
setProofStep(ProofSteps.PROOF_VERIFIED);
newSocket.emit('proof_verified', {
@@ -101,7 +135,8 @@ const OpenPassportQRcode = ({
proofVerified: local_proofVerified.toString(),
});
if (local_proofVerified.valid && onSuccess) {
onSuccess(local_proofVerified);
const openPassport1StepInputs = new OpenPassport1StepInputs(data.proof);
onSuccess(openPassport1StepInputs, local_proofVerified);
}
} catch (error) {
console.error('Error verifying proof:', error);
@@ -120,11 +155,10 @@ const OpenPassportQRcode = ({
setProofStep(ProofSteps.WAITING_FOR_MOBILE);
});
newSocket.on('mobile_status', handleMobileStatus);
return () => {
newSocket.disconnect();
};
}, [sessionId, scope, requirements, devMode, onSuccess]);
}, [sessionId, scope, requirements, devMode, onSuccess, size]);
useEffect(() => {
if (qrElement && qrcodeRef.current) {
@@ -140,12 +174,35 @@ const OpenPassportQRcode = ({
}
}, [proofStep, proofVerified]);
const containerStyle: React.CSSProperties = {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
width: '100%',
};
const ledContainerStyle: React.CSSProperties = {
marginBottom: '4px',
};
const qrContainerStyle: React.CSSProperties = {
width: `${size}px`,
height: `${size}px`,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
};
const renderProofStatus = () => (
<div className="flex flex-col items-center">
<LED
connectionStatus={connectionStatus as 'disconnected' | 'web_connected' | 'mobile_connected'}
/>
<div className="w-[300px] h-[300px] flex items-center justify-center">
<div style={containerStyle}>
<div style={ledContainerStyle}>
<LED
connectionStatus={
connectionStatus as 'disconnected' | 'web_connected' | 'mobile_connected'
}
/>
</div>
<div style={qrContainerStyle}>
{(() => {
switch (proofStep) {
case ProofSteps.WAITING_FOR_MOBILE:
@@ -190,7 +247,7 @@ const OpenPassportQRcode = ({
</div>
);
return renderProofStatus();
return <div style={containerStyle}>{renderProofStatus()}</div>;
};
export default OpenPassportQRcode;
export { OpenPassportQRcode };

12
sdk/src/index.node.ts Normal file
View File

@@ -0,0 +1,12 @@
import { OpenPassportVerifierReport } from './OpenPassportVerifierReport';
import { countryCodes } from '../../common/src/constants/constants';
import { AppType } from '../../common/src/utils/appType';
import { OpenPassport1StepVerifier, OpenPassport1StepInputs } from './OpenPassport1Step';
export {
AppType,
OpenPassport1StepVerifier,
OpenPassport1StepInputs,
OpenPassportVerifierReport,
countryCodes,
};

View File

@@ -1,20 +1,14 @@
import { OpenPassport2StepVerifier } from './OpenPassport2Step';
import { OpenPassport2StepInputs } from './OpenPassport2Step';
import { OpenPassportVerifierReport } from './OpenPassportVerifierReport';
import { countryCodes } from '../../common/src/constants/constants';
import { QRCodeGenerator } from './QRcode/QRCodeGenerator';
import { AppType } from '../../common/src/utils/appType';
import { OpenPassport1StepVerifier, OpenPassport1StepInputs } from './OpenPassport1Step';
import OpenPassportQRcode from './QRcode/OpenPassportQRcode';
import { OpenPassportQRcode } from './QRcode/OpenPassportQRcode';
export {
OpenPassport2StepVerifier,
OpenPassport2StepInputs,
OpenPassportVerifierReport,
QRCodeGenerator,
AppType,
countryCodes,
OpenPassport1StepVerifier,
OpenPassport1StepInputs,
OpenPassportQRcode,
OpenPassportVerifierReport,
countryCodes,
OpenPassportQRcode
};

View File

@@ -53,7 +53,7 @@ describe('\x1b[95mOpenPassport1Step\x1b[0m', function () {
circuit: 'prove',
});
const result = await openPassport1StepVerifier.verify(openPassportProverInputs);
verifyResult(result);
verifyResult(result, openPassportProverInputs);
});
it('OpenPassport1Step - rsa sha1', async function () {
@@ -91,7 +91,7 @@ describe('\x1b[95mOpenPassport1Step\x1b[0m', function () {
circuit: 'prove',
});
const result = await openPassport1StepVerifier.verify(openPassportProverInputs);
verifyResult(result);
verifyResult(result, openPassportProverInputs);
});
it('OpenPassport1Step - rsapss sha256', async function () {
@@ -129,16 +129,19 @@ describe('\x1b[95mOpenPassport1Step\x1b[0m', function () {
circuit: 'prove',
});
const result = await openPassport1StepVerifier.verify(openPassportProverInputs);
verifyResult(result);
verifyResult(result, openPassportProverInputs);
});
const verifyResult = (result: OpenPassportVerifierReport) => {
const verifyResult = (
result: OpenPassportVerifierReport,
openPassportProverInputs: OpenPassport1StepInputs
) => {
if (!result.valid) {
console.log(result);
}
console.log('\x1b[34muser_identifier: \x1b[0m', result.getUUID());
console.log('\x1b[34mnullifier: \x1b[0m', result.getNullifier());
expect(result.getUUID()).to.equal(user_identifier);
console.log('\x1b[34muser_identifier: \x1b[0m', openPassportProverInputs.getUserId());
console.log('\x1b[34mnullifier: \x1b[0m', openPassportProverInputs.getNullifier());
expect(openPassportProverInputs.getUserId()).to.equal(user_identifier);
expect(result.valid).to.be.true;
};
});

View File

@@ -3,22 +3,29 @@
"target": "ES2020",
"module": "commonjs",
"declaration": true,
"declarationDir": "./dist/types",
"outDir": "./dist",
"strict": false,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"jsx": "react", // Add this line
"moduleResolution": "node" // Add this line if not already present
"jsx": "react",
"moduleResolution": "node"
},
"include": [
"src/index.ts",
"src/index.web.ts",
"src/index.node.ts",
"src/**/*",
"common/**/*",
"circuits/**/*",
"circuits/**/*.json",
"utils/utils.ts"
],
"exclude": ["node_modules", "**/__tests__/*", "dist", "common/src/utils/csca.ts"]
}
"exclude": [
"node_modules",
"**/__tests__/*",
"dist",
"common/src/utils/csca.ts"
]
}

View File

@@ -0,0 +1,30 @@
const path = require('path');
module.exports = {
mode: 'production',
entry: './src/index.node.ts',
output: {
filename: 'bundle.node.js',
path: path.resolve(__dirname, 'dist'),
libraryTarget: 'umd',
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
fallback: {
"bufferutil": false,
"utf-8-validate": false,
"debug": require.resolve('debug')
}
},
target: 'node',
};

34
sdk/webpack.web.config.js Normal file
View File

@@ -0,0 +1,34 @@
const path = require('path');
module.exports = {
mode: 'production',
entry: './src/index.web.ts', // Updated entry point
output: {
filename: 'bundle.web.js',
path: path.resolve(__dirname, 'dist'),
libraryTarget: 'umd',
},
module: {
rules: [
{
test: /\.(ts|tsx)$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js', '.jsx'],
fallback: {
"bufferutil": false,
"utf-8-validate": false,
"debug": require.resolve('debug')
}
},
target: 'web',
externals: {
react: 'react',
'react-dom': 'react-dom',
'lottie-react': 'lottie-react'
},
};