UNPKG

@sphereon/pex

Version:

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

188 lines 20.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.UriEvaluationHandler = void 0; const jsonpath_1 = require("@astronautlabs/jsonpath"); const ssi_types_1 = require("@sphereon/ssi-types"); const nanoid_1 = require("nanoid"); const ConstraintUtils_1 = require("../../ConstraintUtils"); const types_1 = require("../../types"); const Messages_1 = __importDefault(require("../../types/Messages")); const abstractEvaluationHandler_1 = require("./abstractEvaluationHandler"); class UriEvaluationHandler extends abstractEvaluationHandler_1.AbstractEvaluationHandler { constructor(client) { super(client); } getName() { return 'UriEvaluation'; } handle(definition, wrappedVcs) { var _a, _b, _c; // This filter is removed in V2 definition.input_descriptors.forEach((inDesc, descriptorIdx) => { const uris = definition.getVersion() !== types_1.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 = ((_a = definition.format) === null || _a === void 0 ? void 0 : _a.di) || ((_b = definition.format) === null || _b === void 0 ? void 0 : _b.di_vc) || ((_c = definition.format) === null || _c === void 0 ? void 0 : _c.di_vp); const descriptorMap = this.getResults() .filter((result) => result.status === ConstraintUtils_1.Status.INFO) .map((result) => { var _a, _b, _c, _d; let format = (_a = result.payload) === null || _a === void 0 ? void 0 : _a.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 = jsonpath_1.JSONPath.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 !== ssi_types_1.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 = jsonpath_1.JSONPath.nodes(definition, result.input_descriptor_path)[0].value; const inputDescriptorAllowsDataIntegrity = !inputDescriptor['format'] || ((_b = inputDescriptor === null || inputDescriptor === void 0 ? void 0 : inputDescriptor.format) === null || _b === void 0 ? void 0 : _b.di) || ((_c = inputDescriptor === null || inputDescriptor === void 0 ? void 0 : inputDescriptor.format) === null || _c === void 0 ? void 0 : _c.di_vc) || ((_d = inputDescriptor === null || inputDescriptor === void 0 ? void 0 : inputDescriptor.format) === null || _d === void 0 ? void 0 : _d.di_vp); if (commonCryptosuites.length > 0 && inputDescriptorAllowsDataIntegrity) { format = 'di_vc'; } } const inputDescriptor = jsonpath_1.JSONPath.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: (0, nanoid_1.nanoid)(), definition_id: definition.id, descriptor_map: descriptorMap, }; } } evaluateUris(wvc, verifiableCredentialUris, inputDescriptorsUris, idIdx, vcIdx, pdVersion) { let hasAnyMatch = false; if (pdVersion === types_1.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 (ssi_types_1.CredentialMapper.isMsoMdocDecodedCredential(credential)) { return uris; } // W3C credential if (ssi_types_1.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 === types_1.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 (ssi_types_1.CredentialMapper.isSdJwtDecodedCredential(credential)) { if (version === types_1.PEVersion.v1) { uris.push(credential.decodedPayload.vct); } } return uris; } createSuccessResultObject(wvc, inputDescriptorsUris, idIdx, vcIdx) { const result = this.createResult(idIdx, vcIdx); result.status = ConstraintUtils_1.Status.INFO; result.message = Messages_1.default.URI_EVALUATION_PASSED; result.payload = { format: wvc.format, vcContext: ssi_types_1.CredentialMapper.isW3cCredential(wvc.credential) ? wvc.credential['@context'] : undefined, vcCredentialSchema: ssi_types_1.CredentialMapper.isW3cCredential(wvc.credential) ? wvc.credential.credentialSchema : undefined, inputDescriptorsUris, }; return result; } createErrorResultObject(wvc, inputDescriptorsUris, idIdx, vcIdx) { const result = this.createResult(idIdx, vcIdx); result.status = ConstraintUtils_1.Status.ERROR; result.message = Messages_1.default.URI_EVALUATION_DIDNT_PASS; result.payload = { format: wvc.format, vcContext: ssi_types_1.CredentialMapper.isW3cCredential(wvc.credential) ? wvc.credential['@context'] : undefined, vcCredentialSchema: ssi_types_1.CredentialMapper.isW3cCredential(wvc.credential) ? wvc.credential.credentialSchema : undefined, inputDescriptorsUris, }; return result; } createWarnResultObject(idIdx, vcIdx) { const result = this.createResult(idIdx, vcIdx); result.status = ConstraintUtils_1.Status.WARN; result.message = Messages_1.default.URI_EVALUATION_DIDNT_PASS; result.payload = Messages_1.default.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: ConstraintUtils_1.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); } } exports.UriEvaluationHandler = UriEvaluationHandler; UriEvaluationHandler.HASHLINK_URL_ENCODED_REGEX = /hl:[a-zA-Z0-9]+:[a-zA-Z0-9]+/g; UriEvaluationHandler.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; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXJpRXZhbHVhdGlvbkhhbmRsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9saWIvZXZhbHVhdGlvbi9oYW5kbGVycy91cmlFdmFsdWF0aW9uSGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxzREFBeUQ7QUFFekQsbURBUTZCO0FBQzdCLG1DQUFnQztBQUVoQywyREFBK0M7QUFDL0MsdUNBQTJHO0FBQzNHLG9FQUErQztBQUkvQywyRUFBd0U7QUFFeEUsTUFBYSxvQkFBcUIsU0FBUSxxREFBeUI7SUFDakUsWUFBWSxNQUF3QjtRQUNsQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDaEIsQ0FBQztJQUVNLE9BQU87UUFDWixPQUFPLGVBQWUsQ0FBQztJQUN6QixDQUFDO0lBTU0sTUFBTSxDQUFDLFVBQTJDLEVBQUUsVUFBeUM7O1FBQ2xHLCtCQUErQjtRQUNJLFVBQVcsQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLENBQUMsQ0FBQyxNQUF5QixFQUFFLGFBQXFCLEVBQUUsRUFBRTtZQUM1SCxNQUFNLElBQUksR0FBYSxVQUFVLENBQUMsVUFBVSxFQUFFLEtBQUssaUJBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUN6RyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBZ0MsRUFBRSxZQUFvQixFQUFFLEVBQUU7Z0JBQzVFLE1BQU0sTUFBTSxHQUFhLG9CQUFvQixDQUFDLDJCQUEyQixDQUFDLEdBQUcsQ0FBQyxVQUFVLEVBQUUsVUFBVSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUM7Z0JBQ25ILElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsYUFBYSxFQUFF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