From c2c836725f6bad064fa8cbc3105778b625866657 Mon Sep 17 00:00:00 2001 From: Niels Klomp Date: Tue, 28 Nov 2023 03:11:56 +0100 Subject: [PATCH 1/3] fix: submission generation logic --- CHANGELOG.md | 15 +++++++++++++++ lib/PEX.ts | 40 ++++++++++++++++++++++++++++------------ package.json | 4 ++-- test/PEX.spec.ts | 9 ++++++--- yarn.lock | 8 ++++---- 5 files changed, 55 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c836982..5d1e0d58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Release Notes +## v2.2.2 - 2023-11-28 + +- Updated: + - Updated pex-model deps + - Added more logic to deduce holder(s) for a VP +- Fixed: + - Logic when to generate a presentation submission was incorrect + +## v2.2.1 - 2023-10-23 + +- Updated: + - Updated logic to return holder DID when constructing presentation +- Fixed: + - Issue with determining whether to generate submission data or not. + ## v2.2.0 - 2023-10-12 - Updated: diff --git a/lib/PEX.ts b/lib/PEX.ts index af34d8bd..c3efd143 100644 --- a/lib/PEX.ts +++ b/lib/PEX.ts @@ -1,5 +1,6 @@ import { Format, PresentationDefinitionV1, PresentationDefinitionV2, PresentationSubmission } from '@sphereon/pex-models'; import { + CredentialMapper, IPresentation, IProof, OriginalVerifiableCredential, @@ -21,7 +22,7 @@ import { VerifiablePresentationResult, } from './signing'; import { DiscoveredVersion, IInternalPresentationDefinition, IPresentationDefinition, PEVersion, SSITypesBuilder } from './types'; -import { definitionVersionDiscovery } from './utils'; +import { definitionVersionDiscovery, getSubjectIdsAsString } from './utils'; import { PresentationDefinitionV1VB, PresentationDefinitionV2VB, PresentationSubmissionVB, Validated, ValidationEngine } from './validation'; /** @@ -58,7 +59,7 @@ export class PEX { }, ): EvaluationResults { const generatePresentationSubmission = - opts?.generatePresentationSubmission !== undefined ? opts.generatePresentationSubmission : opts?.presentationSubmission !== undefined; + opts?.generatePresentationSubmission !== undefined ? opts.generatePresentationSubmission : opts?.presentationSubmission === undefined; const pd: IInternalPresentationDefinition = SSITypesBuilder.toInternalPresentationDefinition(presentationDefinition); const presentationCopy: OriginalVerifiablePresentation = JSON.parse(JSON.stringify(presentation)); const wrappedPresentation: WrappedVerifiablePresentation = SSITypesBuilder.mapExternalVerifiablePresentationToWrappedVP(presentationCopy); @@ -190,6 +191,7 @@ export class PEX { const presentationSubmission = this.presentationSubmissionFrom(presentationDefinition, selectedCredentials, opts); const presentation = PEX.constructPresentation(selectedCredentials, { ...opts, + // We only pass in the submission in case it needs to be included in the presentation presentationSubmission: presentationSubmissionLocation === PresentationSubmissionLocation.PRESENTATION ? presentationSubmission : undefined, }); return { @@ -207,12 +209,28 @@ export class PEX { basePresentationPayload?: IPresentation; }, ): IPresentation { - const holder = opts?.holderDID; - const type = Array.isArray(opts?.basePresentationPayload?.type) - ? opts?.basePresentationPayload?.type || [] - : opts?.basePresentationPayload?.type - ? [opts.basePresentationPayload.type] + if (!selectedCredentials) { + throw Error(`At least a verifiable credential needs to be passed in to create a presentation`); + } + const verifiableCredential = (Array.isArray(selectedCredentials) ? selectedCredentials : [selectedCredentials]) as W3CVerifiableCredential[]; + const wVCs = verifiableCredential.map((vc) => CredentialMapper.toWrappedVerifiableCredential(vc)); + const holders = Array.from(new Set(wVCs.flatMap((wvc) => getSubjectIdsAsString(wvc.credential)))); + if (holders.length !== 1 && !opts?.holderDID) { + console.log( + `We deduced ${holders.length} subject from ${wVCs.length} Verifiable Credentials, and no holder property was given. This might lead to undesired results`, + ); + } + const holder = opts?.holderDID ?? (holders.length === 1 ? holders[0] : undefined); + + const type = opts?.basePresentationPayload?.type + ? Array.isArray(opts.basePresentationPayload.type) + ? opts.basePresentationPayload.type + : [opts.basePresentationPayload.type] : []; + if (!type.includes('VerifiablePresentation')) { + type.push('VerifiablePresentation'); + } + const context = opts?.basePresentationPayload?.['@context'] ? Array.isArray(opts.basePresentationPayload['@context']) ? opts.basePresentationPayload['@context'] @@ -222,9 +240,6 @@ export class PEX { context.push('https://www.w3.org/2018/credentials/v1'); } - if (!type.includes('VerifiablePresentation')) { - type.push('VerifiablePresentation'); - } if (opts?.presentationSubmission) { if (!type.includes('PresentationSubmission')) { type.push('PresentationSubmission'); @@ -238,8 +253,8 @@ export class PEX { '@context': context, type, holder, - ...(!!opts?.presentationSubmission && { presentation_submission: opts.presentationSubmission }), - verifiableCredential: (Array.isArray(selectedCredentials) ? selectedCredentials : [selectedCredentials]) as W3CVerifiableCredential[], + ...(opts?.presentationSubmission && { presentation_submission: opts.presentationSubmission }), + verifiableCredential, }; } @@ -334,6 +349,7 @@ export class PEX { const evaluationResults = this.evaluatePresentation(presentationDefinition, presentationResult.presentation, { limitDisclosureSignatureSuites, ...(presentationSubmissionLocation === PresentationSubmissionLocation.EXTERNAL && { + // The method will pickup submissions included in the Presentation anyway presentationSubmission: presentationResult.presentationSubmission, }), }); diff --git a/package.json b/package.json index 9e133070..b5decd87 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@sphereon/pex", - "version": "2.2.1-unstable.0", + "version": "2.2.2-unstable.0", "description": "A Typescript implementation of the v1 and v2 DIF Presentation Exchange specification", "main": "dist/main/index.js", "module": "dist/module/index.js", @@ -41,7 +41,7 @@ "node": ">=16" }, "dependencies": { - "@sphereon/pex-models": "^2.1.1", + "@sphereon/pex-models": "^2.1.2", "@sphereon/ssi-types": "^0.17.5", "ajv": "^8.12.0", "ajv-formats": "^2.1.1", diff --git a/test/PEX.spec.ts b/test/PEX.spec.ts index a85f84b7..814ab028 100644 --- a/test/PEX.spec.ts +++ b/test/PEX.spec.ts @@ -135,9 +135,12 @@ describe('evaluate', () => { // Delete the submission to trigger an error delete vpSimple.presentation_submission; const pex: PEX = new PEX(); - expect(() => pex.evaluatePresentation(pdSchema, vpSimple, { limitDisclosureSignatureSuites: LIMIT_DISCLOSURE_SIGNATURE_SUITES })).toThrowError( - 'Either a presentation submission as part of the VP or provided separately was expected', - ); + expect(() => + pex.evaluatePresentation(pdSchema, vpSimple, { + limitDisclosureSignatureSuites: LIMIT_DISCLOSURE_SIGNATURE_SUITES, + generatePresentationSubmission: false, + }), + ).toThrowError('Either a presentation submission as part of the VP or provided separately was expected'); }); it('Evaluate case without any error 2', () => { diff --git a/yarn.lock b/yarn.lock index 9b76a0ef..d73413e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -689,10 +689,10 @@ dependencies: "@sinonjs/commons" "^3.0.0" -"@sphereon/pex-models@^2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@sphereon/pex-models/-/pex-models-2.1.1.tgz#399e529db2a7e3b9abbd7314cdba619ceb6cb758" - integrity sha512-0UX/CMwgiJSxzuBn6SLOTSKkm+uPq3dkNjl8w4EtppXp6zBB4lQMd1mJX7OifX5Bp5vPUfoz7bj2B+yyDtbZww== +"@sphereon/pex-models@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@sphereon/pex-models/-/pex-models-2.1.2.tgz#e1a0ce16ccc6b32128fc8c2da79d65fc35f6d10f" + integrity sha512-Ec1qZl8tuPd+s6E+ZM7v+HkGkSOjGDMLNN1kqaxAfWpITBYtTLb+d5YvwjvBZ1P2upZ7zwNER97FfW5n/30y2w== "@sphereon/ssi-types@^0.17.5": version "0.17.5" From 9a55f6605b74f73e67984b02dae84fe6f0dcc3a0 Mon Sep 17 00:00:00 2001 From: Niels Klomp Date: Tue, 28 Nov 2023 03:28:40 +0100 Subject: [PATCH 2/3] chore: release v2.2.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b5decd87..d689e00f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@sphereon/pex", - "version": "2.2.2-unstable.0", + "version": "2.2.2", "description": "A Typescript implementation of the v1 and v2 DIF Presentation Exchange specification", "main": "dist/main/index.js", "module": "dist/module/index.js", From dbea36c4e03d626926871cbb51d55e2f3e9cba5b Mon Sep 17 00:00:00 2001 From: Niels Klomp Date: Tue, 28 Nov 2023 03:29:24 +0100 Subject: [PATCH 3/3] chore: prepare for next release --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d689e00f..142b4d58 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@sphereon/pex", - "version": "2.2.2", + "version": "2.2.3.unstable.0", "description": "A Typescript implementation of the v1 and v2 DIF Presentation Exchange specification", "main": "dist/main/index.js", "module": "dist/module/index.js",