diff --git a/lib/evaluation/core/submissionRequirementMatch.ts b/lib/evaluation/core/submissionRequirementMatch.ts index 455e3f9a..9188c1f7 100644 --- a/lib/evaluation/core/submissionRequirementMatch.ts +++ b/lib/evaluation/core/submissionRequirementMatch.ts @@ -1,6 +1,32 @@ import { Rules } from '@sphereon/pex-models'; +export enum SubmissionRequirementMatchType { + /** + * Match for a submission_requirements entry in the presentation definition. If the match type + * is `SubmissionRequirement` the {@link SubmissionRequirementMatch.id} property refers to the index + * of the `submission_requirements` entry in the presentation definition. + * + * If the match is a nested match result, this match type refers to the nested index. E.g. a presentation + * definition has three `submission_requirements` entries where the second submission requirement (index 1) + * has two `from_nested` `submission_requirements` entries and this match refers to the second (index 1) of + * this from nested, the {@link SubmissionRequirementMatch.id} property of the outer match refers to the outer index + * in the `submission_requirements` entries, and the nested {@link SubmissionRequirementMatch.id} refers to index of the + * `from_nested` entries. This can go multiple layers deep. + */ + SubmissionRequirement = 'SubmissionRequirement', + + /** + * Match for an input_descriptors entry in the presentation definition. This type will be used + * if no submission_requirements are present in the presentation definition. If the match type + * is `InputDescriptor` the {@link SubmissionRequirementMatch.id} property refers to the `id` + * of the `input_descriptors` entry in the presentation definition. + */ + InputDescriptor = 'InputDescriptor', +} + export interface SubmissionRequirementMatch { + type: SubmissionRequirementMatchType; + id: string | number; name?: string; rule: Rules; min?: number; diff --git a/lib/evaluation/evaluationClientWrapper.ts b/lib/evaluation/evaluationClientWrapper.ts index 257b11a6..4c16c280 100644 --- a/lib/evaluation/evaluationClientWrapper.ts +++ b/lib/evaluation/evaluationClientWrapper.ts @@ -22,7 +22,14 @@ import { import { JsonPathUtils, ObjectUtils } from '../utils'; import { getVpFormatForVcFormat } from '../utils/formatMap'; -import { EvaluationResults, HandlerCheckResult, PresentationEvaluationResults, SelectResults, SubmissionRequirementMatch } from './core'; +import { + EvaluationResults, + HandlerCheckResult, + PresentationEvaluationResults, + SelectResults, + SubmissionRequirementMatch, + SubmissionRequirementMatchType, +} from './core'; import { EvaluationClient } from './evaluationClient'; interface SubmissionSatisfiesSubmissionRequirementResult { @@ -252,13 +259,17 @@ export class EvaluationClientWrapper { marked: HandlerCheckResult[], ): SubmissionRequirementMatch[] { const submissionRequirementMatches: SubmissionRequirementMatch[] = []; - for (const sr of submissionRequirements) { + for (const [srIndex, sr] of Object.entries(submissionRequirements)) { // Create a default SubmissionRequirementMatch object const srm: SubmissionRequirementMatch = { - name: pd.name || pd.id, rule: sr.rule, vc_path: [], + + name: sr.name, + type: SubmissionRequirementMatchType.SubmissionRequirement, + id: Number(srIndex), }; + if (sr.from) { srm.from = sr.from; } @@ -268,12 +279,9 @@ export class EvaluationClientWrapper { sr.count ? (srm.count = sr.count) : undefined; if (sr.from) { - const matchingDescriptors = this.mapMatchingDescriptors(pd, sr, marked); - if (matchingDescriptors) { - srm.vc_path.push(...matchingDescriptors.vc_path); - srm.name = matchingDescriptors.name; - submissionRequirementMatches.push(srm); - } + const matchingVcPaths = this.getMatchingVcPathsForSubmissionRequirement(pd, sr, marked); + srm.vc_path.push(...matchingVcPaths); + submissionRequirementMatches.push(srm); } else if (sr.from_nested) { // Recursive call to matchSubmissionRequirements for nested requirements try { @@ -298,12 +306,16 @@ export class EvaluationClientWrapper { continue; } for (const vcPath of sameIdVcs) { - const idRes = JsonPathUtils.extractInputField(pd, [idPath]); - if (idRes.length) { + const inputDescriptorResults = JsonPathUtils.extractInputField(pd, [idPath]); + if (inputDescriptorResults.length) { + const inputDescriptor = inputDescriptorResults[0].value; submissionRequirementMatches.push({ - name: (idRes[0].value as InputDescriptorV1 | InputDescriptorV2).name || (idRes[0].value as InputDescriptorV1 | InputDescriptorV2).id, + name: inputDescriptor.name || inputDescriptor.id, rule: Rules.All, vc_path: [vcPath], + + type: SubmissionRequirementMatchType.InputDescriptor, + id: inputDescriptor.id, }); } } @@ -311,29 +323,26 @@ export class EvaluationClientWrapper { return this.removeDuplicateSubmissionRequirementMatches(submissionRequirementMatches); } - private mapMatchingDescriptors( + private getMatchingVcPathsForSubmissionRequirement( pd: IInternalPresentationDefinition, sr: SubmissionRequirement, marked: HandlerCheckResult[], - ): SubmissionRequirementMatch { - const srm: Partial = { rule: sr.rule, vc_path: [] }; - if (sr?.from) { - srm.from = sr.from; - // updating the srm.name everytime and since we have only one, we're sending the last one - for (const m of marked) { - const inDesc: InputDescriptorV2 = jp.query(pd, m.input_descriptor_path)[0]; - if (inDesc.group && inDesc.group.indexOf(sr.from) === -1) { - continue; - } - srm.name = inDesc.name || inDesc.id; - if (m.payload.group.includes(sr.from)) { - if (srm.vc_path?.indexOf(m.verifiable_credential_path) === -1) { - srm.vc_path.push(m.verifiable_credential_path); - } - } + ): string[] { + const vcPaths = new Set(); + + if (!sr.from) return Array.from(vcPaths); + + for (const m of marked) { + const inputDescriptor: InputDescriptorV2 = jp.query(pd, m.input_descriptor_path)[0]; + if (inputDescriptor.group && inputDescriptor.group.indexOf(sr.from) === -1) { + continue; + } + if (m.payload.group.includes(sr.from)) { + vcPaths.add(m.verifiable_credential_path); } } - return srm as SubmissionRequirementMatch; + + return Array.from(vcPaths); } public evaluate( diff --git a/lib/utils/jsonPathUtils.ts b/lib/utils/jsonPathUtils.ts index da8d7a4d..18296c71 100644 --- a/lib/utils/jsonPathUtils.ts +++ b/lib/utils/jsonPathUtils.ts @@ -48,7 +48,7 @@ export class JsonPathUtils { } result: [ { value: 19, path: [ '$', 'details', 'information', 0, 'age' ] } ] */ - public static extractInputField(obj: InputFieldType, paths: string[]): { value: unknown; path: PathComponent[] }[] { + public static extractInputField(obj: InputFieldType, paths: string[]): { value: PathValue; path: PathComponent[] }[] { let result: { value: unknown; path: PathComponent[] }[] = []; if (paths) { for (const path of paths) { @@ -58,7 +58,7 @@ export class JsonPathUtils { } } } - return result; + return result as { value: PathValue; path: PathComponent[] }[]; } public static changePropertyNameRecursively( diff --git a/test/PEX.spec.ts b/test/PEX.spec.ts index 7b566c0f..daa2d451 100644 --- a/test/PEX.spec.ts +++ b/test/PEX.spec.ts @@ -1236,6 +1236,198 @@ describe('evaluate', () => { ]); }); + it('selectFrom adds id of input descriptor and type of match when not using submission_requirements', () => { + const sdJwtVcs = [ + 'eyJ4NWMiOlsiTUlJQ2REQ0NBaHVnQXdJQkFnSUJBakFLQmdncWhrak9QUVFEQWpDQmlERUxNQWtHQTFVRUJoTUNSRVV4RHpBTkJnTlZCQWNNQmtKbGNteHBiakVkTUJzR0ExVUVDZ3dVUW5WdVpHVnpaSEoxWTJ0bGNtVnBJRWR0WWtneEVUQVBCZ05WQkFzTUNGUWdRMU1nU1VSRk1UWXdOQVlEVlFRRERDMVRVRkpKVGtRZ1JuVnVhMlVnUlZWRVNTQlhZV3hzWlhRZ1VISnZkRzkwZVhCbElFbHpjM1ZwYm1jZ1EwRXdIaGNOTWpRd05UTXhNRGd4TXpFM1doY05NalV3TnpBMU1EZ3hNekUzV2pCc01Rc3dDUVlEVlFRR0V3SkVSVEVkTUJzR0ExVUVDZ3dVUW5WdVpHVnpaSEoxWTJ0bGNtVnBJRWR0WWtneENqQUlCZ05WQkFzTUFVa3hNakF3QmdOVkJBTU1LVk5RVWtsT1JDQkdkVzVyWlNCRlZVUkpJRmRoYkd4bGRDQlFjbTkwYjNSNWNHVWdTWE56ZFdWeU1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRU9GQnE0WU1LZzR3NWZUaWZzeXR3QnVKZi83RTdWaFJQWGlObTUyUzNxMUVUSWdCZFh5REsza1Z4R3hnZUhQaXZMUDN1dU12UzZpREVjN3FNeG12ZHVLT0JrRENCalRBZEJnTlZIUTRFRmdRVWlQaENrTEVyRFhQTFcyL0owV1ZlZ2h5dyttSXdEQVlEVlIwVEFRSC9CQUl3QURBT0JnTlZIUThCQWY4RUJBTUNCNEF3TFFZRFZSMFJCQ1l3SklJaVpHVnRieTV3YVdRdGFYTnpkV1Z5TG1KMWJtUmxjMlJ5ZFdOclpYSmxhUzVrWlRBZkJnTlZIU01FR0RBV2dCVFVWaGpBaVRqb0RsaUVHTWwyWXIrcnU4V1F2akFLQmdncWhrak9QUVFEQWdOSEFEQkVBaUFiZjVUemtjUXpoZldvSW95aTFWTjdkOEk5QnNGS20xTVdsdVJwaDJieUdRSWdLWWtkck5mMnhYUGpWU2JqVy9VLzVTNXZBRUM1WHhjT2FudXNPQnJvQmJVPSIsIk1JSUNlVENDQWlDZ0F3SUJBZ0lVQjVFOVFWWnRtVVljRHRDaktCL0gzVlF2NzJnd0NnWUlLb1pJemowRUF3SXdnWWd4Q3pBSkJnTlZCQVlUQWtSRk1ROHdEUVlEVlFRSERBWkNaWEpzYVc0eEhUQWJCZ05WQkFvTUZFSjFibVJsYzJSeWRXTnJaWEpsYVNCSGJXSklNUkV3RHdZRFZRUUxEQWhVSUVOVElFbEVSVEUyTURRR0ExVUVBd3d0VTFCU1NVNUVJRVoxYm10bElFVlZSRWtnVjJGc2JHVjBJRkJ5YjNSdmRIbHdaU0JKYzNOMWFXNW5JRU5CTUI0WERUSTBNRFV6TVRBMk5EZ3dPVm9YRFRNME1EVXlPVEEyTkRnd09Wb3dnWWd4Q3pBSkJnTlZCQVlUQWtSRk1ROHdEUVlEVlFRSERBWkNaWEpzYVc0eEhUQWJCZ05WQkFvTUZFSjFibVJsYzJSeWRXTnJaWEpsYVNCSGJXSklNUkV3RHdZRFZRUUxEQWhVSUVOVElFbEVSVEUyTURRR0ExVUVBd3d0VTFCU1NVNUVJRVoxYm10bElFVlZSRWtnVjJGc2JHVjBJRkJ5YjNSdmRIbHdaU0JKYzNOMWFXNW5JRU5CTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFWUd6ZHdGRG5jNytLbjVpYkF2Q09NOGtlNzdWUXhxZk1jd1pMOElhSUErV0NST2NDZm1ZL2dpSDkycU1ydTVwL2t5T2l2RTBSQy9JYmRNT052RG9VeWFObU1HUXdIUVlEVlIwT0JCWUVGTlJXR01DSk9PZ09XSVFZeVhaaXY2dTd4WkMrTUI4R0ExVWRJd1FZTUJhQUZOUldHTUNKT09nT1dJUVl5WFppdjZ1N3haQytNQklHQTFVZEV3RUIvd1FJTUFZQkFmOENBUUF3RGdZRFZSMFBBUUgvQkFRREFnR0dNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJR0VtN3drWktIdC9hdGI0TWRGblhXNnlybndNVVQydTEzNmdkdGwxMFk2aEFpQnVURnF2Vll0aDFyYnh6Q1AweFdaSG1RSzlrVnl4bjhHUGZYMjdFSXp6c3c9PSJdLCJraWQiOiJNSUdVTUlHT3BJR0xNSUdJTVFzd0NRWURWUVFHRXdKRVJURVBNQTBHQTFVRUJ3d0dRbVZ5YkdsdU1SMHdHd1lEVlFRS0RCUkNkVzVrWlhOa2NuVmphMlZ5WldrZ1IyMWlTREVSTUE4R0ExVUVDd3dJVkNCRFV5QkpSRVV4TmpBMEJnTlZCQU1NTFZOUVVrbE9SQ0JHZFc1clpTQkZWVVJKSUZkaGJHeGxkQ0JRY205MGIzUjVjR1VnU1hOemRXbHVaeUJEUVFJQkFnPT0iLCJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFUzI1NiJ9.eyJ2Y3QiOiJJRCIsIl9zZF9hbGciOiJzaGEtMjU2IiwiaXNzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbSIsImNuZiI6eyJqd2siOnsia3R5IjoiRUMiLCJjcnYiOiJQLTI1NiIsImtpZCI6IkhOa3V2RDNmMTMzcG9uZGRJcmZYbmZxQ0U4T1VBRzBrcFNKZHlzUFZMUU0iLCJ4IjoiVDVWWHYtUUpmMzhBblhkOTZxcS1qNmZjSVd3NXZjTXpqNUllRWFMQm9qSSIsInkiOiJyandIN0I5RmVXc1VoWURmTWpaeDVCYWFLalVCWWdTbU1vQTM4S3ZIWkRrIn19LCJpYXQiOjE3MjQ4Njg0Mzl9.PxjYlyQJYu5tYIwOu-VPsIBFXB1z-WI7_QSRs8mPWeLlPfJ8POs23vZtrcBD-lXFQm38z4QRG9zw_yKYF0qDLw~', + 'eyJ4NWMiOlsiTUlJQ2REQ0NBaHVnQXdJQkFnSUJBakFLQmdncWhrak9QUVFEQWpDQmlERUxNQWtHQTFVRUJoTUNSRVV4RHpBTkJnTlZCQWNNQmtKbGNteHBiakVkTUJzR0ExVUVDZ3dVUW5WdVpHVnpaSEoxWTJ0bGNtVnBJRWR0WWtneEVUQVBCZ05WQkFzTUNGUWdRMU1nU1VSRk1UWXdOQVlEVlFRRERDMVRVRkpKVGtRZ1JuVnVhMlVnUlZWRVNTQlhZV3hzWlhRZ1VISnZkRzkwZVhCbElFbHpjM1ZwYm1jZ1EwRXdIaGNOTWpRd05UTXhNRGd4TXpFM1doY05NalV3TnpBMU1EZ3hNekUzV2pCc01Rc3dDUVlEVlFRR0V3SkVSVEVkTUJzR0ExVUVDZ3dVUW5WdVpHVnpaSEoxWTJ0bGNtVnBJRWR0WWtneENqQUlCZ05WQkFzTUFVa3hNakF3QmdOVkJBTU1LVk5RVWtsT1JDQkdkVzVyWlNCRlZVUkpJRmRoYkd4bGRDQlFjbTkwYjNSNWNHVWdTWE56ZFdWeU1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRU9GQnE0WU1LZzR3NWZUaWZzeXR3QnVKZi83RTdWaFJQWGlObTUyUzNxMUVUSWdCZFh5REsza1Z4R3hnZUhQaXZMUDN1dU12UzZpREVjN3FNeG12ZHVLT0JrRENCalRBZEJnTlZIUTRFRmdRVWlQaENrTEVyRFhQTFcyL0owV1ZlZ2h5dyttSXdEQVlEVlIwVEFRSC9CQUl3QURBT0JnTlZIUThCQWY4RUJBTUNCNEF3TFFZRFZSMFJCQ1l3SklJaVpHVnRieTV3YVdRdGFYTnpkV1Z5TG1KMWJtUmxjMlJ5ZFdOclpYSmxhUzVrWlRBZkJnTlZIU01FR0RBV2dCVFVWaGpBaVRqb0RsaUVHTWwyWXIrcnU4V1F2akFLQmdncWhrak9QUVFEQWdOSEFEQkVBaUFiZjVUemtjUXpoZldvSW95aTFWTjdkOEk5QnNGS20xTVdsdVJwaDJieUdRSWdLWWtkck5mMnhYUGpWU2JqVy9VLzVTNXZBRUM1WHhjT2FudXNPQnJvQmJVPSIsIk1JSUNlVENDQWlDZ0F3SUJBZ0lVQjVFOVFWWnRtVVljRHRDaktCL0gzVlF2NzJnd0NnWUlLb1pJemowRUF3SXdnWWd4Q3pBSkJnTlZCQVlUQWtSRk1ROHdEUVlEVlFRSERBWkNaWEpzYVc0eEhUQWJCZ05WQkFvTUZFSjFibVJsYzJSeWRXTnJaWEpsYVNCSGJXSklNUkV3RHdZRFZRUUxEQWhVSUVOVElFbEVSVEUyTURRR0ExVUVBd3d0VTFCU1NVNUVJRVoxYm10bElFVlZSRWtnVjJGc2JHVjBJRkJ5YjNSdmRIbHdaU0JKYzNOMWFXNW5JRU5CTUI0WERUSTBNRFV6TVRBMk5EZ3dPVm9YRFRNME1EVXlPVEEyTkRnd09Wb3dnWWd4Q3pBSkJnTlZCQVlUQWtSRk1ROHdEUVlEVlFRSERBWkNaWEpzYVc0eEhUQWJCZ05WQkFvTUZFSjFibVJsYzJSeWRXTnJaWEpsYVNCSGJXSklNUkV3RHdZRFZRUUxEQWhVSUVOVElFbEVSVEUyTURRR0ExVUVBd3d0VTFCU1NVNUVJRVoxYm10bElFVlZSRWtnVjJGc2JHVjBJRkJ5YjNSdmRIbHdaU0JKYzNOMWFXNW5JRU5CTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFWUd6ZHdGRG5jNytLbjVpYkF2Q09NOGtlNzdWUXhxZk1jd1pMOElhSUErV0NST2NDZm1ZL2dpSDkycU1ydTVwL2t5T2l2RTBSQy9JYmRNT052RG9VeWFObU1HUXdIUVlEVlIwT0JCWUVGTlJXR01DSk9PZ09XSVFZeVhaaXY2dTd4WkMrTUI4R0ExVWRJd1FZTUJhQUZOUldHTUNKT09nT1dJUVl5WFppdjZ1N3haQytNQklHQTFVZEV3RUIvd1FJTUFZQkFmOENBUUF3RGdZRFZSMFBBUUgvQkFRREFnR0dNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJR0VtN3drWktIdC9hdGI0TWRGblhXNnlybndNVVQydTEzNmdkdGwxMFk2aEFpQnVURnF2Vll0aDFyYnh6Q1AweFdaSG1RSzlrVnl4bjhHUGZYMjdFSXp6c3c9PSJdLCJraWQiOiJNSUdVTUlHT3BJR0xNSUdJTVFzd0NRWURWUVFHRXdKRVJURVBNQTBHQTFVRUJ3d0dRbVZ5YkdsdU1SMHdHd1lEVlFRS0RCUkNkVzVrWlhOa2NuVmphMlZ5WldrZ1IyMWlTREVSTUE4R0ExVUVDd3dJVkNCRFV5QkpSRVV4TmpBMEJnTlZCQU1NTFZOUVVrbE9SQ0JHZFc1clpTQkZWVVJKSUZkaGJHeGxkQ0JRY205MGIzUjVjR1VnU1hOemRXbHVaeUJEUVFJQkFnPT0iLCJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFUzI1NiJ9.eyJ2Y3QiOiJEUklWSU5HX0xJQ0VOQ0UiLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vZXhhbXBsZS5jb20iLCJjbmYiOnsiandrIjp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJraWQiOiJITmt1dkQzZjEzM3BvbmRkSXJmWG5mcUNFOE9VQUcwa3BTSmR5c1BWTFFNIiwieCI6IlQ1Vlh2LVFKZjM4QW5YZDk2cXEtajZmY0lXdzV2Y016ajVJZUVhTEJvakkiLCJ5Ijoicmp3SDdCOUZlV3NVaFlEZk1qWng1QmFhS2pVQllnU21Nb0EzOEt2SFpEayJ9fSwiaWF0IjoxNzI0ODY4NDM5fQ.PxjYlyQJYu5tYIwOu-VPsIBFXB1z-WI7_QSRs8mPWeLlPfJ8POs23vZtrcBD-lXFQm38z4QRG9zw_yKYF0qDLw~', + 'eyJ4NWMiOlsiTUlJQ2REQ0NBaHVnQXdJQkFnSUJBakFLQmdncWhrak9QUVFEQWpDQmlERUxNQWtHQTFVRUJoTUNSRVV4RHpBTkJnTlZCQWNNQmtKbGNteHBiakVkTUJzR0ExVUVDZ3dVUW5WdVpHVnpaSEoxWTJ0bGNtVnBJRWR0WWtneEVUQVBCZ05WQkFzTUNGUWdRMU1nU1VSRk1UWXdOQVlEVlFRRERDMVRVRkpKVGtRZ1JuVnVhMlVnUlZWRVNTQlhZV3hzWlhRZ1VISnZkRzkwZVhCbElFbHpjM1ZwYm1jZ1EwRXdIaGNOTWpRd05UTXhNRGd4TXpFM1doY05NalV3TnpBMU1EZ3hNekUzV2pCc01Rc3dDUVlEVlFRR0V3SkVSVEVkTUJzR0ExVUVDZ3dVUW5WdVpHVnpaSEoxWTJ0bGNtVnBJRWR0WWtneENqQUlCZ05WQkFzTUFVa3hNakF3QmdOVkJBTU1LVk5RVWtsT1JDQkdkVzVyWlNCRlZVUkpJRmRoYkd4bGRDQlFjbTkwYjNSNWNHVWdTWE56ZFdWeU1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRU9GQnE0WU1LZzR3NWZUaWZzeXR3QnVKZi83RTdWaFJQWGlObTUyUzNxMUVUSWdCZFh5REsza1Z4R3hnZUhQaXZMUDN1dU12UzZpREVjN3FNeG12ZHVLT0JrRENCalRBZEJnTlZIUTRFRmdRVWlQaENrTEVyRFhQTFcyL0owV1ZlZ2h5dyttSXdEQVlEVlIwVEFRSC9CQUl3QURBT0JnTlZIUThCQWY4RUJBTUNCNEF3TFFZRFZSMFJCQ1l3SklJaVpHVnRieTV3YVdRdGFYTnpkV1Z5TG1KMWJtUmxjMlJ5ZFdOclpYSmxhUzVrWlRBZkJnTlZIU01FR0RBV2dCVFVWaGpBaVRqb0RsaUVHTWwyWXIrcnU4V1F2akFLQmdncWhrak9QUVFEQWdOSEFEQkVBaUFiZjVUemtjUXpoZldvSW95aTFWTjdkOEk5QnNGS20xTVdsdVJwaDJieUdRSWdLWWtkck5mMnhYUGpWU2JqVy9VLzVTNXZBRUM1WHhjT2FudXNPQnJvQmJVPSIsIk1JSUNlVENDQWlDZ0F3SUJBZ0lVQjVFOVFWWnRtVVljRHRDaktCL0gzVlF2NzJnd0NnWUlLb1pJemowRUF3SXdnWWd4Q3pBSkJnTlZCQVlUQWtSRk1ROHdEUVlEVlFRSERBWkNaWEpzYVc0eEhUQWJCZ05WQkFvTUZFSjFibVJsYzJSeWRXTnJaWEpsYVNCSGJXSklNUkV3RHdZRFZRUUxEQWhVSUVOVElFbEVSVEUyTURRR0ExVUVBd3d0VTFCU1NVNUVJRVoxYm10bElFVlZSRWtnVjJGc2JHVjBJRkJ5YjNSdmRIbHdaU0JKYzNOMWFXNW5JRU5CTUI0WERUSTBNRFV6TVRBMk5EZ3dPVm9YRFRNME1EVXlPVEEyTkRnd09Wb3dnWWd4Q3pBSkJnTlZCQVlUQWtSRk1ROHdEUVlEVlFRSERBWkNaWEpzYVc0eEhUQWJCZ05WQkFvTUZFSjFibVJsYzJSeWRXTnJaWEpsYVNCSGJXSklNUkV3RHdZRFZRUUxEQWhVSUVOVElFbEVSVEUyTURRR0ExVUVBd3d0VTFCU1NVNUVJRVoxYm10bElFVlZSRWtnVjJGc2JHVjBJRkJ5YjNSdmRIbHdaU0JKYzNOMWFXNW5JRU5CTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFWUd6ZHdGRG5jNytLbjVpYkF2Q09NOGtlNzdWUXhxZk1jd1pMOElhSUErV0NST2NDZm1ZL2dpSDkycU1ydTVwL2t5T2l2RTBSQy9JYmRNT052RG9VeWFObU1HUXdIUVlEVlIwT0JCWUVGTlJXR01DSk9PZ09XSVFZeVhaaXY2dTd4WkMrTUI4R0ExVWRJd1FZTUJhQUZOUldHTUNKT09nT1dJUVl5WFppdjZ1N3haQytNQklHQTFVZEV3RUIvd1FJTUFZQkFmOENBUUF3RGdZRFZSMFBBUUgvQkFRREFnR0dNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJR0VtN3drWktIdC9hdGI0TWRGblhXNnlybndNVVQydTEzNmdkdGwxMFk2aEFpQnVURnF2Vll0aDFyYnh6Q1AweFdaSG1RSzlrVnl4bjhHUGZYMjdFSXp6c3c9PSJdLCJraWQiOiJNSUdVTUlHT3BJR0xNSUdJTVFzd0NRWURWUVFHRXdKRVJURVBNQTBHQTFVRUJ3d0dRbVZ5YkdsdU1SMHdHd1lEVlFRS0RCUkNkVzVrWlhOa2NuVmphMlZ5WldrZ1IyMWlTREVSTUE4R0ExVUVDd3dJVkNCRFV5QkpSRVV4TmpBMEJnTlZCQU1NTFZOUVVrbE9SQ0JHZFc1clpTQkZWVVJKSUZkaGJHeGxkQ0JRY205MGIzUjVjR1VnU1hOemRXbHVaeUJEUVFJQkFnPT0iLCJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFUzI1NiJ9.eyJ2Y3QiOiJSRVNJREVOQ0VfUEVSTUlUIiwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tIiwiY25mIjp7Imp3ayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2Iiwia2lkIjoiSE5rdXZEM2YxMzNwb25kZElyZlhuZnFDRThPVUFHMGtwU0pkeXNQVkxRTSIsIngiOiJUNVZYdi1RSmYzOEFuWGQ5NnFxLWo2ZmNJV3c1dmNNemo1SWVFYUxCb2pJIiwieSI6InJqd0g3QjlGZVdzVWhZRGZNalp4NUJhYUtqVUJZZ1NtTW9BMzhLdkhaRGsifX0sImlhdCI6MTcyNDg2ODQzOX0.PxjYlyQJYu5tYIwOu-VPsIBFXB1z-WI7_QSRs8mPWeLlPfJ8POs23vZtrcBD-lXFQm38z4QRG9zw_yKYF0qDLw~', + ]; + const pd = { + id: 'OverAgeCheck', + purpose: 'Age check', + input_descriptors: [ + { + name: 'Residence permit date of birth and photo', + id: 'ResidencePermit', + constraints: { + limit_disclosure: 'required', + fields: [ + { + path: ['$.vc.type.*', '$.vct', '$.type'], + filter: { + type: 'string', + const: 'RESIDENCE_PERMIT', + }, + }, + ], + }, + }, + { + name: 'ID date of birth and photo', + id: 'IDDoB', + constraints: { + limit_disclosure: 'required', + fields: [ + { + path: ['$.vc.type.*', '$.vct', '$.type'], + filter: { + type: 'string', + const: 'ID', + }, + }, + ], + }, + }, + { + name: 'Driving licence date of birth and photo', + id: 'DrivingLicenceDoB', + constraints: { + limit_disclosure: 'required', + fields: [ + { + path: ['$.vc.type.*', '$.vct', '$.type'], + filter: { + type: 'string', + const: 'DRIVING_LICENCE', + }, + }, + ], + }, + }, + ], + } satisfies IPresentationDefinition; + const pex: PEX = new PEX({ hasher }); + + const result = pex.selectFrom(pd, sdJwtVcs); + + expect(result.matches).toEqual([ + { + name: 'Residence permit date of birth and photo', + rule: 'all', + vc_path: ['$.verifiableCredential[0]'], + type: 'InputDescriptor', + id: 'ResidencePermit', + }, + { + name: 'ID date of birth and photo', + rule: 'all', + vc_path: ['$.verifiableCredential[1]'], + type: 'InputDescriptor', + id: 'IDDoB', + }, + { + name: 'Driving licence date of birth and photo', + rule: 'all', + vc_path: ['$.verifiableCredential[2]'], + type: 'InputDescriptor', + id: 'DrivingLicenceDoB', + }, + ]); + }); + + it('selectFrom adds index of submission requirement as id and type of match when using submission_requirements', () => { + const sdJwtVcs = [ + 'eyJ4NWMiOlsiTUlJQ2REQ0NBaHVnQXdJQkFnSUJBakFLQmdncWhrak9QUVFEQWpDQmlERUxNQWtHQTFVRUJoTUNSRVV4RHpBTkJnTlZCQWNNQmtKbGNteHBiakVkTUJzR0ExVUVDZ3dVUW5WdVpHVnpaSEoxWTJ0bGNtVnBJRWR0WWtneEVUQVBCZ05WQkFzTUNGUWdRMU1nU1VSRk1UWXdOQVlEVlFRRERDMVRVRkpKVGtRZ1JuVnVhMlVnUlZWRVNTQlhZV3hzWlhRZ1VISnZkRzkwZVhCbElFbHpjM1ZwYm1jZ1EwRXdIaGNOTWpRd05UTXhNRGd4TXpFM1doY05NalV3TnpBMU1EZ3hNekUzV2pCc01Rc3dDUVlEVlFRR0V3SkVSVEVkTUJzR0ExVUVDZ3dVUW5WdVpHVnpaSEoxWTJ0bGNtVnBJRWR0WWtneENqQUlCZ05WQkFzTUFVa3hNakF3QmdOVkJBTU1LVk5RVWtsT1JDQkdkVzVyWlNCRlZVUkpJRmRoYkd4bGRDQlFjbTkwYjNSNWNHVWdTWE56ZFdWeU1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRU9GQnE0WU1LZzR3NWZUaWZzeXR3QnVKZi83RTdWaFJQWGlObTUyUzNxMUVUSWdCZFh5REsza1Z4R3hnZUhQaXZMUDN1dU12UzZpREVjN3FNeG12ZHVLT0JrRENCalRBZEJnTlZIUTRFRmdRVWlQaENrTEVyRFhQTFcyL0owV1ZlZ2h5dyttSXdEQVlEVlIwVEFRSC9CQUl3QURBT0JnTlZIUThCQWY4RUJBTUNCNEF3TFFZRFZSMFJCQ1l3SklJaVpHVnRieTV3YVdRdGFYTnpkV1Z5TG1KMWJtUmxjMlJ5ZFdOclpYSmxhUzVrWlRBZkJnTlZIU01FR0RBV2dCVFVWaGpBaVRqb0RsaUVHTWwyWXIrcnU4V1F2akFLQmdncWhrak9QUVFEQWdOSEFEQkVBaUFiZjVUemtjUXpoZldvSW95aTFWTjdkOEk5QnNGS20xTVdsdVJwaDJieUdRSWdLWWtkck5mMnhYUGpWU2JqVy9VLzVTNXZBRUM1WHhjT2FudXNPQnJvQmJVPSIsIk1JSUNlVENDQWlDZ0F3SUJBZ0lVQjVFOVFWWnRtVVljRHRDaktCL0gzVlF2NzJnd0NnWUlLb1pJemowRUF3SXdnWWd4Q3pBSkJnTlZCQVlUQWtSRk1ROHdEUVlEVlFRSERBWkNaWEpzYVc0eEhUQWJCZ05WQkFvTUZFSjFibVJsYzJSeWRXTnJaWEpsYVNCSGJXSklNUkV3RHdZRFZRUUxEQWhVSUVOVElFbEVSVEUyTURRR0ExVUVBd3d0VTFCU1NVNUVJRVoxYm10bElFVlZSRWtnVjJGc2JHVjBJRkJ5YjNSdmRIbHdaU0JKYzNOMWFXNW5JRU5CTUI0WERUSTBNRFV6TVRBMk5EZ3dPVm9YRFRNME1EVXlPVEEyTkRnd09Wb3dnWWd4Q3pBSkJnTlZCQVlUQWtSRk1ROHdEUVlEVlFRSERBWkNaWEpzYVc0eEhUQWJCZ05WQkFvTUZFSjFibVJsYzJSeWRXTnJaWEpsYVNCSGJXSklNUkV3RHdZRFZRUUxEQWhVSUVOVElFbEVSVEUyTURRR0ExVUVBd3d0VTFCU1NVNUVJRVoxYm10bElFVlZSRWtnVjJGc2JHVjBJRkJ5YjNSdmRIbHdaU0JKYzNOMWFXNW5JRU5CTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFWUd6ZHdGRG5jNytLbjVpYkF2Q09NOGtlNzdWUXhxZk1jd1pMOElhSUErV0NST2NDZm1ZL2dpSDkycU1ydTVwL2t5T2l2RTBSQy9JYmRNT052RG9VeWFObU1HUXdIUVlEVlIwT0JCWUVGTlJXR01DSk9PZ09XSVFZeVhaaXY2dTd4WkMrTUI4R0ExVWRJd1FZTUJhQUZOUldHTUNKT09nT1dJUVl5WFppdjZ1N3haQytNQklHQTFVZEV3RUIvd1FJTUFZQkFmOENBUUF3RGdZRFZSMFBBUUgvQkFRREFnR0dNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJR0VtN3drWktIdC9hdGI0TWRGblhXNnlybndNVVQydTEzNmdkdGwxMFk2aEFpQnVURnF2Vll0aDFyYnh6Q1AweFdaSG1RSzlrVnl4bjhHUGZYMjdFSXp6c3c9PSJdLCJraWQiOiJNSUdVTUlHT3BJR0xNSUdJTVFzd0NRWURWUVFHRXdKRVJURVBNQTBHQTFVRUJ3d0dRbVZ5YkdsdU1SMHdHd1lEVlFRS0RCUkNkVzVrWlhOa2NuVmphMlZ5WldrZ1IyMWlTREVSTUE4R0ExVUVDd3dJVkNCRFV5QkpSRVV4TmpBMEJnTlZCQU1NTFZOUVVrbE9SQ0JHZFc1clpTQkZWVVJKSUZkaGJHeGxkQ0JRY205MGIzUjVjR1VnU1hOemRXbHVaeUJEUVFJQkFnPT0iLCJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFUzI1NiJ9.eyJ2Y3QiOiJJRCIsIl9zZF9hbGciOiJzaGEtMjU2IiwiaXNzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbSIsImNuZiI6eyJqd2siOnsia3R5IjoiRUMiLCJjcnYiOiJQLTI1NiIsImtpZCI6IkhOa3V2RDNmMTMzcG9uZGRJcmZYbmZxQ0U4T1VBRzBrcFNKZHlzUFZMUU0iLCJ4IjoiVDVWWHYtUUpmMzhBblhkOTZxcS1qNmZjSVd3NXZjTXpqNUllRWFMQm9qSSIsInkiOiJyandIN0I5RmVXc1VoWURmTWpaeDVCYWFLalVCWWdTbU1vQTM4S3ZIWkRrIn19LCJpYXQiOjE3MjQ4Njg0Mzl9.PxjYlyQJYu5tYIwOu-VPsIBFXB1z-WI7_QSRs8mPWeLlPfJ8POs23vZtrcBD-lXFQm38z4QRG9zw_yKYF0qDLw~', + 'eyJ4NWMiOlsiTUlJQ2REQ0NBaHVnQXdJQkFnSUJBakFLQmdncWhrak9QUVFEQWpDQmlERUxNQWtHQTFVRUJoTUNSRVV4RHpBTkJnTlZCQWNNQmtKbGNteHBiakVkTUJzR0ExVUVDZ3dVUW5WdVpHVnpaSEoxWTJ0bGNtVnBJRWR0WWtneEVUQVBCZ05WQkFzTUNGUWdRMU1nU1VSRk1UWXdOQVlEVlFRRERDMVRVRkpKVGtRZ1JuVnVhMlVnUlZWRVNTQlhZV3hzWlhRZ1VISnZkRzkwZVhCbElFbHpjM1ZwYm1jZ1EwRXdIaGNOTWpRd05UTXhNRGd4TXpFM1doY05NalV3TnpBMU1EZ3hNekUzV2pCc01Rc3dDUVlEVlFRR0V3SkVSVEVkTUJzR0ExVUVDZ3dVUW5WdVpHVnpaSEoxWTJ0bGNtVnBJRWR0WWtneENqQUlCZ05WQkFzTUFVa3hNakF3QmdOVkJBTU1LVk5RVWtsT1JDQkdkVzVyWlNCRlZVUkpJRmRoYkd4bGRDQlFjbTkwYjNSNWNHVWdTWE56ZFdWeU1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRU9GQnE0WU1LZzR3NWZUaWZzeXR3QnVKZi83RTdWaFJQWGlObTUyUzNxMUVUSWdCZFh5REsza1Z4R3hnZUhQaXZMUDN1dU12UzZpREVjN3FNeG12ZHVLT0JrRENCalRBZEJnTlZIUTRFRmdRVWlQaENrTEVyRFhQTFcyL0owV1ZlZ2h5dyttSXdEQVlEVlIwVEFRSC9CQUl3QURBT0JnTlZIUThCQWY4RUJBTUNCNEF3TFFZRFZSMFJCQ1l3SklJaVpHVnRieTV3YVdRdGFYTnpkV1Z5TG1KMWJtUmxjMlJ5ZFdOclpYSmxhUzVrWlRBZkJnTlZIU01FR0RBV2dCVFVWaGpBaVRqb0RsaUVHTWwyWXIrcnU4V1F2akFLQmdncWhrak9QUVFEQWdOSEFEQkVBaUFiZjVUemtjUXpoZldvSW95aTFWTjdkOEk5QnNGS20xTVdsdVJwaDJieUdRSWdLWWtkck5mMnhYUGpWU2JqVy9VLzVTNXZBRUM1WHhjT2FudXNPQnJvQmJVPSIsIk1JSUNlVENDQWlDZ0F3SUJBZ0lVQjVFOVFWWnRtVVljRHRDaktCL0gzVlF2NzJnd0NnWUlLb1pJemowRUF3SXdnWWd4Q3pBSkJnTlZCQVlUQWtSRk1ROHdEUVlEVlFRSERBWkNaWEpzYVc0eEhUQWJCZ05WQkFvTUZFSjFibVJsYzJSeWRXTnJaWEpsYVNCSGJXSklNUkV3RHdZRFZRUUxEQWhVSUVOVElFbEVSVEUyTURRR0ExVUVBd3d0VTFCU1NVNUVJRVoxYm10bElFVlZSRWtnVjJGc2JHVjBJRkJ5YjNSdmRIbHdaU0JKYzNOMWFXNW5JRU5CTUI0WERUSTBNRFV6TVRBMk5EZ3dPVm9YRFRNME1EVXlPVEEyTkRnd09Wb3dnWWd4Q3pBSkJnTlZCQVlUQWtSRk1ROHdEUVlEVlFRSERBWkNaWEpzYVc0eEhUQWJCZ05WQkFvTUZFSjFibVJsYzJSeWRXTnJaWEpsYVNCSGJXSklNUkV3RHdZRFZRUUxEQWhVSUVOVElFbEVSVEUyTURRR0ExVUVBd3d0VTFCU1NVNUVJRVoxYm10bElFVlZSRWtnVjJGc2JHVjBJRkJ5YjNSdmRIbHdaU0JKYzNOMWFXNW5JRU5CTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFWUd6ZHdGRG5jNytLbjVpYkF2Q09NOGtlNzdWUXhxZk1jd1pMOElhSUErV0NST2NDZm1ZL2dpSDkycU1ydTVwL2t5T2l2RTBSQy9JYmRNT052RG9VeWFObU1HUXdIUVlEVlIwT0JCWUVGTlJXR01DSk9PZ09XSVFZeVhaaXY2dTd4WkMrTUI4R0ExVWRJd1FZTUJhQUZOUldHTUNKT09nT1dJUVl5WFppdjZ1N3haQytNQklHQTFVZEV3RUIvd1FJTUFZQkFmOENBUUF3RGdZRFZSMFBBUUgvQkFRREFnR0dNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJR0VtN3drWktIdC9hdGI0TWRGblhXNnlybndNVVQydTEzNmdkdGwxMFk2aEFpQnVURnF2Vll0aDFyYnh6Q1AweFdaSG1RSzlrVnl4bjhHUGZYMjdFSXp6c3c9PSJdLCJraWQiOiJNSUdVTUlHT3BJR0xNSUdJTVFzd0NRWURWUVFHRXdKRVJURVBNQTBHQTFVRUJ3d0dRbVZ5YkdsdU1SMHdHd1lEVlFRS0RCUkNkVzVrWlhOa2NuVmphMlZ5WldrZ1IyMWlTREVSTUE4R0ExVUVDd3dJVkNCRFV5QkpSRVV4TmpBMEJnTlZCQU1NTFZOUVVrbE9SQ0JHZFc1clpTQkZWVVJKSUZkaGJHeGxkQ0JRY205MGIzUjVjR1VnU1hOemRXbHVaeUJEUVFJQkFnPT0iLCJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFUzI1NiJ9.eyJ2Y3QiOiJEUklWSU5HX0xJQ0VOQ0UiLCJfc2RfYWxnIjoic2hhLTI1NiIsImlzcyI6Imh0dHBzOi8vZXhhbXBsZS5jb20iLCJjbmYiOnsiandrIjp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJraWQiOiJITmt1dkQzZjEzM3BvbmRkSXJmWG5mcUNFOE9VQUcwa3BTSmR5c1BWTFFNIiwieCI6IlQ1Vlh2LVFKZjM4QW5YZDk2cXEtajZmY0lXdzV2Y016ajVJZUVhTEJvakkiLCJ5Ijoicmp3SDdCOUZlV3NVaFlEZk1qWng1QmFhS2pVQllnU21Nb0EzOEt2SFpEayJ9fSwiaWF0IjoxNzI0ODY4NDM5fQ.PxjYlyQJYu5tYIwOu-VPsIBFXB1z-WI7_QSRs8mPWeLlPfJ8POs23vZtrcBD-lXFQm38z4QRG9zw_yKYF0qDLw~', + 'eyJ4NWMiOlsiTUlJQ2REQ0NBaHVnQXdJQkFnSUJBakFLQmdncWhrak9QUVFEQWpDQmlERUxNQWtHQTFVRUJoTUNSRVV4RHpBTkJnTlZCQWNNQmtKbGNteHBiakVkTUJzR0ExVUVDZ3dVUW5WdVpHVnpaSEoxWTJ0bGNtVnBJRWR0WWtneEVUQVBCZ05WQkFzTUNGUWdRMU1nU1VSRk1UWXdOQVlEVlFRRERDMVRVRkpKVGtRZ1JuVnVhMlVnUlZWRVNTQlhZV3hzWlhRZ1VISnZkRzkwZVhCbElFbHpjM1ZwYm1jZ1EwRXdIaGNOTWpRd05UTXhNRGd4TXpFM1doY05NalV3TnpBMU1EZ3hNekUzV2pCc01Rc3dDUVlEVlFRR0V3SkVSVEVkTUJzR0ExVUVDZ3dVUW5WdVpHVnpaSEoxWTJ0bGNtVnBJRWR0WWtneENqQUlCZ05WQkFzTUFVa3hNakF3QmdOVkJBTU1LVk5RVWtsT1JDQkdkVzVyWlNCRlZVUkpJRmRoYkd4bGRDQlFjbTkwYjNSNWNHVWdTWE56ZFdWeU1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRU9GQnE0WU1LZzR3NWZUaWZzeXR3QnVKZi83RTdWaFJQWGlObTUyUzNxMUVUSWdCZFh5REsza1Z4R3hnZUhQaXZMUDN1dU12UzZpREVjN3FNeG12ZHVLT0JrRENCalRBZEJnTlZIUTRFRmdRVWlQaENrTEVyRFhQTFcyL0owV1ZlZ2h5dyttSXdEQVlEVlIwVEFRSC9CQUl3QURBT0JnTlZIUThCQWY4RUJBTUNCNEF3TFFZRFZSMFJCQ1l3SklJaVpHVnRieTV3YVdRdGFYTnpkV1Z5TG1KMWJtUmxjMlJ5ZFdOclpYSmxhUzVrWlRBZkJnTlZIU01FR0RBV2dCVFVWaGpBaVRqb0RsaUVHTWwyWXIrcnU4V1F2akFLQmdncWhrak9QUVFEQWdOSEFEQkVBaUFiZjVUemtjUXpoZldvSW95aTFWTjdkOEk5QnNGS20xTVdsdVJwaDJieUdRSWdLWWtkck5mMnhYUGpWU2JqVy9VLzVTNXZBRUM1WHhjT2FudXNPQnJvQmJVPSIsIk1JSUNlVENDQWlDZ0F3SUJBZ0lVQjVFOVFWWnRtVVljRHRDaktCL0gzVlF2NzJnd0NnWUlLb1pJemowRUF3SXdnWWd4Q3pBSkJnTlZCQVlUQWtSRk1ROHdEUVlEVlFRSERBWkNaWEpzYVc0eEhUQWJCZ05WQkFvTUZFSjFibVJsYzJSeWRXTnJaWEpsYVNCSGJXSklNUkV3RHdZRFZRUUxEQWhVSUVOVElFbEVSVEUyTURRR0ExVUVBd3d0VTFCU1NVNUVJRVoxYm10bElFVlZSRWtnVjJGc2JHVjBJRkJ5YjNSdmRIbHdaU0JKYzNOMWFXNW5JRU5CTUI0WERUSTBNRFV6TVRBMk5EZ3dPVm9YRFRNME1EVXlPVEEyTkRnd09Wb3dnWWd4Q3pBSkJnTlZCQVlUQWtSRk1ROHdEUVlEVlFRSERBWkNaWEpzYVc0eEhUQWJCZ05WQkFvTUZFSjFibVJsYzJSeWRXTnJaWEpsYVNCSGJXSklNUkV3RHdZRFZRUUxEQWhVSUVOVElFbEVSVEUyTURRR0ExVUVBd3d0VTFCU1NVNUVJRVoxYm10bElFVlZSRWtnVjJGc2JHVjBJRkJ5YjNSdmRIbHdaU0JKYzNOMWFXNW5JRU5CTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFWUd6ZHdGRG5jNytLbjVpYkF2Q09NOGtlNzdWUXhxZk1jd1pMOElhSUErV0NST2NDZm1ZL2dpSDkycU1ydTVwL2t5T2l2RTBSQy9JYmRNT052RG9VeWFObU1HUXdIUVlEVlIwT0JCWUVGTlJXR01DSk9PZ09XSVFZeVhaaXY2dTd4WkMrTUI4R0ExVWRJd1FZTUJhQUZOUldHTUNKT09nT1dJUVl5WFppdjZ1N3haQytNQklHQTFVZEV3RUIvd1FJTUFZQkFmOENBUUF3RGdZRFZSMFBBUUgvQkFRREFnR0dNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJR0VtN3drWktIdC9hdGI0TWRGblhXNnlybndNVVQydTEzNmdkdGwxMFk2aEFpQnVURnF2Vll0aDFyYnh6Q1AweFdaSG1RSzlrVnl4bjhHUGZYMjdFSXp6c3c9PSJdLCJraWQiOiJNSUdVTUlHT3BJR0xNSUdJTVFzd0NRWURWUVFHRXdKRVJURVBNQTBHQTFVRUJ3d0dRbVZ5YkdsdU1SMHdHd1lEVlFRS0RCUkNkVzVrWlhOa2NuVmphMlZ5WldrZ1IyMWlTREVSTUE4R0ExVUVDd3dJVkNCRFV5QkpSRVV4TmpBMEJnTlZCQU1NTFZOUVVrbE9SQ0JHZFc1clpTQkZWVVJKSUZkaGJHeGxkQ0JRY205MGIzUjVjR1VnU1hOemRXbHVaeUJEUVFJQkFnPT0iLCJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFUzI1NiJ9.eyJ2Y3QiOiJSRVNJREVOQ0VfUEVSTUlUIiwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tIiwiY25mIjp7Imp3ayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2Iiwia2lkIjoiSE5rdXZEM2YxMzNwb25kZElyZlhuZnFDRThPVUFHMGtwU0pkeXNQVkxRTSIsIngiOiJUNVZYdi1RSmYzOEFuWGQ5NnFxLWo2ZmNJV3c1dmNNemo1SWVFYUxCb2pJIiwieSI6InJqd0g3QjlGZVdzVWhZRGZNalp4NUJhYUtqVUJZZ1NtTW9BMzhLdkhaRGsifX0sImlhdCI6MTcyNDg2ODQzOX0.PxjYlyQJYu5tYIwOu-VPsIBFXB1z-WI7_QSRs8mPWeLlPfJ8POs23vZtrcBD-lXFQm38z4QRG9zw_yKYF0qDLw~', + ]; + const pd = { + id: 'OverAgeCheck', + purpose: 'Age check', + submission_requirements: [ + { + name: 'Proof of age and photo', + rule: 'pick', + count: 1, + from: 'validAgeCheckInputDescriptor', + }, + { + name: 'Proof of other', + rule: 'pick', + count: 1, + from: 'validOtherCheck', + }, + ], + input_descriptors: [ + { + name: 'Residence permit date of birth and photo', + id: 'ResidencePermit', + group: ['validOtherCheck'], + constraints: { + limit_disclosure: 'required', + fields: [ + { + path: ['$.vc.type.*', '$.vct', '$.type'], + filter: { + type: 'string', + const: 'RESIDENCE_PERMIT', + }, + }, + ], + }, + }, + { + name: 'ID date of birth and photo', + id: 'IDDoB', + group: ['validAgeCheckInputDescriptor', 'validOtherCheck'], + constraints: { + limit_disclosure: 'required', + fields: [ + { + path: ['$.vc.type.*', '$.vct', '$.type'], + filter: { + type: 'string', + const: 'ID', + }, + }, + ], + }, + }, + { + name: 'Driving licence date of birth and photo', + id: 'DrivingLicenceDoB', + group: ['validAgeCheckInputDescriptor'], + constraints: { + limit_disclosure: 'required', + fields: [ + { + path: ['$.vc.type.*', '$.vct', '$.type'], + filter: { + type: 'string', + const: 'DRIVING_LICENCE', + }, + }, + ], + }, + }, + ], + } satisfies IPresentationDefinition; + const pex: PEX = new PEX({ hasher }); + + const result = pex.selectFrom(pd, sdJwtVcs); + + expect(result.matches).toEqual([ + { + rule: 'pick', + vc_path: ['$.verifiableCredential[0]', '$.verifiableCredential[1]'], + name: 'Proof of age and photo', + type: 'SubmissionRequirement', + id: 0, + from: 'validAgeCheckInputDescriptor', + count: 1, + }, + { + rule: 'pick', + vc_path: ['$.verifiableCredential[2]', '$.verifiableCredential[0]'], + name: 'Proof of other', + type: 'SubmissionRequirement', + id: 1, + from: 'validOtherCheck', + count: 1, + }, + ]); + }); + it('should map the sd-jwt credential correctly with the indices of selecFrom result', () => { const sdJwt: OriginalVerifiableCredential = 'eyJ4NWMiOlsiTUlJQ2REQ0NBaHVnQXdJQkFnSUJBakFLQmdncWhrak9QUVFEQWpDQmlERUxNQWtHQTFVRUJoTUNSRVV4RHpBTkJnTlZCQWNNQmtKbGNteHBiakVkTUJzR0ExVUVDZ3dVUW5WdVpHVnpaSEoxWTJ0bGNtVnBJRWR0WWtneEVUQVBCZ05WQkFzTUNGUWdRMU1nU1VSRk1UWXdOQVlEVlFRRERDMVRVRkpKVGtRZ1JuVnVhMlVnUlZWRVNTQlhZV3hzWlhRZ1VISnZkRzkwZVhCbElFbHpjM1ZwYm1jZ1EwRXdIaGNOTWpRd05UTXhNRGd4TXpFM1doY05NalV3TnpBMU1EZ3hNekUzV2pCc01Rc3dDUVlEVlFRR0V3SkVSVEVkTUJzR0ExVUVDZ3dVUW5WdVpHVnpaSEoxWTJ0bGNtVnBJRWR0WWtneENqQUlCZ05WQkFzTUFVa3hNakF3QmdOVkJBTU1LVk5RVWtsT1JDQkdkVzVyWlNCRlZVUkpJRmRoYkd4bGRDQlFjbTkwYjNSNWNHVWdTWE56ZFdWeU1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRU9GQnE0WU1LZzR3NWZUaWZzeXR3QnVKZi83RTdWaFJQWGlObTUyUzNxMUVUSWdCZFh5REsza1Z4R3hnZUhQaXZMUDN1dU12UzZpREVjN3FNeG12ZHVLT0JrRENCalRBZEJnTlZIUTRFRmdRVWlQaENrTEVyRFhQTFcyL0owV1ZlZ2h5dyttSXdEQVlEVlIwVEFRSC9CQUl3QURBT0JnTlZIUThCQWY4RUJBTUNCNEF3TFFZRFZSMFJCQ1l3SklJaVpHVnRieTV3YVdRdGFYTnpkV1Z5TG1KMWJtUmxjMlJ5ZFdOclpYSmxhUzVrWlRBZkJnTlZIU01FR0RBV2dCVFVWaGpBaVRqb0RsaUVHTWwyWXIrcnU4V1F2akFLQmdncWhrak9QUVFEQWdOSEFEQkVBaUFiZjVUemtjUXpoZldvSW95aTFWTjdkOEk5QnNGS20xTVdsdVJwaDJieUdRSWdLWWtkck5mMnhYUGpWU2JqVy9VLzVTNXZBRUM1WHhjT2FudXNPQnJvQmJVPSIsIk1JSUNlVENDQWlDZ0F3SUJBZ0lVQjVFOVFWWnRtVVljRHRDaktCL0gzVlF2NzJnd0NnWUlLb1pJemowRUF3SXdnWWd4Q3pBSkJnTlZCQVlUQWtSRk1ROHdEUVlEVlFRSERBWkNaWEpzYVc0eEhUQWJCZ05WQkFvTUZFSjFibVJsYzJSeWRXTnJaWEpsYVNCSGJXSklNUkV3RHdZRFZRUUxEQWhVSUVOVElFbEVSVEUyTURRR0ExVUVBd3d0VTFCU1NVNUVJRVoxYm10bElFVlZSRWtnVjJGc2JHVjBJRkJ5YjNSdmRIbHdaU0JKYzNOMWFXNW5JRU5CTUI0WERUSTBNRFV6TVRBMk5EZ3dPVm9YRFRNME1EVXlPVEEyTkRnd09Wb3dnWWd4Q3pBSkJnTlZCQVlUQWtSRk1ROHdEUVlEVlFRSERBWkNaWEpzYVc0eEhUQWJCZ05WQkFvTUZFSjFibVJsYzJSeWRXTnJaWEpsYVNCSGJXSklNUkV3RHdZRFZRUUxEQWhVSUVOVElFbEVSVEUyTURRR0ExVUVBd3d0VTFCU1NVNUVJRVoxYm10bElFVlZSRWtnVjJGc2JHVjBJRkJ5YjNSdmRIbHdaU0JKYzNOMWFXNW5JRU5CTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFWUd6ZHdGRG5jNytLbjVpYkF2Q09NOGtlNzdWUXhxZk1jd1pMOElhSUErV0NST2NDZm1ZL2dpSDkycU1ydTVwL2t5T2l2RTBSQy9JYmRNT052RG9VeWFObU1HUXdIUVlEVlIwT0JCWUVGTlJXR01DSk9PZ09XSVFZeVhaaXY2dTd4WkMrTUI4R0ExVWRJd1FZTUJhQUZOUldHTUNKT09nT1dJUVl5WFppdjZ1N3haQytNQklHQTFVZEV3RUIvd1FJTUFZQkFmOENBUUF3RGdZRFZSMFBBUUgvQkFRREFnR0dNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJR0VtN3drWktIdC9hdGI0TWRGblhXNnlybndNVVQydTEzNmdkdGwxMFk2aEFpQnVURnF2Vll0aDFyYnh6Q1AweFdaSG1RSzlrVnl4bjhHUGZYMjdFSXp6c3c9PSJdLCJraWQiOiJNSUdVTUlHT3BJR0xNSUdJTVFzd0NRWURWUVFHRXdKRVJURVBNQTBHQTFVRUJ3d0dRbVZ5YkdsdU1SMHdHd1lEVlFRS0RCUkNkVzVrWlhOa2NuVmphMlZ5WldrZ1IyMWlTREVSTUE4R0ExVUVDd3dJVkNCRFV5QkpSRVV4TmpBMEJnTlZCQU1NTFZOUVVrbE9SQ0JHZFc1clpTQkZWVVJKSUZkaGJHeGxkQ0JRY205MGIzUjVjR1VnU1hOemRXbHVaeUJEUVFJQkFnPT0iLCJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFUzI1NiJ9.eyJwbGFjZV9vZl9iaXJ0aCI6eyJfc2QiOlsiODhTejY5dlo1ZzFXdUZFUUpyQzBqY0c2WEVoa1Mwd1ppR0NGQ29xU3FzOCJdfSwiX3NkIjpbIjJZemluX0V0WkVSellUQlVhUW1ZbEpxd3VyUEt3SGJkaW9PN1o5QmF5N0UiLCJFdEFFdmoyb2FIQzFReEtOalZEWkxqeWtINVhYWGY1d25tRGlqMDJ0NnM4IiwiTEJ3UjlrdE1tdWVQd3A4NmNVM2hIMV9MNTNCY0dNWjl6QmU4RE9jZ2pTOCIsIlk2Ulhac202blg0WlZYa2dJQXR2UTFMR19RWFRIT05kamJIYzB6Y3RFYkUiLCJoM0Vvd2VtNmtFTnNKZ0VudWFOQVZEYjYwXzczSVprX28wTHpQTGd6Q2pRIiwidHdnUXVZMVl1d2U1dDg0Y2wtaHphN2xWV0JHTlFFOWNGYlF4cWZxQlBWMCIsInpuSG5JV1F2a0d5cEtxajNfd3R2SmZCa0FZQmM3N1M1VTNVNGw4TG1nZW8iXSwiYWRkcmVzcyI6eyJfc2QiOlsiT05GYkVTTjU3ZjgzUXNEUWlyLWF2MVdUQ1piSFg0a3BiWmltZFFBRmx3TSIsIlF5UG5DQnlwZjhCa0lmejNzRVk4MEIwblZKeTNCWlVLcmxpSnB6YV83Z0kiLCJ0STdFNS1mNVNOdngzcDUzWVZOWTRPSmRUQkJfLWZzQ1dNZUFOdFR1SUtVIiwid21rajBYc1RQMEFJeWtmcjlMZUV0bVRqTkx6S2JWYllUTzhTWFVCOEY0byJdfSwiaXNzdWluZ19jb3VudHJ5IjoiREUiLCJ2Y3QiOiJ1cm46ZXUuZXVyb3BhLmVjLmV1ZGk6cGlkOjEiLCJpc3N1aW5nX2F1dGhvcml0eSI6IkRFIiwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2RlbW8ucGlkLWlzc3Vlci5idW5kZXNkcnVja2VyZWkuZGUvYyIsImNuZiI6eyJqd2siOnsia3R5IjoiRUMiLCJjcnYiOiJQLTI1NiIsImtpZCI6IkhOa3V2RDNmMTMzcG9uZGRJcmZYbmZxQ0U4T1VBRzBrcFNKZHlzUFZMUU0iLCJ4IjoiVDVWWHYtUUpmMzhBblhkOTZxcS1qNmZjSVd3NXZjTXpqNUllRWFMQm9qSSIsInkiOiJyandIN0I5RmVXc1VoWURmTWpaeDVCYWFLalVCWWdTbU1vQTM4S3ZIWkRrIiwiYWxnIjoiRVMyNTYifX0sImV4cCI6MTcyNjA3ODAzOSwiaWF0IjoxNzI0ODY4NDM5LCJhZ2VfZXF1YWxfb3Jfb3ZlciI6eyJfc2QiOlsiR000blpmaGJtWEVKVnFrUGh0T0Q2NS1BakNUNXBMQ1czZTZPN2MxMDRObyIsIk1iUWZPM3VmV3dKd19EM01oMG5xeXZZUHQtdGZxRUd1X3B0R3dBUzhYSFkiLCJQeVVaX1hmRV9keEZNRV9YdjBTR0ljRnRFY0ZRbHA1Mld6eVJCeWxldjY0IiwiWDVMMkJCUlhMbUdDdHRVckFqWF9LWGdEdzBpNlBmUFRhOUhBdVJuNy1GNCIsImE4RGxyMnYyZWZQZGxkNnlrMXN5dlJHTjFUajg3clZ5X3FjOUY1MjlPenMiLCJ4SmdyV2ZMaVlwbmFQN0JRMjNmVmJ5S1FXNlVnTTRJTnd0M2I3SFY2RmZZIl19fQ.PxjYlyQJYu5tYIwOu-VPsIBFXB1z-WI7_QSRs8mPWeLlPfJ8POs23vZtrcBD-lXFQm38z4QRG9zw_yKYF0qDLw~WyJFaWozRW9QUTMwZHV1N2ZoQTYxODJ3IiwiZmFtaWx5X25hbWUiLCJNVVNURVJNQU5OIl0~WyJ3NUsybVhOSVBBa1NoNXBjUjlFalZ3IiwiZ2l2ZW5fbmFtZSIsIkVSSUtBIl0~WyJNOXlQZzBvaWQ0eHlHN25zRU9LdV9RIiwiYmlydGhkYXRlIiwiMTk4NC0wMS0yNiJd~WyJYd2dleGd6dmh6bDY5U2tONTQ5R293IiwiYWdlX2JpcnRoX3llYXIiLDE5ODRd~WyJZMXZqekg4QWZZNk1sak1xT1lmS1F3IiwiYWdlX2luX3llYXJzIiw0MF0~WyJySlU1SHhUQ0VvLW0yMFBDNGtPblp3IiwiYmlydGhfZmFtaWx5X25hbWUiLCJHQUJMRVIiXQ~WyJDMm1wSzZpT0RpZ0ZQNkh2OE1NTDJRIiwibmF0aW9uYWxpdGllcyIsWyJERSJdXQ~WyJRdVc4Uko3eWQzZ2FKaGZFby1nUmNBIiwiMTIiLHRydWVd~WyJFQUJGT09LazRBYkZyTFNrN0NVTjlBIiwiMTQiLHRydWVd~WyJJaGR2cUxNLWVzZGdjQkx6a0ZVQ3B3IiwiMTYiLHRydWVd~WyJtc0did3NsY01Sem5jV19DVDFULW9BIiwiMTgiLHRydWVd~WyI1SU1uR1FzRmZRTkNtT0l6ZjhocVJ3IiwiMjEiLHRydWVd~WyJud0F0QzlZQ2VMVHdSakVNMHU2VkRnIiwiNjUiLGZhbHNlXQ~WyJCSmRmOGVselViNVdQMVRzV0FzeU9RIiwibG9jYWxpdHkiLCJCRVJMSU4iXQ~WyJOWFFQS1VVTWdyUzJ4WmFxemJrckZBIiwibG9jYWxpdHkiLCJLw5ZMTiJd~WyJyUnh3M09hcF9lekJrdm9mNGIzVUh3IiwiY291bnRyeSIsIkRFIl0~WyI4c3QyanlNVy1hcGFrQ0V6NTQ4NklRIiwicG9zdGFsX2NvZGUiLCI1MTE0NyJd~WyJIZ2xRQ3d4eWQwb0dyWWdUQXRxTzBRIiwic3RyZWV0X2FkZHJlc3MiLCJIRUlERVNUUkFTU0UgMTciXQ~'; diff --git a/test/PEXv2.spec.ts b/test/PEXv2.spec.ts index effd5ab2..3c384559 100644 --- a/test/PEXv2.spec.ts +++ b/test/PEXv2.spec.ts @@ -312,7 +312,15 @@ describe('evaluate', () => { }); expect(result!.errors!.length).toEqual(0); expect(JSON.stringify(result!.matches)).toBe( - JSON.stringify([{ name: 'Verify Valid License', rule: 'all', vc_path: ['$.verifiableCredential[0]'] }]), + JSON.stringify([ + { + name: 'Verify Valid License', + rule: 'all', + vc_path: ['$.verifiableCredential[0]'], + type: 'InputDescriptor', + id: 'drivers_license_information', + }, + ]), ); expect(result!.areRequiredCredentialsPresent).toBe('info'); }); diff --git a/test/SdJwt.spec.ts b/test/SdJwt.spec.ts index bde09626..0c994d41 100644 --- a/test/SdJwt.spec.ts +++ b/test/SdJwt.spec.ts @@ -4,6 +4,7 @@ import { PresentationDefinitionV2 } from '@sphereon/pex-models'; import { SdJwtDecodedVerifiableCredential } from '@sphereon/ssi-types'; import { PEX, PresentationSubmissionLocation, SdJwtDecodedVerifiableCredentialWithKbJwtInput, Status, Validated } from '../lib'; +import { SubmissionRequirementMatchType } from '../lib/evaluation/core'; import { calculateSdHash } from '../lib/utils'; export const hasher = (data: string) => createHash('sha256').update(data).digest(); @@ -178,7 +179,15 @@ describe('evaluate', () => { it('selectFrom with vc+sd-jwt format compact', () => { const result = pex.selectFrom(getPresentationDefinitionV2(), [decodedSdJwtVc.compactSdJwtVc]); expect(result.errors?.length).toEqual(0); - expect(result.matches).toEqual([{ name: 'Washington State Business License', rule: 'all', vc_path: ['$.verifiableCredential[0]'] }]); + expect(result.matches).toEqual([ + { + name: 'Washington State Business License', + rule: 'all', + vc_path: ['$.verifiableCredential[0]'], + type: SubmissionRequirementMatchType.InputDescriptor, + id: 'wa_driver_license', + }, + ]); expect(result.areRequiredCredentialsPresent).toBe('info'); // Should have already applied selective disclosure on the SD-JWT @@ -188,7 +197,15 @@ describe('evaluate', () => { it('selectFrom with vc+sd-jwt format already decoded', () => { const result = pex.selectFrom(getPresentationDefinitionV2(), [decodedSdJwtVc]); expect(result.errors?.length).toEqual(0); - expect(result.matches).toEqual([{ name: 'Washington State Business License', rule: 'all', vc_path: ['$.verifiableCredential[0]'] }]); + expect(result.matches).toEqual([ + { + name: 'Washington State Business License', + rule: 'all', + vc_path: ['$.verifiableCredential[0]'], + type: SubmissionRequirementMatchType.InputDescriptor, + id: 'wa_driver_license', + }, + ]); expect(result.areRequiredCredentialsPresent).toBe('info'); // Should have already applied selective disclosure on the SD-JWT diff --git a/test/evaluation/EvaluationClientWrapperData.ts b/test/evaluation/EvaluationClientWrapperData.ts index e501fd4d..62418330 100644 --- a/test/evaluation/EvaluationClientWrapperData.ts +++ b/test/evaluation/EvaluationClientWrapperData.ts @@ -2,6 +2,7 @@ import { PresentationSubmission, Rules } from '@sphereon/pex-models'; import { IVerifiableCredential } from '@sphereon/ssi-types'; import { HandlerCheckResult, SelectResults, Status } from '../../lib'; +import { SubmissionRequirementMatchType } from '../../lib/evaluation/core'; import PexMessages from '../../lib/types/Messages'; export class EvaluationClientWrapperData { @@ -197,6 +198,8 @@ export class EvaluationClientWrapperData { name: 'test', rule: Rules.All, vc_path: ['$.verifiableCredential[0]'], + id: 'Educational transcripts', + type: SubmissionRequirementMatchType.InputDescriptor, }, ], }; diff --git a/test/evaluation/check-scenario-1.spec.ts b/test/evaluation/check-scenario-1.spec.ts index 65326320..fad513eb 100644 --- a/test/evaluation/check-scenario-1.spec.ts +++ b/test/evaluation/check-scenario-1.spec.ts @@ -2,6 +2,7 @@ import { PresentationDefinitionV1 as PdV1 } from '@sphereon/pex-models'; import { IPresentation, IVerifiableCredential } from '@sphereon/ssi-types'; import { PEX } from '../../lib'; +import { SubmissionRequirementMatchType } from '../../lib/evaluation/core'; import { Wallet } from './core/Wallet'; @@ -203,8 +204,20 @@ describe('1st scenario', () => { }); expect(selectFromResult.matches?.length).toEqual(2); expect(selectFromResult.matches).toEqual([ - { rule: 'all', vc_path: ['$.verifiableCredential[0]'], name: 'e73646de-43e2-4d72-ba4f-090d01c11eac' }, - { rule: 'all', vc_path: ['$.verifiableCredential[0]'], name: '867bfe7a-5b91-46b2-9ba4-70028b8d9cc8' }, + { + rule: 'all', + vc_path: ['$.verifiableCredential[0]'], + name: 'e73646de-43e2-4d72-ba4f-090d01c11eac', + type: SubmissionRequirementMatchType.InputDescriptor, + id: 'e73646de-43e2-4d72-ba4f-090d01c11eac', + }, + { + rule: 'all', + vc_path: ['$.verifiableCredential[0]'], + name: '867bfe7a-5b91-46b2-9ba4-70028b8d9cc8', + type: SubmissionRequirementMatchType.InputDescriptor, + id: '867bfe7a-5b91-46b2-9ba4-70028b8d9cc8', + }, ]); expect(selectFromResult.verifiableCredential?.length).toEqual(1); diff --git a/test/evaluation/core/submissionRequirementMatch.spec.ts b/test/evaluation/core/submissionRequirementMatch.spec.ts index 8f6892a8..3df213b1 100644 --- a/test/evaluation/core/submissionRequirementMatch.spec.ts +++ b/test/evaluation/core/submissionRequirementMatch.spec.ts @@ -1,6 +1,7 @@ import { Rules } from '@sphereon/pex-models'; import { SubmissionRequirementMatch } from '../../../lib'; +import { SubmissionRequirementMatchType } from '../../../lib/evaluation/core'; describe('submissionRequirementMatch', () => { it('should return ok constructor works correctly', function () { @@ -9,6 +10,8 @@ describe('submissionRequirementMatch', () => { rule: Rules.All, vc_path: ['$.verifiableCredential[1]'], from: 'A', + id: 0, + type: SubmissionRequirementMatchType.SubmissionRequirement, }; expect(submissionRequirementMatch.from).toContain('A'); expect(submissionRequirementMatch.rule).toBe(Rules.All); diff --git a/test/evaluation/selectFrom.spec.ts b/test/evaluation/selectFrom.spec.ts index 7201a16e..149aaae7 100644 --- a/test/evaluation/selectFrom.spec.ts +++ b/test/evaluation/selectFrom.spec.ts @@ -5,6 +5,7 @@ import { IVerifiableCredential, WrappedVerifiableCredential } from '@sphereon/ss import { Status } from '../../lib'; import { EvaluationClientWrapper } from '../../lib/evaluation'; +import { SubmissionRequirementMatchType } from '../../lib/evaluation/core'; import { InternalPresentationDefinitionV1, SSITypesBuilder } from '../../lib/types'; import PexMessages from '../../lib/types/Messages'; @@ -39,6 +40,8 @@ describe('selectFrom tests', () => { vc_path: ['$.verifiableCredential[0]', '$.verifiableCredential[1]', '$.verifiableCredential[2]'], name: 'Submission of educational transcripts', rule: 'all', + id: 0, + type: SubmissionRequirementMatchType.SubmissionRequirement, }, ], verifiableCredential: [ @@ -158,8 +161,10 @@ describe('selectFrom tests', () => { from: 'B', vc_path: ['$.verifiableCredential[0]', '$.verifiableCredential[1]'], min: 2, - name: 'Submission of educational transcripts', + name: 'Eligibility to Work Proof', rule: 'pick', + id: 0, + type: SubmissionRequirementMatchType.SubmissionRequirement, }, ], verifiableCredential: [ @@ -248,8 +253,10 @@ describe('selectFrom tests', () => { from: 'B', vc_path: ['$.verifiableCredential[0]', '$.verifiableCredential[1]'], max: 2, - name: 'Submission of educational transcripts', rule: 'pick', + id: 0, + name: 'Eligibility to Work Proof', + type: SubmissionRequirementMatchType.SubmissionRequirement, }, ], verifiableCredential: [ @@ -320,20 +327,28 @@ describe('selectFrom tests', () => { { from: 'A', vc_path: ['$.verifiableCredential[0]', '$.verifiableCredential[1]', '$.verifiableCredential[2]'], - name: 'Submission of educational transcripts', rule: 'all', + id: 0, + // submission requirement from_nested has no name + name: undefined, + type: SubmissionRequirementMatchType.SubmissionRequirement, }, { count: 2, from: 'B', vc_path: ['$.verifiableCredential[1]', '$.verifiableCredential[2]'], - name: 'Submission of educational transcripts', rule: 'pick', + id: 1, + // submission requirement from_nested has no name + name: undefined, + type: SubmissionRequirementMatchType.SubmissionRequirement, }, ], vc_path: [], - name: '32f54163-7166-48f1-93d8-ff217bdb0653', rule: 'all', + id: 0, + name: 'Confirm banking relationship or employment and residence proofs', + type: SubmissionRequirementMatchType.SubmissionRequirement, }, ], verifiableCredential: [ @@ -435,21 +450,29 @@ describe('selectFrom tests', () => { { from: 'A', vc_path: ['$.verifiableCredential[0]', '$.verifiableCredential[1]', '$.verifiableCredential[2]'], - name: 'Submission of educational transcripts', rule: 'all', + id: 0, + // submission requirement from_nested has no name + name: undefined, + type: SubmissionRequirementMatchType.SubmissionRequirement, }, { count: 2, from: 'B', vc_path: ['$.verifiableCredential[1]', '$.verifiableCredential[2]'], - name: 'Submission of educational transcripts', rule: 'pick', + id: 1, + // submission requirement from_nested has no name + name: undefined, + type: SubmissionRequirementMatchType.SubmissionRequirement, }, ], vc_path: [], min: 1, - name: '32f54163-7166-48f1-93d8-ff217bdb0653', rule: 'pick', + id: 0, + name: 'Confirm banking relationship or employment and residence proofs', + type: SubmissionRequirementMatchType.SubmissionRequirement, }, ], verifiableCredential: [ @@ -551,21 +574,29 @@ describe('selectFrom tests', () => { { from: 'A', vc_path: ['$.verifiableCredential[0]', '$.verifiableCredential[1]', '$.verifiableCredential[2]'], - name: 'Submission of educational transcripts', rule: 'all', + id: 0, + // submission requirement from_nested has no name + name: undefined, + type: SubmissionRequirementMatchType.SubmissionRequirement, }, { count: 2, from: 'B', vc_path: ['$.verifiableCredential[1]', '$.verifiableCredential[2]'], - name: 'Submission of educational transcripts', rule: 'pick', + id: 1, + // submission requirement from_nested has no name + name: undefined, + type: SubmissionRequirementMatchType.SubmissionRequirement, }, ], vc_path: [], max: 2, - name: '32f54163-7166-48f1-93d8-ff217bdb0653', rule: 'pick', + id: 0, + name: 'Confirm banking relationship or employment and residence proofs', + type: SubmissionRequirementMatchType.SubmissionRequirement, }, ], verifiableCredential: [ @@ -748,8 +779,10 @@ describe('selectFrom tests', () => { from: 'B', vc_path: ['$.verifiableCredential[0]', '$.verifiableCredential[1]'], min: 3, - name: 'Submission of educational transcripts', rule: 'pick', + id: 0, + type: SubmissionRequirementMatchType.SubmissionRequirement, + name: 'Eligibility to Work Proof', }, ]); }); @@ -774,8 +807,10 @@ describe('selectFrom tests', () => { from: 'B', vc_path: ['$.verifiableCredential[0]', '$.verifiableCredential[1]'], max: 1, - name: 'Submission of educational transcripts', rule: 'pick', + type: SubmissionRequirementMatchType.SubmissionRequirement, + name: 'Eligibility to Work Proof', + id: 0, }, ]); expect(result.errors?.length).toEqual(16); @@ -847,22 +882,30 @@ describe('selectFrom tests', () => { from_nested: [ { from: 'A', - name: 'Submission of educational transcripts', rule: Rules.All, vc_path: ['$.verifiableCredential[0]', '$.verifiableCredential[1]', '$.verifiableCredential[2]'], + id: 0, + // submission requirement from_nested has no name + name: undefined, + type: SubmissionRequirementMatchType.SubmissionRequirement, }, { count: 2, from: 'B', - name: 'Submission of educational transcripts', rule: Rules.Pick, vc_path: ['$.verifiableCredential[1]', '$.verifiableCredential[2]'], + id: 1, + // submission requirement from_nested has no name + name: undefined, + type: SubmissionRequirementMatchType.SubmissionRequirement, }, ], min: 1, - name: '32f54163-7166-48f1-93d8-ff217bdb0653', + name: 'Confirm banking relationship or employment and residence proofs', rule: Rules.Pick, vc_path: [], + id: 0, + type: SubmissionRequirementMatchType.SubmissionRequirement, }); }); @@ -888,21 +931,30 @@ describe('selectFrom tests', () => { { from: 'A', vc_path: ['$.verifiableCredential[0]', '$.verifiableCredential[1]', '$.verifiableCredential[2]'], - name: 'Submission of educational transcripts', rule: 'all', + id: 0, + // submission requirement from_nested has no name + name: undefined, + type: SubmissionRequirementMatchType.SubmissionRequirement, }, { count: 2, from: 'B', vc_path: ['$.verifiableCredential[1]', '$.verifiableCredential[2]'], - name: 'Submission of educational transcripts', rule: 'pick', + id: 1, + // submission requirement from_nested has no name + name: undefined, + type: SubmissionRequirementMatchType.SubmissionRequirement, }, ], vc_path: [], - name: '32f54163-7166-48f1-93d8-ff217bdb0653', + // submission requirement name + name: 'Confirm banking relationship or employment and residence proofs', rule: 'pick', max: 1, + type: SubmissionRequirementMatchType.SubmissionRequirement, + id: 0, }, ]); expect(result.errors?.length).toEqual(16); @@ -922,6 +974,8 @@ describe('selectFrom tests', () => { expect(result!.matches![0]!.name).toEqual("EU Driver's License"); expect(result!.matches![0]).toEqual({ name: "EU Driver's License", + id: 'citizenship_input_1', + type: SubmissionRequirementMatchType.InputDescriptor, rule: 'all', vc_path: ['$.verifiableCredential[0]'], }); @@ -939,6 +993,6 @@ describe('selectFrom tests', () => { limitDisclosureSignatureSuites: LIMIT_DISCLOSURE_SIGNATURE_SUITES, }); expect(result!.errors!.length).toEqual(0); - expect(result!.matches![0]!.name).toEqual("EU Driver's License"); + expect(result!.matches![0]!.name).toEqual("Name on driver's license"); }); }); diff --git a/test/thirdParty/Animo.spec.ts b/test/thirdParty/Animo.spec.ts index 7aafbea9..d5239225 100644 --- a/test/thirdParty/Animo.spec.ts +++ b/test/thirdParty/Animo.spec.ts @@ -2,6 +2,7 @@ import { Rules } from '@sphereon/pex-models'; import { W3CVerifiableCredential } from '@sphereon/ssi-types'; import { IPresentationDefinition, PEX, Status } from '../../lib'; +import { SubmissionRequirementMatchType } from '../../lib/evaluation/core'; describe('evaluate animo tests', () => { it('should pass with 2 VCs and 2 IDs', () => { @@ -133,10 +134,26 @@ describe('evaluate animo tests', () => { const pex: PEX = new PEX(); const result = pex.selectFrom(pd, vcs); expect(result.areRequiredCredentialsPresent).toEqual(Status.INFO); - expect(result.matches?.length).toEqual(2); - expect(new Set(result.matches?.map((value) => value.name)).size).toEqual(2); - expect(result.matches?.map((value) => value.name).indexOf('c2834d0e-3c95-4721-b21a-40e3d7ea2549')).toBeGreaterThanOrEqual(0); - expect(result.matches?.map((value) => value.name).indexOf('c2834d0e-3c95-4721-b21a-40e3d7ea25434')).toBeGreaterThanOrEqual(0); + expect(result.matches).toEqual([ + { + count: 1, + from: 'A', + id: 0, + name: undefined, + rule: 'pick', + type: SubmissionRequirementMatchType.SubmissionRequirement, + vc_path: ['$.verifiableCredential[0]'], + }, + { + count: 1, + from: 'B', + id: 1, + name: undefined, + rule: 'pick', + type: SubmissionRequirementMatchType.SubmissionRequirement, + vc_path: ['$.verifiableCredential[1]'], + }, + ]); }); const vcs: W3CVerifiableCredential[] = [ diff --git a/test/thirdParty/Gataca.spec.ts b/test/thirdParty/Gataca.spec.ts index ba4fd3fe..1e72d86d 100644 --- a/test/thirdParty/Gataca.spec.ts +++ b/test/thirdParty/Gataca.spec.ts @@ -2,6 +2,7 @@ import { PresentationDefinitionV1 } from '@sphereon/pex-models'; import { IPresentation, IProofType, IVerifiableCredential } from '@sphereon/ssi-types'; import { PEX, PEXv1, Status } from '../../lib'; +import { SubmissionRequirementMatchType } from '../../lib/evaluation/core'; import { GatacaPresentationDefinition } from '../test_data/gataca/gatacaPresentationDefinition'; import { GatacaSelectedCredentials } from '../test_data/gataca/gatacaSelectedCredentials'; @@ -28,13 +29,17 @@ describe('evaluate gataca tests', () => { rule: 'all', from: 'mandatory', vc_path: ['$.verifiableCredential[0]'], - name: 'emailCredential', + id: 0, + name: 'Mandatory data', + type: SubmissionRequirementMatchType.SubmissionRequirement, }, { rule: 'pick', from: 'optional', vc_path: ['$.verifiableCredential[1]'], - name: 'transcriptOfRecordsCredential', + id: 1, + name: 'Optional data', + type: SubmissionRequirementMatchType.SubmissionRequirement, }, ]); expect(result.verifiableCredential?.length).toEqual(2); @@ -102,13 +107,17 @@ describe('evaluate gataca tests', () => { rule: 'all', from: 'mandatory', vc_path: ['$.verifiableCredential[0]'], - name: 'emailCredential', + id: 0, + name: 'Mandatory data', + type: SubmissionRequirementMatchType.SubmissionRequirement, }, { rule: 'pick', from: 'optional', vc_path: ['$.verifiableCredential[1]'], - name: 'transcriptOfRecordsCredential', + id: 1, + name: 'Optional data', + type: SubmissionRequirementMatchType.SubmissionRequirement, }, ]); expect(result.verifiableCredential?.length).toEqual(2); diff --git a/test/thirdParty/JGiter.spec.ts b/test/thirdParty/JGiter.spec.ts index d8685e52..db7cb210 100644 --- a/test/thirdParty/JGiter.spec.ts +++ b/test/thirdParty/JGiter.spec.ts @@ -3,6 +3,7 @@ import { IPresentation, IProofType, IVerifiableCredential } from '@sphereon/ssi- import { EvaluationResults, PEX, Status } from '../../lib'; import { PresentationEvaluationResults } from '../../lib/evaluation'; +import { SubmissionRequirementMatchType } from '../../lib/evaluation/core'; const LIMIT_DISCLOSURE_SIGNATURE_SUITES = [IProofType.BbsBlsSignatureProof2020]; @@ -580,16 +581,22 @@ describe('evaluate JGiter tests', () => { name: 'Subject identity input', rule: Rules.All, vc_path: ['$.verifiableCredential[0]'], + id: 'identity_input', + type: SubmissionRequirementMatchType.InputDescriptor, }, { name: 'Subject name input', rule: Rules.All, vc_path: ['$.verifiableCredential[0]'], + id: 'name_input', + type: SubmissionRequirementMatchType.InputDescriptor, }, { name: 'Admin role input', rule: Rules.All, vc_path: ['$.verifiableCredential[1]'], + id: 'role_input', + type: SubmissionRequirementMatchType.InputDescriptor, }, ]); expect(resultSelectFrom.verifiableCredential?.length).toEqual(2);