mirror of
https://github.com/selfxyz/self.git
synced 2026-04-27 03:01:15 -04:00
Merge branch 'sdk' of https://github.com/zk-passport/openpassport into dev
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)]
|
||||
};
|
||||
|
||||
|
||||
@@ -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
11
mock_node_app/index.js
Normal 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.');
|
||||
}
|
||||
9
mock_node_app/package.json
Normal file
9
mock_node_app/package.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "mock_node_app",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@proofofpassport/sdk": "^2.0.9"
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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
0
sdk/rollup.config.ts
Normal 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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':
|
||||
|
||||
1
sdk/src/QRcode/OpenPassportQRcode.d.ts
vendored
1
sdk/src/QRcode/OpenPassportQRcode.d.ts
vendored
@@ -6,6 +6,7 @@ export interface OpenPassportQRcodeProps {
|
||||
userId: string;
|
||||
requirements: any[];
|
||||
onSuccess: (result: any) => void;
|
||||
size?: number;
|
||||
devMode?: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -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
12
sdk/src/index.node.ts
Normal 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,
|
||||
};
|
||||
@@ -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
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
});
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
30
sdk/webpack.node.config.js
Normal file
30
sdk/webpack.node.config.js
Normal 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
34
sdk/webpack.web.config.js
Normal 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'
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user