mirror of
https://github.com/selfxyz/self.git
synced 2026-04-05 03:00:53 -04:00
update sdk
This commit is contained in:
@@ -19,17 +19,20 @@
|
||||
"js-sha256": "^0.11.0",
|
||||
"js-sha512": "^0.9.0",
|
||||
"lottie-react": "^2.4.0",
|
||||
"msgpack-lite": "^0.1.26",
|
||||
"next": "^14.2.8",
|
||||
"node-forge": "https://github.com/remicolin/forge",
|
||||
"pako": "^2.1.0",
|
||||
"pkijs": "^3.2.4",
|
||||
"poseidon-lite": "^0.2.0",
|
||||
"qrcode.react": "^4.0.1",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"react-spinners": "^0.14.1",
|
||||
"snarkjs": "^0.7.4",
|
||||
"socket.io-client": "^4.7.5",
|
||||
"uuid": "^10.0.0",
|
||||
"node-forge": "https://github.com/remicolin/forge"
|
||||
"zlib": "^1.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.3.6",
|
||||
@@ -39,10 +42,16 @@
|
||||
"@types/mocha": "^10.0.6",
|
||||
"@types/node": "^20.11.19",
|
||||
"@types/node-forge": "^1.3.5",
|
||||
"@types/pako": "^2.0.3",
|
||||
"@types/snarkjs": "^0.7.8",
|
||||
"@zk-kit/imt": "^2.0.0-beta.5",
|
||||
"@zk-kit/lean-imt": "^2.0.1",
|
||||
"asn1js": "^3.0.5",
|
||||
"axios": "^1.7.2",
|
||||
"chai": "^4.3.8",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"dotenv": "^16.4.5",
|
||||
"ethers": "^6.13.0",
|
||||
"mocha": "^10.3.0",
|
||||
"prettier": "^3.3.3",
|
||||
"ts-loader": "^9.5.1",
|
||||
@@ -50,12 +59,7 @@
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.4.5",
|
||||
"webpack": "^5.94.0",
|
||||
"webpack-cli": "^5.1.4",
|
||||
"@zk-kit/imt": "^2.0.0-beta.5",
|
||||
"@zk-kit/lean-imt": "^2.0.1",
|
||||
"asn1js": "^3.0.5",
|
||||
"axios": "^1.7.2",
|
||||
"ethers": "^6.13.0"
|
||||
"webpack-cli": "^5.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
"build:ts": "tsc && tsc -p tsconfig.react.json",
|
||||
|
||||
@@ -1,216 +1,113 @@
|
||||
import { groth16 } from 'snarkjs';
|
||||
import {
|
||||
countryCodes,
|
||||
DEFAULT_RPC_URL,
|
||||
ECDSA_K_LENGTH_FACTOR,
|
||||
k_dsc,
|
||||
k_dsc_ecdsa,
|
||||
n_dsc,
|
||||
PASSPORT_ATTESTATION_ID,
|
||||
} from '../../common/src/constants/constants';
|
||||
import { getAttributeFromUnpackedReveal } from '../../common/src/utils/utils';
|
||||
import {
|
||||
areArraysEqual,
|
||||
getCurrentDateFormatted,
|
||||
getVkeyFromArtifacts,
|
||||
verifyDSCValidity,
|
||||
} from '../utils/utils';
|
||||
import { unpackReveal } from '../../common/src/utils/revealBitmap';
|
||||
import { OpenPassportVerifierReport } from './OpenPassportVerifierReport';
|
||||
import {
|
||||
OpenPassportAttestation,
|
||||
parsePublicSignalsProve,
|
||||
} from '../../common/src/utils/openPassportAttestation';
|
||||
|
||||
import forge from 'node-forge';
|
||||
import { castToScope, splitToWords } from '../../common/src/utils/utils';
|
||||
import { parseDSC } from '../../common/src/utils/certificates/handleCertificate';
|
||||
import { CircuitMode, CircuitName } from '../../common/src/utils/appType';
|
||||
|
||||
import { ArgumentsProveOffChain, ArgumentsRegisterOffChain, ArgumentsRegisterOnChain, Mode, OpenPassportAppPartial } from "../../common/src/utils/appType";
|
||||
import { DEFAULT_RPC_URL, MODAL_SERVER_ADDRESS, WEBSOCKET_URL, countryNames } from "../../common/src/constants/constants";
|
||||
import { OpenPassportApp } from "../../common/src/utils/appType";
|
||||
import { UserIdType } from "../../common/src/utils/utils";
|
||||
import * as pako from 'pako';
|
||||
import msgpack from 'msgpack-lite';
|
||||
import { OpenPassportAttestation } from "./index.web";
|
||||
export class OpenPassportVerifier {
|
||||
scope: string;
|
||||
attestationId: string;
|
||||
olderThan?: string;
|
||||
nationality?: (typeof countryCodes)[keyof typeof countryCodes];
|
||||
ofac?: string;
|
||||
forbidden_countries_list?: string[];
|
||||
rpcUrl: string;
|
||||
report: OpenPassportVerifierReport;
|
||||
dev_mode: boolean;
|
||||
parsedPublicSignals: any;
|
||||
circuit: string;
|
||||
circuitMode?: string;
|
||||
constructor(options: {
|
||||
scope: string;
|
||||
attestationId?: string;
|
||||
olderThan?: string;
|
||||
nationality?: (typeof countryCodes)[keyof typeof countryCodes];
|
||||
ofac?: string;
|
||||
forbidden_countries_list?: string[];
|
||||
rpcUrl?: string;
|
||||
dev_mode?: boolean;
|
||||
circuit: CircuitName;
|
||||
circuitMode?: CircuitMode;
|
||||
}) {
|
||||
this.scope = options.scope;
|
||||
this.attestationId = options.attestationId || PASSPORT_ATTESTATION_ID;
|
||||
this.olderThan = options.olderThan || null;
|
||||
this.nationality = options.nationality || null;
|
||||
this.ofac = options.ofac || null;
|
||||
this.forbidden_countries_list = options.forbidden_countries_list || null;
|
||||
this.rpcUrl = options.rpcUrl || DEFAULT_RPC_URL;
|
||||
this.report = new OpenPassportVerifierReport();
|
||||
this.dev_mode = options.dev_mode || false;
|
||||
this.circuit = options.circuit;
|
||||
this.circuitMode = options.circuitMode || 'prove_offchain';
|
||||
private mode: Mode;
|
||||
private scope: string;
|
||||
private minimumAge: { enabled: boolean; value: number } = { enabled: false, value: 0 };
|
||||
private nationality: { enabled: boolean; value: typeof countryNames[number] } = { enabled: false, value: '' as typeof countryNames[number] };
|
||||
private excludedCountries: { enabled: boolean; value: typeof countryNames[number][] } = { enabled: false, value: [] };
|
||||
private ofac: boolean = false;
|
||||
private modalServerUrl: string = MODAL_SERVER_ADDRESS;
|
||||
private rpcUrl: string = DEFAULT_RPC_URL;
|
||||
private cscaMerkleTreeUrl: string = "";
|
||||
private devMode: boolean = false;
|
||||
|
||||
constructor(mode: Mode, scope: string) {
|
||||
this.mode = mode;
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
async verify(attestation: OpenPassportAttestation): Promise<OpenPassportVerifierReport> {
|
||||
const {
|
||||
proof: {
|
||||
value: { proof, publicSignals },
|
||||
},
|
||||
dsc: { value: dsc },
|
||||
dscProof: {
|
||||
value: { proof: dscProof, publicSignals: dscPublicSignals },
|
||||
},
|
||||
} = attestation;
|
||||
// Disclose
|
||||
setMinimumAge(age: number): this {
|
||||
this.minimumAge = { enabled: true, value: age };
|
||||
return this;
|
||||
}
|
||||
|
||||
const { signatureAlgorithm, hashFunction } = parseDSC(dsc);
|
||||
const kScaled = signatureAlgorithm === 'ecdsa' ? ECDSA_K_LENGTH_FACTOR * k_dsc_ecdsa : k_dsc;
|
||||
this.parsedPublicSignals = parsePublicSignalsProve(publicSignals, kScaled);
|
||||
console.log('this.parsedPublicSignals', this.parsedPublicSignals);
|
||||
setNationality(country: typeof countryNames[number]): this {
|
||||
this.nationality = { enabled: true, value: country };
|
||||
return this;
|
||||
}
|
||||
|
||||
await this.verifyProof(proof, publicSignals, dsc);
|
||||
console.log('this.circuit', this.circuit);
|
||||
switch (this.circuit) {
|
||||
case 'prove':
|
||||
if (this.circuitMode === 'prove_offchain') {
|
||||
await this.verifyProveArguments();
|
||||
await this.verifyDsc(dsc);
|
||||
} else if (this.circuitMode === 'register') {
|
||||
await this.verifyRegisterArguments();
|
||||
await this.verifyDscProof(dscProof, dscPublicSignals, dsc);
|
||||
}
|
||||
excludeCountries(...countries: typeof countryNames[number][]): this {
|
||||
this.excludedCountries = { enabled: true, value: countries };
|
||||
return this;
|
||||
}
|
||||
|
||||
enableOFACCheck(): this {
|
||||
this.ofac = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
// Register
|
||||
setModalServerUrl(modalServerUrl: string): this {
|
||||
this.modalServerUrl = modalServerUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
// On chain
|
||||
setRpcUrl(rpcUrl: string): this {
|
||||
this.rpcUrl = rpcUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
setDevMode(devMode: boolean): this {
|
||||
this.devMode = devMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
getIntent(appName: string, userId: string, userIdType: UserIdType, sessionId: string, websocketUrl: string = WEBSOCKET_URL): string {
|
||||
const intent_raw: OpenPassportAppPartial = {
|
||||
appName: appName,
|
||||
mode: this.mode,
|
||||
scope: this.scope,
|
||||
websocketUrl: websocketUrl,
|
||||
};
|
||||
|
||||
let openPassportArguments: ArgumentsProveOffChain | ArgumentsRegisterOnChain;
|
||||
switch (this.mode) {
|
||||
case "prove_offchain":
|
||||
const argsProveOffChain: ArgumentsProveOffChain = {
|
||||
disclosureOptions: {
|
||||
minimumAge: this.minimumAge,
|
||||
nationality: this.nationality,
|
||||
excludedCountries: this.excludedCountries,
|
||||
ofac: this.ofac,
|
||||
},
|
||||
};
|
||||
openPassportArguments = argsProveOffChain;
|
||||
break;
|
||||
case 'disclose':
|
||||
await this.verifyDiscloseArguments();
|
||||
case "register":
|
||||
const argsRegisterOnChain: ArgumentsRegisterOnChain = {
|
||||
modalServerUrl: this.modalServerUrl,
|
||||
cscaMerkleTreeUrl: this.cscaMerkleTreeUrl,
|
||||
rpcUrl: this.rpcUrl,
|
||||
};
|
||||
openPassportArguments = argsRegisterOnChain;
|
||||
break;
|
||||
}
|
||||
return this.report;
|
||||
}
|
||||
|
||||
private async verifyProof(proof: string[], publicSignals: string[], dsc: string) {
|
||||
const vkey = this.getVkey(dsc);
|
||||
const verified_prove = await groth16.verify(vkey, publicSignals, proof as any);
|
||||
this.verifyAttribute('proof', verified_prove.toString(), 'true');
|
||||
}
|
||||
|
||||
private async verifyProveArguments() {
|
||||
this.verifyAttribute('scope', castToScope(this.parsedPublicSignals.scope), this.scope);
|
||||
this.verifyAttribute(
|
||||
'current_date',
|
||||
this.parsedPublicSignals.current_date.toString(),
|
||||
getCurrentDateFormatted().toString()
|
||||
);
|
||||
|
||||
// requirements
|
||||
const unpackedReveal = unpackReveal(this.parsedPublicSignals.revealedData_packed);
|
||||
if (this.olderThan) {
|
||||
const attributeValue = this.parsedPublicSignals.older_than;
|
||||
const attributeValueInt = parseInt(String.fromCharCode(...attributeValue));
|
||||
const selfAttributeOlderThan = parseInt(this.olderThan);
|
||||
console.log('attributeValue', attributeValueInt);
|
||||
console.log('selfAttributeOlderThan', selfAttributeOlderThan);
|
||||
if (attributeValueInt < selfAttributeOlderThan) {
|
||||
console.log(attributeValueInt, selfAttributeOlderThan);
|
||||
this.report.exposeAttribute('older_than', attributeValueInt.toString(), this.olderThan);
|
||||
}
|
||||
}
|
||||
if (this.nationality) {
|
||||
const attributeValue = getAttributeFromUnpackedReveal(unpackedReveal, 'nationality');
|
||||
this.verifyAttribute('nationality', countryCodes[attributeValue], this.nationality);
|
||||
}
|
||||
// if (this.ofac) {
|
||||
// const attributeValue = getAttributeFromUnpackedReveal(unpackedReveal, 'ofac');
|
||||
// this.verifyAttribute('ofac', attributeValue, this.ofac);
|
||||
// }
|
||||
if (this.forbidden_countries_list) {
|
||||
const countryList1 = unpackReveal(this.parsedPublicSignals.forbidden_countries_list_packed_disclosed[0]);
|
||||
const countryList2 = unpackReveal(this.parsedPublicSignals.forbidden_countries_list_packed_disclosed[1]);
|
||||
const concatenatedCountryList = countryList1.concat(countryList2);
|
||||
// dump every '\x00' value from the list
|
||||
const cleanedCountryList = concatenatedCountryList.filter(value => value !== '\x00');
|
||||
// Concatenate every 3 elements to form country codes
|
||||
const formattedCountryList = [];
|
||||
for (let i = 0; i < cleanedCountryList.length; i += 3) {
|
||||
const countryCode = cleanedCountryList.slice(i, i + 3).join('');
|
||||
if (countryCode.length === 3) {
|
||||
formattedCountryList.push(countryCode);
|
||||
}
|
||||
}
|
||||
console.log('formattedCountryList', formattedCountryList);
|
||||
this.verifyAttribute('forbidden_countries_list', formattedCountryList.toString(), this.forbidden_countries_list.toString());
|
||||
}
|
||||
|
||||
return this.report;
|
||||
}
|
||||
|
||||
private async verifyDiscloseArguments() { }
|
||||
|
||||
private verifyAttribute(
|
||||
attribute: keyof OpenPassportVerifierReport,
|
||||
value: string,
|
||||
expectedValue: string
|
||||
) {
|
||||
if (value !== expectedValue) {
|
||||
this.report.exposeAttribute(attribute, this.parsedPublicSignals[attribute], expectedValue);
|
||||
}
|
||||
console.log('\x1b[34m%s\x1b[0m', `- attribute ${attribute} verified`);
|
||||
}
|
||||
|
||||
private getVkey(dsc: string) {
|
||||
const { signatureAlgorithm, hashFunction } = parseDSC(dsc);
|
||||
if (this.circuit === 'prove') {
|
||||
return getVkeyFromArtifacts(this.circuit, signatureAlgorithm, hashFunction);
|
||||
} else {
|
||||
throw new Error('vkey of ' + this.circuit + ' not found');
|
||||
const intent: OpenPassportApp = {
|
||||
...intent_raw,
|
||||
args: openPassportArguments,
|
||||
};
|
||||
const encoded = msgpack.encode(intent);
|
||||
try {
|
||||
const compressedData = pako.deflate(encoded);
|
||||
return btoa(String.fromCharCode(...new Uint8Array(compressedData)));
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
private getVkeyDsc(dsc: string) {
|
||||
const { signatureAlgorithm, hashFunction } = parseDSC(dsc);
|
||||
return getVkeyFromArtifacts('dsc', signatureAlgorithm, hashFunction);
|
||||
}
|
||||
|
||||
private verifyDsc(dsc: string) {
|
||||
const dscCertificate = forge.pki.certificateFromPem(dsc);
|
||||
const verified_certificate = verifyDSCValidity(dscCertificate, this.dev_mode);
|
||||
console.log('\x1b[34m%s\x1b[0m', '- certificate verified');
|
||||
if (!verified_certificate) {
|
||||
this.report.exposeAttribute('dsc', dsc, 'certificate chain is not valid');
|
||||
}
|
||||
|
||||
const dsc_modulus = BigInt((dscCertificate.publicKey as any).n);
|
||||
const dsc_modulus_words = splitToWords(dsc_modulus, n_dsc, k_dsc);
|
||||
const pubKeyFromProof = this.parsedPublicSignals.pubKey_disclosed;
|
||||
|
||||
const verified_modulus = areArraysEqual(dsc_modulus_words, pubKeyFromProof);
|
||||
console.log('\x1b[34m%s\x1b[0m', '- modulus verified');
|
||||
if (!verified_modulus) {
|
||||
this.report.exposeAttribute('pubKey', pubKeyFromProof, dsc_modulus_words);
|
||||
}
|
||||
}
|
||||
|
||||
private async verifyDscProof(proof: string[], publicSignals: string[], dsc: string) {
|
||||
console.log('verifyDscProof', publicSignals, proof);
|
||||
const vkey = this.getVkeyDsc(dsc);
|
||||
const verified_dscProof = await groth16.verify(vkey, publicSignals, proof as any);
|
||||
this.verifyAttribute('dscProof', verified_dscProof.toString(), 'true');
|
||||
}
|
||||
|
||||
private verifyRegisterArguments() {
|
||||
// verify that the blindedDscCommitment is the same in both proofs
|
||||
const blindedPubKeyCommitmentFromLocalProof = this.parsedPublicSignals.blinded_dsc_commitment;
|
||||
verify(attestation: OpenPassportAttestation): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
OpenPassportVerifierInputs,
|
||||
OpenPassportAttestation,
|
||||
OpenPassportVerifier,
|
||||
OpenPassportVerifierReport,
|
||||
} from '../index.web';
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
WEBSOCKET_URL,
|
||||
} from '../../../common/src/constants/constants';
|
||||
import { UserIdType } from '../../../common/src/utils/utils';
|
||||
import { CircuitMode, CircuitName, reconstructAppType } from '../../../common/src/utils/appType';
|
||||
import { CircuitName, Mode } from '../../../common/src/utils/appType';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { QRcodeSteps } from './utils/utils';
|
||||
import { containerStyle, ledContainerStyle, qrContainerStyle } from './utils/styles';
|
||||
@@ -26,122 +26,17 @@ const QRCodeSVG = dynamic(() => import('qrcode.react').then((mod) => mod.QRCodeS
|
||||
});
|
||||
|
||||
interface OpenPassportQRcodeProps {
|
||||
appName: string;
|
||||
scope: string;
|
||||
userId?: string;
|
||||
userIdType?: UserIdType;
|
||||
olderThan?: string;
|
||||
nationality?: string;
|
||||
ofac?: string;
|
||||
forbidden_countries_list?: string[];
|
||||
onSuccess?: (proof: OpenPassportVerifierInputs, report: OpenPassportVerifierReport) => void;
|
||||
circuit: CircuitName;
|
||||
circuitMode?: CircuitMode;
|
||||
devMode?: boolean;
|
||||
size?: number;
|
||||
openPassportVerifier: OpenPassportVerifier;
|
||||
onSuccess: (proof: OpenPassportAttestation, report: OpenPassportVerifierReport) => void;
|
||||
websocketUrl?: string;
|
||||
merkleTreeUrl?: string;
|
||||
modalServerUrl?: string;
|
||||
size?: number;
|
||||
}
|
||||
|
||||
const OpenPassportQRcode: React.FC<OpenPassportQRcodeProps> = ({
|
||||
appName,
|
||||
scope,
|
||||
userId,
|
||||
userIdType = DEFAULT_USER_ID_TYPE,
|
||||
olderThan = '',
|
||||
nationality = '',
|
||||
ofac = null,
|
||||
forbidden_countries_list = null,
|
||||
onSuccess = (proof: OpenPassportVerifierInputs, report: OpenPassportVerifierReport) => {
|
||||
console.log(proof, report);
|
||||
},
|
||||
circuit,
|
||||
circuitMode = 'prove_onchain',
|
||||
devMode = false,
|
||||
size = 300,
|
||||
websocketUrl = WEBSOCKET_URL,
|
||||
modalServerUrl = MODAL_SERVER_ADDRESS,
|
||||
merkleTreeUrl,
|
||||
}) => {
|
||||
const OpenPassportQRcode: React.FC<OpenPassportQRcodeProps> = ({ openPassportVerifier, onSuccess, websocketUrl = WEBSOCKET_URL, size = 300 }) => {
|
||||
const [proofStep, setProofStep] = useState(QRcodeSteps.WAITING_FOR_MOBILE);
|
||||
const [proofVerified, setProofVerified] = useState(null);
|
||||
const [sessionId, setSessionId] = useState(uuidv4());
|
||||
|
||||
const openPassportVerifier = new OpenPassportVerifier({
|
||||
scope: scope,
|
||||
olderThan: olderThan,
|
||||
nationality: nationality,
|
||||
ofac: ofac,
|
||||
forbidden_countries_list: forbidden_countries_list,
|
||||
dev_mode: devMode,
|
||||
circuit: circuit,
|
||||
circuitMode: circuitMode,
|
||||
});
|
||||
|
||||
const getAppStringified = () => {
|
||||
if (circuit === 'prove') {
|
||||
if (circuitMode == 'register') {
|
||||
return JSON.stringify(
|
||||
reconstructAppType({
|
||||
name: appName,
|
||||
scope: scope,
|
||||
userId: userId,
|
||||
userIdType: userIdType,
|
||||
sessionId: sessionId,
|
||||
circuit: circuit,
|
||||
circuitMode: circuitMode,
|
||||
arguments: {
|
||||
modalServerUrl: modalServerUrl,
|
||||
merkleTreeUrl: merkleTreeUrl,
|
||||
},
|
||||
websocketUrl: websocketUrl,
|
||||
})
|
||||
);
|
||||
} else if (circuitMode === 'prove_offchain') {
|
||||
const disclosureOptions = [
|
||||
['nationality', nationality],
|
||||
['older_than', olderThan],
|
||||
['ofac', ofac],
|
||||
['forbidden_countries_list', forbidden_countries_list],
|
||||
];
|
||||
return JSON.stringify(
|
||||
reconstructAppType({
|
||||
name: appName,
|
||||
scope: scope,
|
||||
userId: userId,
|
||||
userIdType: userIdType,
|
||||
sessionId: sessionId,
|
||||
circuit: circuit,
|
||||
circuitMode: circuitMode,
|
||||
arguments: {
|
||||
disclosureOptions: Object.fromEntries(disclosureOptions),
|
||||
},
|
||||
websocketUrl: websocketUrl,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
// } else if (circuit === 'prove' && circuitMode === 'register') {
|
||||
// return JSON.stringify(
|
||||
// reconstructAppType({
|
||||
// name: appName,
|
||||
// scope: scope,
|
||||
// userId: userId,
|
||||
// userIdType: userIdType,
|
||||
// sessionId: sessionId,
|
||||
// circuit: circuit,
|
||||
// circuitMode: circuitMode,
|
||||
// arguments: {
|
||||
// attestation_id: attestationId,
|
||||
// merkleTreeUrl: merkleTreeUrl,
|
||||
// },
|
||||
// websocketUrl: websocketUrl,
|
||||
// })
|
||||
// );
|
||||
// }
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
initWebSocket(
|
||||
websocketUrl,
|
||||
@@ -189,7 +84,7 @@ const OpenPassportQRcode: React.FC<OpenPassportQRcodeProps> = ({
|
||||
);
|
||||
}
|
||||
default:
|
||||
return <QRCodeSVG value={getAppStringified()} size={size} />;
|
||||
return <QRCodeSVG value={openPassportVerifier.getIntent("Mock App", "mockUid", "uuid", sessionId)} size={size} />;
|
||||
}
|
||||
})()}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user