From 7df0e64ad6553e8153cf96d62156867fde8e4cef Mon Sep 17 00:00:00 2001 From: nklomp Date: Fri, 5 May 2023 19:13:51 +0200 Subject: [PATCH] feat: instead of returning a boolean value, return an object with more information about verification of LD creds/VPs --- packages/ssi-types/src/types/vc.ts | 61 ++++ .../vc-handler-ld-local/plugin.schema.json | 269 +++++++++++++++++- .../src/__tests__/issue-verify-flow.test.ts | 240 +++++++++++++++- .../shared/vcHandlerLocalAgentBbsLogic.ts | 33 ++- .../src/agent/CredentialHandlerLDLocal.ts | 9 +- .../src/ld-credential-module.ts | 76 ++--- .../src/types/ICredentialHandlerLDLocal.ts | 5 +- yarn.lock | 8 +- 8 files changed, 634 insertions(+), 67 deletions(-) diff --git a/packages/ssi-types/src/types/vc.ts b/packages/ssi-types/src/types/vc.ts index b46d70d6c..bc3e43a40 100644 --- a/packages/ssi-types/src/types/vc.ts +++ b/packages/ssi-types/src/types/vc.ts @@ -211,3 +211,64 @@ export const enum DocumentFormat { JSONLD, EIP712, } + +export interface IVerifyStatusResult { + verified: boolean + /** + * Optional Error object for the + * but currently the machine readable errors are not exported from DID-JWT package to be imported here + */ + error?: IError | undefined + + /** + * Other options can be specified for verification. + * They will be forwarded to the lower level modules. that performt the checks + */ + [x: string]: any +} + +export interface IVerifyResult { + /** + * This value is used to transmit the global result of verification. + */ + verified: boolean + + results: [ + { + credential: ICredential + verified: boolean + error?: IError + log: [{ id: string; valid: boolean }] + } + ] + + statusResult?: IVerifyStatusResult + + /** + * Optional Error object for the + * but currently the machine readable errors are not exported from DID-JWT package to be imported here + */ + error?: IError | undefined + + /** + * Other options can be specified for verification. + * They will be forwarded to the lower level modules. that performt the checks + */ + [x: string]: any +} + +/** + * An error object, which can contain a code. + * @beta + */ +export interface IError { + /** + * The details of the error being throw or forwarded + */ + message?: string + + /** + * The code for the error being throw + */ + errorCode?: string +} diff --git a/packages/vc-handler-ld-local/plugin.schema.json b/packages/vc-handler-ld-local/plugin.schema.json index afe9fe045..02aa8b4d3 100644 --- a/packages/vc-handler-ld-local/plugin.schema.json +++ b/packages/vc-handler-ld-local/plugin.schema.json @@ -827,6 +827,271 @@ "caller" ] }, + "IVerifyResult": { + "type": "object", + "properties": { + "verified": { + "type": "boolean", + "description": "This value is used to transmit the global result of verification." + }, + "results": { + "type": "array", + "items": { + "type": "object", + "properties": { + "credential": { + "$ref": "#/components/schemas/ICredential" + }, + "verified": { + "type": "boolean" + }, + "error": { + "$ref": "#/components/schemas/IError" + }, + "log": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "valid": { + "type": "boolean" + } + }, + "required": [ + "id", + "valid" + ] + }, + "minItems": 1, + "maxItems": 1 + } + }, + "required": [ + "credential", + "verified", + "log" + ] + }, + "minItems": 1, + "maxItems": 1 + }, + "statusResult": { + "$ref": "#/components/schemas/IVerifyStatusResult" + }, + "error": { + "$ref": "#/components/schemas/IError", + "description": "Optional Error object for the but currently the machine readable errors are not exported from DID-JWT package to be imported here" + } + }, + "required": [ + "verified", + "results" + ], + "additionalProperties": { + "description": "Other options can be specified for verification. They will be forwarded to the lower level modules. that performt the checks" + } + }, + "ICredential": { + "type": "object", + "properties": { + "@context": { + "anyOf": [ + { + "$ref": "#/components/schemas/ICredentialContextType" + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/ICredentialContextType" + } + } + ] + }, + "type": { + "type": "array", + "items": { + "type": "string" + } + }, + "credentialSchema": { + "anyOf": [ + { + "$ref": "#/components/schemas/ICredentialSchemaType" + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/ICredentialSchemaType" + } + } + ] + }, + "issuer": { + "anyOf": [ + { + "$ref": "#/components/schemas/IIssuerId" + }, + { + "$ref": "#/components/schemas/IIssuer" + } + ] + }, + "issuanceDate": { + "type": "string" + }, + "credentialSubject": { + "anyOf": [ + { + "type": "object", + "properties": { + "id": { + "type": "string" + } + } + }, + { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + } + } + } + ] + }, + "expirationDate": { + "type": "string" + }, + "id": { + "type": "string" + }, + "credentialStatus": { + "$ref": "#/components/schemas/ICredentialStatus" + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "@context", + "type", + "issuer", + "issuanceDate", + "credentialSubject" + ] + }, + "ICredentialContextType": { + "anyOf": [ + { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "did": { + "type": "string" + } + } + }, + { + "type": "string" + } + ] + }, + "ICredentialSchemaType": { + "anyOf": [ + { + "$ref": "#/components/schemas/ICredentialSchema" + }, + { + "type": "string" + } + ] + }, + "ICredentialSchema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "id" + ] + }, + "IIssuerId": { + "type": "string" + }, + "IIssuer": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + }, + "required": [ + "id" + ] + }, + "ICredentialStatus": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "id", + "type" + ] + }, + "IError": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "The details of the error being throw or forwarded" + }, + "errorCode": { + "type": "string", + "description": "The code for the error being throw" + } + }, + "description": "An error object, which can contain a code." + }, + "IVerifyStatusResult": { + "type": "object", + "properties": { + "verified": { + "type": "boolean" + }, + "error": { + "$ref": "#/components/schemas/IError", + "description": "Optional Error object for the but currently the machine readable errors are not exported from DID-JWT package to be imported here" + } + }, + "required": [ + "verified" + ], + "additionalProperties": { + "description": "Other options can be specified for verification. They will be forwarded to the lower level modules. that performt the checks" + } + }, "IVerifyPresentationLDArgs": { "type": "object", "properties": { @@ -980,7 +1245,7 @@ "$ref": "#/components/schemas/IVerifyCredentialLDArgs" }, "returnType": { - "type": "boolean" + "$ref": "#/components/schemas/IVerifyResult" } }, "verifyPresentationLDLocal": { @@ -989,7 +1254,7 @@ "$ref": "#/components/schemas/IVerifyPresentationLDArgs" }, "returnType": { - "type": "boolean" + "$ref": "#/components/schemas/IVerifyResult" } } } diff --git a/packages/vc-handler-ld-local/src/__tests__/issue-verify-flow.test.ts b/packages/vc-handler-ld-local/src/__tests__/issue-verify-flow.test.ts index 6201d292e..6f7a91566 100644 --- a/packages/vc-handler-ld-local/src/__tests__/issue-verify-flow.test.ts +++ b/packages/vc-handler-ld-local/src/__tests__/issue-verify-flow.test.ts @@ -128,7 +128,65 @@ describe('credential-LD full flow', () => { fetchRemoteContexts: true, }) - expect(verifiedCredential).toBe(true) + expect(verifiedCredential).toMatchObject({ + log: [ + { + id: 'expiration', + valid: true, + }, + { + id: 'valid_signature', + valid: true, + }, + { + id: 'issuer_did_resolves', + valid: true, + }, + { + id: 'revocation_status', + valid: true, + }, + ], + results: [ + { + log: [ + { + id: 'expiration', + valid: true, + }, + { + id: 'valid_signature', + valid: true, + }, + { + id: 'issuer_did_resolves', + valid: true, + }, + { + id: 'revocation_status', + valid: true, + }, + ], + proof: { + '@context': ['https://www.w3.org/2018/credentials/v1', 'https://www.w3.org/2018/credentials/examples/v1'], + proofPurpose: 'assertionMethod', + type: 'Ed25519Signature2018', + }, + purposeResult: { + controller: { + '@context': ['https://www.w3.org/ns/did/v1', 'https://w3id.org/security/suites/ed25519-2018/v1'], + }, + valid: true, + }, + verificationMethod: { + '@context': 'https://w3id.org/security/suites/ed25519-2018/v1', + type: 'Ed25519VerificationKey2018', + }, + verified: true, + }, + ], + verified: true, + }) const presentationPayload: PresentationPayload = { holder: didLtoIdentifier.did, @@ -151,7 +209,98 @@ describe('credential-LD full flow', () => { presentationPurpose: new ControllerProofPurpose({ term: 'verificationMethod' }), }) - expect(verifiedPresentation).toBe(true) + expect(verifiedPresentation).toMatchObject({ + credentialResults: [ + { + log: [ + { + id: 'expiration', + valid: true, + }, + { + id: 'valid_signature', + valid: true, + }, + { + id: 'issuer_did_resolves', + valid: true, + }, + { + id: 'revocation_status', + valid: true, + }, + ], + results: [ + { + log: [ + { + id: 'expiration', + valid: true, + }, + { + id: 'valid_signature', + valid: true, + }, + { + id: 'issuer_did_resolves', + valid: true, + }, + { + id: 'revocation_status', + valid: true, + }, + ], + proof: { + '@context': ['https://www.w3.org/2018/credentials/v1', 'https://www.w3.org/2018/credentials/examples/v1'], + proofPurpose: 'assertionMethod', + type: 'Ed25519Signature2018', + }, + purposeResult: { + valid: true, + }, + verificationMethod: { + '@context': 'https://w3id.org/security/suites/ed25519-2018/v1', + type: 'Ed25519VerificationKey2018', + }, + verified: true, + }, + ], + verified: true, + }, + ], + presentationResult: { + results: [ + { + proof: { + '@context': ['https://www.w3.org/2018/credentials/v1'], + proofPurpose: 'verificationMethod', + type: 'Ed25519Signature2018', + }, + purposeResult: { + controller: { + '@context': 'https://www.w3.org/ns/did/v1', + verificationMethod: [ + { + type: 'Ed25519VerificationKey2018', + }, + { + type: 'Ed25519VerificationKey2018', + }, + ], + }, + valid: true, + }, + verificationMethod: { + '@context': 'https://w3id.org/security/suites/ed25519-2018/v1', + type: 'Ed25519VerificationKey2018', + }, + verified: true, + }, + ], + verified: true, + }, + verified: true, + }) }) it('should verify issued credential with Factom issuer', async () => { @@ -201,6 +350,91 @@ describe('credential-LD full flow', () => { fetchRemoteContexts: true, }) - expect(verifiedCredential).toBe(true) + expect(verifiedCredential).toMatchObject({ + log: [ + { + id: 'expiration', + valid: true, + }, + { + id: 'valid_signature', + valid: true, + }, + { + id: 'issuer_did_resolves', + valid: true, + }, + { + id: 'revocation_status', + valid: true, + }, + ], + results: [ + { + log: [ + { + id: 'expiration', + valid: true, + }, + { + id: 'valid_signature', + valid: true, + }, + { + id: 'issuer_did_resolves', + valid: true, + }, + { + id: 'revocation_status', + valid: true, + }, + ], + proof: { + '@context': [ + 'https://www.w3.org/2018/credentials/v1', + 'https://sphereon-opensource.github.io/vc-contexts/myc/bedrijfsinformatie-v1.jsonld', + ], + type: 'Ed25519Signature2018', + }, + purposeResult: { + controller: { + '@context': ['https://www.w3.org/ns/did/v1'], + assertionMethod: [ + { + type: 'Ed25519VerificationKey2018', + }, + ], + authentication: [ + { + type: 'Ed25519VerificationKey2018', + }, + ], + capabilityInvocation: [ + { + type: 'Ed25519VerificationKey2018', + }, + ], + keyAgreement: [ + { + type: 'Ed25519VerificationKey2018', + }, + ], + verificationMethod: [ + { + type: 'Ed25519VerificationKey2018', + }, + ], + }, + valid: true, + }, + verificationMethod: { + '@context': 'https://w3id.org/security/suites/ed25519-2018/v1', + type: 'Ed25519VerificationKey2018', + }, + verified: true, + }, + ], + verified: true, + }) }) }) diff --git a/packages/vc-handler-ld-local/src/__tests__/shared/vcHandlerLocalAgentBbsLogic.ts b/packages/vc-handler-ld-local/src/__tests__/shared/vcHandlerLocalAgentBbsLogic.ts index 761d82e61..0f7ac2f7f 100644 --- a/packages/vc-handler-ld-local/src/__tests__/shared/vcHandlerLocalAgentBbsLogic.ts +++ b/packages/vc-handler-ld-local/src/__tests__/shared/vcHandlerLocalAgentBbsLogic.ts @@ -136,7 +136,24 @@ export default (testContext: { setup: () => Promise; tearDown: () => Pr }) it('Should verify a BBS+ verifiable credential', async () => { - await expect(agent.verifyCredentialLDLocal({ credential: verifiableCredential, fetchRemoteContexts: false })).resolves.toEqual(true) + await expect( + agent.verifyCredentialLDLocal({ + credential: verifiableCredential, + fetchRemoteContexts: false, + }) + ).resolves.toMatchObject({ + results: [ + { + proof: { + '@context': 'https://w3id.org/security/v2', + proofPurpose: 'assertionMethod', + type: 'sec:BbsBlsSignature2020', + }, + verified: true, + }, + ], + verified: true, + }) }) it('Should create a BBS+ verifiable presentation', async () => { @@ -202,7 +219,19 @@ export default (testContext: { setup: () => Promise; tearDown: () => Pr }) it('Should verify a BBS+ verifiable presentation', async () => { - await expect(agent.verifyPresentationLDLocal({ presentation: verifiablePresentation })).resolves.toEqual(true) + await expect(agent.verifyPresentationLDLocal({ presentation: verifiablePresentation })).resolves.toMatchObject({ + results: [ + { + proof: { + '@context': 'https://w3id.org/security/v2', + proofPurpose: 'assertionMethod', + type: 'sec:BbsBlsSignature2020', + }, + verified: true, + }, + ], + verified: true, + }) }) }) } diff --git a/packages/vc-handler-ld-local/src/agent/CredentialHandlerLDLocal.ts b/packages/vc-handler-ld-local/src/agent/CredentialHandlerLDLocal.ts index b94e06f86..365ac1871 100644 --- a/packages/vc-handler-ld-local/src/agent/CredentialHandlerLDLocal.ts +++ b/packages/vc-handler-ld-local/src/agent/CredentialHandlerLDLocal.ts @@ -9,15 +9,16 @@ import { LdContextLoader } from '../ld-context-loader' import { LdCredentialModule } from '../ld-credential-module' import { LdSuiteLoader } from '../ld-suite-loader' import { SphereonLdSignature } from '../ld-suites' -import { ICredentialHandlerLDLocal } from '../types' import { ContextDoc, ICreateVerifiableCredentialLDArgs, ICreateVerifiablePresentationLDArgs, + ICredentialHandlerLDLocal, IVerifyCredentialLDArgs, IVerifyPresentationLDArgs, -} from '../types/types' +} from '../types' import { mapIdentifierKeysToDocWithJwkSupport } from '@sphereon/ssi-sdk-did-utils' +import { IVerifyResult } from '@sphereon/ssi-types' const debug = Debug('sphereon:ssi-sdk:ld-credential-module-local') @@ -198,13 +199,13 @@ export class CredentialHandlerLDLocal implements IAgentPlugin { } /** {@inheritdoc ICredentialHandlerLDLocal.verifyCredentialLDLocal} */ - public async verifyCredentialLDLocal(args: IVerifyCredentialLDArgs, context: IRequiredContext): Promise { + public async verifyCredentialLDLocal(args: IVerifyCredentialLDArgs, context: IRequiredContext): Promise { const credential = args.credential return this.ldCredentialModule.verifyCredential(credential, context, args.fetchRemoteContexts, args.purpose, args.checkStatus) } /** {@inheritdoc ICredentialHandlerLDLocal.verifyPresentationLDLocal} */ - public async verifyPresentationLDLocal(args: IVerifyPresentationLDArgs, context: IRequiredContext): Promise { + public async verifyPresentationLDLocal(args: IVerifyPresentationLDArgs, context: IRequiredContext): Promise { const presentation = args.presentation return this.ldCredentialModule.verifyPresentation( presentation, diff --git a/packages/vc-handler-ld-local/src/ld-credential-module.ts b/packages/vc-handler-ld-local/src/ld-credential-module.ts index 1b22b62b4..8f94ec647 100644 --- a/packages/vc-handler-ld-local/src/ld-credential-module.ts +++ b/packages/vc-handler-ld-local/src/ld-credential-module.ts @@ -19,6 +19,7 @@ import Debug from 'debug' import { LdContextLoader } from './ld-context-loader' import { LdDocumentLoader } from './ld-document-loader' import { LdSuiteLoader } from './ld-suite-loader' +import { IVerifyResult } from '@sphereon/ssi-types' // import jsigs from '@digitalcredentials/jsonld-signatures' //Support for Typescript added in version 9.0.0 @@ -134,19 +135,21 @@ export class LdCredentialModule { fetchRemoteContexts = false, purpose: typeof ProofPurpose = new AssertionProofPurpose(), checkStatus?: Function - ): Promise { + ): Promise { const verificationSuites = this.getAllVerificationSuites() this.ldSuiteLoader.getAllSignatureSuites().forEach((suite) => suite.preVerificationCredModification(credential)) - let result + let result: IVerifyResult if (credential.proof.type?.includes('BbsBlsSignature2020')) { //Should never be null or undefined const suite = this.ldSuiteLoader .getAllSignatureSuites() .find((s) => s.getSupportedVeramoKeyType() === 'Bls12381G2') ?.getSuiteForVerification() as BbsBlsSignature2020 + + // fixme: check signature of verify method, adjust result if needed result = await jsigs.verify(credential, { suite, - purpose: purpose, + purpose, documentLoader: this.ldDocumentLoader.getLoader(context, fetchRemoteContexts), compactProof: true, }) @@ -155,29 +158,20 @@ export class LdCredentialModule { credential, suite: verificationSuites, documentLoader: this.ldDocumentLoader.getLoader(context, fetchRemoteContexts), - purpose: purpose, + purpose, compactProof: false, - checkStatus: checkStatus, + checkStatus, }) } if (result.verified) { - result.results.forEach((item: any) => { - const eventData = { - credential: credential, - result: item, - } - context.agent.emit(events.CREDENTIAL_VERIFIED, eventData) - }) - return true + context.agent.emit(events.CREDENTIAL_VERIFIED, { credential, ...result }) + } else { + // result can include raw Error + debug(`Error verifying LD Verifiable Credential: ${JSON.stringify(result, null, 2)}`) + console.log(`ERROR verifying LD VC:\n${JSON.stringify(result, null, 2)}`) + context.agent.emit(events.CREDENTIAL_VERIFY_FAILED, { credential, ...result }) } - - // NOT verified. - - // result can include raw Error - debug(`Error verifying LD Verifiable Credential: ${JSON.stringify(result, null, 2)}`) - console.log(JSON.stringify(result, null, 2)) - context.agent.emit(events.CREDENTIAL_VERIFY_FAILED, credential) - throw Error('Error verifying LD Verifiable Credential') + return result } private getAllVerificationSuites() { @@ -195,9 +189,9 @@ export class LdCredentialModule { : new AuthenticationProofPurpose({ domain, challenge }), checkStatus?: Function //AssertionProofPurpose() - ): Promise { + ): Promise { // console.log(JSON.stringify(presentation, null, 2)) - let result + let result: IVerifyResult if (presentation.proof.type?.includes('BbsBlsSignature2020')) { //Should never be null or undefined const suite = this.ldSuiteLoader @@ -210,15 +204,6 @@ export class LdCredentialModule { documentLoader: this.ldDocumentLoader.getLoader(context, fetchRemoteContexts), compactProof: true, }) - - if (result.verified) { - const eventData = { - presentation: presentation, - result: result, - } - context.agent.emit(events.PRESENTATION_VERIFIED, eventData) - return true - } } else { result = await vc.verify({ presentation, @@ -230,25 +215,16 @@ export class LdCredentialModule { compactProof: false, checkStatus, }) - - if (result.verified && result.presentationResult.verified) { - result.presentationResult.results.forEach((item: any) => { - const eventData = { - presentation: presentation, - result: item, - } - context.agent.emit(events.PRESENTATION_VERIFIED, eventData) - }) - return true - } } - // NOT verified. - - // result can include raw Error - console.log(`Error verifying LD Verifiable Presentation`) - console.log(JSON.stringify(result, null, 2)) - context.agent.emit(events.PRESENTATION_VERIFY_FAILED, presentation) - throw Error('Error verifying LD Verifiable Presentation') + if (result.verified && (!result.presentationResult || result.presentationResult.verified)) { + context.agent.emit(events.PRESENTATION_VERIFIED, { presentation, ...result }) + } else { + // NOT verified. + console.log(`Error verifying LD Verifiable Presentation`) + console.log(JSON.stringify(result, null, 2)) + context.agent.emit(events.PRESENTATION_VERIFY_FAILED, { presentation, ...result }) + } + return result } } diff --git a/packages/vc-handler-ld-local/src/types/ICredentialHandlerLDLocal.ts b/packages/vc-handler-ld-local/src/types/ICredentialHandlerLDLocal.ts index ff582014b..7f0a1a799 100644 --- a/packages/vc-handler-ld-local/src/types/ICredentialHandlerLDLocal.ts +++ b/packages/vc-handler-ld-local/src/types/ICredentialHandlerLDLocal.ts @@ -8,6 +8,7 @@ import { IVerifyCredentialLDArgs, IVerifyPresentationLDArgs, } from './types' +import { IVerifyResult } from '@sphereon/ssi-types' /** * The interface definition for a plugin that can issue and verify Verifiable Credentials and Presentations @@ -62,7 +63,7 @@ export interface ICredentialHandlerLDLocal extends IPluginMethodMap { * * @beta This API is likely to change without a BREAKING CHANGE notice */ - verifyCredentialLDLocal(args: IVerifyCredentialLDArgs, context: IRequiredContext): Promise + verifyCredentialLDLocal(args: IVerifyCredentialLDArgs, context: IRequiredContext): Promise /** * Verifies a Verifiable Presentation JWT or LDS Format. @@ -76,7 +77,7 @@ export interface ICredentialHandlerLDLocal extends IPluginMethodMap { * * @beta This API is likely to change without a BREAKING CHANGE notice */ - verifyPresentationLDLocal(args: IVerifyPresentationLDArgs, context: IRequiredContext): Promise + verifyPresentationLDLocal(args: IVerifyPresentationLDArgs, context: IRequiredContext): Promise } /** diff --git a/yarn.lock b/yarn.lock index 6ff7c223a..e4bfa3edb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2312,10 +2312,10 @@ "@trust/keyto" "^2.0.0-alpha1" "@veramo/core" "4.2.0" -"@sphereon/did-auth-siop@0.3.1-unstable.0": - version "0.3.1-unstable.0" - resolved "https://registry.yarnpkg.com/@sphereon/did-auth-siop/-/did-auth-siop-0.3.1-unstable.0.tgz#01b7d7697f09f918be5adf2077ab86723c10c8c7" - integrity sha512-Omb3Vlr/PO+0GtP8dm6Ve4MGdy8B25rosH05w3OAclnSLciY8/cdU48Q2Q/me/tPURGwQK7Okz5/oTJqSnNulw== +"@sphereon/did-auth-siop@0.3.1-unstable.1": + version "0.3.1-unstable.1" + resolved "https://registry.yarnpkg.com/@sphereon/did-auth-siop/-/did-auth-siop-0.3.1-unstable.1.tgz#c5a37dbc9f7cbd9062ef0a416b6a1c76d8f55167" + integrity sha512-AvK4r8e6fqJ0Ww9/pFxjcw1wtqW2tANZFSFHujEEACnn25ubz5sMCBKIePKeV8/9eFc+inpYJANBulTwf34fiQ== dependencies: "@sphereon/did-uni-client" "^0.6.0" "@sphereon/pex" "^2.0.1"