mirror of
https://github.com/selfxyz/self.git
synced 2026-01-09 14:48:06 -05:00
* fix build issues * generate disclosure proof with euids * generate disclosure proof with euids * Eu id updates 2 (#648) * update vc_and_disclose_id test (dev branch) (#641) * fix: vc_and_disclose_id test * chore: yarn prettier * Show modal on NFC scan error (#642) * Add help button and error modal actions * fix the screen management * yarn nice * Bump build v2.5.4: ios 132; android 71 (#631) * bump version and build numbers * remove tamagui/toast * fix marketing version * fix: update TD1 and TD3 checks (#643) * bum yarn.lock * add version and user defined data --------- Co-authored-by: Vishalkulkarni45 <109329073+Vishalkulkarni45@users.noreply.github.com> Co-authored-by: Justin Hernandez <justin.hernandez@self.xyz> Co-authored-by: Seshanth.S🐺 <35675963+seshanthS@users.noreply.github.com> * remove the mock user define data * get the useridentifier as a hash from the user defined data * chore: add version and userDefinedData * feat: use the version in register / dsc proofs as well * update calculateUserIdentifierHash * yarn nice * refactor: consolidate user context data handling and update payload structure * fix typing issues on sha1 * remove console.log(sha1) * fix sha1 import * refactor: streamline userDefinedData handling and adjust payload type for circuit * refactor: update sha1 usage and enhance logging in calculateUserIdentifierHash * yarn nice * yarn lint common * use ts-ignore for sha1 import * fix app ci tests * fix typing issue * remove unused ts-ignore * cast uuid before calling generateinputs * bump qrcode version * add tsup on the qrcode sdk * fix: exports on selfxyz/qrcode * update how we define config.version * fix yarn imports * yarn format --------- Co-authored-by: Vishalkulkarni45 <109329073+Vishalkulkarni45@users.noreply.github.com> Co-authored-by: Justin Hernandez <justin.hernandez@self.xyz> Co-authored-by: Seshanth.S🐺 <35675963+seshanthS@users.noreply.github.com> Co-authored-by: Ayman <aymanshaik1015@gmail.com>
238 lines
7.1 KiB
TypeScript
238 lines
7.1 KiB
TypeScript
import { LeanIMT } from '@openpassport/zk-kit-lean-imt';
|
|
import {
|
|
API_URL,
|
|
formatMrz,
|
|
generateCommitment,
|
|
generateNullifier,
|
|
getCircuitNameFromPassportData,
|
|
getLeafDscTree,
|
|
Hash,
|
|
ID_CARD_ATTESTATION_ID,
|
|
parseCertificateSimple,
|
|
PASSPORT_ATTESTATION_ID,
|
|
type PassportData,
|
|
} from '@selfxyz/common';
|
|
import { DocumentCategory } from '@selfxyz/common';
|
|
import { poseidon2, poseidon5 } from 'poseidon-lite';
|
|
|
|
import { useProtocolStore } from '../../stores/protocolStore';
|
|
|
|
export type PassportSupportStatus =
|
|
| 'passport_metadata_missing'
|
|
| 'csca_not_found'
|
|
| 'registration_circuit_not_supported'
|
|
| 'dsc_circuit_not_supported'
|
|
| 'passport_supported';
|
|
export async function checkPassportSupported(
|
|
passportData: PassportData,
|
|
): Promise<{
|
|
status: PassportSupportStatus;
|
|
details: string;
|
|
}> {
|
|
const passportMetadata = passportData.passportMetadata;
|
|
const document: DocumentCategory = passportData.documentCategory;
|
|
if (!passportMetadata) {
|
|
console.log('Passport metadata is null');
|
|
return { status: 'passport_metadata_missing', details: passportData.dsc };
|
|
}
|
|
if (!passportMetadata.cscaFound) {
|
|
console.log('CSCA not found');
|
|
return { status: 'csca_not_found', details: passportData.dsc };
|
|
}
|
|
const circuitNameRegister = getCircuitNameFromPassportData(
|
|
passportData,
|
|
'register',
|
|
);
|
|
const deployedCircuits =
|
|
useProtocolStore.getState()[document].deployed_circuits; // change this to the document type
|
|
if (
|
|
!circuitNameRegister ||
|
|
!(
|
|
deployedCircuits.REGISTER.includes(circuitNameRegister) ||
|
|
deployedCircuits.REGISTER_ID.includes(circuitNameRegister)
|
|
)
|
|
) {
|
|
return {
|
|
status: 'registration_circuit_not_supported',
|
|
details: circuitNameRegister,
|
|
};
|
|
}
|
|
const circuitNameDsc = getCircuitNameFromPassportData(passportData, 'dsc');
|
|
if (
|
|
!circuitNameDsc ||
|
|
!(
|
|
deployedCircuits.DSC.includes(circuitNameDsc) ||
|
|
deployedCircuits.DSC_ID.includes(circuitNameDsc)
|
|
)
|
|
) {
|
|
console.log('DSC circuit not supported:', circuitNameDsc);
|
|
return { status: 'dsc_circuit_not_supported', details: circuitNameDsc };
|
|
}
|
|
console.log('Passport supported');
|
|
return { status: 'passport_supported', details: 'null' };
|
|
}
|
|
|
|
export async function isUserRegistered(
|
|
passportData: PassportData,
|
|
secret: string,
|
|
) {
|
|
if (!passportData) {
|
|
return false;
|
|
}
|
|
const attestationId =
|
|
passportData.documentCategory === 'passport'
|
|
? PASSPORT_ATTESTATION_ID
|
|
: ID_CARD_ATTESTATION_ID;
|
|
const commitment = generateCommitment(secret, attestationId, passportData);
|
|
const document: DocumentCategory = passportData.documentCategory;
|
|
const serializedTree = useProtocolStore.getState()[document].commitment_tree;
|
|
const tree = LeanIMT.import((a, b) => poseidon2([a, b]), serializedTree);
|
|
const index = tree.indexOf(BigInt(commitment));
|
|
return index !== -1;
|
|
}
|
|
|
|
export async function isUserRegisteredWithAlternativeCSCA(
|
|
passportData: PassportData,
|
|
secret: string,
|
|
): Promise<{ isRegistered: boolean; csca: string | null }> {
|
|
if (!passportData) {
|
|
console.error('Passport data is null');
|
|
return { isRegistered: false, csca: null };
|
|
}
|
|
const alternativeCSCA = useProtocolStore.getState().passport.alternative_csca;
|
|
console.log('alternativeCSCA: ', alternativeCSCA);
|
|
const { commitment_list, csca_list } = generateCommitmentInApp(
|
|
secret,
|
|
PASSPORT_ATTESTATION_ID,
|
|
passportData,
|
|
alternativeCSCA,
|
|
);
|
|
|
|
if (commitment_list.length === 0) {
|
|
console.error(
|
|
'No valid CSCA certificates could be parsed from alternativeCSCA',
|
|
);
|
|
return { isRegistered: false, csca: null };
|
|
}
|
|
|
|
const serializedTree = useProtocolStore.getState().passport.commitment_tree;
|
|
const tree = LeanIMT.import((a, b) => poseidon2([a, b]), serializedTree);
|
|
for (let i = 0; i < commitment_list.length; i++) {
|
|
const commitment = commitment_list[i];
|
|
const index = tree.indexOf(BigInt(commitment));
|
|
if (index !== -1) {
|
|
return { isRegistered: true, csca: csca_list[i] };
|
|
}
|
|
}
|
|
console.warn(
|
|
'None of the following CSCA correspond to the commitment:',
|
|
csca_list,
|
|
);
|
|
return { isRegistered: false, csca: null };
|
|
}
|
|
|
|
export async function isPassportNullified(passportData: PassportData) {
|
|
const nullifier = generateNullifier(passportData);
|
|
const nullifierHex = `0x${BigInt(nullifier).toString(16)}`;
|
|
console.log('checking for nullifier', nullifierHex);
|
|
const response = await fetch(`${API_URL}/is-nullifier-onchain/`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ nullifier: nullifierHex }),
|
|
});
|
|
const data = await response.json();
|
|
console.log('isPassportNullified', data);
|
|
return data.data;
|
|
}
|
|
|
|
export async function checkIfPassportDscIsInTree(
|
|
passportData: PassportData,
|
|
dscTree: string,
|
|
): Promise<boolean> {
|
|
const hashFunction = (a: any, b: any) => poseidon2([a, b]);
|
|
const tree = LeanIMT.import(hashFunction, dscTree);
|
|
const leaf = getLeafDscTree(
|
|
passportData.dsc_parsed!,
|
|
passportData.csca_parsed!,
|
|
);
|
|
const index = tree.indexOf(BigInt(leaf));
|
|
if (index === -1) {
|
|
console.log('DSC not found in the tree');
|
|
return false;
|
|
} else {
|
|
console.log('DSC found in the tree');
|
|
return true;
|
|
}
|
|
}
|
|
|
|
export function generateCommitmentInApp(
|
|
secret: string,
|
|
attestation_id: string,
|
|
passportData: PassportData,
|
|
alternativeCSCA: Record<string, string>,
|
|
) {
|
|
const dg1_packed_hash = Hash.packBytesAndPoseidon(
|
|
formatMrz(passportData.mrz),
|
|
);
|
|
const eContent_packed_hash = Hash.packBytesAndPoseidon(
|
|
(
|
|
Hash.hash(
|
|
passportData.passportMetadata!.eContentHashFunction,
|
|
Array.from(passportData.eContent),
|
|
'bytes',
|
|
) as number[]
|
|
)
|
|
// eslint-disable-next-line no-bitwise
|
|
.map(byte => byte & 0xff),
|
|
);
|
|
|
|
const csca_list: string[] = [];
|
|
const commitment_list: string[] = [];
|
|
|
|
for (const [cscaKey, cscaValue] of Object.entries(alternativeCSCA)) {
|
|
try {
|
|
const formattedCsca = formatCSCAPem(cscaValue);
|
|
const cscaParsed = parseCertificateSimple(formattedCsca);
|
|
|
|
const commitment = poseidon5([
|
|
secret,
|
|
attestation_id,
|
|
dg1_packed_hash,
|
|
eContent_packed_hash,
|
|
getLeafDscTree(passportData.dsc_parsed!, cscaParsed),
|
|
]).toString();
|
|
|
|
csca_list.push(formatCSCAPem(cscaValue));
|
|
commitment_list.push(commitment);
|
|
} catch (error) {
|
|
console.warn(
|
|
`Failed to parse CSCA certificate for key ${cscaKey}:`,
|
|
error,
|
|
);
|
|
}
|
|
}
|
|
|
|
if (commitment_list.length === 0) {
|
|
console.error('No valid CSCA certificates found in alternativeCSCA');
|
|
}
|
|
|
|
return { commitment_list, csca_list };
|
|
}
|
|
|
|
function formatCSCAPem(cscaPem: string): string {
|
|
let cleanedPem = cscaPem.trim();
|
|
|
|
if (!cleanedPem.includes('-----BEGIN CERTIFICATE-----')) {
|
|
cleanedPem = cleanedPem.replace(/[^A-Za-z0-9+/=]/g, '');
|
|
try {
|
|
Buffer.from(cleanedPem, 'base64');
|
|
} catch (error) {
|
|
throw new Error(`Invalid base64 certificate data: ${error}`);
|
|
}
|
|
cleanedPem = `-----BEGIN CERTIFICATE-----\n${cleanedPem}\n-----END CERTIFICATE-----`;
|
|
}
|
|
return cleanedPem;
|
|
}
|