import { CredentialFormatTuple, PresentationResult, } from './vpTokenCredentialsExtractor.js'; import { DCQLQuery } from '../../shared/dto/dcqlQuery.dto.js'; import joseWrapper from '../../shared/middleware/joseWrapper.js'; import { DcqlCredentialPresentation, DcqlPresentationResult, DcqlQuery, } from 'dcql'; enum DcqlCredentialFormats { JwtVc = 'jwt_vc_json', LdpVc = 'ldp_vc', MdocVc = 'mso_mdoc', SdJwtVc = 'dc+sd-jwt', } export class DcqlQueryValidator { constructor( private verifiableCredentials: CredentialFormatTuple[], private dcqlQuery: DCQLQuery, private credentialQueryIds: string[], ) {} validate(): PresentationResult { const result: PresentationResult = { valid: true }; this.dcqlQuery.credentials.forEach((credentialQuery) => { const indexes = this.credentialQueryIds .map((credentialQueryId, index) => credentialQueryId === credentialQuery.id ? index : -1, ) .filter((index) => index !== -1); const credentials = indexes.map( (index) => this.verifiableCredentials[index], ); const parsedCredentials = credentials.map((credential, index) => { const credentialAttributes = this.getCredentialPayload( credential.verifiableCredential as string, ); const credentialFormat = this.getCredentialFormat( credential.verifiableCredential as string, ); return { credential_format: credentialFormat, ...(credentialFormat === DcqlCredentialFormats.SdJwtVc && credentialAttributes.vct && { vct: credentialAttributes.vct, }), ...(credentialFormat === DcqlCredentialFormats.LdpVc && credentialAttributes.type && { type: credentialAttributes?.type, }), ...(credentialFormat === DcqlCredentialFormats.JwtVc && credentialAttributes?.type && { type: credentialAttributes.type, }), cryptographic_holder_binding: false, ...(credentialFormat !== DcqlCredentialFormats.MdocVc && { claims: credentialAttributes, }), ...(credentialFormat === DcqlCredentialFormats.MdocVc && { doctype: credentialAttributes.docType, namespaces: { ...credentialAttributes.attributes }, }), }; }); const presentationQueryResult = DcqlPresentationResult.fromDcqlPresentation( { [credentialQuery.id]: parsedCredentials as unknown as DcqlCredentialPresentation[], }, { dcqlQuery: { credentials: [credentialQuery], } as unknown as DcqlQuery, }, ); if (!presentationQueryResult.can_be_satisfied) { result.valid = false; result.message = `Credential presented does not satisfy Presentation Query with id ${credentialQuery.id}.`; return result; } }); return result; } private getCredentialPayload(credential: string | object) { if (typeof credential === 'object' && credential !== null) { return credential; } if ( (credential as string).startsWith('ey') && !(credential as string).includes('~') ) { return joseWrapper.decodeJWT(credential as string)?.vc; } return JSON.parse(credential as string); } private getCredentialFormat( credential: string | object, ): DcqlCredentialFormats { if (typeof credential === 'object' && credential !== null) { return DcqlCredentialFormats.LdpVc; } if ((credential as string).includes('~')) { return DcqlCredentialFormats.SdJwtVc; } if ((credential as string).startsWith('ey')) { return DcqlCredentialFormats.JwtVc; } return DcqlCredentialFormats.LdpVc; } }