@sphereon/ssi-sdk.linked-vp 0.37.2-next.34 → 0.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +6 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +6 -22
- package/dist/index.js.map +1 -1
- package/package.json +13 -13
- package/plugin.schema.json +7 -23
- package/src/agent/LinkedVPManager.ts +5 -6
package/dist/index.cjs
CHANGED
|
@@ -40,9 +40,7 @@ var plugin_schema_default = {
|
|
|
40
40
|
type: "string"
|
|
41
41
|
}
|
|
42
42
|
},
|
|
43
|
-
required: [
|
|
44
|
-
"linkedVpId"
|
|
45
|
-
],
|
|
43
|
+
required: ["linkedVpId"],
|
|
46
44
|
additionalProperties: false
|
|
47
45
|
},
|
|
48
46
|
LinkedVPPresentation: {
|
|
@@ -81,11 +79,7 @@ var plugin_schema_default = {
|
|
|
81
79
|
type: "string"
|
|
82
80
|
}
|
|
83
81
|
},
|
|
84
|
-
required: [
|
|
85
|
-
"id",
|
|
86
|
-
"type",
|
|
87
|
-
"serviceEndpoint"
|
|
88
|
-
],
|
|
82
|
+
required: ["id", "type", "serviceEndpoint"],
|
|
89
83
|
additionalProperties: false
|
|
90
84
|
},
|
|
91
85
|
HasLinkedVPEntryArgs: {
|
|
@@ -95,9 +89,7 @@ var plugin_schema_default = {
|
|
|
95
89
|
type: "string"
|
|
96
90
|
}
|
|
97
91
|
},
|
|
98
|
-
required: [
|
|
99
|
-
"linkedVpId"
|
|
100
|
-
],
|
|
92
|
+
required: ["linkedVpId"],
|
|
101
93
|
additionalProperties: false
|
|
102
94
|
},
|
|
103
95
|
PublishCredentialArgs: {
|
|
@@ -113,9 +105,7 @@ var plugin_schema_default = {
|
|
|
113
105
|
type: "string"
|
|
114
106
|
}
|
|
115
107
|
},
|
|
116
|
-
required: [
|
|
117
|
-
"digitalCredentialId"
|
|
118
|
-
],
|
|
108
|
+
required: ["digitalCredentialId"],
|
|
119
109
|
additionalProperties: false
|
|
120
110
|
},
|
|
121
111
|
LinkedVPEntry: {
|
|
@@ -139,11 +129,7 @@ var plugin_schema_default = {
|
|
|
139
129
|
format: "date-time"
|
|
140
130
|
}
|
|
141
131
|
},
|
|
142
|
-
required: [
|
|
143
|
-
"id",
|
|
144
|
-
"linkedVpId",
|
|
145
|
-
"createdAt"
|
|
146
|
-
],
|
|
132
|
+
required: ["id", "linkedVpId", "createdAt"],
|
|
147
133
|
additionalProperties: false
|
|
148
134
|
},
|
|
149
135
|
UnpublishCredentialArgs: {
|
|
@@ -153,9 +139,7 @@ var plugin_schema_default = {
|
|
|
153
139
|
type: "string"
|
|
154
140
|
}
|
|
155
141
|
},
|
|
156
|
-
required: [
|
|
157
|
-
"linkedVpId"
|
|
158
|
-
],
|
|
142
|
+
required: ["linkedVpId"],
|
|
159
143
|
additionalProperties: false
|
|
160
144
|
}
|
|
161
145
|
},
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../plugin.schema.json","../src/agent/LinkedVPManager.ts","../src/services/LinkedVPService.ts","../src/types/ILinkedVPManager.ts"],"sourcesContent":["/**\n * @public\n */\nimport schema from '../plugin.schema.json'\nexport { schema }\nexport { LinkedVPManager, linkedVPManagerMethods } from './agent/LinkedVPManager'\nexport * from './types/ILinkedVPManager'\n","{\n \"ILinkedVPManager\": {\n \"components\": {\n \"schemas\": {\n \"GeneratePresentationArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"linkedVpId\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"linkedVpId\"\n ],\n \"additionalProperties\": false\n },\n \"LinkedVPPresentation\": {\n \"anyOf\": [\n {\n \"type\": \"string\"\n },\n {\n \"$ref\": \"#/components/schemas/Record<string,any>\"\n }\n ]\n },\n \"Record<string,any>\": {\n \"type\": \"object\"\n },\n \"GetServiceEntriesArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"tenantId\": {\n \"type\": \"string\"\n }\n },\n \"additionalProperties\": false\n },\n \"LinkedVPServiceEntry\": {\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\n \"type\": \"string\"\n },\n \"type\": {\n \"type\": \"string\",\n \"const\": \"LinkedVerifiablePresentation\"\n },\n \"serviceEndpoint\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"id\",\n \"type\",\n \"serviceEndpoint\"\n ],\n \"additionalProperties\": false\n },\n \"HasLinkedVPEntryArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"linkedVpId\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"linkedVpId\"\n ],\n \"additionalProperties\": false\n },\n \"PublishCredentialArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"digitalCredentialId\": {\n \"type\": \"string\"\n },\n \"linkedVpId\": {\n \"type\": \"string\"\n },\n \"tenantId\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"digitalCredentialId\"\n ],\n \"additionalProperties\": false\n },\n \"LinkedVPEntry\": {\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\n \"type\": \"string\"\n },\n \"linkedVpId\": {\n \"type\": \"string\"\n },\n \"tenantId\": {\n \"type\": \"string\"\n },\n \"linkedVpFrom\": {\n \"type\": \"string\",\n \"format\": \"date-time\"\n },\n \"createdAt\": {\n \"type\": \"string\",\n \"format\": \"date-time\"\n }\n },\n \"required\": [\n \"id\",\n \"linkedVpId\",\n \"createdAt\"\n ],\n \"additionalProperties\": false\n },\n \"UnpublishCredentialArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"linkedVpId\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"linkedVpId\"\n ],\n \"additionalProperties\": false\n }\n },\n \"methods\": {\n \"lvpGeneratePresentation\": {\n \"description\": \"Generate and return a Verifiable Presentation for a published LinkedVP This is the main endpoint handler for GET /linked-vp/\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/GeneratePresentationArgs\"\n },\n \"returnType\": {\n \"$ref\": \"#/components/schemas/LinkedVPPresentation\"\n }\n },\n \"lvpGetServiceEntries\": {\n \"description\": \"Get LinkedVP service entries for a DID to be added to a DID Document This is useful when generating DID Documents with toDidDocument\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/GetServiceEntriesArgs\"\n },\n \"returnType\": {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/components/schemas/LinkedVPServiceEntry\"\n }\n }\n },\n \"lvpHasEntry\": {\n \"description\": \"Check if a LinkedVP entry exists by linkedVpId\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/HasLinkedVPEntryArgs\"\n },\n \"returnType\": {\n \"type\": \"boolean\"\n }\n },\n \"lvpPublishCredential\": {\n \"description\": \"Publish a credential as a LinkedVP by adding it to the holder's DID Document\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/PublishCredentialArgs\"\n },\n \"returnType\": {\n \"$ref\": \"#/components/schemas/LinkedVPEntry\"\n }\n },\n \"lvpUnpublishCredential\": {\n \"description\": \"Unpublish a credential by removing its LinkedVP entry from the DID Document\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/UnpublishCredentialArgs\"\n },\n \"returnType\": {\n \"type\": \"boolean\"\n }\n }\n }\n }\n }\n}","import { DigitalCredential } from '@sphereon/ssi-sdk.data-store-types'\nimport { type IVerifiableCredential } from '@sphereon/ssi-types'\nimport { IAgentPlugin } from '@veramo/core'\nimport { IsNull, Not } from 'typeorm'\nimport { schema } from '../index'\nimport { createLinkedVPPresentation } from '../services/LinkedVPService'\nimport {\n GeneratePresentationArgs,\n GetServiceEntriesArgs,\n HasLinkedVPEntryArgs,\n ILinkedVPManager,\n LinkedVPEntry,\n LinkedVPPresentation,\n LinkedVPServiceEntry,\n PublishCredentialArgs,\n RequiredContext,\n UnpublishCredentialArgs,\n} from '../types'\n\n// Exposing the methods here for any REST implementation\nexport const linkedVPManagerMethods: Array<string> = [\n 'lvpPublishCredential',\n 'lvpUnpublishCredential',\n 'lvpHasEntry',\n 'lvpGetServiceEntries',\n 'lvpGeneratePresentation',\n]\n\n/**\n * {@inheritDoc ILinkedVPManager}\n */\nexport class LinkedVPManager implements IAgentPlugin {\n readonly schema = schema.ILinkedVPManager\n readonly methods: ILinkedVPManager = {\n lvpPublishCredential: this.lvpPublishCredential.bind(this),\n lvpUnpublishCredential: this.lvpUnpublishCredential.bind(this),\n lvpHasEntry: this.lvpHasEntry.bind(this),\n lvpGetServiceEntries: this.lvpGetServiceEntries.bind(this),\n lvpGeneratePresentation: this.lvpGeneratePresentation.bind(this),\n }\n\n private async lvpPublishCredential(args: PublishCredentialArgs, context: RequiredContext): Promise<LinkedVPEntry> {\n const { digitalCredentialId } = args\n\n const credential: DigitalCredential = await context.agent.crsGetCredential({ id: digitalCredentialId })\n\n if (credential.linkedVpId) {\n return Promise.reject(new Error(`Credential ${digitalCredentialId} is already published with linkedVpId ${credential.linkedVpId}`))\n }\n\n const linkedVpId = this.buildLinkedVpId(args.linkedVpId, credential.tenantId)\n\n await this.ensureLinkedVpIdUnique(linkedVpId, context, credential.tenantId)\n\n const publishAt = args.linkedVpFrom ?? new Date()\n await context.agent.crsUpdateCredential({\n id: digitalCredentialId,\n linkedVpId,\n linkedVpFrom: publishAt,\n linkedVpUntil: args.linkedVpUntil,\n })\n\n return {\n id: credential.id,\n linkedVpId,\n tenantId: credential.tenantId,\n linkedVpFrom: publishAt,\n linkedVpUntil: args.linkedVpUntil,\n createdAt: credential.createdAt,\n }\n }\n\n private async lvpUnpublishCredential(args: UnpublishCredentialArgs, context: RequiredContext): Promise<boolean> {\n const { linkedVpId } = args\n\n // Find credential by linkedVpId and tenantId\n const credentials = await context.agent.crsGetCredentials({\n filter: [{ linkedVpId }],\n })\n if (credentials.length === 0) {\n return Promise.reject(Error(`No credential found with linkedVpId ${linkedVpId}`))\n }\n\n const credential = credentials[0]\n await context.agent.crsUpdateCredential({\n id: credential.id,\n linkedVpId: undefined,\n linkedVpFrom: undefined,\n })\n\n return true\n }\n\n private async lvpHasEntry(args: HasLinkedVPEntryArgs, context: RequiredContext): Promise<boolean> {\n const { linkedVpId } = args\n\n try {\n const credentials = await context.agent.crsGetCredentials({\n filter: [{ linkedVpId }],\n })\n return credentials.length > 0\n } catch (error) {\n return false\n }\n }\n\n private async lvpGetServiceEntries(args: GetServiceEntriesArgs, context: RequiredContext): Promise<Array<LinkedVPServiceEntry>> {\n const { tenantId, subjectDid } = args\n\n // Get all published credentials (credentials with linkedVpId set)\n const filter: any = { linkedVpId: Not(IsNull()) }\n if (tenantId) {\n filter.tenantId = tenantId\n }\n if (subjectDid) {\n filter.subjectCorrelationId = subjectDid\n }\n\n const credentials = await context.agent.crsGetCredentials({\n filter: [filter],\n })\n\n return credentials\n .flatMap((cred) => {\n const uniformDocument = JSON.parse(cred.uniformDocument) as IVerifiableCredential\n const holderDidForEntry = this.getHolderDid(uniformDocument)\n return holderDidForEntry && holderDidForEntry.startsWith('did:web') ? [this.credentialToServiceEntry(cred, holderDidForEntry)] : []\n })\n }\n\n private async lvpGeneratePresentation(args: GeneratePresentationArgs, context: RequiredContext): Promise<LinkedVPPresentation> {\n const { linkedVpId } = args\n const tenantId = this.parseTenantFromLinkedVpId(linkedVpId)\n\n const uniqueCredentials = await context.agent.crsGetUniqueCredentials({\n filter: [\n {\n linkedVpId: args.linkedVpId,\n linkedVpUntil: args.linkedVpUntil,\n ...(tenantId && { tenantId }),\n },\n ],\n })\n if (uniqueCredentials.length === 0) {\n return Promise.reject(Error(`No published credentials found for linkedVpId ${linkedVpId}`))\n }\n if (uniqueCredentials.length > 1) {\n return Promise.reject(Error(`Multiple credentials found for linkedVpId ${linkedVpId}`))\n }\n\n const uniqueDigitalCredential = uniqueCredentials[0]\n if (!uniqueDigitalCredential.uniformVerifiableCredential) {\n return Promise.reject(Error(`uniformVerifiableCredential could not be found for credential ${uniqueDigitalCredential.digitalCredential.id}`))\n }\n const holderDid = this.getHolderDid(uniqueDigitalCredential.uniformVerifiableCredential)\n if (!holderDid) {\n return Promise.reject(Error(`Could not extract the holder did:web from cnf nor the credentialSubject id`))\n }\n\n // Generate the Verifiable Presentation with all published credentials\n return createLinkedVPPresentation(holderDid, uniqueDigitalCredential, context.agent)\n }\n\n private getHolderDid(uniformDocument: IVerifiableCredential): string | undefined {\n // Determine holder DID for identifier resolution\n if ('cnf' in uniformDocument && 'jwk' in uniformDocument.cnf && 'kid' in uniformDocument.cnf.jwk) {\n return uniformDocument.cnf.jwk.kid.split('#')[0]\n }\n\n if ('credentialSubject' in uniformDocument) {\n const credentialSubject = Array.isArray(uniformDocument.credentialSubject)\n ? uniformDocument.credentialSubject[0]\n : uniformDocument.credentialSubject\n if ('id' in credentialSubject && credentialSubject.id) {\n if (credentialSubject.id.startsWith('did:web')) {\n return credentialSubject.id\n }\n }\n }\n\n return undefined\n }\n\n private parseTenantFromLinkedVpId(linkedVpId: string): string | undefined {\n const idx = linkedVpId.lastIndexOf('@')\n return idx === -1 ? undefined : linkedVpId.substring(idx + 1)\n }\n\n private generateLinkedVpId(): string {\n return `lvp-${Math.random().toString(36).substring(2, 15)}`\n }\n\n private async ensureLinkedVpIdUnique(linkedVpId: string, context: RequiredContext, tenantId?: string): Promise<void> {\n const credentials = await context.agent.crsGetCredentials({\n filter: [{ linkedVpId, ...(tenantId && { tenantId }) }],\n })\n\n if (credentials.length > 0) {\n throw new Error(`LinkedVP ID ${linkedVpId} already exists${tenantId ? ` for tenant ${tenantId}` : ''}`)\n }\n }\n\n private buildLinkedVpId(linkedVpId: string | undefined, tenantId: string | undefined) {\n let finalLinkedVpId = linkedVpId || this.generateLinkedVpId()\n\n // Validate that user-provided ID doesn't contain @ char reserved for tenant id separator\n if (linkedVpId && linkedVpId.includes('@')) {\n throw new Error(`LinkedVP ID cannot contain '@' character as it is reserved for tenant separation`)\n }\n\n // Append tenantId if provided\n if (tenantId && tenantId !== '') {\n finalLinkedVpId = `${finalLinkedVpId}@${tenantId}`\n }\n return finalLinkedVpId\n }\n\n private getBaseUrlFromDid(holderDid: string): string {\n if (!holderDid.startsWith('did:web:')) {\n throw new Error(`Invalid DID: ${holderDid}, must be did:web`)\n }\n\n const withoutPrefix = holderDid.replace('did:web:', '') // example.com:tenants:tenant1\n const parts = withoutPrefix.split(':')\n const domain = parts.shift()! // example.com\n const path = parts.join('/') // tenants/tenant1\n\n return path\n ? `https://${domain}/${path}` // https://example.com/tenants/tenant1\n : `https://${domain}` // https://example.com\n }\n\n private buildServiceEndpoint(holderDid: string, linkedVpId: string): string {\n const baseUrl = this.getBaseUrlFromDid(holderDid)\n const cleanBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl\n return `${cleanBaseUrl}/linked-vp/${linkedVpId}`\n }\n\n private credentialToServiceEntry(credential: DigitalCredential, holderDid: string): LinkedVPServiceEntry {\n if (!credential.linkedVpId) {\n throw new Error(`Credential ${credential.id} does not have a linkedVpId`)\n }\n\n return {\n id: `${holderDid}#${credential.linkedVpId}`,\n type: 'LinkedVerifiablePresentation',\n serviceEndpoint: this.buildServiceEndpoint(holderDid, credential.linkedVpId),\n }\n }\n}\n","import { UniqueDigitalCredential } from '@sphereon/ssi-sdk.credential-store'\nimport { calculateSdHash, defaultGenerateDigest, PartialSdJwtKbJwt } from '@sphereon/ssi-sdk.sd-jwt'\n\nimport {\n CredentialMapper,\n DocumentFormat,\n Loggers,\n OriginalVerifiableCredential,\n SdJwtDecodedVerifiableCredential,\n WrappedVerifiableCredential,\n} from '@sphereon/ssi-types'\nimport { LinkedVPPresentation, LOGGER_NAMESPACE, RequiredContext } from '../types'\n\nconst logger = Loggers.DEFAULT.get(LOGGER_NAMESPACE)\nconst CLOCK_SKEW = 120 // TODO make adjustable?\n\n/**\n * Creates a Verifiable Presentation for LinkedVP publishing\n * Contains multiple credentials in a single JWT VP\n * No nonce or audience since this is for publishing, not responding to verification\n */\nexport async function createLinkedVPPresentation(\n holderDid: string,\n credential: UniqueDigitalCredential,\n agent: RequiredContext['agent'],\n): Promise<LinkedVPPresentation> {\n logger.debug(`Creating LinkedVP presentation for ${holderDid} of credential ${credential.id}`)\n\n const originalCredential = extractOriginalCredential(credential)\n const documentFormat = CredentialMapper.detectDocumentType(originalCredential)\n\n switch (documentFormat) {\n case DocumentFormat.SD_JWT_VC: {\n return createSdJwtPresentation(originalCredential, agent)\n }\n case DocumentFormat.JSONLD: {\n return createJsonLdPresentation(holderDid, originalCredential, agent)\n }\n case DocumentFormat.MSO_MDOC: {\n return createMdocPresentation(originalCredential)\n }\n default: {\n return createJwtPresentation(holderDid, originalCredential, agent)\n }\n }\n}\n\n/**\n * Extracts the original credential from various wrapper types\n */\nfunction extractOriginalCredential(\n credential: UniqueDigitalCredential | WrappedVerifiableCredential | OriginalVerifiableCredential,\n): OriginalVerifiableCredential {\n if (typeof credential === 'string') {\n return credential\n }\n\n if ('digitalCredential' in credential) {\n const udc = credential as UniqueDigitalCredential\n if (udc.originalVerifiableCredential) {\n return udc.originalVerifiableCredential\n }\n return udc.uniformVerifiableCredential as OriginalVerifiableCredential\n }\n\n if ('original' in credential) {\n return credential.original\n }\n\n return credential as OriginalVerifiableCredential\n}\n\n/**\n * Creates an SD-JWT presentation with KB-JWT\n */\nasync function createSdJwtPresentation(\n originalCredential: OriginalVerifiableCredential,\n agent: RequiredContext['agent'],\n): Promise<LinkedVPPresentation> {\n // SD-JWT with KB-JWT\n const decodedSdJwt = await CredentialMapper.decodeSdJwtVcAsync(\n typeof originalCredential === 'string' ? originalCredential : (originalCredential as SdJwtDecodedVerifiableCredential).compactSdJwtVc,\n defaultGenerateDigest,\n )\n\n const hashAlg = decodedSdJwt.signedPayload._sd_alg ?? 'sha-256'\n const sdHash = calculateSdHash(decodedSdJwt.compactSdJwtVc, hashAlg, defaultGenerateDigest)\n const kbJwtPayload: PartialSdJwtKbJwt['payload'] = {\n iat: Math.floor(Date.now() / 1000 - CLOCK_SKEW),\n sd_hash: sdHash,\n }\n\n const presentationResult = await agent.createSdJwtPresentation({\n presentation: decodedSdJwt.compactSdJwtVc,\n kb: {\n payload: kbJwtPayload as any, // FIXME? (typescript seems impossible)\n },\n })\n\n return {\n documentFormat: DocumentFormat.SD_JWT_VC,\n presentationPayload: presentationResult.presentation,\n }\n}\n\n/**\n * Creates a JSON-LD presentation with proof\n */\nasync function createJsonLdPresentation(\n holderDid: string,\n originalCredential: OriginalVerifiableCredential,\n agent: RequiredContext['agent'],\n): Promise<LinkedVPPresentation> {\n // JSON-LD VC - create JSON-LD VP with challenge and domain in proof\n const vcObject = typeof originalCredential === 'string' ? JSON.parse(originalCredential) : originalCredential\n\n const vpObject = {\n '@context': ['https://www.w3.org/2018/credentials/v1'],\n type: ['VerifiablePresentation'],\n verifiableCredential: [vcObject],\n holder: holderDid,\n }\n\n const identifier = await agent.identifierManagedGet({ identifier: holderDid })\n\n // Create JSON-LD VP with proof\n const verifiablePresentationSP = await agent.createVerifiablePresentation({\n presentation: vpObject,\n proofFormat: 'lds',\n keyRef: identifier.kmsKeyRef || identifier.kid,\n })\n return {\n documentFormat: DocumentFormat.JSONLD,\n presentationPayload: verifiablePresentationSP,\n }\n}\n\n/**\n * Creates an ISO mdoc presentation (basic support)\n */\nasync function createMdocPresentation(originalCredential: OriginalVerifiableCredential): Promise<LinkedVPPresentation> {\n // ISO mdoc - create mdoc VP token\n // This is a placeholder implementation\n // Full implementation would require:\n // 1. Decode the mdoc using CredentialMapper or mdoc utilities\n // 2. Build proper mdoc VP token with session transcript\n // 3. Include nonce/audience in the session transcript\n logger.warning('mso_mdoc format has basic support - production use requires proper mdoc VP token implementation')\n\n return {\n documentFormat: DocumentFormat.MSO_MDOC,\n presentationPayload: originalCredential,\n }\n}\n\n/**\n * Creates a JWT presentation\n */\nasync function createJwtPresentation(\n holderDid: string,\n originalCredential: OriginalVerifiableCredential,\n agent: RequiredContext['agent'],\n): Promise<LinkedVPPresentation> {\n // JWT VC - create JWT VP with nonce and aud in payload\n const vcJwt = typeof originalCredential === 'string' ? originalCredential : JSON.stringify(originalCredential)\n\n const identifier = await agent.identifierManagedGet({ identifier: holderDid })\n\n // Create VP JWT using agent method\n const vpPayload = {\n iss: holderDid,\n vp: {\n '@context': ['https://www.w3.org/2018/credentials/v1'],\n type: ['VerifiablePresentation'],\n holder: holderDid,\n verifiableCredential: [vcJwt],\n },\n iat: Math.floor(Date.now() / 1000 - CLOCK_SKEW),\n exp: Math.floor(Date.now() / 1000 + 600 + CLOCK_SKEW), // 10 minutes\n }\n\n // Use the agent's JWT creation capability\n const vpJwt = await agent.createVerifiablePresentation({\n presentation: vpPayload.vp,\n proofFormat: 'jwt',\n keyRef: identifier.kmsKeyRef || identifier.kid,\n })\n\n return {\n documentFormat: DocumentFormat.JWT,\n presentationPayload: (vpJwt.proof && 'jwt' in vpJwt.proof && vpJwt.proof.jwt) || vpJwt,\n }\n}\n","import { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resolution'\nimport { ICredentialStore } from '@sphereon/ssi-sdk.credential-store'\nimport { VcdmCredentialPlugin } from '@sphereon/ssi-sdk.credential-vcdm'\nimport { ISDJwtPlugin } from '@sphereon/ssi-sdk.sd-jwt'\nimport { DocumentFormat } from '@sphereon/ssi-types'\nimport { IAgentContext, IPluginMethodMap } from '@veramo/core'\nimport { IKeyManager } from '@veramo/core/src/types/IKeyManager'\n\nexport const LOGGER_NAMESPACE = 'sphereon:linked-vp'\n\nexport type LinkedVPPresentation = {\n documentFormat: DocumentFormat\n presentationPayload: string | Record<string, any>\n}\n\nexport interface ILinkedVPManager extends IPluginMethodMap {\n /**\n * Publish a credential as a LinkedVP by adding it to the holder's DID Document\n * @param args - Publication arguments including credential ID and scope configuration\n * @param context - Agent context\n */\n lvpPublishCredential(args: PublishCredentialArgs, context: RequiredContext): Promise<LinkedVPEntry>\n\n /**\n * Unpublish a credential by removing its LinkedVP entry from the DID Document\n * @param args - Unpublish arguments\n * @param context - Agent context\n */\n lvpUnpublishCredential(args: UnpublishCredentialArgs, context: RequiredContext): Promise<boolean>\n\n /**\n * Check if a LinkedVP entry exists by linkedVpId\n * @param args - Query arguments\n * @param context - Agent context\n */\n lvpHasEntry(args: HasLinkedVPEntryArgs, context: RequiredContext): Promise<boolean>\n\n /**\n * Get LinkedVP service entries for a DID to be added to a DID Document\n * This is useful when generating DID Documents with toDidDocument\n * @param args - Query arguments for the DID\n * @param context - Agent context\n */\n lvpGetServiceEntries(args: GetServiceEntriesArgs, context: RequiredContext): Promise<Array<LinkedVPServiceEntry>>\n\n /**\n * Generate and return a Verifiable Presentation for a published LinkedVP\n * This is the main endpoint handler for GET /linked-vp/{linkedVpId}\n * @param args - Generation arguments\n * @param context - Agent context\n */\n lvpGeneratePresentation(args: GeneratePresentationArgs, context: RequiredContext): Promise<LinkedVPPresentation>\n}\n\nexport type PublishCredentialArgs = {\n digitalCredentialId: string\n linkedVpId?: string // Optional: if not provided, will be auto-generated\n linkedVpFrom?: Date\n linkedVpUntil?: Date\n}\n\nexport type UnpublishCredentialArgs = {\n linkedVpId: string\n}\n\nexport type HasLinkedVPEntryArgs = {\n linkedVpId: string\n}\n\nexport type GetServiceEntriesArgs = {\n subjectDid?: string\n tenantId?: string\n}\n\nexport type GeneratePresentationArgs = {\n linkedVpId: string\n linkedVpUntil?: Date\n}\n\nexport type LinkedVPEntry = {\n id: string\n linkedVpId: string\n linkedVpFrom?: Date\n linkedVpUntil?: Date\n tenantId?: string\n createdAt: Date\n}\n\nexport type LinkedVPServiceEntry = {\n id: string\n type: 'LinkedVerifiablePresentation'\n serviceEndpoint: string\n}\n\nexport type RequiredContext = IAgentContext<IIdentifierResolution & ICredentialStore & IKeyManager & VcdmCredentialPlugin & ISDJwtPlugin>\n"],"mappings":"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","names":["LOGGER_NAMESPACE","logger","Loggers","DEFAULT","get","LOGGER_NAMESPACE","CLOCK_SKEW","createLinkedVPPresentation","holderDid","credential","agent","debug","id","originalCredential","extractOriginalCredential","documentFormat","CredentialMapper","detectDocumentType","DocumentFormat","SD_JWT_VC","createSdJwtPresentation","JSONLD","createJsonLdPresentation","MSO_MDOC","createMdocPresentation","createJwtPresentation","udc","originalVerifiableCredential","uniformVerifiableCredential","original","decodedSdJwt","decodeSdJwtVcAsync","compactSdJwtVc","defaultGenerateDigest","hashAlg","signedPayload","_sd_alg","sdHash","calculateSdHash","kbJwtPayload","iat","Math","floor","Date","now","sd_hash","presentationResult","presentation","kb","payload","presentationPayload","vcObject","JSON","parse","vpObject","type","verifiableCredential","holder","identifier","identifierManagedGet","verifiablePresentationSP","createVerifiablePresentation","proofFormat","keyRef","kmsKeyRef","kid","warning","vcJwt","stringify","vpPayload","iss","vp","exp","vpJwt","JWT","proof","jwt","linkedVPManagerMethods","LinkedVPManager","schema","ILinkedVPManager","methods","lvpPublishCredential","bind","lvpUnpublishCredential","lvpHasEntry","lvpGetServiceEntries","lvpGeneratePresentation","args","context","digitalCredentialId","credential","agent","crsGetCredential","id","linkedVpId","Promise","reject","Error","buildLinkedVpId","tenantId","ensureLinkedVpIdUnique","publishAt","linkedVpFrom","Date","crsUpdateCredential","linkedVpUntil","createdAt","credentials","crsGetCredentials","filter","length","undefined","error","subjectDid","Not","IsNull","subjectCorrelationId","flatMap","cred","uniformDocument","JSON","parse","holderDidForEntry","getHolderDid","startsWith","credentialToServiceEntry","parseTenantFromLinkedVpId","uniqueCredentials","crsGetUniqueCredentials","uniqueDigitalCredential","uniformVerifiableCredential","digitalCredential","holderDid","createLinkedVPPresentation","cnf","jwk","kid","split","credentialSubject","Array","isArray","idx","lastIndexOf","substring","generateLinkedVpId","Math","random","toString","finalLinkedVpId","includes","getBaseUrlFromDid","withoutPrefix","replace","parts","domain","shift","path","join","buildServiceEndpoint","baseUrl","cleanBaseUrl","endsWith","slice","type","serviceEndpoint"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../plugin.schema.json","../src/agent/LinkedVPManager.ts","../src/services/LinkedVPService.ts","../src/types/ILinkedVPManager.ts"],"sourcesContent":["/**\n * @public\n */\nimport schema from '../plugin.schema.json'\nexport { schema }\nexport { LinkedVPManager, linkedVPManagerMethods } from './agent/LinkedVPManager'\nexport * from './types/ILinkedVPManager'\n","{\n \"ILinkedVPManager\": {\n \"components\": {\n \"schemas\": {\n \"GeneratePresentationArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"linkedVpId\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\"linkedVpId\"],\n \"additionalProperties\": false\n },\n \"LinkedVPPresentation\": {\n \"anyOf\": [\n {\n \"type\": \"string\"\n },\n {\n \"$ref\": \"#/components/schemas/Record<string,any>\"\n }\n ]\n },\n \"Record<string,any>\": {\n \"type\": \"object\"\n },\n \"GetServiceEntriesArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"tenantId\": {\n \"type\": \"string\"\n }\n },\n \"additionalProperties\": false\n },\n \"LinkedVPServiceEntry\": {\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\n \"type\": \"string\"\n },\n \"type\": {\n \"type\": \"string\",\n \"const\": \"LinkedVerifiablePresentation\"\n },\n \"serviceEndpoint\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\"id\", \"type\", \"serviceEndpoint\"],\n \"additionalProperties\": false\n },\n \"HasLinkedVPEntryArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"linkedVpId\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\"linkedVpId\"],\n \"additionalProperties\": false\n },\n \"PublishCredentialArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"digitalCredentialId\": {\n \"type\": \"string\"\n },\n \"linkedVpId\": {\n \"type\": \"string\"\n },\n \"tenantId\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\"digitalCredentialId\"],\n \"additionalProperties\": false\n },\n \"LinkedVPEntry\": {\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\n \"type\": \"string\"\n },\n \"linkedVpId\": {\n \"type\": \"string\"\n },\n \"tenantId\": {\n \"type\": \"string\"\n },\n \"linkedVpFrom\": {\n \"type\": \"string\",\n \"format\": \"date-time\"\n },\n \"createdAt\": {\n \"type\": \"string\",\n \"format\": \"date-time\"\n }\n },\n \"required\": [\"id\", \"linkedVpId\", \"createdAt\"],\n \"additionalProperties\": false\n },\n \"UnpublishCredentialArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"linkedVpId\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\"linkedVpId\"],\n \"additionalProperties\": false\n }\n },\n \"methods\": {\n \"lvpGeneratePresentation\": {\n \"description\": \"Generate and return a Verifiable Presentation for a published LinkedVP This is the main endpoint handler for GET /linked-vp/\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/GeneratePresentationArgs\"\n },\n \"returnType\": {\n \"$ref\": \"#/components/schemas/LinkedVPPresentation\"\n }\n },\n \"lvpGetServiceEntries\": {\n \"description\": \"Get LinkedVP service entries for a DID to be added to a DID Document This is useful when generating DID Documents with toDidDocument\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/GetServiceEntriesArgs\"\n },\n \"returnType\": {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/components/schemas/LinkedVPServiceEntry\"\n }\n }\n },\n \"lvpHasEntry\": {\n \"description\": \"Check if a LinkedVP entry exists by linkedVpId\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/HasLinkedVPEntryArgs\"\n },\n \"returnType\": {\n \"type\": \"boolean\"\n }\n },\n \"lvpPublishCredential\": {\n \"description\": \"Publish a credential as a LinkedVP by adding it to the holder's DID Document\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/PublishCredentialArgs\"\n },\n \"returnType\": {\n \"$ref\": \"#/components/schemas/LinkedVPEntry\"\n }\n },\n \"lvpUnpublishCredential\": {\n \"description\": \"Unpublish a credential by removing its LinkedVP entry from the DID Document\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/UnpublishCredentialArgs\"\n },\n \"returnType\": {\n \"type\": \"boolean\"\n }\n }\n }\n }\n }\n}\n","import { DigitalCredential } from '@sphereon/ssi-sdk.data-store-types'\nimport { type IVerifiableCredential } from '@sphereon/ssi-types'\nimport { IAgentPlugin } from '@veramo/core'\nimport { IsNull, Not } from 'typeorm'\nimport { schema } from '../index'\nimport { createLinkedVPPresentation } from '../services/LinkedVPService'\nimport {\n GeneratePresentationArgs,\n GetServiceEntriesArgs,\n HasLinkedVPEntryArgs,\n ILinkedVPManager,\n LinkedVPEntry,\n LinkedVPPresentation,\n LinkedVPServiceEntry,\n PublishCredentialArgs,\n RequiredContext,\n UnpublishCredentialArgs,\n} from '../types'\n\n// Exposing the methods here for any REST implementation\nexport const linkedVPManagerMethods: Array<string> = [\n 'lvpPublishCredential',\n 'lvpUnpublishCredential',\n 'lvpHasEntry',\n 'lvpGetServiceEntries',\n 'lvpGeneratePresentation',\n]\n\n/**\n * {@inheritDoc ILinkedVPManager}\n */\nexport class LinkedVPManager implements IAgentPlugin {\n readonly schema = schema.ILinkedVPManager\n readonly methods: ILinkedVPManager = {\n lvpPublishCredential: this.lvpPublishCredential.bind(this),\n lvpUnpublishCredential: this.lvpUnpublishCredential.bind(this),\n lvpHasEntry: this.lvpHasEntry.bind(this),\n lvpGetServiceEntries: this.lvpGetServiceEntries.bind(this),\n lvpGeneratePresentation: this.lvpGeneratePresentation.bind(this),\n }\n\n private async lvpPublishCredential(args: PublishCredentialArgs, context: RequiredContext): Promise<LinkedVPEntry> {\n const { digitalCredentialId } = args\n\n const credential: DigitalCredential = await context.agent.crsGetCredential({ id: digitalCredentialId })\n\n if (credential.linkedVpId) {\n return Promise.reject(new Error(`Credential ${digitalCredentialId} is already published with linkedVpId ${credential.linkedVpId}`))\n }\n\n const linkedVpId = this.buildLinkedVpId(args.linkedVpId, credential.tenantId)\n\n await this.ensureLinkedVpIdUnique(linkedVpId, context, credential.tenantId)\n\n const publishAt = args.linkedVpFrom ?? new Date()\n await context.agent.crsUpdateCredential({\n id: digitalCredentialId,\n linkedVpId,\n linkedVpFrom: publishAt,\n linkedVpUntil: args.linkedVpUntil,\n })\n\n return {\n id: credential.id,\n linkedVpId,\n tenantId: credential.tenantId,\n linkedVpFrom: publishAt,\n linkedVpUntil: args.linkedVpUntil,\n createdAt: credential.createdAt,\n }\n }\n\n private async lvpUnpublishCredential(args: UnpublishCredentialArgs, context: RequiredContext): Promise<boolean> {\n const { linkedVpId } = args\n\n // Find credential by linkedVpId and tenantId\n const credentials = await context.agent.crsGetCredentials({\n filter: [{ linkedVpId }],\n })\n if (credentials.length === 0) {\n return Promise.reject(Error(`No credential found with linkedVpId ${linkedVpId}`))\n }\n\n const credential = credentials[0]\n await context.agent.crsUpdateCredential({\n id: credential.id,\n linkedVpId: undefined,\n linkedVpFrom: undefined,\n })\n\n return true\n }\n\n private async lvpHasEntry(args: HasLinkedVPEntryArgs, context: RequiredContext): Promise<boolean> {\n const { linkedVpId } = args\n\n try {\n const credentials = await context.agent.crsGetCredentials({\n filter: [{ linkedVpId }],\n })\n return credentials.length > 0\n } catch (error) {\n return false\n }\n }\n\n private async lvpGetServiceEntries(args: GetServiceEntriesArgs, context: RequiredContext): Promise<Array<LinkedVPServiceEntry>> {\n const { tenantId, subjectDid } = args\n\n // Get all published credentials (credentials with linkedVpId set)\n const filter: any = { linkedVpId: Not(IsNull()) }\n if (tenantId) {\n filter.tenantId = tenantId\n }\n if (subjectDid) {\n filter.subjectCorrelationId = subjectDid\n }\n\n const credentials = await context.agent.crsGetCredentials({\n filter: [filter],\n })\n\n return credentials.flatMap((cred) => {\n const uniformDocument = JSON.parse(cred.uniformDocument) as IVerifiableCredential\n const holderDidForEntry = this.getHolderDid(uniformDocument)\n return holderDidForEntry && holderDidForEntry.startsWith('did:web') ? [this.credentialToServiceEntry(cred, holderDidForEntry)] : []\n })\n }\n\n private async lvpGeneratePresentation(args: GeneratePresentationArgs, context: RequiredContext): Promise<LinkedVPPresentation> {\n const { linkedVpId } = args\n const tenantId = this.parseTenantFromLinkedVpId(linkedVpId)\n\n const uniqueCredentials = await context.agent.crsGetUniqueCredentials({\n filter: [\n {\n linkedVpId: args.linkedVpId,\n linkedVpUntil: args.linkedVpUntil,\n ...(tenantId && { tenantId }),\n },\n ],\n })\n if (uniqueCredentials.length === 0) {\n return Promise.reject(Error(`No published credentials found for linkedVpId ${linkedVpId}`))\n }\n if (uniqueCredentials.length > 1) {\n return Promise.reject(Error(`Multiple credentials found for linkedVpId ${linkedVpId}`))\n }\n\n const uniqueDigitalCredential = uniqueCredentials[0]\n if (!uniqueDigitalCredential.uniformVerifiableCredential) {\n return Promise.reject(Error(`uniformVerifiableCredential could not be found for credential ${uniqueDigitalCredential.digitalCredential.id}`))\n }\n const holderDid = this.getHolderDid(uniqueDigitalCredential.uniformVerifiableCredential)\n if (!holderDid) {\n return Promise.reject(Error(`Could not extract the holder did:web from cnf nor the credentialSubject id`))\n }\n\n // Generate the Verifiable Presentation with all published credentials\n return createLinkedVPPresentation(holderDid, uniqueDigitalCredential, context.agent)\n }\n\n private getHolderDid(uniformDocument: IVerifiableCredential): string | undefined {\n // Determine holder DID for identifier resolution\n if ('cnf' in uniformDocument && 'jwk' in uniformDocument.cnf && 'kid' in uniformDocument.cnf.jwk) {\n return uniformDocument.cnf.jwk.kid.split('#')[0]\n }\n\n if ('credentialSubject' in uniformDocument) {\n const credentialSubject = Array.isArray(uniformDocument.credentialSubject)\n ? uniformDocument.credentialSubject[0]\n : uniformDocument.credentialSubject\n if ('id' in credentialSubject && credentialSubject.id) {\n if (credentialSubject.id.startsWith('did:web')) {\n return credentialSubject.id\n }\n }\n }\n\n return undefined\n }\n\n private parseTenantFromLinkedVpId(linkedVpId: string): string | undefined {\n const idx = linkedVpId.lastIndexOf('@')\n return idx === -1 ? undefined : linkedVpId.substring(idx + 1)\n }\n\n private generateLinkedVpId(): string {\n return `lvp-${Math.random().toString(36).substring(2, 15)}`\n }\n\n private async ensureLinkedVpIdUnique(linkedVpId: string, context: RequiredContext, tenantId?: string): Promise<void> {\n const credentials = await context.agent.crsGetCredentials({\n filter: [{ linkedVpId, ...(tenantId && { tenantId }) }],\n })\n\n if (credentials.length > 0) {\n throw new Error(`LinkedVP ID ${linkedVpId} already exists${tenantId ? ` for tenant ${tenantId}` : ''}`)\n }\n }\n\n private buildLinkedVpId(linkedVpId: string | undefined, tenantId: string | undefined) {\n let finalLinkedVpId = linkedVpId || this.generateLinkedVpId()\n\n // Validate that user-provided ID doesn't contain @ char reserved for tenant id separator\n if (linkedVpId && linkedVpId.includes('@')) {\n throw new Error(`LinkedVP ID cannot contain '@' character as it is reserved for tenant separation`)\n }\n\n // Append tenantId if provided\n if (tenantId && tenantId !== '') {\n finalLinkedVpId = `${finalLinkedVpId}@${tenantId}`\n }\n return finalLinkedVpId\n }\n\n private getBaseUrlFromDid(holderDid: string): string {\n if (!holderDid.startsWith('did:web:')) {\n throw new Error(`Invalid DID: ${holderDid}, must be did:web`)\n }\n\n const withoutPrefix = holderDid.replace('did:web:', '') // example.com:tenants:tenant1\n const parts = withoutPrefix.split(':')\n const domain = parts.shift()! // example.com\n const path = parts.join('/') // tenants/tenant1\n\n return path\n ? `https://${domain}/${path}` // https://example.com/tenants/tenant1\n : `https://${domain}` // https://example.com\n }\n\n private buildServiceEndpoint(holderDid: string, linkedVpId: string): string {\n const baseUrl = this.getBaseUrlFromDid(holderDid)\n const cleanBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl\n return `${cleanBaseUrl}/linked-vp/${linkedVpId}`\n }\n\n private credentialToServiceEntry(credential: DigitalCredential, holderDid: string): LinkedVPServiceEntry {\n if (!credential.linkedVpId) {\n throw new Error(`Credential ${credential.id} does not have a linkedVpId`)\n }\n\n return {\n id: `${holderDid}#${credential.linkedVpId}`,\n type: 'LinkedVerifiablePresentation',\n serviceEndpoint: this.buildServiceEndpoint(holderDid, credential.linkedVpId),\n }\n }\n}\n","import { UniqueDigitalCredential } from '@sphereon/ssi-sdk.credential-store'\nimport { calculateSdHash, defaultGenerateDigest, PartialSdJwtKbJwt } from '@sphereon/ssi-sdk.sd-jwt'\n\nimport {\n CredentialMapper,\n DocumentFormat,\n Loggers,\n OriginalVerifiableCredential,\n SdJwtDecodedVerifiableCredential,\n WrappedVerifiableCredential,\n} from '@sphereon/ssi-types'\nimport { LinkedVPPresentation, LOGGER_NAMESPACE, RequiredContext } from '../types'\n\nconst logger = Loggers.DEFAULT.get(LOGGER_NAMESPACE)\nconst CLOCK_SKEW = 120 // TODO make adjustable?\n\n/**\n * Creates a Verifiable Presentation for LinkedVP publishing\n * Contains multiple credentials in a single JWT VP\n * No nonce or audience since this is for publishing, not responding to verification\n */\nexport async function createLinkedVPPresentation(\n holderDid: string,\n credential: UniqueDigitalCredential,\n agent: RequiredContext['agent'],\n): Promise<LinkedVPPresentation> {\n logger.debug(`Creating LinkedVP presentation for ${holderDid} of credential ${credential.id}`)\n\n const originalCredential = extractOriginalCredential(credential)\n const documentFormat = CredentialMapper.detectDocumentType(originalCredential)\n\n switch (documentFormat) {\n case DocumentFormat.SD_JWT_VC: {\n return createSdJwtPresentation(originalCredential, agent)\n }\n case DocumentFormat.JSONLD: {\n return createJsonLdPresentation(holderDid, originalCredential, agent)\n }\n case DocumentFormat.MSO_MDOC: {\n return createMdocPresentation(originalCredential)\n }\n default: {\n return createJwtPresentation(holderDid, originalCredential, agent)\n }\n }\n}\n\n/**\n * Extracts the original credential from various wrapper types\n */\nfunction extractOriginalCredential(\n credential: UniqueDigitalCredential | WrappedVerifiableCredential | OriginalVerifiableCredential,\n): OriginalVerifiableCredential {\n if (typeof credential === 'string') {\n return credential\n }\n\n if ('digitalCredential' in credential) {\n const udc = credential as UniqueDigitalCredential\n if (udc.originalVerifiableCredential) {\n return udc.originalVerifiableCredential\n }\n return udc.uniformVerifiableCredential as OriginalVerifiableCredential\n }\n\n if ('original' in credential) {\n return credential.original\n }\n\n return credential as OriginalVerifiableCredential\n}\n\n/**\n * Creates an SD-JWT presentation with KB-JWT\n */\nasync function createSdJwtPresentation(\n originalCredential: OriginalVerifiableCredential,\n agent: RequiredContext['agent'],\n): Promise<LinkedVPPresentation> {\n // SD-JWT with KB-JWT\n const decodedSdJwt = await CredentialMapper.decodeSdJwtVcAsync(\n typeof originalCredential === 'string' ? originalCredential : (originalCredential as SdJwtDecodedVerifiableCredential).compactSdJwtVc,\n defaultGenerateDigest,\n )\n\n const hashAlg = decodedSdJwt.signedPayload._sd_alg ?? 'sha-256'\n const sdHash = calculateSdHash(decodedSdJwt.compactSdJwtVc, hashAlg, defaultGenerateDigest)\n const kbJwtPayload: PartialSdJwtKbJwt['payload'] = {\n iat: Math.floor(Date.now() / 1000 - CLOCK_SKEW),\n sd_hash: sdHash,\n }\n\n const presentationResult = await agent.createSdJwtPresentation({\n presentation: decodedSdJwt.compactSdJwtVc,\n kb: {\n payload: kbJwtPayload as any, // FIXME? (typescript seems impossible)\n },\n })\n\n return {\n documentFormat: DocumentFormat.SD_JWT_VC,\n presentationPayload: presentationResult.presentation,\n }\n}\n\n/**\n * Creates a JSON-LD presentation with proof\n */\nasync function createJsonLdPresentation(\n holderDid: string,\n originalCredential: OriginalVerifiableCredential,\n agent: RequiredContext['agent'],\n): Promise<LinkedVPPresentation> {\n // JSON-LD VC - create JSON-LD VP with challenge and domain in proof\n const vcObject = typeof originalCredential === 'string' ? JSON.parse(originalCredential) : originalCredential\n\n const vpObject = {\n '@context': ['https://www.w3.org/2018/credentials/v1'],\n type: ['VerifiablePresentation'],\n verifiableCredential: [vcObject],\n holder: holderDid,\n }\n\n const identifier = await agent.identifierManagedGet({ identifier: holderDid })\n\n // Create JSON-LD VP with proof\n const verifiablePresentationSP = await agent.createVerifiablePresentation({\n presentation: vpObject,\n proofFormat: 'lds',\n keyRef: identifier.kmsKeyRef || identifier.kid,\n })\n return {\n documentFormat: DocumentFormat.JSONLD,\n presentationPayload: verifiablePresentationSP,\n }\n}\n\n/**\n * Creates an ISO mdoc presentation (basic support)\n */\nasync function createMdocPresentation(originalCredential: OriginalVerifiableCredential): Promise<LinkedVPPresentation> {\n // ISO mdoc - create mdoc VP token\n // This is a placeholder implementation\n // Full implementation would require:\n // 1. Decode the mdoc using CredentialMapper or mdoc utilities\n // 2. Build proper mdoc VP token with session transcript\n // 3. Include nonce/audience in the session transcript\n logger.warning('mso_mdoc format has basic support - production use requires proper mdoc VP token implementation')\n\n return {\n documentFormat: DocumentFormat.MSO_MDOC,\n presentationPayload: originalCredential,\n }\n}\n\n/**\n * Creates a JWT presentation\n */\nasync function createJwtPresentation(\n holderDid: string,\n originalCredential: OriginalVerifiableCredential,\n agent: RequiredContext['agent'],\n): Promise<LinkedVPPresentation> {\n // JWT VC - create JWT VP with nonce and aud in payload\n const vcJwt = typeof originalCredential === 'string' ? originalCredential : JSON.stringify(originalCredential)\n\n const identifier = await agent.identifierManagedGet({ identifier: holderDid })\n\n // Create VP JWT using agent method\n const vpPayload = {\n iss: holderDid,\n vp: {\n '@context': ['https://www.w3.org/2018/credentials/v1'],\n type: ['VerifiablePresentation'],\n holder: holderDid,\n verifiableCredential: [vcJwt],\n },\n iat: Math.floor(Date.now() / 1000 - CLOCK_SKEW),\n exp: Math.floor(Date.now() / 1000 + 600 + CLOCK_SKEW), // 10 minutes\n }\n\n // Use the agent's JWT creation capability\n const vpJwt = await agent.createVerifiablePresentation({\n presentation: vpPayload.vp,\n proofFormat: 'jwt',\n keyRef: identifier.kmsKeyRef || identifier.kid,\n })\n\n return {\n documentFormat: DocumentFormat.JWT,\n presentationPayload: (vpJwt.proof && 'jwt' in vpJwt.proof && vpJwt.proof.jwt) || vpJwt,\n }\n}\n","import { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resolution'\nimport { ICredentialStore } from '@sphereon/ssi-sdk.credential-store'\nimport { VcdmCredentialPlugin } from '@sphereon/ssi-sdk.credential-vcdm'\nimport { ISDJwtPlugin } from '@sphereon/ssi-sdk.sd-jwt'\nimport { DocumentFormat } from '@sphereon/ssi-types'\nimport { IAgentContext, IPluginMethodMap } from '@veramo/core'\nimport { IKeyManager } from '@veramo/core/src/types/IKeyManager'\n\nexport const LOGGER_NAMESPACE = 'sphereon:linked-vp'\n\nexport type LinkedVPPresentation = {\n documentFormat: DocumentFormat\n presentationPayload: string | Record<string, any>\n}\n\nexport interface ILinkedVPManager extends IPluginMethodMap {\n /**\n * Publish a credential as a LinkedVP by adding it to the holder's DID Document\n * @param args - Publication arguments including credential ID and scope configuration\n * @param context - Agent context\n */\n lvpPublishCredential(args: PublishCredentialArgs, context: RequiredContext): Promise<LinkedVPEntry>\n\n /**\n * Unpublish a credential by removing its LinkedVP entry from the DID Document\n * @param args - Unpublish arguments\n * @param context - Agent context\n */\n lvpUnpublishCredential(args: UnpublishCredentialArgs, context: RequiredContext): Promise<boolean>\n\n /**\n * Check if a LinkedVP entry exists by linkedVpId\n * @param args - Query arguments\n * @param context - Agent context\n */\n lvpHasEntry(args: HasLinkedVPEntryArgs, context: RequiredContext): Promise<boolean>\n\n /**\n * Get LinkedVP service entries for a DID to be added to a DID Document\n * This is useful when generating DID Documents with toDidDocument\n * @param args - Query arguments for the DID\n * @param context - Agent context\n */\n lvpGetServiceEntries(args: GetServiceEntriesArgs, context: RequiredContext): Promise<Array<LinkedVPServiceEntry>>\n\n /**\n * Generate and return a Verifiable Presentation for a published LinkedVP\n * This is the main endpoint handler for GET /linked-vp/{linkedVpId}\n * @param args - Generation arguments\n * @param context - Agent context\n */\n lvpGeneratePresentation(args: GeneratePresentationArgs, context: RequiredContext): Promise<LinkedVPPresentation>\n}\n\nexport type PublishCredentialArgs = {\n digitalCredentialId: string\n linkedVpId?: string // Optional: if not provided, will be auto-generated\n linkedVpFrom?: Date\n linkedVpUntil?: Date\n}\n\nexport type UnpublishCredentialArgs = {\n linkedVpId: string\n}\n\nexport type HasLinkedVPEntryArgs = {\n linkedVpId: string\n}\n\nexport type GetServiceEntriesArgs = {\n subjectDid?: string\n tenantId?: string\n}\n\nexport type GeneratePresentationArgs = {\n linkedVpId: string\n linkedVpUntil?: Date\n}\n\nexport type LinkedVPEntry = {\n id: string\n linkedVpId: string\n linkedVpFrom?: Date\n linkedVpUntil?: Date\n tenantId?: string\n createdAt: Date\n}\n\nexport type LinkedVPServiceEntry = {\n id: string\n type: 'LinkedVerifiablePresentation'\n serviceEndpoint: string\n}\n\nexport type RequiredContext = IAgentContext<IIdentifierResolution & ICredentialStore & IKeyManager & VcdmCredentialPlugin & ISDJwtPlugin>\n"],"mappings":"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","names":["LOGGER_NAMESPACE","logger","Loggers","DEFAULT","get","LOGGER_NAMESPACE","CLOCK_SKEW","createLinkedVPPresentation","holderDid","credential","agent","debug","id","originalCredential","extractOriginalCredential","documentFormat","CredentialMapper","detectDocumentType","DocumentFormat","SD_JWT_VC","createSdJwtPresentation","JSONLD","createJsonLdPresentation","MSO_MDOC","createMdocPresentation","createJwtPresentation","udc","originalVerifiableCredential","uniformVerifiableCredential","original","decodedSdJwt","decodeSdJwtVcAsync","compactSdJwtVc","defaultGenerateDigest","hashAlg","signedPayload","_sd_alg","sdHash","calculateSdHash","kbJwtPayload","iat","Math","floor","Date","now","sd_hash","presentationResult","presentation","kb","payload","presentationPayload","vcObject","JSON","parse","vpObject","type","verifiableCredential","holder","identifier","identifierManagedGet","verifiablePresentationSP","createVerifiablePresentation","proofFormat","keyRef","kmsKeyRef","kid","warning","vcJwt","stringify","vpPayload","iss","vp","exp","vpJwt","JWT","proof","jwt","linkedVPManagerMethods","LinkedVPManager","schema","ILinkedVPManager","methods","lvpPublishCredential","bind","lvpUnpublishCredential","lvpHasEntry","lvpGetServiceEntries","lvpGeneratePresentation","args","context","digitalCredentialId","credential","agent","crsGetCredential","id","linkedVpId","Promise","reject","Error","buildLinkedVpId","tenantId","ensureLinkedVpIdUnique","publishAt","linkedVpFrom","Date","crsUpdateCredential","linkedVpUntil","createdAt","credentials","crsGetCredentials","filter","length","undefined","error","subjectDid","Not","IsNull","subjectCorrelationId","flatMap","cred","uniformDocument","JSON","parse","holderDidForEntry","getHolderDid","startsWith","credentialToServiceEntry","parseTenantFromLinkedVpId","uniqueCredentials","crsGetUniqueCredentials","uniqueDigitalCredential","uniformVerifiableCredential","digitalCredential","holderDid","createLinkedVPPresentation","cnf","jwk","kid","split","credentialSubject","Array","isArray","idx","lastIndexOf","substring","generateLinkedVpId","Math","random","toString","finalLinkedVpId","includes","getBaseUrlFromDid","withoutPrefix","replace","parts","domain","shift","path","join","buildServiceEndpoint","baseUrl","cleanBaseUrl","endsWith","slice","type","serviceEndpoint"]}
|
package/dist/index.js
CHANGED
|
@@ -13,9 +13,7 @@ var plugin_schema_default = {
|
|
|
13
13
|
type: "string"
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
|
-
required: [
|
|
17
|
-
"linkedVpId"
|
|
18
|
-
],
|
|
16
|
+
required: ["linkedVpId"],
|
|
19
17
|
additionalProperties: false
|
|
20
18
|
},
|
|
21
19
|
LinkedVPPresentation: {
|
|
@@ -54,11 +52,7 @@ var plugin_schema_default = {
|
|
|
54
52
|
type: "string"
|
|
55
53
|
}
|
|
56
54
|
},
|
|
57
|
-
required: [
|
|
58
|
-
"id",
|
|
59
|
-
"type",
|
|
60
|
-
"serviceEndpoint"
|
|
61
|
-
],
|
|
55
|
+
required: ["id", "type", "serviceEndpoint"],
|
|
62
56
|
additionalProperties: false
|
|
63
57
|
},
|
|
64
58
|
HasLinkedVPEntryArgs: {
|
|
@@ -68,9 +62,7 @@ var plugin_schema_default = {
|
|
|
68
62
|
type: "string"
|
|
69
63
|
}
|
|
70
64
|
},
|
|
71
|
-
required: [
|
|
72
|
-
"linkedVpId"
|
|
73
|
-
],
|
|
65
|
+
required: ["linkedVpId"],
|
|
74
66
|
additionalProperties: false
|
|
75
67
|
},
|
|
76
68
|
PublishCredentialArgs: {
|
|
@@ -86,9 +78,7 @@ var plugin_schema_default = {
|
|
|
86
78
|
type: "string"
|
|
87
79
|
}
|
|
88
80
|
},
|
|
89
|
-
required: [
|
|
90
|
-
"digitalCredentialId"
|
|
91
|
-
],
|
|
81
|
+
required: ["digitalCredentialId"],
|
|
92
82
|
additionalProperties: false
|
|
93
83
|
},
|
|
94
84
|
LinkedVPEntry: {
|
|
@@ -112,11 +102,7 @@ var plugin_schema_default = {
|
|
|
112
102
|
format: "date-time"
|
|
113
103
|
}
|
|
114
104
|
},
|
|
115
|
-
required: [
|
|
116
|
-
"id",
|
|
117
|
-
"linkedVpId",
|
|
118
|
-
"createdAt"
|
|
119
|
-
],
|
|
105
|
+
required: ["id", "linkedVpId", "createdAt"],
|
|
120
106
|
additionalProperties: false
|
|
121
107
|
},
|
|
122
108
|
UnpublishCredentialArgs: {
|
|
@@ -126,9 +112,7 @@ var plugin_schema_default = {
|
|
|
126
112
|
type: "string"
|
|
127
113
|
}
|
|
128
114
|
},
|
|
129
|
-
required: [
|
|
130
|
-
"linkedVpId"
|
|
131
|
-
],
|
|
115
|
+
required: ["linkedVpId"],
|
|
132
116
|
additionalProperties: false
|
|
133
117
|
}
|
|
134
118
|
},
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../plugin.schema.json","../src/agent/LinkedVPManager.ts","../src/services/LinkedVPService.ts","../src/types/ILinkedVPManager.ts"],"sourcesContent":["{\n \"ILinkedVPManager\": {\n \"components\": {\n \"schemas\": {\n \"GeneratePresentationArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"linkedVpId\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"linkedVpId\"\n ],\n \"additionalProperties\": false\n },\n \"LinkedVPPresentation\": {\n \"anyOf\": [\n {\n \"type\": \"string\"\n },\n {\n \"$ref\": \"#/components/schemas/Record<string,any>\"\n }\n ]\n },\n \"Record<string,any>\": {\n \"type\": \"object\"\n },\n \"GetServiceEntriesArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"tenantId\": {\n \"type\": \"string\"\n }\n },\n \"additionalProperties\": false\n },\n \"LinkedVPServiceEntry\": {\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\n \"type\": \"string\"\n },\n \"type\": {\n \"type\": \"string\",\n \"const\": \"LinkedVerifiablePresentation\"\n },\n \"serviceEndpoint\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"id\",\n \"type\",\n \"serviceEndpoint\"\n ],\n \"additionalProperties\": false\n },\n \"HasLinkedVPEntryArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"linkedVpId\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"linkedVpId\"\n ],\n \"additionalProperties\": false\n },\n \"PublishCredentialArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"digitalCredentialId\": {\n \"type\": \"string\"\n },\n \"linkedVpId\": {\n \"type\": \"string\"\n },\n \"tenantId\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"digitalCredentialId\"\n ],\n \"additionalProperties\": false\n },\n \"LinkedVPEntry\": {\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\n \"type\": \"string\"\n },\n \"linkedVpId\": {\n \"type\": \"string\"\n },\n \"tenantId\": {\n \"type\": \"string\"\n },\n \"linkedVpFrom\": {\n \"type\": \"string\",\n \"format\": \"date-time\"\n },\n \"createdAt\": {\n \"type\": \"string\",\n \"format\": \"date-time\"\n }\n },\n \"required\": [\n \"id\",\n \"linkedVpId\",\n \"createdAt\"\n ],\n \"additionalProperties\": false\n },\n \"UnpublishCredentialArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"linkedVpId\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"linkedVpId\"\n ],\n \"additionalProperties\": false\n }\n },\n \"methods\": {\n \"lvpGeneratePresentation\": {\n \"description\": \"Generate and return a Verifiable Presentation for a published LinkedVP This is the main endpoint handler for GET /linked-vp/\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/GeneratePresentationArgs\"\n },\n \"returnType\": {\n \"$ref\": \"#/components/schemas/LinkedVPPresentation\"\n }\n },\n \"lvpGetServiceEntries\": {\n \"description\": \"Get LinkedVP service entries for a DID to be added to a DID Document This is useful when generating DID Documents with toDidDocument\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/GetServiceEntriesArgs\"\n },\n \"returnType\": {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/components/schemas/LinkedVPServiceEntry\"\n }\n }\n },\n \"lvpHasEntry\": {\n \"description\": \"Check if a LinkedVP entry exists by linkedVpId\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/HasLinkedVPEntryArgs\"\n },\n \"returnType\": {\n \"type\": \"boolean\"\n }\n },\n \"lvpPublishCredential\": {\n \"description\": \"Publish a credential as a LinkedVP by adding it to the holder's DID Document\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/PublishCredentialArgs\"\n },\n \"returnType\": {\n \"$ref\": \"#/components/schemas/LinkedVPEntry\"\n }\n },\n \"lvpUnpublishCredential\": {\n \"description\": \"Unpublish a credential by removing its LinkedVP entry from the DID Document\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/UnpublishCredentialArgs\"\n },\n \"returnType\": {\n \"type\": \"boolean\"\n }\n }\n }\n }\n }\n}","import { DigitalCredential } from '@sphereon/ssi-sdk.data-store-types'\nimport { type IVerifiableCredential } from '@sphereon/ssi-types'\nimport { IAgentPlugin } from '@veramo/core'\nimport { IsNull, Not } from 'typeorm'\nimport { schema } from '../index'\nimport { createLinkedVPPresentation } from '../services/LinkedVPService'\nimport {\n GeneratePresentationArgs,\n GetServiceEntriesArgs,\n HasLinkedVPEntryArgs,\n ILinkedVPManager,\n LinkedVPEntry,\n LinkedVPPresentation,\n LinkedVPServiceEntry,\n PublishCredentialArgs,\n RequiredContext,\n UnpublishCredentialArgs,\n} from '../types'\n\n// Exposing the methods here for any REST implementation\nexport const linkedVPManagerMethods: Array<string> = [\n 'lvpPublishCredential',\n 'lvpUnpublishCredential',\n 'lvpHasEntry',\n 'lvpGetServiceEntries',\n 'lvpGeneratePresentation',\n]\n\n/**\n * {@inheritDoc ILinkedVPManager}\n */\nexport class LinkedVPManager implements IAgentPlugin {\n readonly schema = schema.ILinkedVPManager\n readonly methods: ILinkedVPManager = {\n lvpPublishCredential: this.lvpPublishCredential.bind(this),\n lvpUnpublishCredential: this.lvpUnpublishCredential.bind(this),\n lvpHasEntry: this.lvpHasEntry.bind(this),\n lvpGetServiceEntries: this.lvpGetServiceEntries.bind(this),\n lvpGeneratePresentation: this.lvpGeneratePresentation.bind(this),\n }\n\n private async lvpPublishCredential(args: PublishCredentialArgs, context: RequiredContext): Promise<LinkedVPEntry> {\n const { digitalCredentialId } = args\n\n const credential: DigitalCredential = await context.agent.crsGetCredential({ id: digitalCredentialId })\n\n if (credential.linkedVpId) {\n return Promise.reject(new Error(`Credential ${digitalCredentialId} is already published with linkedVpId ${credential.linkedVpId}`))\n }\n\n const linkedVpId = this.buildLinkedVpId(args.linkedVpId, credential.tenantId)\n\n await this.ensureLinkedVpIdUnique(linkedVpId, context, credential.tenantId)\n\n const publishAt = args.linkedVpFrom ?? new Date()\n await context.agent.crsUpdateCredential({\n id: digitalCredentialId,\n linkedVpId,\n linkedVpFrom: publishAt,\n linkedVpUntil: args.linkedVpUntil,\n })\n\n return {\n id: credential.id,\n linkedVpId,\n tenantId: credential.tenantId,\n linkedVpFrom: publishAt,\n linkedVpUntil: args.linkedVpUntil,\n createdAt: credential.createdAt,\n }\n }\n\n private async lvpUnpublishCredential(args: UnpublishCredentialArgs, context: RequiredContext): Promise<boolean> {\n const { linkedVpId } = args\n\n // Find credential by linkedVpId and tenantId\n const credentials = await context.agent.crsGetCredentials({\n filter: [{ linkedVpId }],\n })\n if (credentials.length === 0) {\n return Promise.reject(Error(`No credential found with linkedVpId ${linkedVpId}`))\n }\n\n const credential = credentials[0]\n await context.agent.crsUpdateCredential({\n id: credential.id,\n linkedVpId: undefined,\n linkedVpFrom: undefined,\n })\n\n return true\n }\n\n private async lvpHasEntry(args: HasLinkedVPEntryArgs, context: RequiredContext): Promise<boolean> {\n const { linkedVpId } = args\n\n try {\n const credentials = await context.agent.crsGetCredentials({\n filter: [{ linkedVpId }],\n })\n return credentials.length > 0\n } catch (error) {\n return false\n }\n }\n\n private async lvpGetServiceEntries(args: GetServiceEntriesArgs, context: RequiredContext): Promise<Array<LinkedVPServiceEntry>> {\n const { tenantId, subjectDid } = args\n\n // Get all published credentials (credentials with linkedVpId set)\n const filter: any = { linkedVpId: Not(IsNull()) }\n if (tenantId) {\n filter.tenantId = tenantId\n }\n if (subjectDid) {\n filter.subjectCorrelationId = subjectDid\n }\n\n const credentials = await context.agent.crsGetCredentials({\n filter: [filter],\n })\n\n return credentials\n .flatMap((cred) => {\n const uniformDocument = JSON.parse(cred.uniformDocument) as IVerifiableCredential\n const holderDidForEntry = this.getHolderDid(uniformDocument)\n return holderDidForEntry && holderDidForEntry.startsWith('did:web') ? [this.credentialToServiceEntry(cred, holderDidForEntry)] : []\n })\n }\n\n private async lvpGeneratePresentation(args: GeneratePresentationArgs, context: RequiredContext): Promise<LinkedVPPresentation> {\n const { linkedVpId } = args\n const tenantId = this.parseTenantFromLinkedVpId(linkedVpId)\n\n const uniqueCredentials = await context.agent.crsGetUniqueCredentials({\n filter: [\n {\n linkedVpId: args.linkedVpId,\n linkedVpUntil: args.linkedVpUntil,\n ...(tenantId && { tenantId }),\n },\n ],\n })\n if (uniqueCredentials.length === 0) {\n return Promise.reject(Error(`No published credentials found for linkedVpId ${linkedVpId}`))\n }\n if (uniqueCredentials.length > 1) {\n return Promise.reject(Error(`Multiple credentials found for linkedVpId ${linkedVpId}`))\n }\n\n const uniqueDigitalCredential = uniqueCredentials[0]\n if (!uniqueDigitalCredential.uniformVerifiableCredential) {\n return Promise.reject(Error(`uniformVerifiableCredential could not be found for credential ${uniqueDigitalCredential.digitalCredential.id}`))\n }\n const holderDid = this.getHolderDid(uniqueDigitalCredential.uniformVerifiableCredential)\n if (!holderDid) {\n return Promise.reject(Error(`Could not extract the holder did:web from cnf nor the credentialSubject id`))\n }\n\n // Generate the Verifiable Presentation with all published credentials\n return createLinkedVPPresentation(holderDid, uniqueDigitalCredential, context.agent)\n }\n\n private getHolderDid(uniformDocument: IVerifiableCredential): string | undefined {\n // Determine holder DID for identifier resolution\n if ('cnf' in uniformDocument && 'jwk' in uniformDocument.cnf && 'kid' in uniformDocument.cnf.jwk) {\n return uniformDocument.cnf.jwk.kid.split('#')[0]\n }\n\n if ('credentialSubject' in uniformDocument) {\n const credentialSubject = Array.isArray(uniformDocument.credentialSubject)\n ? uniformDocument.credentialSubject[0]\n : uniformDocument.credentialSubject\n if ('id' in credentialSubject && credentialSubject.id) {\n if (credentialSubject.id.startsWith('did:web')) {\n return credentialSubject.id\n }\n }\n }\n\n return undefined\n }\n\n private parseTenantFromLinkedVpId(linkedVpId: string): string | undefined {\n const idx = linkedVpId.lastIndexOf('@')\n return idx === -1 ? undefined : linkedVpId.substring(idx + 1)\n }\n\n private generateLinkedVpId(): string {\n return `lvp-${Math.random().toString(36).substring(2, 15)}`\n }\n\n private async ensureLinkedVpIdUnique(linkedVpId: string, context: RequiredContext, tenantId?: string): Promise<void> {\n const credentials = await context.agent.crsGetCredentials({\n filter: [{ linkedVpId, ...(tenantId && { tenantId }) }],\n })\n\n if (credentials.length > 0) {\n throw new Error(`LinkedVP ID ${linkedVpId} already exists${tenantId ? ` for tenant ${tenantId}` : ''}`)\n }\n }\n\n private buildLinkedVpId(linkedVpId: string | undefined, tenantId: string | undefined) {\n let finalLinkedVpId = linkedVpId || this.generateLinkedVpId()\n\n // Validate that user-provided ID doesn't contain @ char reserved for tenant id separator\n if (linkedVpId && linkedVpId.includes('@')) {\n throw new Error(`LinkedVP ID cannot contain '@' character as it is reserved for tenant separation`)\n }\n\n // Append tenantId if provided\n if (tenantId && tenantId !== '') {\n finalLinkedVpId = `${finalLinkedVpId}@${tenantId}`\n }\n return finalLinkedVpId\n }\n\n private getBaseUrlFromDid(holderDid: string): string {\n if (!holderDid.startsWith('did:web:')) {\n throw new Error(`Invalid DID: ${holderDid}, must be did:web`)\n }\n\n const withoutPrefix = holderDid.replace('did:web:', '') // example.com:tenants:tenant1\n const parts = withoutPrefix.split(':')\n const domain = parts.shift()! // example.com\n const path = parts.join('/') // tenants/tenant1\n\n return path\n ? `https://${domain}/${path}` // https://example.com/tenants/tenant1\n : `https://${domain}` // https://example.com\n }\n\n private buildServiceEndpoint(holderDid: string, linkedVpId: string): string {\n const baseUrl = this.getBaseUrlFromDid(holderDid)\n const cleanBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl\n return `${cleanBaseUrl}/linked-vp/${linkedVpId}`\n }\n\n private credentialToServiceEntry(credential: DigitalCredential, holderDid: string): LinkedVPServiceEntry {\n if (!credential.linkedVpId) {\n throw new Error(`Credential ${credential.id} does not have a linkedVpId`)\n }\n\n return {\n id: `${holderDid}#${credential.linkedVpId}`,\n type: 'LinkedVerifiablePresentation',\n serviceEndpoint: this.buildServiceEndpoint(holderDid, credential.linkedVpId),\n }\n }\n}\n","import { UniqueDigitalCredential } from '@sphereon/ssi-sdk.credential-store'\nimport { calculateSdHash, defaultGenerateDigest, PartialSdJwtKbJwt } from '@sphereon/ssi-sdk.sd-jwt'\n\nimport {\n CredentialMapper,\n DocumentFormat,\n Loggers,\n OriginalVerifiableCredential,\n SdJwtDecodedVerifiableCredential,\n WrappedVerifiableCredential,\n} from '@sphereon/ssi-types'\nimport { LinkedVPPresentation, LOGGER_NAMESPACE, RequiredContext } from '../types'\n\nconst logger = Loggers.DEFAULT.get(LOGGER_NAMESPACE)\nconst CLOCK_SKEW = 120 // TODO make adjustable?\n\n/**\n * Creates a Verifiable Presentation for LinkedVP publishing\n * Contains multiple credentials in a single JWT VP\n * No nonce or audience since this is for publishing, not responding to verification\n */\nexport async function createLinkedVPPresentation(\n holderDid: string,\n credential: UniqueDigitalCredential,\n agent: RequiredContext['agent'],\n): Promise<LinkedVPPresentation> {\n logger.debug(`Creating LinkedVP presentation for ${holderDid} of credential ${credential.id}`)\n\n const originalCredential = extractOriginalCredential(credential)\n const documentFormat = CredentialMapper.detectDocumentType(originalCredential)\n\n switch (documentFormat) {\n case DocumentFormat.SD_JWT_VC: {\n return createSdJwtPresentation(originalCredential, agent)\n }\n case DocumentFormat.JSONLD: {\n return createJsonLdPresentation(holderDid, originalCredential, agent)\n }\n case DocumentFormat.MSO_MDOC: {\n return createMdocPresentation(originalCredential)\n }\n default: {\n return createJwtPresentation(holderDid, originalCredential, agent)\n }\n }\n}\n\n/**\n * Extracts the original credential from various wrapper types\n */\nfunction extractOriginalCredential(\n credential: UniqueDigitalCredential | WrappedVerifiableCredential | OriginalVerifiableCredential,\n): OriginalVerifiableCredential {\n if (typeof credential === 'string') {\n return credential\n }\n\n if ('digitalCredential' in credential) {\n const udc = credential as UniqueDigitalCredential\n if (udc.originalVerifiableCredential) {\n return udc.originalVerifiableCredential\n }\n return udc.uniformVerifiableCredential as OriginalVerifiableCredential\n }\n\n if ('original' in credential) {\n return credential.original\n }\n\n return credential as OriginalVerifiableCredential\n}\n\n/**\n * Creates an SD-JWT presentation with KB-JWT\n */\nasync function createSdJwtPresentation(\n originalCredential: OriginalVerifiableCredential,\n agent: RequiredContext['agent'],\n): Promise<LinkedVPPresentation> {\n // SD-JWT with KB-JWT\n const decodedSdJwt = await CredentialMapper.decodeSdJwtVcAsync(\n typeof originalCredential === 'string' ? originalCredential : (originalCredential as SdJwtDecodedVerifiableCredential).compactSdJwtVc,\n defaultGenerateDigest,\n )\n\n const hashAlg = decodedSdJwt.signedPayload._sd_alg ?? 'sha-256'\n const sdHash = calculateSdHash(decodedSdJwt.compactSdJwtVc, hashAlg, defaultGenerateDigest)\n const kbJwtPayload: PartialSdJwtKbJwt['payload'] = {\n iat: Math.floor(Date.now() / 1000 - CLOCK_SKEW),\n sd_hash: sdHash,\n }\n\n const presentationResult = await agent.createSdJwtPresentation({\n presentation: decodedSdJwt.compactSdJwtVc,\n kb: {\n payload: kbJwtPayload as any, // FIXME? (typescript seems impossible)\n },\n })\n\n return {\n documentFormat: DocumentFormat.SD_JWT_VC,\n presentationPayload: presentationResult.presentation,\n }\n}\n\n/**\n * Creates a JSON-LD presentation with proof\n */\nasync function createJsonLdPresentation(\n holderDid: string,\n originalCredential: OriginalVerifiableCredential,\n agent: RequiredContext['agent'],\n): Promise<LinkedVPPresentation> {\n // JSON-LD VC - create JSON-LD VP with challenge and domain in proof\n const vcObject = typeof originalCredential === 'string' ? JSON.parse(originalCredential) : originalCredential\n\n const vpObject = {\n '@context': ['https://www.w3.org/2018/credentials/v1'],\n type: ['VerifiablePresentation'],\n verifiableCredential: [vcObject],\n holder: holderDid,\n }\n\n const identifier = await agent.identifierManagedGet({ identifier: holderDid })\n\n // Create JSON-LD VP with proof\n const verifiablePresentationSP = await agent.createVerifiablePresentation({\n presentation: vpObject,\n proofFormat: 'lds',\n keyRef: identifier.kmsKeyRef || identifier.kid,\n })\n return {\n documentFormat: DocumentFormat.JSONLD,\n presentationPayload: verifiablePresentationSP,\n }\n}\n\n/**\n * Creates an ISO mdoc presentation (basic support)\n */\nasync function createMdocPresentation(originalCredential: OriginalVerifiableCredential): Promise<LinkedVPPresentation> {\n // ISO mdoc - create mdoc VP token\n // This is a placeholder implementation\n // Full implementation would require:\n // 1. Decode the mdoc using CredentialMapper or mdoc utilities\n // 2. Build proper mdoc VP token with session transcript\n // 3. Include nonce/audience in the session transcript\n logger.warning('mso_mdoc format has basic support - production use requires proper mdoc VP token implementation')\n\n return {\n documentFormat: DocumentFormat.MSO_MDOC,\n presentationPayload: originalCredential,\n }\n}\n\n/**\n * Creates a JWT presentation\n */\nasync function createJwtPresentation(\n holderDid: string,\n originalCredential: OriginalVerifiableCredential,\n agent: RequiredContext['agent'],\n): Promise<LinkedVPPresentation> {\n // JWT VC - create JWT VP with nonce and aud in payload\n const vcJwt = typeof originalCredential === 'string' ? originalCredential : JSON.stringify(originalCredential)\n\n const identifier = await agent.identifierManagedGet({ identifier: holderDid })\n\n // Create VP JWT using agent method\n const vpPayload = {\n iss: holderDid,\n vp: {\n '@context': ['https://www.w3.org/2018/credentials/v1'],\n type: ['VerifiablePresentation'],\n holder: holderDid,\n verifiableCredential: [vcJwt],\n },\n iat: Math.floor(Date.now() / 1000 - CLOCK_SKEW),\n exp: Math.floor(Date.now() / 1000 + 600 + CLOCK_SKEW), // 10 minutes\n }\n\n // Use the agent's JWT creation capability\n const vpJwt = await agent.createVerifiablePresentation({\n presentation: vpPayload.vp,\n proofFormat: 'jwt',\n keyRef: identifier.kmsKeyRef || identifier.kid,\n })\n\n return {\n documentFormat: DocumentFormat.JWT,\n presentationPayload: (vpJwt.proof && 'jwt' in vpJwt.proof && vpJwt.proof.jwt) || vpJwt,\n }\n}\n","import { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resolution'\nimport { ICredentialStore } from '@sphereon/ssi-sdk.credential-store'\nimport { VcdmCredentialPlugin } from '@sphereon/ssi-sdk.credential-vcdm'\nimport { ISDJwtPlugin } from '@sphereon/ssi-sdk.sd-jwt'\nimport { DocumentFormat } from '@sphereon/ssi-types'\nimport { IAgentContext, IPluginMethodMap } from '@veramo/core'\nimport { IKeyManager } from '@veramo/core/src/types/IKeyManager'\n\nexport const LOGGER_NAMESPACE = 'sphereon:linked-vp'\n\nexport type LinkedVPPresentation = {\n documentFormat: DocumentFormat\n presentationPayload: string | Record<string, any>\n}\n\nexport interface ILinkedVPManager extends IPluginMethodMap {\n /**\n * Publish a credential as a LinkedVP by adding it to the holder's DID Document\n * @param args - Publication arguments including credential ID and scope configuration\n * @param context - Agent context\n */\n lvpPublishCredential(args: PublishCredentialArgs, context: RequiredContext): Promise<LinkedVPEntry>\n\n /**\n * Unpublish a credential by removing its LinkedVP entry from the DID Document\n * @param args - Unpublish arguments\n * @param context - Agent context\n */\n lvpUnpublishCredential(args: UnpublishCredentialArgs, context: RequiredContext): Promise<boolean>\n\n /**\n * Check if a LinkedVP entry exists by linkedVpId\n * @param args - Query arguments\n * @param context - Agent context\n */\n lvpHasEntry(args: HasLinkedVPEntryArgs, context: RequiredContext): Promise<boolean>\n\n /**\n * Get LinkedVP service entries for a DID to be added to a DID Document\n * This is useful when generating DID Documents with toDidDocument\n * @param args - Query arguments for the DID\n * @param context - Agent context\n */\n lvpGetServiceEntries(args: GetServiceEntriesArgs, context: RequiredContext): Promise<Array<LinkedVPServiceEntry>>\n\n /**\n * Generate and return a Verifiable Presentation for a published LinkedVP\n * This is the main endpoint handler for GET /linked-vp/{linkedVpId}\n * @param args - Generation arguments\n * @param context - Agent context\n */\n lvpGeneratePresentation(args: GeneratePresentationArgs, context: RequiredContext): Promise<LinkedVPPresentation>\n}\n\nexport type PublishCredentialArgs = {\n digitalCredentialId: string\n linkedVpId?: string // Optional: if not provided, will be auto-generated\n linkedVpFrom?: Date\n linkedVpUntil?: Date\n}\n\nexport type UnpublishCredentialArgs = {\n linkedVpId: string\n}\n\nexport type HasLinkedVPEntryArgs = {\n linkedVpId: string\n}\n\nexport type GetServiceEntriesArgs = {\n subjectDid?: string\n tenantId?: string\n}\n\nexport type GeneratePresentationArgs = {\n linkedVpId: string\n linkedVpUntil?: Date\n}\n\nexport type LinkedVPEntry = {\n id: string\n linkedVpId: string\n linkedVpFrom?: Date\n linkedVpUntil?: Date\n tenantId?: string\n createdAt: Date\n}\n\nexport type LinkedVPServiceEntry = {\n id: string\n type: 'LinkedVerifiablePresentation'\n serviceEndpoint: string\n}\n\nexport type RequiredContext = IAgentContext<IIdentifierResolution & ICredentialStore & IKeyManager & VcdmCredentialPlugin & ISDJwtPlugin>\n"],"mappings":"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","names":["IsNull","Not","calculateSdHash","defaultGenerateDigest","CredentialMapper","DocumentFormat","Loggers","LOGGER_NAMESPACE","logger","Loggers","DEFAULT","get","LOGGER_NAMESPACE","CLOCK_SKEW","createLinkedVPPresentation","holderDid","credential","agent","debug","id","originalCredential","extractOriginalCredential","documentFormat","CredentialMapper","detectDocumentType","DocumentFormat","SD_JWT_VC","createSdJwtPresentation","JSONLD","createJsonLdPresentation","MSO_MDOC","createMdocPresentation","createJwtPresentation","udc","originalVerifiableCredential","uniformVerifiableCredential","original","decodedSdJwt","decodeSdJwtVcAsync","compactSdJwtVc","defaultGenerateDigest","hashAlg","signedPayload","_sd_alg","sdHash","calculateSdHash","kbJwtPayload","iat","Math","floor","Date","now","sd_hash","presentationResult","presentation","kb","payload","presentationPayload","vcObject","JSON","parse","vpObject","type","verifiableCredential","holder","identifier","identifierManagedGet","verifiablePresentationSP","createVerifiablePresentation","proofFormat","keyRef","kmsKeyRef","kid","warning","vcJwt","stringify","vpPayload","iss","vp","exp","vpJwt","JWT","proof","jwt","linkedVPManagerMethods","LinkedVPManager","schema","ILinkedVPManager","methods","lvpPublishCredential","bind","lvpUnpublishCredential","lvpHasEntry","lvpGetServiceEntries","lvpGeneratePresentation","args","context","digitalCredentialId","credential","agent","crsGetCredential","id","linkedVpId","Promise","reject","Error","buildLinkedVpId","tenantId","ensureLinkedVpIdUnique","publishAt","linkedVpFrom","Date","crsUpdateCredential","linkedVpUntil","createdAt","credentials","crsGetCredentials","filter","length","undefined","error","subjectDid","Not","IsNull","subjectCorrelationId","flatMap","cred","uniformDocument","JSON","parse","holderDidForEntry","getHolderDid","startsWith","credentialToServiceEntry","parseTenantFromLinkedVpId","uniqueCredentials","crsGetUniqueCredentials","uniqueDigitalCredential","uniformVerifiableCredential","digitalCredential","holderDid","createLinkedVPPresentation","cnf","jwk","kid","split","credentialSubject","Array","isArray","idx","lastIndexOf","substring","generateLinkedVpId","Math","random","toString","finalLinkedVpId","includes","getBaseUrlFromDid","withoutPrefix","replace","parts","domain","shift","path","join","buildServiceEndpoint","baseUrl","cleanBaseUrl","endsWith","slice","type","serviceEndpoint"]}
|
|
1
|
+
{"version":3,"sources":["../plugin.schema.json","../src/agent/LinkedVPManager.ts","../src/services/LinkedVPService.ts","../src/types/ILinkedVPManager.ts"],"sourcesContent":["{\n \"ILinkedVPManager\": {\n \"components\": {\n \"schemas\": {\n \"GeneratePresentationArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"linkedVpId\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\"linkedVpId\"],\n \"additionalProperties\": false\n },\n \"LinkedVPPresentation\": {\n \"anyOf\": [\n {\n \"type\": \"string\"\n },\n {\n \"$ref\": \"#/components/schemas/Record<string,any>\"\n }\n ]\n },\n \"Record<string,any>\": {\n \"type\": \"object\"\n },\n \"GetServiceEntriesArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"tenantId\": {\n \"type\": \"string\"\n }\n },\n \"additionalProperties\": false\n },\n \"LinkedVPServiceEntry\": {\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\n \"type\": \"string\"\n },\n \"type\": {\n \"type\": \"string\",\n \"const\": \"LinkedVerifiablePresentation\"\n },\n \"serviceEndpoint\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\"id\", \"type\", \"serviceEndpoint\"],\n \"additionalProperties\": false\n },\n \"HasLinkedVPEntryArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"linkedVpId\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\"linkedVpId\"],\n \"additionalProperties\": false\n },\n \"PublishCredentialArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"digitalCredentialId\": {\n \"type\": \"string\"\n },\n \"linkedVpId\": {\n \"type\": \"string\"\n },\n \"tenantId\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\"digitalCredentialId\"],\n \"additionalProperties\": false\n },\n \"LinkedVPEntry\": {\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\n \"type\": \"string\"\n },\n \"linkedVpId\": {\n \"type\": \"string\"\n },\n \"tenantId\": {\n \"type\": \"string\"\n },\n \"linkedVpFrom\": {\n \"type\": \"string\",\n \"format\": \"date-time\"\n },\n \"createdAt\": {\n \"type\": \"string\",\n \"format\": \"date-time\"\n }\n },\n \"required\": [\"id\", \"linkedVpId\", \"createdAt\"],\n \"additionalProperties\": false\n },\n \"UnpublishCredentialArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"linkedVpId\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\"linkedVpId\"],\n \"additionalProperties\": false\n }\n },\n \"methods\": {\n \"lvpGeneratePresentation\": {\n \"description\": \"Generate and return a Verifiable Presentation for a published LinkedVP This is the main endpoint handler for GET /linked-vp/\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/GeneratePresentationArgs\"\n },\n \"returnType\": {\n \"$ref\": \"#/components/schemas/LinkedVPPresentation\"\n }\n },\n \"lvpGetServiceEntries\": {\n \"description\": \"Get LinkedVP service entries for a DID to be added to a DID Document This is useful when generating DID Documents with toDidDocument\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/GetServiceEntriesArgs\"\n },\n \"returnType\": {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/components/schemas/LinkedVPServiceEntry\"\n }\n }\n },\n \"lvpHasEntry\": {\n \"description\": \"Check if a LinkedVP entry exists by linkedVpId\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/HasLinkedVPEntryArgs\"\n },\n \"returnType\": {\n \"type\": \"boolean\"\n }\n },\n \"lvpPublishCredential\": {\n \"description\": \"Publish a credential as a LinkedVP by adding it to the holder's DID Document\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/PublishCredentialArgs\"\n },\n \"returnType\": {\n \"$ref\": \"#/components/schemas/LinkedVPEntry\"\n }\n },\n \"lvpUnpublishCredential\": {\n \"description\": \"Unpublish a credential by removing its LinkedVP entry from the DID Document\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/UnpublishCredentialArgs\"\n },\n \"returnType\": {\n \"type\": \"boolean\"\n }\n }\n }\n }\n }\n}\n","import { DigitalCredential } from '@sphereon/ssi-sdk.data-store-types'\nimport { type IVerifiableCredential } from '@sphereon/ssi-types'\nimport { IAgentPlugin } from '@veramo/core'\nimport { IsNull, Not } from 'typeorm'\nimport { schema } from '../index'\nimport { createLinkedVPPresentation } from '../services/LinkedVPService'\nimport {\n GeneratePresentationArgs,\n GetServiceEntriesArgs,\n HasLinkedVPEntryArgs,\n ILinkedVPManager,\n LinkedVPEntry,\n LinkedVPPresentation,\n LinkedVPServiceEntry,\n PublishCredentialArgs,\n RequiredContext,\n UnpublishCredentialArgs,\n} from '../types'\n\n// Exposing the methods here for any REST implementation\nexport const linkedVPManagerMethods: Array<string> = [\n 'lvpPublishCredential',\n 'lvpUnpublishCredential',\n 'lvpHasEntry',\n 'lvpGetServiceEntries',\n 'lvpGeneratePresentation',\n]\n\n/**\n * {@inheritDoc ILinkedVPManager}\n */\nexport class LinkedVPManager implements IAgentPlugin {\n readonly schema = schema.ILinkedVPManager\n readonly methods: ILinkedVPManager = {\n lvpPublishCredential: this.lvpPublishCredential.bind(this),\n lvpUnpublishCredential: this.lvpUnpublishCredential.bind(this),\n lvpHasEntry: this.lvpHasEntry.bind(this),\n lvpGetServiceEntries: this.lvpGetServiceEntries.bind(this),\n lvpGeneratePresentation: this.lvpGeneratePresentation.bind(this),\n }\n\n private async lvpPublishCredential(args: PublishCredentialArgs, context: RequiredContext): Promise<LinkedVPEntry> {\n const { digitalCredentialId } = args\n\n const credential: DigitalCredential = await context.agent.crsGetCredential({ id: digitalCredentialId })\n\n if (credential.linkedVpId) {\n return Promise.reject(new Error(`Credential ${digitalCredentialId} is already published with linkedVpId ${credential.linkedVpId}`))\n }\n\n const linkedVpId = this.buildLinkedVpId(args.linkedVpId, credential.tenantId)\n\n await this.ensureLinkedVpIdUnique(linkedVpId, context, credential.tenantId)\n\n const publishAt = args.linkedVpFrom ?? new Date()\n await context.agent.crsUpdateCredential({\n id: digitalCredentialId,\n linkedVpId,\n linkedVpFrom: publishAt,\n linkedVpUntil: args.linkedVpUntil,\n })\n\n return {\n id: credential.id,\n linkedVpId,\n tenantId: credential.tenantId,\n linkedVpFrom: publishAt,\n linkedVpUntil: args.linkedVpUntil,\n createdAt: credential.createdAt,\n }\n }\n\n private async lvpUnpublishCredential(args: UnpublishCredentialArgs, context: RequiredContext): Promise<boolean> {\n const { linkedVpId } = args\n\n // Find credential by linkedVpId and tenantId\n const credentials = await context.agent.crsGetCredentials({\n filter: [{ linkedVpId }],\n })\n if (credentials.length === 0) {\n return Promise.reject(Error(`No credential found with linkedVpId ${linkedVpId}`))\n }\n\n const credential = credentials[0]\n await context.agent.crsUpdateCredential({\n id: credential.id,\n linkedVpId: undefined,\n linkedVpFrom: undefined,\n })\n\n return true\n }\n\n private async lvpHasEntry(args: HasLinkedVPEntryArgs, context: RequiredContext): Promise<boolean> {\n const { linkedVpId } = args\n\n try {\n const credentials = await context.agent.crsGetCredentials({\n filter: [{ linkedVpId }],\n })\n return credentials.length > 0\n } catch (error) {\n return false\n }\n }\n\n private async lvpGetServiceEntries(args: GetServiceEntriesArgs, context: RequiredContext): Promise<Array<LinkedVPServiceEntry>> {\n const { tenantId, subjectDid } = args\n\n // Get all published credentials (credentials with linkedVpId set)\n const filter: any = { linkedVpId: Not(IsNull()) }\n if (tenantId) {\n filter.tenantId = tenantId\n }\n if (subjectDid) {\n filter.subjectCorrelationId = subjectDid\n }\n\n const credentials = await context.agent.crsGetCredentials({\n filter: [filter],\n })\n\n return credentials.flatMap((cred) => {\n const uniformDocument = JSON.parse(cred.uniformDocument) as IVerifiableCredential\n const holderDidForEntry = this.getHolderDid(uniformDocument)\n return holderDidForEntry && holderDidForEntry.startsWith('did:web') ? [this.credentialToServiceEntry(cred, holderDidForEntry)] : []\n })\n }\n\n private async lvpGeneratePresentation(args: GeneratePresentationArgs, context: RequiredContext): Promise<LinkedVPPresentation> {\n const { linkedVpId } = args\n const tenantId = this.parseTenantFromLinkedVpId(linkedVpId)\n\n const uniqueCredentials = await context.agent.crsGetUniqueCredentials({\n filter: [\n {\n linkedVpId: args.linkedVpId,\n linkedVpUntil: args.linkedVpUntil,\n ...(tenantId && { tenantId }),\n },\n ],\n })\n if (uniqueCredentials.length === 0) {\n return Promise.reject(Error(`No published credentials found for linkedVpId ${linkedVpId}`))\n }\n if (uniqueCredentials.length > 1) {\n return Promise.reject(Error(`Multiple credentials found for linkedVpId ${linkedVpId}`))\n }\n\n const uniqueDigitalCredential = uniqueCredentials[0]\n if (!uniqueDigitalCredential.uniformVerifiableCredential) {\n return Promise.reject(Error(`uniformVerifiableCredential could not be found for credential ${uniqueDigitalCredential.digitalCredential.id}`))\n }\n const holderDid = this.getHolderDid(uniqueDigitalCredential.uniformVerifiableCredential)\n if (!holderDid) {\n return Promise.reject(Error(`Could not extract the holder did:web from cnf nor the credentialSubject id`))\n }\n\n // Generate the Verifiable Presentation with all published credentials\n return createLinkedVPPresentation(holderDid, uniqueDigitalCredential, context.agent)\n }\n\n private getHolderDid(uniformDocument: IVerifiableCredential): string | undefined {\n // Determine holder DID for identifier resolution\n if ('cnf' in uniformDocument && 'jwk' in uniformDocument.cnf && 'kid' in uniformDocument.cnf.jwk) {\n return uniformDocument.cnf.jwk.kid.split('#')[0]\n }\n\n if ('credentialSubject' in uniformDocument) {\n const credentialSubject = Array.isArray(uniformDocument.credentialSubject)\n ? uniformDocument.credentialSubject[0]\n : uniformDocument.credentialSubject\n if ('id' in credentialSubject && credentialSubject.id) {\n if (credentialSubject.id.startsWith('did:web')) {\n return credentialSubject.id\n }\n }\n }\n\n return undefined\n }\n\n private parseTenantFromLinkedVpId(linkedVpId: string): string | undefined {\n const idx = linkedVpId.lastIndexOf('@')\n return idx === -1 ? undefined : linkedVpId.substring(idx + 1)\n }\n\n private generateLinkedVpId(): string {\n return `lvp-${Math.random().toString(36).substring(2, 15)}`\n }\n\n private async ensureLinkedVpIdUnique(linkedVpId: string, context: RequiredContext, tenantId?: string): Promise<void> {\n const credentials = await context.agent.crsGetCredentials({\n filter: [{ linkedVpId, ...(tenantId && { tenantId }) }],\n })\n\n if (credentials.length > 0) {\n throw new Error(`LinkedVP ID ${linkedVpId} already exists${tenantId ? ` for tenant ${tenantId}` : ''}`)\n }\n }\n\n private buildLinkedVpId(linkedVpId: string | undefined, tenantId: string | undefined) {\n let finalLinkedVpId = linkedVpId || this.generateLinkedVpId()\n\n // Validate that user-provided ID doesn't contain @ char reserved for tenant id separator\n if (linkedVpId && linkedVpId.includes('@')) {\n throw new Error(`LinkedVP ID cannot contain '@' character as it is reserved for tenant separation`)\n }\n\n // Append tenantId if provided\n if (tenantId && tenantId !== '') {\n finalLinkedVpId = `${finalLinkedVpId}@${tenantId}`\n }\n return finalLinkedVpId\n }\n\n private getBaseUrlFromDid(holderDid: string): string {\n if (!holderDid.startsWith('did:web:')) {\n throw new Error(`Invalid DID: ${holderDid}, must be did:web`)\n }\n\n const withoutPrefix = holderDid.replace('did:web:', '') // example.com:tenants:tenant1\n const parts = withoutPrefix.split(':')\n const domain = parts.shift()! // example.com\n const path = parts.join('/') // tenants/tenant1\n\n return path\n ? `https://${domain}/${path}` // https://example.com/tenants/tenant1\n : `https://${domain}` // https://example.com\n }\n\n private buildServiceEndpoint(holderDid: string, linkedVpId: string): string {\n const baseUrl = this.getBaseUrlFromDid(holderDid)\n const cleanBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl\n return `${cleanBaseUrl}/linked-vp/${linkedVpId}`\n }\n\n private credentialToServiceEntry(credential: DigitalCredential, holderDid: string): LinkedVPServiceEntry {\n if (!credential.linkedVpId) {\n throw new Error(`Credential ${credential.id} does not have a linkedVpId`)\n }\n\n return {\n id: `${holderDid}#${credential.linkedVpId}`,\n type: 'LinkedVerifiablePresentation',\n serviceEndpoint: this.buildServiceEndpoint(holderDid, credential.linkedVpId),\n }\n }\n}\n","import { UniqueDigitalCredential } from '@sphereon/ssi-sdk.credential-store'\nimport { calculateSdHash, defaultGenerateDigest, PartialSdJwtKbJwt } from '@sphereon/ssi-sdk.sd-jwt'\n\nimport {\n CredentialMapper,\n DocumentFormat,\n Loggers,\n OriginalVerifiableCredential,\n SdJwtDecodedVerifiableCredential,\n WrappedVerifiableCredential,\n} from '@sphereon/ssi-types'\nimport { LinkedVPPresentation, LOGGER_NAMESPACE, RequiredContext } from '../types'\n\nconst logger = Loggers.DEFAULT.get(LOGGER_NAMESPACE)\nconst CLOCK_SKEW = 120 // TODO make adjustable?\n\n/**\n * Creates a Verifiable Presentation for LinkedVP publishing\n * Contains multiple credentials in a single JWT VP\n * No nonce or audience since this is for publishing, not responding to verification\n */\nexport async function createLinkedVPPresentation(\n holderDid: string,\n credential: UniqueDigitalCredential,\n agent: RequiredContext['agent'],\n): Promise<LinkedVPPresentation> {\n logger.debug(`Creating LinkedVP presentation for ${holderDid} of credential ${credential.id}`)\n\n const originalCredential = extractOriginalCredential(credential)\n const documentFormat = CredentialMapper.detectDocumentType(originalCredential)\n\n switch (documentFormat) {\n case DocumentFormat.SD_JWT_VC: {\n return createSdJwtPresentation(originalCredential, agent)\n }\n case DocumentFormat.JSONLD: {\n return createJsonLdPresentation(holderDid, originalCredential, agent)\n }\n case DocumentFormat.MSO_MDOC: {\n return createMdocPresentation(originalCredential)\n }\n default: {\n return createJwtPresentation(holderDid, originalCredential, agent)\n }\n }\n}\n\n/**\n * Extracts the original credential from various wrapper types\n */\nfunction extractOriginalCredential(\n credential: UniqueDigitalCredential | WrappedVerifiableCredential | OriginalVerifiableCredential,\n): OriginalVerifiableCredential {\n if (typeof credential === 'string') {\n return credential\n }\n\n if ('digitalCredential' in credential) {\n const udc = credential as UniqueDigitalCredential\n if (udc.originalVerifiableCredential) {\n return udc.originalVerifiableCredential\n }\n return udc.uniformVerifiableCredential as OriginalVerifiableCredential\n }\n\n if ('original' in credential) {\n return credential.original\n }\n\n return credential as OriginalVerifiableCredential\n}\n\n/**\n * Creates an SD-JWT presentation with KB-JWT\n */\nasync function createSdJwtPresentation(\n originalCredential: OriginalVerifiableCredential,\n agent: RequiredContext['agent'],\n): Promise<LinkedVPPresentation> {\n // SD-JWT with KB-JWT\n const decodedSdJwt = await CredentialMapper.decodeSdJwtVcAsync(\n typeof originalCredential === 'string' ? originalCredential : (originalCredential as SdJwtDecodedVerifiableCredential).compactSdJwtVc,\n defaultGenerateDigest,\n )\n\n const hashAlg = decodedSdJwt.signedPayload._sd_alg ?? 'sha-256'\n const sdHash = calculateSdHash(decodedSdJwt.compactSdJwtVc, hashAlg, defaultGenerateDigest)\n const kbJwtPayload: PartialSdJwtKbJwt['payload'] = {\n iat: Math.floor(Date.now() / 1000 - CLOCK_SKEW),\n sd_hash: sdHash,\n }\n\n const presentationResult = await agent.createSdJwtPresentation({\n presentation: decodedSdJwt.compactSdJwtVc,\n kb: {\n payload: kbJwtPayload as any, // FIXME? (typescript seems impossible)\n },\n })\n\n return {\n documentFormat: DocumentFormat.SD_JWT_VC,\n presentationPayload: presentationResult.presentation,\n }\n}\n\n/**\n * Creates a JSON-LD presentation with proof\n */\nasync function createJsonLdPresentation(\n holderDid: string,\n originalCredential: OriginalVerifiableCredential,\n agent: RequiredContext['agent'],\n): Promise<LinkedVPPresentation> {\n // JSON-LD VC - create JSON-LD VP with challenge and domain in proof\n const vcObject = typeof originalCredential === 'string' ? JSON.parse(originalCredential) : originalCredential\n\n const vpObject = {\n '@context': ['https://www.w3.org/2018/credentials/v1'],\n type: ['VerifiablePresentation'],\n verifiableCredential: [vcObject],\n holder: holderDid,\n }\n\n const identifier = await agent.identifierManagedGet({ identifier: holderDid })\n\n // Create JSON-LD VP with proof\n const verifiablePresentationSP = await agent.createVerifiablePresentation({\n presentation: vpObject,\n proofFormat: 'lds',\n keyRef: identifier.kmsKeyRef || identifier.kid,\n })\n return {\n documentFormat: DocumentFormat.JSONLD,\n presentationPayload: verifiablePresentationSP,\n }\n}\n\n/**\n * Creates an ISO mdoc presentation (basic support)\n */\nasync function createMdocPresentation(originalCredential: OriginalVerifiableCredential): Promise<LinkedVPPresentation> {\n // ISO mdoc - create mdoc VP token\n // This is a placeholder implementation\n // Full implementation would require:\n // 1. Decode the mdoc using CredentialMapper or mdoc utilities\n // 2. Build proper mdoc VP token with session transcript\n // 3. Include nonce/audience in the session transcript\n logger.warning('mso_mdoc format has basic support - production use requires proper mdoc VP token implementation')\n\n return {\n documentFormat: DocumentFormat.MSO_MDOC,\n presentationPayload: originalCredential,\n }\n}\n\n/**\n * Creates a JWT presentation\n */\nasync function createJwtPresentation(\n holderDid: string,\n originalCredential: OriginalVerifiableCredential,\n agent: RequiredContext['agent'],\n): Promise<LinkedVPPresentation> {\n // JWT VC - create JWT VP with nonce and aud in payload\n const vcJwt = typeof originalCredential === 'string' ? originalCredential : JSON.stringify(originalCredential)\n\n const identifier = await agent.identifierManagedGet({ identifier: holderDid })\n\n // Create VP JWT using agent method\n const vpPayload = {\n iss: holderDid,\n vp: {\n '@context': ['https://www.w3.org/2018/credentials/v1'],\n type: ['VerifiablePresentation'],\n holder: holderDid,\n verifiableCredential: [vcJwt],\n },\n iat: Math.floor(Date.now() / 1000 - CLOCK_SKEW),\n exp: Math.floor(Date.now() / 1000 + 600 + CLOCK_SKEW), // 10 minutes\n }\n\n // Use the agent's JWT creation capability\n const vpJwt = await agent.createVerifiablePresentation({\n presentation: vpPayload.vp,\n proofFormat: 'jwt',\n keyRef: identifier.kmsKeyRef || identifier.kid,\n })\n\n return {\n documentFormat: DocumentFormat.JWT,\n presentationPayload: (vpJwt.proof && 'jwt' in vpJwt.proof && vpJwt.proof.jwt) || vpJwt,\n }\n}\n","import { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resolution'\nimport { ICredentialStore } from '@sphereon/ssi-sdk.credential-store'\nimport { VcdmCredentialPlugin } from '@sphereon/ssi-sdk.credential-vcdm'\nimport { ISDJwtPlugin } from '@sphereon/ssi-sdk.sd-jwt'\nimport { DocumentFormat } from '@sphereon/ssi-types'\nimport { IAgentContext, IPluginMethodMap } from '@veramo/core'\nimport { IKeyManager } from '@veramo/core/src/types/IKeyManager'\n\nexport const LOGGER_NAMESPACE = 'sphereon:linked-vp'\n\nexport type LinkedVPPresentation = {\n documentFormat: DocumentFormat\n presentationPayload: string | Record<string, any>\n}\n\nexport interface ILinkedVPManager extends IPluginMethodMap {\n /**\n * Publish a credential as a LinkedVP by adding it to the holder's DID Document\n * @param args - Publication arguments including credential ID and scope configuration\n * @param context - Agent context\n */\n lvpPublishCredential(args: PublishCredentialArgs, context: RequiredContext): Promise<LinkedVPEntry>\n\n /**\n * Unpublish a credential by removing its LinkedVP entry from the DID Document\n * @param args - Unpublish arguments\n * @param context - Agent context\n */\n lvpUnpublishCredential(args: UnpublishCredentialArgs, context: RequiredContext): Promise<boolean>\n\n /**\n * Check if a LinkedVP entry exists by linkedVpId\n * @param args - Query arguments\n * @param context - Agent context\n */\n lvpHasEntry(args: HasLinkedVPEntryArgs, context: RequiredContext): Promise<boolean>\n\n /**\n * Get LinkedVP service entries for a DID to be added to a DID Document\n * This is useful when generating DID Documents with toDidDocument\n * @param args - Query arguments for the DID\n * @param context - Agent context\n */\n lvpGetServiceEntries(args: GetServiceEntriesArgs, context: RequiredContext): Promise<Array<LinkedVPServiceEntry>>\n\n /**\n * Generate and return a Verifiable Presentation for a published LinkedVP\n * This is the main endpoint handler for GET /linked-vp/{linkedVpId}\n * @param args - Generation arguments\n * @param context - Agent context\n */\n lvpGeneratePresentation(args: GeneratePresentationArgs, context: RequiredContext): Promise<LinkedVPPresentation>\n}\n\nexport type PublishCredentialArgs = {\n digitalCredentialId: string\n linkedVpId?: string // Optional: if not provided, will be auto-generated\n linkedVpFrom?: Date\n linkedVpUntil?: Date\n}\n\nexport type UnpublishCredentialArgs = {\n linkedVpId: string\n}\n\nexport type HasLinkedVPEntryArgs = {\n linkedVpId: string\n}\n\nexport type GetServiceEntriesArgs = {\n subjectDid?: string\n tenantId?: string\n}\n\nexport type GeneratePresentationArgs = {\n linkedVpId: string\n linkedVpUntil?: Date\n}\n\nexport type LinkedVPEntry = {\n id: string\n linkedVpId: string\n linkedVpFrom?: Date\n linkedVpUntil?: Date\n tenantId?: string\n createdAt: Date\n}\n\nexport type LinkedVPServiceEntry = {\n id: string\n type: 'LinkedVerifiablePresentation'\n serviceEndpoint: string\n}\n\nexport type RequiredContext = IAgentContext<IIdentifierResolution & ICredentialStore & IKeyManager & VcdmCredentialPlugin & ISDJwtPlugin>\n"],"mappings":"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","names":["IsNull","Not","calculateSdHash","defaultGenerateDigest","CredentialMapper","DocumentFormat","Loggers","LOGGER_NAMESPACE","logger","Loggers","DEFAULT","get","LOGGER_NAMESPACE","CLOCK_SKEW","createLinkedVPPresentation","holderDid","credential","agent","debug","id","originalCredential","extractOriginalCredential","documentFormat","CredentialMapper","detectDocumentType","DocumentFormat","SD_JWT_VC","createSdJwtPresentation","JSONLD","createJsonLdPresentation","MSO_MDOC","createMdocPresentation","createJwtPresentation","udc","originalVerifiableCredential","uniformVerifiableCredential","original","decodedSdJwt","decodeSdJwtVcAsync","compactSdJwtVc","defaultGenerateDigest","hashAlg","signedPayload","_sd_alg","sdHash","calculateSdHash","kbJwtPayload","iat","Math","floor","Date","now","sd_hash","presentationResult","presentation","kb","payload","presentationPayload","vcObject","JSON","parse","vpObject","type","verifiableCredential","holder","identifier","identifierManagedGet","verifiablePresentationSP","createVerifiablePresentation","proofFormat","keyRef","kmsKeyRef","kid","warning","vcJwt","stringify","vpPayload","iss","vp","exp","vpJwt","JWT","proof","jwt","linkedVPManagerMethods","LinkedVPManager","schema","ILinkedVPManager","methods","lvpPublishCredential","bind","lvpUnpublishCredential","lvpHasEntry","lvpGetServiceEntries","lvpGeneratePresentation","args","context","digitalCredentialId","credential","agent","crsGetCredential","id","linkedVpId","Promise","reject","Error","buildLinkedVpId","tenantId","ensureLinkedVpIdUnique","publishAt","linkedVpFrom","Date","crsUpdateCredential","linkedVpUntil","createdAt","credentials","crsGetCredentials","filter","length","undefined","error","subjectDid","Not","IsNull","subjectCorrelationId","flatMap","cred","uniformDocument","JSON","parse","holderDidForEntry","getHolderDid","startsWith","credentialToServiceEntry","parseTenantFromLinkedVpId","uniqueCredentials","crsGetUniqueCredentials","uniqueDigitalCredential","uniformVerifiableCredential","digitalCredential","holderDid","createLinkedVPPresentation","cnf","jwk","kid","split","credentialSubject","Array","isArray","idx","lastIndexOf","substring","generateLinkedVpId","Math","random","toString","finalLinkedVpId","includes","getBaseUrlFromDid","withoutPrefix","replace","parts","domain","shift","path","join","buildServiceEndpoint","baseUrl","cleanBaseUrl","endsWith","slice","type","serviceEndpoint"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sphereon/ssi-sdk.linked-vp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.38.0",
|
|
4
4
|
"source": "src/index.ts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -27,13 +27,13 @@
|
|
|
27
27
|
"generate-plugin-schema": "tsx ../../packages/dev/bin/sphereon.js dev generate-plugin-schema"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@sphereon/ssi-sdk-ext.identifier-resolution": "0.
|
|
31
|
-
"@sphereon/ssi-sdk.credential-store": "0.
|
|
32
|
-
"@sphereon/ssi-sdk.credential-vcdm": "0.
|
|
33
|
-
"@sphereon/ssi-sdk.data-store": "0.
|
|
34
|
-
"@sphereon/ssi-sdk.data-store-types": "0.
|
|
35
|
-
"@sphereon/ssi-sdk.sd-jwt": "0.
|
|
36
|
-
"@sphereon/ssi-types": "0.
|
|
30
|
+
"@sphereon/ssi-sdk-ext.identifier-resolution": "0.38.0",
|
|
31
|
+
"@sphereon/ssi-sdk.credential-store": "0.38.0",
|
|
32
|
+
"@sphereon/ssi-sdk.credential-vcdm": "0.38.0",
|
|
33
|
+
"@sphereon/ssi-sdk.data-store": "0.38.0",
|
|
34
|
+
"@sphereon/ssi-sdk.data-store-types": "0.38.0",
|
|
35
|
+
"@sphereon/ssi-sdk.sd-jwt": "0.38.0",
|
|
36
|
+
"@sphereon/ssi-types": "0.38.0",
|
|
37
37
|
"@veramo/utils": "4.2.0",
|
|
38
38
|
"cross-fetch": "^4.1.0",
|
|
39
39
|
"dcql": "1.0.1",
|
|
@@ -43,10 +43,10 @@
|
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@sd-jwt/types": "^0.15.0",
|
|
46
|
-
"@sphereon/ssi-sdk-ext.key-manager": "0.
|
|
47
|
-
"@sphereon/ssi-sdk-ext.kms-local": "0.
|
|
48
|
-
"@sphereon/ssi-sdk.agent-config": "0.
|
|
49
|
-
"@sphereon/ssi-sdk.credential-vcdm1-jwt-provider": "0.
|
|
46
|
+
"@sphereon/ssi-sdk-ext.key-manager": "0.38.0",
|
|
47
|
+
"@sphereon/ssi-sdk-ext.kms-local": "0.38.0",
|
|
48
|
+
"@sphereon/ssi-sdk.agent-config": "0.38.0",
|
|
49
|
+
"@sphereon/ssi-sdk.credential-vcdm1-jwt-provider": "0.38.0",
|
|
50
50
|
"@veramo/data-store": "4.2.0",
|
|
51
51
|
"@veramo/did-manager": "4.2.0",
|
|
52
52
|
"@veramo/did-provider-web": "4.2.0",
|
|
@@ -77,5 +77,5 @@
|
|
|
77
77
|
"Veramo",
|
|
78
78
|
"Linked VP Manager"
|
|
79
79
|
],
|
|
80
|
-
"gitHead": "
|
|
80
|
+
"gitHead": "a93cb5bf52d46acaf3b2b2d8eba83cc88aa5cda4"
|
|
81
81
|
}
|
package/plugin.schema.json
CHANGED
|
@@ -9,9 +9,7 @@
|
|
|
9
9
|
"type": "string"
|
|
10
10
|
}
|
|
11
11
|
},
|
|
12
|
-
"required": [
|
|
13
|
-
"linkedVpId"
|
|
14
|
-
],
|
|
12
|
+
"required": ["linkedVpId"],
|
|
15
13
|
"additionalProperties": false
|
|
16
14
|
},
|
|
17
15
|
"LinkedVPPresentation": {
|
|
@@ -50,11 +48,7 @@
|
|
|
50
48
|
"type": "string"
|
|
51
49
|
}
|
|
52
50
|
},
|
|
53
|
-
"required": [
|
|
54
|
-
"id",
|
|
55
|
-
"type",
|
|
56
|
-
"serviceEndpoint"
|
|
57
|
-
],
|
|
51
|
+
"required": ["id", "type", "serviceEndpoint"],
|
|
58
52
|
"additionalProperties": false
|
|
59
53
|
},
|
|
60
54
|
"HasLinkedVPEntryArgs": {
|
|
@@ -64,9 +58,7 @@
|
|
|
64
58
|
"type": "string"
|
|
65
59
|
}
|
|
66
60
|
},
|
|
67
|
-
"required": [
|
|
68
|
-
"linkedVpId"
|
|
69
|
-
],
|
|
61
|
+
"required": ["linkedVpId"],
|
|
70
62
|
"additionalProperties": false
|
|
71
63
|
},
|
|
72
64
|
"PublishCredentialArgs": {
|
|
@@ -82,9 +74,7 @@
|
|
|
82
74
|
"type": "string"
|
|
83
75
|
}
|
|
84
76
|
},
|
|
85
|
-
"required": [
|
|
86
|
-
"digitalCredentialId"
|
|
87
|
-
],
|
|
77
|
+
"required": ["digitalCredentialId"],
|
|
88
78
|
"additionalProperties": false
|
|
89
79
|
},
|
|
90
80
|
"LinkedVPEntry": {
|
|
@@ -108,11 +98,7 @@
|
|
|
108
98
|
"format": "date-time"
|
|
109
99
|
}
|
|
110
100
|
},
|
|
111
|
-
"required": [
|
|
112
|
-
"id",
|
|
113
|
-
"linkedVpId",
|
|
114
|
-
"createdAt"
|
|
115
|
-
],
|
|
101
|
+
"required": ["id", "linkedVpId", "createdAt"],
|
|
116
102
|
"additionalProperties": false
|
|
117
103
|
},
|
|
118
104
|
"UnpublishCredentialArgs": {
|
|
@@ -122,9 +108,7 @@
|
|
|
122
108
|
"type": "string"
|
|
123
109
|
}
|
|
124
110
|
},
|
|
125
|
-
"required": [
|
|
126
|
-
"linkedVpId"
|
|
127
|
-
],
|
|
111
|
+
"required": ["linkedVpId"],
|
|
128
112
|
"additionalProperties": false
|
|
129
113
|
}
|
|
130
114
|
},
|
|
@@ -180,4 +164,4 @@
|
|
|
180
164
|
}
|
|
181
165
|
}
|
|
182
166
|
}
|
|
183
|
-
}
|
|
167
|
+
}
|
|
@@ -120,12 +120,11 @@ export class LinkedVPManager implements IAgentPlugin {
|
|
|
120
120
|
filter: [filter],
|
|
121
121
|
})
|
|
122
122
|
|
|
123
|
-
return credentials
|
|
124
|
-
.
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
})
|
|
123
|
+
return credentials.flatMap((cred) => {
|
|
124
|
+
const uniformDocument = JSON.parse(cred.uniformDocument) as IVerifiableCredential
|
|
125
|
+
const holderDidForEntry = this.getHolderDid(uniformDocument)
|
|
126
|
+
return holderDidForEntry && holderDidForEntry.startsWith('did:web') ? [this.credentialToServiceEntry(cred, holderDidForEntry)] : []
|
|
127
|
+
})
|
|
129
128
|
}
|
|
130
129
|
|
|
131
130
|
private async lvpGeneratePresentation(args: GeneratePresentationArgs, context: RequiredContext): Promise<LinkedVPPresentation> {
|