UNPKG

@animo-id/pex

Version:

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

210 lines 23.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.LimitDisclosureEvaluationHandler = void 0; const pex_models_1 = require("@sphereon/pex-models"); const ConstraintUtils_1 = require("../../ConstraintUtils"); const Messages_1 = __importDefault(require("../../types/Messages")); const PexCredentialMapper_1 = require("../../types/PexCredentialMapper"); const utils_1 = require("../../utils"); const abstractEvaluationHandler_1 = require("./abstractEvaluationHandler"); const markForSubmissionEvaluationHandler_1 = require("./markForSubmissionEvaluationHandler"); class LimitDisclosureEvaluationHandler extends abstractEvaluationHandler_1.AbstractEvaluationHandler { constructor(client) { super(client); } getName() { return 'LimitDisclosureEvaluation'; } handle(pd, wrappedVcs) { this.evaluateLimitDisclosure(pd.input_descriptors, wrappedVcs); } isLimitDisclosureSupported(eligibleInputDescriptors, wvc, vcIndex) { if (wvc.format === 'vc+sd-jwt' || wvc.format === 'mso_mdoc') return true; if (wvc.format === 'ldp' || wvc.format === 'jwt') return false; const limitDisclosureSignatures = this.client.limitDisclosureSignatureSuites; const decoded = wvc.decoded; const proofs = Array.isArray(decoded.proof) ? decoded.proof : decoded.proof ? [decoded.proof] : undefined; const requiredLimitDisclosureInputDescriptorIds = eligibleInputDescriptors .map(({ inputDescriptor: { constraints }, inputDescriptorIndex }) => (constraints === null || constraints === void 0 ? void 0 : constraints.limit_disclosure) === pex_models_1.Optionality.Required ? inputDescriptorIndex : undefined) .filter((id) => id !== undefined); if (!proofs || proofs.length === 0 || proofs.length > 1 || !proofs[0].type) { // todo: Support/inspect array based proofs if (requiredLimitDisclosureInputDescriptorIds.length > 0) { this.createLimitDisclosureNotSupportedResult(eligibleInputDescriptors.map((i) => i.inputDescriptorIndex), vcIndex, 'Multiple proofs on verifiable credential not supported for limit disclosure'); } return false; } const proof = proofs[0]; const signatureSuite = proof.cryptosuite ? `${proof.type}.${proof.cryptosuite}` : proof.type; if (!(limitDisclosureSignatures === null || limitDisclosureSignatures === void 0 ? void 0 : limitDisclosureSignatures.includes(signatureSuite))) { if (requiredLimitDisclosureInputDescriptorIds.length > 0) { this.createLimitDisclosureNotSupportedResult(requiredLimitDisclosureInputDescriptorIds, vcIndex, `Signature suite '${signatureSuite}' is not present in limitDisclosureSignatureSuites [${limitDisclosureSignatures.join(',')}]`); } return false; } return true; } evaluateLimitDisclosure(inputDescriptors, wrappedVcs) { wrappedVcs.forEach((wvc, vcIndex) => { const eligibleInputDescriptors = (0, markForSubmissionEvaluationHandler_1.eligibleInputDescriptorsForWrappedVc)(inputDescriptors, vcIndex, this.getResults()); if (eligibleInputDescriptors.length > 0 && this.isLimitDisclosureSupported(eligibleInputDescriptors, wvc, vcIndex)) { this.enforceLimitDisclosure(wrappedVcs, eligibleInputDescriptors, vcIndex); } }); } enforceLimitDisclosure(wrappedVcs, eligibleInputDescriptors, vcIndex) { var _a, _b, _c; const wvc = wrappedVcs[vcIndex]; if (PexCredentialMapper_1.PexCredentialMapper.isWrappedSdJwtVerifiableCredential(wvc)) { const presentationFrame = this.createSdJwtPresentationFrame(eligibleInputDescriptors, wvc.credential, vcIndex); // We update the SD-JWT to it's presentation format (remove disclosures, update pretty payload, etc..), except // we don't create or include the (optional) KB-JWT yet, this is done when we create the presentation if (presentationFrame) { (0, utils_1.applySdJwtLimitDisclosure)(wvc.credential, presentationFrame); wvc.decoded = wvc.credential.decodedPayload; // We need to overwrite the original, as that is returned in the selectFrom method // But we also want to keep the format of the original credential. wvc.original = PexCredentialMapper_1.PexCredentialMapper.isSdJwtDecodedCredential(wvc.original) ? wvc.credential : wvc.credential.compactSdJwtVc; for (const { inputDescriptorIndex, inputDescriptor } of eligibleInputDescriptors) { this.createSuccessResult(inputDescriptorIndex, `$[${vcIndex}]`, (_a = inputDescriptor.constraints) === null || _a === void 0 ? void 0 : _a.limit_disclosure); } } } else if (PexCredentialMapper_1.PexCredentialMapper.isWrappedMdocCredential(wvc)) { for (const { inputDescriptorIndex, inputDescriptor } of eligibleInputDescriptors) { this.createSuccessResult(inputDescriptorIndex, `$[${vcIndex}]`, (_b = inputDescriptor.constraints) === null || _b === void 0 ? void 0 : _b.limit_disclosure); } } else if (PexCredentialMapper_1.PexCredentialMapper.isWrappedW3CVerifiableCredential(wvc)) { const internalCredentialToSend = this.createVcWithRequiredFields(eligibleInputDescriptors, wvc.credential, vcIndex); /* When verifiableCredentialToSend is null/undefined an error is raised, the credential will * remain untouched and the verifiable credential won't be submitted. */ if (internalCredentialToSend) { wvc.credential = internalCredentialToSend; for (const { inputDescriptorIndex, inputDescriptor } of eligibleInputDescriptors) { this.createSuccessResult(inputDescriptorIndex, `$[${vcIndex}]`, (_c = inputDescriptor.constraints) === null || _c === void 0 ? void 0 : _c.limit_disclosure); } } } else { throw new Error('Unsupported format for selective disclosure'); } } createSdJwtPresentationFrame(inputDescriptors, vc, vcIndex) { var _a, _b; // Mapping of key -> true to indicate which values should be disclosed in an SD-JWT // Can be nested array / object const presentationFrame = {}; const processNestedObject = (obj, currentPath, basePath) => { if (obj === null || typeof obj !== 'object') { // For literal values, set the path to true in the presentation frame utils_1.JsonPathUtils.setValue(presentationFrame, currentPath, true); return; } // For arrays, process each element if (Array.isArray(obj)) { obj.forEach((item, index) => { processNestedObject(item, [...currentPath, index], basePath); }); return; } // For objects, process each child property Object.entries(obj).forEach(([key, value]) => { processNestedObject(value, [...currentPath, key], basePath); }); }; for (const { inputDescriptor, inputDescriptorIndex } of inputDescriptors) { for (const field of (_b = (_a = inputDescriptor.constraints) === null || _a === void 0 ? void 0 : _a.fields) !== null && _b !== void 0 ? _b : []) { if (field.path) { const inputField = utils_1.JsonPathUtils.extractInputField(vc.decodedPayload, field.path); if (inputField.length > 0) { const selectedField = inputField[0]; const fieldValue = utils_1.JsonPathUtils.getValue(vc.decodedPayload, selectedField.path); if (fieldValue !== null && typeof fieldValue === 'object') { // For objects, recursively process all nested fields processNestedObject(fieldValue, selectedField.path, selectedField.path); } else { // For literal values, just set the path to true utils_1.JsonPathUtils.setValue(presentationFrame, selectedField.path, true); } } else if (!('optional' in field && field.optional)) { this.createMandatoryFieldNotFoundResult(inputDescriptorIndex, vcIndex, field.path); return undefined; } } } } return presentationFrame; } createVcWithRequiredFields(inputDescriptors, vc, vcIndex) { var _a, _b; let credentialToSend = {}; credentialToSend = Object.assign(credentialToSend, vc); credentialToSend.credentialSubject = {}; for (const { inputDescriptor, inputDescriptorIndex } of inputDescriptors) { for (const field of (_b = (_a = inputDescriptor.constraints) === null || _a === void 0 ? void 0 : _a.fields) !== null && _b !== void 0 ? _b : []) { if (field.path) { const inputField = utils_1.JsonPathUtils.extractInputField(vc, field.path); if (inputField.length > 0) { credentialToSend = this.copyResultPathToDestinationCredential(inputField[0], vc, credentialToSend); } else if (!('optional' in field && field.optional)) { this.createMandatoryFieldNotFoundResult(inputDescriptorIndex, vcIndex, field.path); return undefined; } } } } return credentialToSend; } copyResultPathToDestinationCredential(requiredField, internalCredential, internalCredentialToSend) { //TODO: ESSIFI-186 let credentialSubject = Object.assign({}, internalCredential.credentialSubject); requiredField.path.forEach((e) => { if (credentialSubject[e]) { credentialSubject = { [e]: credentialSubject[e] }; } }); internalCredentialToSend.credentialSubject = Object.assign(Object.assign({}, internalCredentialToSend.credentialSubject), credentialSubject); return internalCredentialToSend; } createSuccessResult(idIdx, path, limitDisclosure) { return this.getResults().push({ input_descriptor_path: `$.input_descriptors[${idIdx}]`, verifiable_credential_path: `${path}`, evaluator: this.getName(), status: limitDisclosure === pex_models_1.Optionality.Required || limitDisclosure === pex_models_1.Optionality.Preferred ? ConstraintUtils_1.Status.INFO : ConstraintUtils_1.Status.WARN, message: Messages_1.default.LIMIT_DISCLOSURE_APPLIED, payload: undefined, }); } createMandatoryFieldNotFoundResult(idIdx, vcIdx, path) { return this.getResults().push({ input_descriptor_path: `$.input_descriptors[${idIdx}]`, verifiable_credential_path: `$[${vcIdx}]`, evaluator: this.getName(), status: ConstraintUtils_1.Status.ERROR, message: Messages_1.default.VERIFIABLE_CREDENTIAL_MANDATORY_FIELD_NOT_PRESENT, payload: path, }); } createLimitDisclosureNotSupportedResult(idIdxs, vcIdx, reason) { return this.getResults().push(...idIdxs.map((idIdx) => ({ input_descriptor_path: `$.input_descriptors[${idIdx}]`, verifiable_credential_path: `$[${vcIdx}]`, evaluator: this.getName(), status: ConstraintUtils_1.Status.ERROR, message: reason ? `${Messages_1.default.LIMIT_DISCLOSURE_NOT_SUPPORTED}. ${reason}` : Messages_1.default.LIMIT_DISCLOSURE_NOT_SUPPORTED, }))); } } exports.LimitDisclosureEvaluationHandler = LimitDisclosureEvaluationHandler; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGltaXREaXNjbG9zdXJlRXZhbHVhdGlvbkhhbmRsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9saWIvZXZhbHVhdGlvbi9oYW5kbGVycy9saW1pdERpc2Nsb3N1cmVFdmFsdWF0aW9uSGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxxREFBeUY7QUFXekYsMkRBQStDO0FBRS9DLG9FQUErQztBQUMvQyx5RUFBbUc7QUFDbkcsdUNBQXVFO0FBR3ZFLDJFQUF3RTtBQUN4RSw2RkFBNEY7QUFFNUYsTUFBYSxnQ0FBaUMsU0FBUSxxREFBeUI7SUFDN0UsWUFBWSxNQUF3QjtRQUNsQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDaEIsQ0FBQztJQUVNLE9BQU87UUFDWixPQUFPLDJCQUEyQixDQUFDO0lBQ3JDLENBQUM7SUFFTSxNQUFNLENBQUMsRUFBbUMsRUFBRSxVQUF5QztRQUMxRixJQUFJLENBQUMsdUJBQXVCLENBQUMsRUFBRSxDQUFDLGlCQUF3QyxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBQ3hGLENBQUM7SUFFTywwQkFBMEIsQ0FDaEMsd0JBQW9ELEVBQ3BELEdBQWdDLEVBQ2hDLE9BQWU7UUFFZixJQUFJLEdBQUcsQ0FBQyxNQUFNLEtBQUssV0FBVyxJQUFJLEdBQUcsQ0FBQyxNQUFNLEtBQUssVUFBVTtZQUFFLE9BQU8sSUFBSSxDQUFDO1FBQ3pFLElBQUksR0FBRyxDQUFDLE1BQU0sS0FBSyxLQUFLLElBQUksR0FBRyxDQUFDLE1BQU0sS0FBSyxLQUFLO1lBQUUsT0FBTyxLQUFLLENBQUM7UUFFL0QsTUFBTSx5QkFBeUIsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLDhCQUE4QixDQUFDO1FBQzdFLE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxPQUFnQyxDQUFDO1FBQ3JELE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxD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