UNPKG

@sphereon/pex

Version:

A Typescript implementation of the v1 and v2 DIF Presentation Exchange specification

179 lines 19.7 kB
import { JSONPath as jp } from '@astronautlabs/jsonpath'; import { CredentialMapper, OriginalType, } from '@sphereon/ssi-types'; import { nanoid } from 'nanoid'; import { Status } from '../../ConstraintUtils'; import { PEVersion } from '../../types'; import PexMessages from '../../types/Messages'; import { AbstractEvaluationHandler } from './abstractEvaluationHandler'; export class UriEvaluationHandler extends AbstractEvaluationHandler { constructor(client) { super(client); } getName() { return 'UriEvaluation'; } static HASHLINK_URL_ENCODED_REGEX = /hl:[a-zA-Z0-9]+:[a-zA-Z0-9]+/g; static HASHLINK_QUERY_URL_REGEX = /https*?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&/=]*)(hl=[a-zA-Z0-9]+)/g; handle(definition, wrappedVcs) { // This filter is removed in V2 definition.input_descriptors.forEach((inDesc, descriptorIdx) => { const uris = definition.getVersion() !== PEVersion.v2 ? inDesc.schema.map((so) => so.uri) : []; wrappedVcs.forEach((wvc, wrappedVCIdx) => { const vcUris = UriEvaluationHandler.buildVcContextAndSchemaUris(wvc.credential, definition.getVersion()); this.evaluateUris(wvc, vcUris, uris, descriptorIdx, wrappedVCIdx, definition.getVersion()); }); }); const definitionAllowsDataIntegrity = definition.format?.di || definition.format?.di_vc || definition.format?.di_vp; const descriptorMap = this.getResults() .filter((result) => result.status === Status.INFO) .map((result) => { let format = result.payload?.format; // This checks if the new data integrity format should be used. // That may be the case if the input descriptor points to credentials that are in ldp_vc or ldp format, // and the presentation definition allows data integrity. if (definitionAllowsDataIntegrity && (format === 'ldp_vc' || format === 'ldp')) { const wvcs = jp.nodes(wrappedVcs, result.verifiable_credential_path).map((node) => node.value); // check if all vc's have a data integrity proof const vcDataIntegrityProofs = wvcs.map((vc) => { if (vc.type !== OriginalType.JSONLD || !vc.credential.proof) return []; const proofs = Array.isArray(vc.credential.proof) ? vc.credential.proof : [vc.credential.proof]; const dataIntegrityProofs = proofs.filter((proof) => proof.type === 'DataIntegrityProof' && proof.cryptosuite !== undefined); return dataIntegrityProofs; }); // determine the common cryptosuites of all vc's const commonCryptosuites = vcDataIntegrityProofs.reduce((a, b) => a.filter((c) => b.includes(c))); // the input descriptor should also allow data integrity const inputDescriptor = jp.nodes(definition, result.input_descriptor_path)[0].value; const inputDescriptorAllowsDataIntegrity = !inputDescriptor['format'] || inputDescriptor?.format?.di || inputDescriptor?.format?.di_vc || inputDescriptor?.format?.di_vp; if (commonCryptosuites.length > 0 && inputDescriptorAllowsDataIntegrity) { format = 'di_vc'; } } const inputDescriptor = jp.nodes(definition, result.input_descriptor_path)[0].value; return { id: inputDescriptor.id, format, path: result.verifiable_credential_path, }; }); // The presentation submission is being created in this handler, then updated in subsequent handler. // TODO: This approach needs to be refactored for a new Major version. // Also there is no apparent need for the indirection and state in this class. // Simply do the first loops and amend the presentation submission in every loop. if (this.client.generatePresentationSubmission && (!this.presentationSubmission || Object.keys(this.presentationSubmission).length === 0)) { this.presentationSubmission = { id: nanoid(), definition_id: definition.id, descriptor_map: descriptorMap, }; } } evaluateUris(wvc, verifiableCredentialUris, inputDescriptorsUris, idIdx, vcIdx, pdVersion) { let hasAnyMatch = false; if (pdVersion === PEVersion.v1) { for (let i = 0; i < inputDescriptorsUris.length; i++) { if (UriEvaluationHandler.containsHashlink(inputDescriptorsUris[i])) { this.getResults().push(this.createWarnResultObject(idIdx, vcIdx)); } } for (let i = 0; i < verifiableCredentialUris.length; i++) { if (inputDescriptorsUris.find((el) => el === verifiableCredentialUris[i]) != undefined) { hasAnyMatch = true; } } } else { hasAnyMatch = true; } if (hasAnyMatch) { this.getResults().push(this.createSuccessResultObject(wvc, inputDescriptorsUris, idIdx, vcIdx)); } else { this.getResults().push(this.createErrorResultObject(wvc, inputDescriptorsUris, idIdx, vcIdx)); } } static buildVcContextAndSchemaUris(credential, version) { const uris = []; if (CredentialMapper.isMsoMdocDecodedCredential(credential)) { return uris; } // W3C credential if (CredentialMapper.isW3cCredential(credential)) { if (Array.isArray(credential['@context'])) { credential['@context'].forEach((value) => uris.push(value)); } else { uris.push(credential['@context']); } if (Array.isArray(credential.credentialSchema) && credential.credentialSchema.length > 0) { credential.credentialSchema.forEach((element) => uris.push(element.id)); } else if (credential.credentialSchema) { uris.push(credential.credentialSchema.id); } if (version === PEVersion.v1) { // JWT VC Profile and MS Entry Verified ID do use the schema from V1 to match against types in the VC Array.isArray(credential.type) ? credential.type.forEach((type) => uris.push(type)) : credential.type ? uris.push(credential.type) : undefined; } } // NOTE: we add the `vct` field of an SD-JWT to the list of uris, to allow SD-JWT // to work with PEX v1 in the same way that JWT vcs can work with pex v1. If we don't // add this, then SD-JWTs can only be used with PEX v2. if (CredentialMapper.isSdJwtDecodedCredential(credential)) { if (version === PEVersion.v1) { uris.push(credential.decodedPayload.vct); } } return uris; } createSuccessResultObject(wvc, inputDescriptorsUris, idIdx, vcIdx) { const result = this.createResult(idIdx, vcIdx); result.status = Status.INFO; result.message = PexMessages.URI_EVALUATION_PASSED; result.payload = { format: wvc.format, vcContext: CredentialMapper.isW3cCredential(wvc.credential) ? wvc.credential['@context'] : undefined, vcCredentialSchema: CredentialMapper.isW3cCredential(wvc.credential) ? wvc.credential.credentialSchema : undefined, inputDescriptorsUris, }; return result; } createErrorResultObject(wvc, inputDescriptorsUris, idIdx, vcIdx) { const result = this.createResult(idIdx, vcIdx); result.status = Status.ERROR; result.message = PexMessages.URI_EVALUATION_DIDNT_PASS; result.payload = { format: wvc.format, vcContext: CredentialMapper.isW3cCredential(wvc.credential) ? wvc.credential['@context'] : undefined, vcCredentialSchema: CredentialMapper.isW3cCredential(wvc.credential) ? wvc.credential.credentialSchema : undefined, inputDescriptorsUris, }; return result; } createWarnResultObject(idIdx, vcIdx) { const result = this.createResult(idIdx, vcIdx); result.status = Status.WARN; result.message = PexMessages.URI_EVALUATION_DIDNT_PASS; result.payload = PexMessages.INPUT_DESCRIPTOR_CONTEXT_CONTAINS_HASHLINK_VERIFICATION_NOT_SUPPORTED; return result; } createResult(idIdx, vcIdx) { return { input_descriptor_path: `$.input_descriptors[${idIdx}]`, verifiable_credential_path: `$[${vcIdx}]`, evaluator: this.getName(), status: Status.INFO, message: undefined, }; } static containsHashlink(url) { return !(url.matchAll(UriEvaluationHandler.HASHLINK_QUERY_URL_REGEX).next().done && url.matchAll(UriEvaluationHandler.HASHLINK_URL_ENCODED_REGEX).next().done); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXJpRXZhbHVhdGlvbkhhbmRsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9saWIvZXZhbHVhdGlvbi9oYW5kbGVycy91cmlFdmFsdWF0aW9uSGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxJQUFJLEVBQUUsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBRXpELE9BQU8sRUFDTCxnQkFBZ0IsRUFJaEIsWUFBWSxHQUdiLE1BQU0scUJBQXFCLENBQUM7QUFDN0IsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUVoQyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDL0MsT0FBTyxFQUFxRSxTQUFTLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDM0csT0FBTyxXQUFXLE1BQU0sc0JBQXNCLENBQUM7QUFJL0MsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFFeEUsTUFBTSxPQUFPLG9CQUFxQixTQUFRLHlCQUF5QjtJQUNqRSxZQUFZLE1BQXdCO1FBQ2xDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNoQixDQUFDO0lBRU0sT0FBTztRQUNaLE9BQU8sZUFBZSxDQUFDO0lBQ3pCLENBQUM7SUFFTyxNQUFNLENBQUMsMEJBQTBCLEdBQUcsK0JBQStCLENBQUM7SUFDcEUsTUFBTSxDQUFDLHdCQUF3QixHQUNyQyx1SEFBdUgsQ0FBQztJQUVuSCxNQUFNLENBQUMsVUFBMkMsRUFBRSxVQUF5QztRQUNsRywrQkFBK0I7UUFDSSxVQUFXLENBQUMsaUJBQWlCLENBQUMsT0FBTyxDQUFDLENBQUMsTUFBeUIsRUFBRSxhQUFxQixFQUFFLEVBQUU7WUFDNUgsTUFBTSxJQUFJLEdBQWEsVUFBVSxDQUFDLFVBQVUsRUFBRSxLQUFLLFNBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMs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