From f2f9fbc0c999664c8c1cfdd4b0f0204ea1b8ccf1 Mon Sep 17 00:00:00 2001 From: Niels Klomp Date: Wed, 9 Aug 2023 23:57:24 +0200 Subject: [PATCH] feat: Allow document loader to also load DID from the agent and fall back to the universal resolver (all configurable) --- .../src/agent/CredentialHandlerLDLocal.ts | 6 + .../src/ld-credential-module.ts | 403 +++++++++--------- .../src/ld-document-loader.ts | 257 +++++------ packages/vc-handler-ld-local/src/ld-suites.ts | 13 +- 4 files changed, 361 insertions(+), 318 deletions(-) diff --git a/packages/vc-handler-ld-local/src/agent/CredentialHandlerLDLocal.ts b/packages/vc-handler-ld-local/src/agent/CredentialHandlerLDLocal.ts index df2ee6b88..13aa317f7 100644 --- a/packages/vc-handler-ld-local/src/agent/CredentialHandlerLDLocal.ts +++ b/packages/vc-handler-ld-local/src/agent/CredentialHandlerLDLocal.ts @@ -57,11 +57,17 @@ export class CredentialHandlerLDLocal implements IAgentPlugin { suites: SphereonLdSignature[] bindingOverrides?: IBindingOverrides keyStore?: AbstractPrivateKeyStore + documentLoader?: { + localResolution?: boolean // Resolve identifiers hosted by the agent + uniresolverResolution?: boolean // Resolve identifiers using universal resolver + resolverResolution?: boolean // Use registered drivers + } }) { this.keyStore = options.keyStore this.ldCredentialModule = new LdCredentialModule({ ldContextLoader: new LdContextLoader({ contextsPaths: options.contextMaps }), ldSuiteLoader: new LdSuiteLoader({ ldSignatureSuites: options.suites }), + documentLoader: options?.documentLoader }) this.overrideBindings(options.bindingOverrides) 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 f4c647dd4..aa5c1df23 100644 --- a/packages/vc-handler-ld-local/src/ld-credential-module.ts +++ b/packages/vc-handler-ld-local/src/ld-credential-module.ts @@ -1,17 +1,24 @@ -import { purposes } from '@digitalcredentials/jsonld-signatures' +import {purposes} from '@digitalcredentials/jsonld-signatures' import * as vc from '@digitalcredentials/vc' -import { CredentialIssuancePurpose } from '@digitalcredentials/vc' -import { BbsBlsSignature2020 } from '@mattrglobal/jsonld-signatures-bbs' -import { VerifiableCredentialSP, VerifiablePresentationSP } from '@sphereon/ssi-sdk.core' -import { IVerifyResult } from '@sphereon/ssi-types' -import { CredentialPayload, IAgentContext, IKey, PresentationPayload, VerifiableCredential, VerifiablePresentation } from '@veramo/core' +import {CredentialIssuancePurpose} from '@digitalcredentials/vc' +import {BbsBlsSignature2020} from '@mattrglobal/jsonld-signatures-bbs' +import {VerifiableCredentialSP, VerifiablePresentationSP} from '@sphereon/ssi-sdk.core' +import {IVerifyResult} from '@sphereon/ssi-types' +import { + CredentialPayload, + IAgentContext, + IKey, + PresentationPayload, + VerifiableCredential, + VerifiablePresentation +} from '@veramo/core' import Debug from 'debug' -import { LdContextLoader } from './ld-context-loader' -import { LdDocumentLoader } from './ld-document-loader' -import { LdSuiteLoader } from './ld-suite-loader' -import { RequiredAgentMethods } from './ld-suites' -import { events } from './types' +import {LdContextLoader} from './ld-context-loader' +import {LdDocumentLoader} from './ld-document-loader' +import {LdSuiteLoader} from './ld-suite-loader' +import {RequiredAgentMethods} from './ld-suites' +import {events} from './types' // import jsigs from '@digitalcredentials/jsonld-signatures' //Support for Typescript added in version 9.0.0 @@ -25,195 +32,201 @@ const AuthenticationProofPurpose = purposes.AuthenticationProofPurpose const debug = Debug('sphereon:ssi-sdk:ld-credential-module-local') export class LdCredentialModule { - /** - * TODO: General Implementation Notes - * - (SOLVED) EcdsaSecp256k1Signature2019 (Signature) and EcdsaSecp256k1VerificationKey2019 (Key) - * are not useable right now, since they are not able to work with blockChainId and ECRecover. - * - DID Fragment Resolution. - * - Key Manager and Verification Methods: Veramo currently implements no link between those. - */ - - ldSuiteLoader: LdSuiteLoader - private ldDocumentLoader: LdDocumentLoader - - constructor(options: { ldContextLoader: LdContextLoader; ldSuiteLoader: LdSuiteLoader }) { - this.ldSuiteLoader = options.ldSuiteLoader - this.ldDocumentLoader = new LdDocumentLoader(options) - } - - async issueLDVerifiableCredential( - credential: CredentialPayload, - issuerDid: string, - key: IKey, - verificationMethodId: string, - purpose: typeof ProofPurpose = new CredentialIssuancePurpose(), - context: IAgentContext - ): Promise { - debug(`Issue VC method called for ${key.kid}...`) - const suite = this.ldSuiteLoader.getSignatureSuiteForKeyType(key.type, key.meta?.verificationMethod?.type) - const documentLoader = this.ldDocumentLoader.getLoader(context, { attemptToFetchContexts: true, verifiableData: credential }) - - // some suites can modify the incoming credential (e.g. add required contexts) - suite.preSigningCredModification(credential) - debug(`Signing suite will be retrieved for ${verificationMethodId}...`) - const signingSuite = await suite.getSuiteForSigning(key, issuerDid, verificationMethodId, context) - debug(`Issuer ${issuerDid} will create VC for ${key.kid}...`) - - let verifiableCredential - //Needs to be signed using jsonld-signaures@5.0.1 - if (key.type === 'Bls12381G2') { - verifiableCredential = await jsigs.sign(credential, { - suite: signingSuite, - purpose, - documentLoader, - compactProof: true, - }) - } else { - verifiableCredential = await vc.issue({ - credential, - purpose, - suite: signingSuite, - documentLoader, - compactProof: false, - }) + /** + * TODO: General Implementation Notes + * - (SOLVED) EcdsaSecp256k1Signature2019 (Signature) and EcdsaSecp256k1VerificationKey2019 (Key) + * are not useable right now, since they are not able to work with blockChainId and ECRecover. + * - DID Fragment Resolution. + * - Key Manager and Verification Methods: Veramo currently implements no link between those. + */ + + ldSuiteLoader: LdSuiteLoader + private ldDocumentLoader: LdDocumentLoader + + constructor(options: { + ldContextLoader: LdContextLoader; ldSuiteLoader: LdSuiteLoader, documentLoader?: { + localResolution?: boolean // Resolve identifiers hosted by the agent + uniresolverResolution?: boolean // Resolve identifiers using universal resolver + resolverResolution?: boolean // Use registered drivers + } + }) { + this.ldSuiteLoader = options.ldSuiteLoader + this.ldDocumentLoader = new LdDocumentLoader(options) } - debug(`Issuer ${issuerDid} created VC for ${key.kid}`) - return verifiableCredential - } - - async signLDVerifiablePresentation( - presentation: PresentationPayload, - holderDid: string, - key: IKey, - verificationMethodId: string, - challenge: string | undefined, - domain: string | undefined, - purpose: typeof ProofPurpose = !challenge && !domain - ? new AssertionProofPurpose() - : new AuthenticationProofPurpose({ - domain, - challenge, - }), - context: IAgentContext - ): Promise { - const suite = this.ldSuiteLoader.getSignatureSuiteForKeyType(key.type, key.meta?.verificationMethod?.type) - const documentLoader = this.ldDocumentLoader.getLoader(context, { attemptToFetchContexts: true, verifiableData: presentation }) - - suite.preSigningPresModification(presentation) - - if (key.type === 'Bls12381G2') { - return await jsigs.sign(presentation, { - suite: await suite.getSuiteForSigning(key, holderDid, verificationMethodId, context), - purpose, - documentLoader, - compactProof: true, - }) + + async issueLDVerifiableCredential( + credential: CredentialPayload, + issuerDid: string, + key: IKey, + verificationMethodId: string, + purpose: typeof ProofPurpose = new CredentialIssuancePurpose(), + context: IAgentContext + ): Promise { + debug(`Issue VC method called for ${key.kid}...`) + const suite = this.ldSuiteLoader.getSignatureSuiteForKeyType(key.type, key.meta?.verificationMethod?.type) + const documentLoader = this.ldDocumentLoader.getLoader(context, {attemptToFetchContexts: true, verifiableData: credential}) + + // some suites can modify the incoming credential (e.g. add required contexts) + suite.preSigningCredModification(credential) + debug(`Signing suite will be retrieved for ${verificationMethodId}...`) + const signingSuite = await suite.getSuiteForSigning(key, issuerDid, verificationMethodId, context) + debug(`Issuer ${issuerDid} will create VC for ${key.kid}...`) + + let verifiableCredential + //Needs to be signed using jsonld-signaures@5.0.1 + if (key.type === 'Bls12381G2') { + verifiableCredential = await jsigs.sign(credential, { + suite: signingSuite, + purpose, + documentLoader, + compactProof: true, + }) + } else { + verifiableCredential = await vc.issue({ + credential, + purpose, + suite: signingSuite, + documentLoader, + compactProof: false, + }) + } + debug(`Issuer ${issuerDid} created VC for ${key.kid}`) + return verifiableCredential } - return await vc.signPresentation({ - presentation, - suite: await suite.getSuiteForSigning(key, holderDid, verificationMethodId, context), - challenge, - domain, - documentLoader, - purpose, - compactProof: false, - }) - } - - async verifyCredential( - credential: VerifiableCredential, - context: IAgentContext, - fetchRemoteContexts = false, - purpose: typeof ProofPurpose = new AssertionProofPurpose(), - checkStatus?: Function - ): Promise { - const verificationSuites = this.getAllVerificationSuites(context) - this.ldSuiteLoader.getAllSignatureSuites().forEach((suite) => suite.preVerificationCredModification(credential)) - 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(context) as BbsBlsSignature2020 - - // fixme: check signature of verify method, adjust result if needed - result = await jsigs.verify(credential, { - suite, - purpose, - documentLoader: this.ldDocumentLoader.getLoader(context, { attemptToFetchContexts: fetchRemoteContexts, verifiableData: credential }), - compactProof: true, - }) - } else { - result = await vc.verifyCredential({ - credential, - suite: verificationSuites, - documentLoader: this.ldDocumentLoader.getLoader(context, { attemptToFetchContexts: fetchRemoteContexts, verifiableData: credential }), - purpose, - compactProof: false, - checkStatus, - }) + + async signLDVerifiablePresentation( + presentation: PresentationPayload, + holderDid: string, + key: IKey, + verificationMethodId: string, + challenge: string | undefined, + domain: string | undefined, + purpose: typeof ProofPurpose = !challenge && !domain + ? new AssertionProofPurpose() + : new AuthenticationProofPurpose({ + domain, + challenge, + }), + context: IAgentContext + ): Promise { + const suite = this.ldSuiteLoader.getSignatureSuiteForKeyType(key.type, key.meta?.verificationMethod?.type) + const documentLoader = this.ldDocumentLoader.getLoader(context, {attemptToFetchContexts: true, verifiableData: presentation}) + + suite.preSigningPresModification(presentation) + + if (key.type === 'Bls12381G2') { + return await jsigs.sign(presentation, { + suite: await suite.getSuiteForSigning(key, holderDid, verificationMethodId, context), + purpose, + documentLoader, + compactProof: true, + }) + } + return await vc.signPresentation({ + presentation, + suite: await suite.getSuiteForSigning(key, holderDid, verificationMethodId, context), + challenge, + domain, + documentLoader, + purpose, + compactProof: false, + }) } - if (result.verified) { - 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 }) + + async verifyCredential( + credential: VerifiableCredential, + context: IAgentContext, + fetchRemoteContexts = false, + purpose: typeof ProofPurpose = new AssertionProofPurpose(), + checkStatus?: Function + ): Promise { + const verificationSuites = this.getAllVerificationSuites(context) + this.ldSuiteLoader.getAllSignatureSuites().forEach((suite) => suite.preVerificationCredModification(credential)) + 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(context) as BbsBlsSignature2020 + + // fixme: check signature of verify method, adjust result if needed + result = await jsigs.verify(credential, { + suite, + purpose, + documentLoader: this.ldDocumentLoader.getLoader(context, {attemptToFetchContexts: fetchRemoteContexts, verifiableData: credential}), + compactProof: true, + }) + } else { + result = await vc.verifyCredential({ + credential, + suite: verificationSuites, + documentLoader: this.ldDocumentLoader.getLoader(context, {attemptToFetchContexts: fetchRemoteContexts, verifiableData: credential}), + purpose, + compactProof: false, + checkStatus, + }) + } + if (result.verified) { + void 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)}`) + void context.agent.emit(events.CREDENTIAL_VERIFY_FAILED, {credential, ...result}) + } + return result } - return result - } - - private getAllVerificationSuites(context: IAgentContext) { - return this.ldSuiteLoader.getAllSignatureSuites().map((x) => x.getSuiteForVerification(context)) - } - - async verifyPresentation( - presentation: VerifiablePresentation, - challenge: string | undefined, - domain: string | undefined, - context: IAgentContext, - fetchRemoteContexts = false, - presentationPurpose: typeof ProofPurpose = !challenge && !domain - ? new AssertionProofPurpose() - : new AuthenticationProofPurpose({ domain, challenge }), - checkStatus?: Function - //AssertionProofPurpose() - ): Promise { - let result: IVerifyResult - if (presentation.proof.type?.includes('BbsBlsSignature2020')) { - //Should never be null or undefined - const suite = this.ldSuiteLoader - .getAllSignatureSuites() - .find((s) => s.getSupportedVeramoKeyType() === 'Bls12381G2') - ?.getSuiteForVerification(context) as BbsBlsSignature2020 - result = await jsigs.verify(presentation, { - suite, - purpose: presentationPurpose, - documentLoader: this.ldDocumentLoader.getLoader(context, { attemptToFetchContexts: fetchRemoteContexts, verifiableData: presentation }), - compactProof: true, - }) - } else { - result = await vc.verify({ - presentation, - suite: this.getAllVerificationSuites(context), - documentLoader: this.ldDocumentLoader.getLoader(context, { attemptToFetchContexts: fetchRemoteContexts, verifiableData: presentation }), - challenge, - domain, - presentationPurpose, - compactProof: false, - checkStatus, - }) + + private getAllVerificationSuites(context: IAgentContext) { + return this.ldSuiteLoader.getAllSignatureSuites().map((x) => x.getSuiteForVerification(context)) } - if (result.verified && (!result.presentationResult || result.presentationResult.verified)) { - context.agent.emit(events.PRESENTATION_VERIFIED, { presentation, ...result }) - } else { - // NOT verified. - debug(`Error verifying LD Verifiable Presentation: ${JSON.stringify(result, null, 2)}`) - context.agent.emit(events.PRESENTATION_VERIFY_FAILED, { presentation, ...result }) + async verifyPresentation( + presentation: VerifiablePresentation, + challenge: string | undefined, + domain: string | undefined, + context: IAgentContext, + fetchRemoteContexts = false, + presentationPurpose: typeof ProofPurpose = !challenge && !domain + ? new AssertionProofPurpose() + : new AuthenticationProofPurpose({domain, challenge}), + checkStatus?: Function + //AssertionProofPurpose() + ): Promise { + let result: IVerifyResult + if (presentation.proof.type?.includes('BbsBlsSignature2020')) { + //Should never be null or undefined + const suite = this.ldSuiteLoader + .getAllSignatureSuites() + .find((s) => s.getSupportedVeramoKeyType() === 'Bls12381G2') + ?.getSuiteForVerification(context) as BbsBlsSignature2020 + result = await jsigs.verify(presentation, { + suite, + purpose: presentationPurpose, + documentLoader: this.ldDocumentLoader.getLoader(context, {attemptToFetchContexts: fetchRemoteContexts, verifiableData: presentation}), + compactProof: true, + }) + } else { + result = await vc.verify({ + presentation, + suite: this.getAllVerificationSuites(context), + documentLoader: this.ldDocumentLoader.getLoader(context, {attemptToFetchContexts: fetchRemoteContexts, verifiableData: presentation}), + challenge, + domain, + presentationPurpose, + compactProof: false, + checkStatus, + }) + } + + if (result.verified && (!result.presentationResult || result.presentationResult.verified)) { + context.agent.emit(events.PRESENTATION_VERIFIED, {presentation, ...result}) + } else { + // NOT verified. + debug(`Error verifying LD Verifiable Presentation: ${JSON.stringify(result, null, 2)}`) + context.agent.emit(events.PRESENTATION_VERIFY_FAILED, {presentation, ...result}) + } + return result } - return result - } } diff --git a/packages/vc-handler-ld-local/src/ld-document-loader.ts b/packages/vc-handler-ld-local/src/ld-document-loader.ts index 0baa7732f..1c21aa9ea 100644 --- a/packages/vc-handler-ld-local/src/ld-document-loader.ts +++ b/packages/vc-handler-ld-local/src/ld-document-loader.ts @@ -1,19 +1,20 @@ -import { extendContextLoader } from '@digitalcredentials/jsonld-signatures' +import {extendContextLoader} from '@digitalcredentials/jsonld-signatures' import vc from '@digitalcredentials/vc' import { - CredentialPayload, - DIDDocument, - IAgentContext, - IResolver, - PresentationPayload, - VerifiableCredential, - VerifiablePresentation, + CredentialPayload, + DIDDocument, + IAgentContext, IDIDManager, + IResolver, + PresentationPayload, + VerifiableCredential, + VerifiablePresentation, } from '@veramo/core' -import { fetch } from 'cross-fetch' +import {fetch} from 'cross-fetch' import Debug from 'debug' -import { LdContextLoader } from './ld-context-loader' -import { LdSuiteLoader } from './ld-suite-loader' +import {LdContextLoader} from './ld-context-loader' +import {LdSuiteLoader} from './ld-suite-loader' +import {getAgentResolver} from "@sphereon/ssi-sdk-ext.did-utils"; const debug = Debug('sphereon:ssi-sdk:vc-handler-ld-local') @@ -21,126 +22,140 @@ const debug = Debug('sphereon:ssi-sdk:vc-handler-ld-local') * Initializes a list of Veramo-wrapped LD Signature suites and exposes those to the Agent Module */ export class LdDocumentLoader { - private ldContextLoader: LdContextLoader - ldSuiteLoader: LdSuiteLoader + private readonly ldContextLoader: LdContextLoader + ldSuiteLoader: LdSuiteLoader + private readonly localResolution?: boolean + private readonly uniresolverResolution?: boolean; + private readonly resolverResolution?: boolean; - constructor(options: { ldContextLoader: LdContextLoader; ldSuiteLoader: LdSuiteLoader }) { - this.ldContextLoader = options.ldContextLoader - this.ldSuiteLoader = options.ldSuiteLoader - } - getLoader( - context: IAgentContext, - { - attemptToFetchContexts = false, - verifiableData, - }: { attemptToFetchContexts: boolean; verifiableData: VerifiableCredential | VerifiablePresentation | CredentialPayload | PresentationPayload } - ) { - return extendContextLoader(async (url: string) => { - if (!url || url.trim().length === 0) { - throw Error('URL needs to be provided to load a context!') - } - const origUrl = url - if (url.startsWith('#') && verifiableData.issuer !== undefined) { - url = (typeof verifiableData.issuer === 'string' ? verifiableData.issuer : verifiableData.issuer.id) + url - debug(url) - } - // did resolution - if (url.toLowerCase().startsWith('did:')) { - const resolutionResult = await context.agent.resolveDid({ didUrl: url }) - let didDoc: DIDDocument | null = resolutionResult.didDocument - if (!didDoc) { - throw new Error(`Could not fetch DID document with url: ${url}. Did you enable the the driver?`) + constructor(options: { + ldContextLoader: LdContextLoader; ldSuiteLoader: LdSuiteLoader, documentLoader?: { + localResolution?: boolean // Resolve identifiers hosted by the agent + uniresolverResolution?: boolean // Resolve identifiers using universal resolver + resolverResolution?: boolean // Use registered drivers } - // currently Veramo LD suites can modify the resolution response for DIDs from - // the document Loader. This allows to fix incompatibilities between DID Documents - // and LD suites to be fixed specifically within the Veramo LD Suites definition - this.ldSuiteLoader.getAllSignatureSuites().forEach((x) => x.preDidResolutionModification(url, didDoc as DIDDocument)) + }) { + this.ldContextLoader = options.ldContextLoader + this.ldSuiteLoader = options.ldSuiteLoader + this.localResolution = options?.documentLoader?.localResolution + this.uniresolverResolution = options?.documentLoader?.uniresolverResolution + this.resolverResolution = options?.documentLoader?.resolverResolution + } - // Move legacy publicKey to verificationMethod, so any dependency that does not support it, keeps functioning - if (didDoc.publicKey) { - if (!didDoc.verificationMethod) { - didDoc.verificationMethod = [] - } - didDoc.verificationMethod = [...didDoc.verificationMethod, ...didDoc.publicKey] - if (didDoc.verificationMethod.length === 0) { - throw new Error(`No verification method available for ${url}`) - } - delete didDoc.publicKey - } + getLoader( + context: IAgentContext, + { + attemptToFetchContexts = false, + verifiableData, + }: { attemptToFetchContexts: boolean; verifiableData: VerifiableCredential | VerifiablePresentation | CredentialPayload | PresentationPayload } + ) { + return extendContextLoader(async (url: string) => { + if (!url || url.trim().length === 0) { + throw Error('URL needs to be provided to load a context!') + } + const origUrl = url + if (url.startsWith('#') && verifiableData.issuer !== undefined) { + url = (typeof verifiableData.issuer === 'string' ? verifiableData.issuer : verifiableData.issuer.id) + url + debug(url) + } + // did resolution + if (url.toLowerCase().startsWith('did:')) { + const resolutionResult = await getAgentResolver(context, {localResolution: this.localResolution, resolverResolution: this.resolverResolution, uniresolverResolution: this.uniresolverResolution}).resolve(url) + // context.agent.resolveDid({didUrl: url}) + let didDoc: DIDDocument | null = resolutionResult.didDocument + if (!didDoc) { + throw new Error(`Could not fetch DID document with url: ${url}. Did you enable the the driver?`) + } + // currently Veramo LD suites can modify the resolution response for DIDs from + // the document Loader. This allows to fix incompatibilities between DID Documents + // and LD suites to be fixed specifically within the Veramo LD Suites definition + this.ldSuiteLoader.getAllSignatureSuites().forEach((x) => x.preDidResolutionModification(url, didDoc as DIDDocument)) - if (url.indexOf('#') > 0 && didDoc['@context']) { - if (origUrl !== url) { - // Make sure we replace the result URLs with the original URLs, so framing keeps working - didDoc = JSON.parse(JSON.stringify(didDoc).replace(url, origUrl)) as DIDDocument - debug('CHANGED:') - debug(didDoc) - } + // Move legacy publicKey to verificationMethod, so any dependency that does not support it, keeps functioning + if (didDoc.publicKey) { + if (!didDoc.verificationMethod) { + didDoc.verificationMethod = [] + } + didDoc.verificationMethod = [...didDoc.verificationMethod, ...didDoc.publicKey] + if (didDoc.verificationMethod.length === 0) { + throw new Error(`No verification method available for ${url}`) + } + delete didDoc.publicKey + } - // Apparently we got a whole DID document, but we are looking for a verification method - // We use origUrl here, as that is how it was used in the VM - const component = await context.agent.getDIDComponentById({ didDocument: didDoc, didUrl: origUrl }) - debug('Component:') - debug(component) - debug('Component stringified:') - debug(JSON.stringify(component)) - if (component && typeof component !== 'string' && component.id) { - // We have to provide a context - const contexts = this.ldSuiteLoader - .getAllSignatureSuites() - .filter((x) => x.getSupportedVerificationType() === component.type /* || component.type === 'Ed25519VerificationKey2018'*/) - .filter((value, index, self) => self.indexOf(value) === index) - .map((value) => value.getContext()) - const fragment = { ...component, '@context': contexts } + if (url.indexOf('#') > 0 && didDoc['@context']) { + if (origUrl !== url) { + // Make sure we replace the result URLs with the original URLs, so framing keeps working + didDoc = JSON.parse(JSON.stringify(didDoc).replace(url, origUrl)) as DIDDocument + debug('CHANGED:') + debug(didDoc) + } - return { - contextUrl: null, - documentUrl: url, - document: fragment, - } - } - } + // Apparently we got a whole DID document, but we are looking for a verification method + // We use origUrl here, as that is how it was used in the VM + const component = await context.agent.getDIDComponentById({didDocument: didDoc, didUrl: origUrl}) + debug('Component:') + debug(component) + debug('Component stringified:') + debug(JSON.stringify(component)) + if (component && typeof component !== 'string' && component.id) { + // We have to provide a context + const contexts = this.ldSuiteLoader + .getAllSignatureSuites() + .filter((x) => x.getSupportedVerificationType() === component.type /* || component.type === 'Ed25519VerificationKey2018'*/) + .filter((value, index, self) => self.indexOf(value) === index) + .map((value) => value.getContext()) + const fragment = {...component, '@context': contexts} - return { - contextUrl: null, - documentUrl: url, - document: didDoc, - } - } + return { + contextUrl: null, + documentUrl: url, + document: fragment, + } + } + } - if (this.ldContextLoader.has(url)) { - const contextDoc = await this.ldContextLoader.get(url) - return { - contextUrl: null, - documentUrl: url, - document: contextDoc, - } - } else { - if (attemptToFetchContexts) { - debug('WARNING: attempting to fetch the doc directly for ', url) - try { - const response = await fetch(url, { redirect: 'follow' }) - if (response.status === 200) { - const document = await response.json() - // fixme: The VC API returns an _id object for RL Credentials, which is not allowed, so delete it here for now - if (url.startsWith('https://vc-api.sphereon.io/services/credentials/')) { - delete document._id - } - return { - contextUrl: null, - documentUrl: url, - document, - } + return { + contextUrl: null, + documentUrl: url, + document: didDoc, + } + } + + if (this.ldContextLoader.has(url)) { + const contextDoc = await this.ldContextLoader.get(url) + return { + contextUrl: null, + documentUrl: url, + document: contextDoc, + } + } else { + if (attemptToFetchContexts) { + debug('WARNING: attempting to fetch the doc directly for ', url) + try { + const response = await fetch(url, {redirect: 'follow'}) + if (response.status === 200) { + const document = await response.json() + // fixme: The VC API returns an _id object for RL Credentials, which is not allowed, so delete it here for now + if (url.startsWith('https://vc-api.sphereon.io/services/credentials/')) { + delete document._id + } + return { + contextUrl: null, + documentUrl: url, + document, + } + } + } catch (e) { + debug('WARNING: unable to fetch the doc or interpret it as JSON', e) + } + } } - } catch (e) { - debug('WARNING: unable to fetch the doc or interpret it as JSON', e) - } - } - } - debug(`WARNING: Possible unknown context/identifier for ${url} \n falling back to default documentLoader`) + debug(`WARNING: Possible unknown context/identifier for ${url} \n falling back to default documentLoader`) - return vc.defaultDocumentLoader(url) - }) - } + return vc.defaultDocumentLoader(url) + }) + } } diff --git a/packages/vc-handler-ld-local/src/ld-suites.ts b/packages/vc-handler-ld-local/src/ld-suites.ts index 229f8edc3..87ae3d980 100644 --- a/packages/vc-handler-ld-local/src/ld-suites.ts +++ b/packages/vc-handler-ld-local/src/ld-suites.ts @@ -1,8 +1,17 @@ import { ISphereonKeyManager } from '@sphereon/ssi-sdk-ext.key-manager' -import { CredentialPayload, IAgentContext, IKey, IResolver, PresentationPayload, TKeyType, VerifiableCredential } from '@veramo/core' +import { + CredentialPayload, + IAgentContext, + IDIDManager, + IKey, + IResolver, + PresentationPayload, + TKeyType, + VerifiableCredential +} from '@veramo/core' import { DIDDocument } from 'did-resolver/lib/resolver' -export type RequiredAgentMethods = IResolver & Pick +export type RequiredAgentMethods = IResolver & IDIDManager & Pick export abstract class SphereonLdSignature { // LinkedDataSignature Suites according to