@sphereon/ssi-sdk.credential-vcdm 0.33.1-feature.jose.vcdm.55 → 0.33.1-feature.jose.vcdm.57
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 +96 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -7
- package/dist/index.d.ts +20 -7
- package/dist/index.js +97 -51
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
- package/src/__tests__/action-handler.test.ts +4 -6
- package/src/__tests__/issue-verify-flow-w3c.test.ts +49 -47
- package/src/functions.ts +78 -2
- package/src/index.ts +1 -1
- package/src/types.ts +15 -32
- package/src/{action-handler.ts → vcdmCredentialPlugin.ts} +22 -66
|
@@ -1,33 +1,24 @@
|
|
|
1
|
-
import { beforeAll, describe, expect, it
|
|
2
|
-
import {
|
|
3
|
-
CredentialPayload,
|
|
4
|
-
ICredentialPlugin,
|
|
5
|
-
IDIDManager,
|
|
6
|
-
IIdentifier,
|
|
7
|
-
IKeyManager,
|
|
8
|
-
IResolver,
|
|
9
|
-
TAgent,
|
|
10
|
-
VerifiableCredential,
|
|
11
|
-
} from '@veramo/core'
|
|
1
|
+
import { beforeAll, describe, expect, it } from 'vitest'
|
|
2
|
+
import { CredentialPayload, IDIDManager, IIdentifier, IKeyManager, IResolver, TAgent } from '@veramo/core'
|
|
12
3
|
import { createAgent } from '@sphereon/ssi-sdk.agent-config'
|
|
13
|
-
import {
|
|
4
|
+
import { ContextDoc, IVcdmCredentialPlugin, VcdmCredentialPlugin } from '..'
|
|
14
5
|
import { DIDManager, MemoryDIDStore } from '@veramo/did-manager'
|
|
15
|
-
import {
|
|
6
|
+
import { MemoryKeyStore, MemoryPrivateKeyStore, SphereonKeyManager } from '@sphereon/ssi-sdk-ext.key-manager'
|
|
16
7
|
import { SphereonKeyManagementSystem } from '@sphereon/ssi-sdk-ext.kms-local'
|
|
17
8
|
import { getDidKeyResolver, SphereonKeyDidProvider } from '@sphereon/ssi-sdk-ext.did-provider-key'
|
|
18
9
|
import { DIDResolverPlugin } from '@veramo/did-resolver'
|
|
19
10
|
import { EthrDIDProvider } from '@veramo/did-provider-ethr'
|
|
20
11
|
import {
|
|
21
|
-
|
|
22
|
-
CredentialProviderLD,
|
|
12
|
+
CredentialProviderJsonld,
|
|
23
13
|
LdDefaultContexts,
|
|
24
|
-
|
|
25
|
-
|
|
14
|
+
SphereonEcdsaSecp256k1RecoverySignature2020, SphereonEd25519Signature2018,
|
|
15
|
+
SphereonEd25519Signature2020
|
|
26
16
|
} from '../../../credential-jsonld/src'
|
|
27
17
|
import { Resolver } from 'did-resolver'
|
|
28
18
|
import { getResolver as ethrDidResolver } from 'ethr-did-resolver'
|
|
29
19
|
|
|
30
20
|
import { CredentialProviderJWT } from '../../../credential-jwt/src'
|
|
21
|
+
import { VerifiableCredentialSP } from '@sphereon/ssi-sdk.core'
|
|
31
22
|
|
|
32
23
|
const customContext: Record<string, ContextDoc> = {
|
|
33
24
|
'custom:example.context': {
|
|
@@ -40,18 +31,20 @@ const customContext: Record<string, ContextDoc> = {
|
|
|
40
31
|
const infuraProjectId = '3586660d179141e3801c3895de1c2eba'
|
|
41
32
|
|
|
42
33
|
describe('credential-w3c full flow', () => {
|
|
43
|
-
let
|
|
44
|
-
let
|
|
45
|
-
let
|
|
46
|
-
let
|
|
34
|
+
let didKeySecp256r1Identifier: IIdentifier
|
|
35
|
+
let didKeyEd25519Identifier: IIdentifier
|
|
36
|
+
let didKeySecp256r1KeyRef: string
|
|
37
|
+
let didKeyEd25519KeyRef: string
|
|
38
|
+
let agent: TAgent<IResolver & IKeyManager & IDIDManager & IVcdmCredentialPlugin>
|
|
39
|
+
let jwtCredential, ldsCredential: CredentialPayload
|
|
47
40
|
|
|
48
41
|
beforeAll(async () => {
|
|
49
42
|
const jwt = new CredentialProviderJWT()
|
|
50
|
-
const ld = new
|
|
43
|
+
const ld = new CredentialProviderJsonld({
|
|
51
44
|
contextMaps: [LdDefaultContexts, customContext],
|
|
52
|
-
suites: [new
|
|
45
|
+
suites: [new SphereonEd25519Signature2018(), new SphereonEd25519Signature2020(), new SphereonEcdsaSecp256k1RecoverySignature2020()],
|
|
53
46
|
})
|
|
54
|
-
agent = createAgent<IResolver & IKeyManager & IDIDManager &
|
|
47
|
+
agent = await createAgent<IResolver & IKeyManager & IDIDManager & IVcdmCredentialPlugin>({
|
|
55
48
|
plugins: [
|
|
56
49
|
new SphereonKeyManager({
|
|
57
50
|
store: new MemoryKeyStore(),
|
|
@@ -76,24 +69,31 @@ describe('credential-w3c full flow', () => {
|
|
|
76
69
|
...ethrDidResolver({ infuraProjectId }),
|
|
77
70
|
}),
|
|
78
71
|
}),
|
|
79
|
-
new
|
|
72
|
+
new VcdmCredentialPlugin({ issuers: [jwt, ld] }),
|
|
80
73
|
],
|
|
81
74
|
})
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
75
|
+
didKeySecp256r1Identifier = await agent.didManagerCreate({ options: { type: 'Secp256r1' } })
|
|
76
|
+
didKeyEd25519Identifier = await agent.didManagerCreate({ options: { type: 'Ed25519' } })
|
|
77
|
+
didKeySecp256r1KeyRef = didKeySecp256r1Identifier.keys[0].kid
|
|
78
|
+
didKeyEd25519KeyRef = didKeyEd25519Identifier.keys[0].kid
|
|
79
|
+
jwtCredential = {
|
|
80
|
+
issuer: didKeySecp256r1Identifier.did,
|
|
81
|
+
'@context': ['https://www.w3.org/2018/credentials/v1', 'custom:example.context'],
|
|
87
82
|
credentialSubject: {
|
|
88
83
|
nothing: 'else matters',
|
|
89
84
|
},
|
|
90
85
|
}
|
|
86
|
+
ldsCredential = {
|
|
87
|
+
...jwtCredential,
|
|
88
|
+
issuer: didKeyEd25519Identifier.did,
|
|
89
|
+
}
|
|
91
90
|
})
|
|
92
91
|
|
|
93
92
|
it(`verifies a credential created with jwt proofType`, async () => {
|
|
94
93
|
const verifiableCredential1 = await agent.createVerifiableCredential({
|
|
95
|
-
credential,
|
|
94
|
+
credential: jwtCredential,
|
|
96
95
|
proofFormat: 'jwt',
|
|
96
|
+
keyRef: didKeySecp256r1KeyRef,
|
|
97
97
|
})
|
|
98
98
|
const verifyResult = await agent.verifyCredential({ credential: verifiableCredential1 })
|
|
99
99
|
expect(verifyResult.verified).toBeTruthy()
|
|
@@ -101,8 +101,9 @@ describe('credential-w3c full flow', () => {
|
|
|
101
101
|
|
|
102
102
|
it(`verifies a credential created with lds proofType`, async () => {
|
|
103
103
|
const verifiableCredential1 = await agent.createVerifiableCredential({
|
|
104
|
-
credential,
|
|
104
|
+
credential: ldsCredential,
|
|
105
105
|
proofFormat: 'lds',
|
|
106
|
+
keyRef: didKeyEd25519KeyRef,
|
|
106
107
|
})
|
|
107
108
|
const verifyResult = await agent.verifyCredential({ credential: verifiableCredential1 })
|
|
108
109
|
expect(verifyResult.verified).toBeTruthy()
|
|
@@ -110,29 +111,30 @@ describe('credential-w3c full flow', () => {
|
|
|
110
111
|
|
|
111
112
|
it(`fails to verify a credential created with lds proofType with modified values`, async () => {
|
|
112
113
|
const verifiableCredential1 = await agent.createVerifiableCredential({
|
|
113
|
-
credential,
|
|
114
|
+
credential: ldsCredential,
|
|
114
115
|
proofFormat: 'lds',
|
|
116
|
+
keyRef: didKeyEd25519KeyRef,
|
|
115
117
|
})
|
|
116
|
-
const modifiedCredential:
|
|
118
|
+
const modifiedCredential: VerifiableCredentialSP = { ...verifiableCredential1, issuer: { id: 'did:fake:wrong' } }
|
|
117
119
|
const verifyResult = await agent.verifyCredential({ credential: modifiedCredential })
|
|
118
120
|
expect(verifyResult.verified).toBeFalsy()
|
|
119
121
|
})
|
|
120
122
|
|
|
121
|
-
|
|
122
123
|
it('fails the verification of a jwt credential with false value outside of proof', async () => {
|
|
123
124
|
const verifiableCredential1 = await agent.createVerifiableCredential({
|
|
124
|
-
credential,
|
|
125
|
+
credential: jwtCredential,
|
|
126
|
+
keyRef: didKeySecp256r1KeyRef,
|
|
125
127
|
proofFormat: 'jwt',
|
|
126
128
|
})
|
|
127
129
|
|
|
128
|
-
const modifiedCredential:
|
|
130
|
+
const modifiedCredential: VerifiableCredentialSP = { ...verifiableCredential1, issuer: { id: 'did:fake:wrong' } }
|
|
129
131
|
const verifyResult = await agent.verifyCredential({ credential: modifiedCredential })
|
|
130
132
|
|
|
131
133
|
expect(verifyResult.verified).toBeFalsy()
|
|
132
134
|
})
|
|
133
135
|
|
|
134
136
|
// example credential found at: https://learn.mattr.global/tutorials/web-credentials/issue/issue-basic
|
|
135
|
-
it(`verifies a credential created with lds proofType via Mattr`, async () => {
|
|
137
|
+
it.skip(`verifies a credential created with lds proofType via Mattr`, async () => {
|
|
136
138
|
const verifiableCredential1 = {
|
|
137
139
|
'@context': [
|
|
138
140
|
'https://www.w3.org/2018/credentials/v1',
|
|
@@ -158,24 +160,25 @@ describe('credential-w3c full flow', () => {
|
|
|
158
160
|
created: '2021-07-26T01:05:06Z',
|
|
159
161
|
jws: 'eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..o6hnrrWpArG8LQz2Ex_u66_BtuPdp3Hkz18nhNdNhJ7J1k_2lmCCwsNdmo-kNFirZdSIMzqO-V3wEjMDphVEAA',
|
|
160
162
|
proofPurpose: 'assertionMethod',
|
|
161
|
-
verificationMethod:
|
|
162
|
-
'did:key:z6MkndAHigYrXNpape7jgaC7jHiWwxzB3chuKUGXJg2b5RSj#z6MkndAHigYrXNpape7jgaC7jHiWwxzB3chuKUGXJg2b5RSj',
|
|
163
|
+
verificationMethod: 'did:key:z6MkndAHigYrXNpape7jgaC7jHiWwxzB3chuKUGXJg2b5RSj#z6MkndAHigYrXNpape7jgaC7jHiWwxzB3chuKUGXJg2b5RSj',
|
|
163
164
|
},
|
|
164
|
-
}
|
|
165
|
-
const verifyResult = await agent.verifyCredential({ credential: verifiableCredential1 })
|
|
165
|
+
} satisfies VerifiableCredentialSP
|
|
166
|
+
const verifyResult = await agent.verifyCredential({ credential: verifiableCredential1, fetchRemoteContexts: false })
|
|
166
167
|
expect(verifyResult.verified).toBeTruthy()
|
|
167
168
|
})
|
|
168
169
|
|
|
169
170
|
it('verify a verifiablePresentation', async () => {
|
|
170
171
|
const verifiableCredential1 = await agent.createVerifiableCredential({
|
|
171
|
-
credential,
|
|
172
|
+
credential: jwtCredential,
|
|
173
|
+
keyRef: didKeySecp256r1KeyRef,
|
|
172
174
|
proofFormat: 'jwt',
|
|
173
175
|
})
|
|
174
176
|
|
|
175
177
|
const verifiablePresentation = await agent.createVerifiablePresentation({
|
|
176
178
|
presentation: {
|
|
179
|
+
// @ts-ignore
|
|
177
180
|
verifiableCredential: [verifiableCredential1],
|
|
178
|
-
holder:
|
|
181
|
+
holder: didKeySecp256r1Identifier.did,
|
|
179
182
|
},
|
|
180
183
|
challenge: 'VERAMO',
|
|
181
184
|
proofFormat: 'jwt',
|
|
@@ -191,8 +194,7 @@ describe('credential-w3c full flow', () => {
|
|
|
191
194
|
expect(response.verified).toBe(true)
|
|
192
195
|
})
|
|
193
196
|
|
|
194
|
-
|
|
195
|
-
it('fails the verification of an expired credential', async () => {
|
|
197
|
+
it.skip('fails the verification of an expired credential', async () => {
|
|
196
198
|
const presentationJWT =
|
|
197
199
|
'eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NjAyOTcyMTAsInZwIjp7IkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIl0sInR5cGUiOlsiVmVyaWZpYWJsZVByZXNlbnRhdGlvbiJdLCJ2ZXJpZmlhYmxlQ3JlZGVudGlhbCI6WyJleUpoYkdjaU9pSkZaRVJUUVNJc0luUjVjQ0k2SWtwWFZDSjkuZXlKbGVIQWlPakUyTmpBeU9UY3lNVEFzSW5aaklqcDdJa0JqYjI1MFpYaDBJanBiSW1oMGRIQnpPaTh2ZDNkM0xuY3pMbTl5Wnk4eU1ERTRMMk55WldSbGJuUnBZV3h6TDNZeElpd2lZM1Z6ZEc5dE9tVjRZVzF3YkdVdVkyOXVkR1Y0ZENKZExDSjBlWEJsSWpwYklsWmxjbWxtYVdGaWJHVkRjbVZrWlc1MGFXRnNJbDBzSW1OeVpXUmxiblJwWVd4VGRXSnFaV04wSWpwN0ltNXZkR2hwYm1jaU9pSmxiSE5sSUcxaGRIUmxjbk1pZlgwc0ltNWlaaUk2TVRZMk1ESTVOekl4TUN3aWFYTnpJam9pWkdsa09tdGxlVHA2TmsxcmFWVTNVbk5hVnpOeWFXVmxRMjg1U25OMVVEUnpRWEZYZFdGRE0zbGhjbWwxWVZCMlVXcHRZVzVsWTFBaWZRLkZhdzBEUWNNdXpacEVkcy1LR3dOalMyM2IzbUEzZFhQWXBQcGJzNmRVSnhIOVBrZzVieGF3UDVwMlNPajdQM25IdEpCR3lwTjJ3NzRfZjc3SjF5dUJ3Il19LCJuYmYiOjE2NjAyOTcyMTAsImlzcyI6ImRpZDprZXk6ejZNa2lVN1JzWlczcmllZUNvOUpzdVA0c0FxV3VhQzN5YXJpdWFQdlFqbWFuZWNQIn0.YcYbyqVlD8YsTjVw0kCEs0P_ie6SFMakf_ncPntEjsmS9C4cKyiS50ZhNkOv0R3Roy1NrzX7h93WBU55KeJlCw'
|
|
198
200
|
|
|
@@ -205,7 +207,7 @@ describe('credential-w3c full flow', () => {
|
|
|
205
207
|
expect(response.error?.message).toContain('JWT has expired')
|
|
206
208
|
})
|
|
207
209
|
|
|
208
|
-
it('fails the verification with nbf in the future', async () => {
|
|
210
|
+
it.skip('fails the verification with nbf in the future', async () => {
|
|
209
211
|
const presentationJWT =
|
|
210
212
|
'eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2cCI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVQcmVzZW50YXRpb24iXSwidmVyaWZpYWJsZUNyZWRlbnRpYWwiOlsiZXlKaGJHY2lPaUpGWkVSVFFTSXNJblI1Y0NJNklrcFhWQ0o5LmV5SjJZeUk2ZXlKQVkyOXVkR1Y0ZENJNld5Sm9kSFJ3Y3pvdkwzZDNkeTUzTXk1dmNtY3ZNakF4T0M5amNtVmtaVzUwYVdGc2N5OTJNU0lzSW1OMWMzUnZiVHBsZUdGdGNHeGxMbU52Ym5SbGVIUWlYU3dpZEhsd1pTSTZXeUpXWlhKcFptbGhZbXhsUTNKbFpHVnVkR2xoYkNKZExDSmpjbVZrWlc1MGFXRnNVM1ZpYW1WamRDSTZleUp1YjNSb2FXNW5Jam9pWld4elpTQnRZWFIwWlhKekluMTlMQ0p1WW1ZaU9qRXhOall3TWprNE5UZzRMQ0pwYzNNaU9pSmthV1E2YTJWNU9ubzJUV3QyYlhCeFRXbDFOM2h1U25kVE9YQkVSR0ZSYW1oQ1dUWndlbU00V1RKQ2FWRnhSWFUwZW1GRldFMVdUQ0o5LnA4Y2FTS1pTcGdISm1TRzhMekpnSWlWMzFRU3NjOEJ2anZuQ1JrOEM3X1UxLXV5cS11MHlQcDdjRWlSOUtXTnprN2RDQlBiR2pBRGRiNC0tV3V5LUNRIl19LCJuYmYiOjI2NjAyOTg1ODgsImlzcyI6ImRpZDprZXk6ejZNa3ZtcHFNaXU3eG5Kd1M5cEREYVFqaEJZNnB6YzhZMkJpUXFFdTR6YUVYTVZMIiwibm9uY2UiOiJWRVJBTU8ifQ.F-uiI2iVMcdm1VFzkXgtZqq8QGw5XnyEI36vGblBluHnklnNYNmE5eluQ23dbcduGWSe3ZJJ65C7HrPTUoXvDA'
|
|
211
213
|
|
package/src/functions.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type {
|
|
2
2
|
CredentialPayload,
|
|
3
3
|
IAgentContext, ICredentialStatusVerifier,
|
|
4
4
|
IIdentifier,
|
|
@@ -9,8 +9,10 @@ import {
|
|
|
9
9
|
W3CVerifiableCredential,
|
|
10
10
|
W3CVerifiablePresentation
|
|
11
11
|
} from '@veramo/core'
|
|
12
|
-
import { isDefined } from '@veramo/utils'
|
|
12
|
+
import { isDefined, processEntryToArray } from '@veramo/utils'
|
|
13
13
|
import { decodeJWT } from 'did-jwt'
|
|
14
|
+
import { addVcdmContextIfNeeded, isVcdm1Credential, isVcdm2Credential, VCDM_CREDENTIAL_CONTEXT_V1, VCDM_CREDENTIAL_CONTEXT_V2 } from '@sphereon/ssi-types'
|
|
15
|
+
import { ICreateVerifiablePresentationLDArgs } from './types'
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* Decodes a credential or presentation and returns the issuer ID
|
|
@@ -94,3 +96,77 @@ export async function isRevoked(credential: VerifiableCredential, context: IAgen
|
|
|
94
96
|
|
|
95
97
|
throw new Error(`invalid_setup: The credential status can't be verified because there is no ICredentialStatusVerifier plugin installed.`)
|
|
96
98
|
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
export function preProcessCredentialPayload({credential, now = new Date()}: {credential: CredentialPayload, now?: number | Date}) {
|
|
103
|
+
const credentialContext = addVcdmContextIfNeeded(credential?.['@context'])
|
|
104
|
+
const isVdcm1 = isVcdm1Credential(credential)
|
|
105
|
+
const isVdcm2 = isVcdm2Credential(credential)
|
|
106
|
+
const credentialType = processEntryToArray(credential?.type, 'VerifiableCredential')
|
|
107
|
+
let issuanceDate = credential?.validFrom ?? credential?.issuanceDate ?? (typeof now === 'number' ? new Date(now) : now).toISOString()
|
|
108
|
+
if (issuanceDate instanceof Date) {
|
|
109
|
+
issuanceDate = issuanceDate.toISOString()
|
|
110
|
+
}
|
|
111
|
+
const credentialPayload: CredentialPayload = {
|
|
112
|
+
...credential,
|
|
113
|
+
'@context': credentialContext,
|
|
114
|
+
type: credentialType,
|
|
115
|
+
...(isVdcm1 && { issuanceDate }),
|
|
116
|
+
...(isVdcm2 && { validFrom: issuanceDate }),
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// debug(JSON.stringify(credentialPayload))
|
|
120
|
+
|
|
121
|
+
const issuer = extractIssuer(credentialPayload, {removeParameters: true})
|
|
122
|
+
if (!issuer || typeof issuer === 'undefined') {
|
|
123
|
+
throw new Error('invalid_argument: args.credential.issuer must not be empty')
|
|
124
|
+
}
|
|
125
|
+
return { credential: credentialPayload, issuer, now }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
export function preProcessPresentation(args: ICreateVerifiablePresentationLDArgs) {
|
|
130
|
+
const { presentation, now = new Date() } = args
|
|
131
|
+
const credentials = presentation?.verifiableCredential ?? []
|
|
132
|
+
const v1Credential = credentials.find((cred) => typeof cred === 'object' && cred['@context'].includes(VCDM_CREDENTIAL_CONTEXT_V1))
|
|
133
|
+
? VCDM_CREDENTIAL_CONTEXT_V1
|
|
134
|
+
: undefined
|
|
135
|
+
const v2Credential = credentials.find((cred) => typeof cred === 'object' && cred['@context'].includes(VCDM_CREDENTIAL_CONTEXT_V2))
|
|
136
|
+
? VCDM_CREDENTIAL_CONTEXT_V2
|
|
137
|
+
: undefined
|
|
138
|
+
const presentationContext = addVcdmContextIfNeeded(args?.presentation?.['@context'] ?? [], v2Credential ?? v1Credential ?? VCDM_CREDENTIAL_CONTEXT_V2)
|
|
139
|
+
const presentationType = processEntryToArray(args?.presentation?.type, 'VerifiablePresentation')
|
|
140
|
+
|
|
141
|
+
let issuanceDate = presentation?.validFrom ?? presentation?.issuanceDate ?? (typeof now === 'number' ? new Date(now) : now).toISOString()
|
|
142
|
+
if (issuanceDate instanceof Date) {
|
|
143
|
+
issuanceDate = issuanceDate.toISOString()
|
|
144
|
+
}
|
|
145
|
+
const presentationPayload: PresentationPayload = {
|
|
146
|
+
...presentation,
|
|
147
|
+
'@context': presentationContext,
|
|
148
|
+
type: presentationType,
|
|
149
|
+
...(v1Credential && { issuanceDate }), // V1 only for JWT, but we remove it in the jsonld processor anyway
|
|
150
|
+
...(v2Credential && { validFrom: issuanceDate }),
|
|
151
|
+
}
|
|
152
|
+
// Workaround for bug in TypeError: Cannot read property 'length' of undefined
|
|
153
|
+
// at VeramoEd25519Signature2018.preSigningPresModification
|
|
154
|
+
/*if (!presentation.verifier) {
|
|
155
|
+
presentation.verifier = []
|
|
156
|
+
}*/
|
|
157
|
+
|
|
158
|
+
if (!isDefined(presentationPayload.holder) || !presentationPayload.holder) {
|
|
159
|
+
throw new Error('invalid_argument: args.presentation.holderDID must not be empty')
|
|
160
|
+
}
|
|
161
|
+
if (presentationPayload.verifiableCredential) {
|
|
162
|
+
presentationPayload.verifiableCredential = presentationPayload.verifiableCredential.map((cred) => {
|
|
163
|
+
// map JWT credentials to their canonical form
|
|
164
|
+
if (typeof cred !== 'string' && cred.proof.jwt) {
|
|
165
|
+
return cred.proof.jwt
|
|
166
|
+
} else {
|
|
167
|
+
return cred
|
|
168
|
+
}
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
return {presentation: presentationPayload, holder: removeDIDParameters(presentationPayload.holder)}
|
|
172
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
export type * from './types'
|
|
12
12
|
export { W3cMessageHandler, MessageTypes } from './message-handler'
|
|
13
|
-
import { VcdmCredentialPlugin } from './
|
|
13
|
+
import { VcdmCredentialPlugin } from './vcdmCredentialPlugin'
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* @deprecated please use {@link VcdmCredentialPlugin} instead
|
package/src/types.ts
CHANGED
|
@@ -3,22 +3,21 @@ import type {
|
|
|
3
3
|
IAgentContext,
|
|
4
4
|
IDIDManager,
|
|
5
5
|
IKey,
|
|
6
|
+
IKeyManager,
|
|
7
|
+
IPluginMethodMap,
|
|
6
8
|
IResolver,
|
|
7
9
|
IVerifyResult,
|
|
8
10
|
PresentationPayload,
|
|
9
|
-
|
|
10
|
-
VerifiablePresentation, VerificationPolicies,
|
|
11
|
+
VerificationPolicies,
|
|
11
12
|
} from '@veramo/core'
|
|
12
13
|
|
|
13
14
|
import type { VerifiableCredentialSP, VerifiablePresentationSP } from '@sphereon/ssi-sdk.core'
|
|
14
|
-
|
|
15
|
+
|
|
15
16
|
import type { IIssueCredentialStatusOpts } from '@sphereon/ssi-sdk.vc-status-list'
|
|
16
|
-
import type {
|
|
17
|
-
import { W3CVerifiableCredential, W3CVerifiablePresentation } from '@sphereon/ssi-types'
|
|
17
|
+
import type { W3CVerifiableCredential, W3CVerifiablePresentation } from '@sphereon/ssi-types'
|
|
18
18
|
|
|
19
19
|
export type IVcdmCredentialPlugin = IVcdmCredentialIssuer & IVcdmCredentialVerifier
|
|
20
20
|
|
|
21
|
-
|
|
22
21
|
/**
|
|
23
22
|
* Encapsulates the parameters required to check if a credential type can be issued
|
|
24
23
|
*
|
|
@@ -40,7 +39,6 @@ export interface ICanVerifyDocumentTypeArgs {
|
|
|
40
39
|
document: W3CVerifiableCredential | W3CVerifiablePresentation
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
|
|
44
42
|
/**
|
|
45
43
|
* Encapsulates the parameters required to create a
|
|
46
44
|
* {@link https://www.w3.org/TR/vc-data-model/#presentations | W3C Verifiable Presentation}
|
|
@@ -179,7 +177,7 @@ export interface IVerifyCredentialLDArgs {
|
|
|
179
177
|
* of the `credential`
|
|
180
178
|
*
|
|
181
179
|
*/
|
|
182
|
-
credential:
|
|
180
|
+
credential: VerifiableCredentialSP
|
|
183
181
|
|
|
184
182
|
/**
|
|
185
183
|
* Set this to true if you want the '@context' URLs to be fetched in case they are not pre-loaded.
|
|
@@ -207,6 +205,8 @@ export interface IVerifyCredentialLDArgs {
|
|
|
207
205
|
* Allows you to use the default integrated statusList 2021 support. If a checkStatus function is provided, this will be ignored
|
|
208
206
|
*/
|
|
209
207
|
statusList?: StatusListCheck
|
|
208
|
+
|
|
209
|
+
[key: string]: any
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
export interface StatusListCheck {
|
|
@@ -236,7 +236,7 @@ export interface IVerifyPresentationLDArgs {
|
|
|
236
236
|
* of the `credential`
|
|
237
237
|
*
|
|
238
238
|
*/
|
|
239
|
-
presentation:
|
|
239
|
+
presentation: VerifiablePresentationSP | W3CVerifiablePresentation
|
|
240
240
|
|
|
241
241
|
/**
|
|
242
242
|
* Optional (only for JWT) string challenge parameter to verify the verifiable presentation against
|
|
@@ -274,6 +274,8 @@ export interface IVerifyPresentationLDArgs {
|
|
|
274
274
|
* Allows you to use the default integrated statusList 2021 support. If a checkStatus function is provided, this will be ignored
|
|
275
275
|
*/
|
|
276
276
|
statusList?: StatusListCheck
|
|
277
|
+
|
|
278
|
+
[key: string]: any
|
|
277
279
|
}
|
|
278
280
|
|
|
279
281
|
/**
|
|
@@ -290,8 +292,6 @@ export type IRequiredContext = IAgentContext<
|
|
|
290
292
|
>
|
|
291
293
|
*/
|
|
292
294
|
|
|
293
|
-
|
|
294
|
-
|
|
295
295
|
/**
|
|
296
296
|
* Represents the requirements that this plugin has.
|
|
297
297
|
* The agent that is using this plugin is expected to provide these methods.
|
|
@@ -301,12 +301,9 @@ export type IRequiredContext = IAgentContext<
|
|
|
301
301
|
* @beta
|
|
302
302
|
*/
|
|
303
303
|
export type IVcdmIssuerAgentContext = IAgentContext<
|
|
304
|
-
IResolver &
|
|
305
|
-
IDIDManager &
|
|
306
|
-
Pick<ISphereonKeyManager, 'keyManagerGet' | 'keyManagerSign' | 'keyManagerVerify'>
|
|
304
|
+
IResolver & IDIDManager & Pick<IKeyManager, 'keyManagerGet' | 'keyManagerSign' | 'keyManagerVerify'>
|
|
307
305
|
>
|
|
308
306
|
|
|
309
|
-
|
|
310
307
|
export type ContextDoc = {
|
|
311
308
|
'@context': string | Record<string, any>
|
|
312
309
|
}
|
|
@@ -446,10 +443,6 @@ export interface IVcdmCredentialProvider {
|
|
|
446
443
|
verifyPresentation(args: IVerifyPresentationLDArgs, context: IVcdmVerifierAgentContext): Promise<IVerifyResult>
|
|
447
444
|
}
|
|
448
445
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
446
|
/**
|
|
454
447
|
* The interface definition for a plugin that can generate Verifiable Credentials and Presentations
|
|
455
448
|
*
|
|
@@ -472,10 +465,7 @@ export interface IVcdmCredentialIssuer extends IPluginMethodMap {
|
|
|
472
465
|
* @remarks Please see {@link https://www.w3.org/TR/vc-data-model/#presentations | Verifiable Presentation data model
|
|
473
466
|
* }
|
|
474
467
|
*/
|
|
475
|
-
createVerifiablePresentation(
|
|
476
|
-
args: ICreateVerifiablePresentationLDArgs,
|
|
477
|
-
context: IVcdmIssuerAgentContext,
|
|
478
|
-
): Promise<VerifiablePresentationSP>
|
|
468
|
+
createVerifiablePresentation(args: ICreateVerifiablePresentationLDArgs, context: IVcdmIssuerAgentContext): Promise<VerifiablePresentationSP>
|
|
479
469
|
|
|
480
470
|
/**
|
|
481
471
|
* Creates a Verifiable Credential.
|
|
@@ -489,14 +479,9 @@ export interface IVcdmCredentialIssuer extends IPluginMethodMap {
|
|
|
489
479
|
*
|
|
490
480
|
* @remarks Please see {@link https://www.w3.org/TR/vc-data-model/#credentials | Verifiable Credential data model}
|
|
491
481
|
*/
|
|
492
|
-
createVerifiableCredential(
|
|
493
|
-
args: ICreateVerifiableCredentialLDArgs,
|
|
494
|
-
context: IVcdmIssuerAgentContext,
|
|
495
|
-
): Promise<VerifiableCredentialSP>
|
|
482
|
+
createVerifiableCredential(args: ICreateVerifiableCredentialLDArgs, context: IVcdmIssuerAgentContext): Promise<VerifiableCredentialSP>
|
|
496
483
|
}
|
|
497
484
|
|
|
498
|
-
|
|
499
|
-
|
|
500
485
|
/**
|
|
501
486
|
* The interface definition for a plugin that can generate Verifiable Credentials and Presentations
|
|
502
487
|
*
|
|
@@ -541,6 +526,4 @@ export interface IVcdmCredentialVerifier extends IPluginMethodMap {
|
|
|
541
526
|
*
|
|
542
527
|
* @beta
|
|
543
528
|
*/
|
|
544
|
-
export type IVcdmVerifierAgentContext = IAgentContext<
|
|
545
|
-
IResolver & Pick<IDIDManager, 'didManagerGet' | 'didManagerFind'>
|
|
546
|
-
>
|
|
529
|
+
export type IVcdmVerifierAgentContext = IAgentContext<IResolver & Pick<IDIDManager, 'didManagerGet' | 'didManagerFind'>>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAgentPlugin, IIdentifier, IVerifyResult, VerifiableCredential
|
|
1
|
+
import type { IAgentPlugin, IIdentifier, IVerifyResult, VerifiableCredential } from '@veramo/core'
|
|
2
2
|
import { schema } from '@veramo/core'
|
|
3
3
|
|
|
4
4
|
import type {
|
|
@@ -11,12 +11,10 @@ import type {
|
|
|
11
11
|
IVerifyCredentialLDArgs,
|
|
12
12
|
IVerifyPresentationLDArgs,
|
|
13
13
|
} from './types'
|
|
14
|
-
|
|
15
|
-
import { isDefined, MANDATORY_CREDENTIAL_CONTEXT, processEntryToArray } from '@veramo/utils'
|
|
16
14
|
import Debug from 'debug'
|
|
17
|
-
import {
|
|
15
|
+
import { isRevoked, preProcessCredentialPayload, preProcessPresentation } from './functions'
|
|
18
16
|
import type { W3CVerifiableCredential, W3CVerifiablePresentation } from '@sphereon/ssi-types'
|
|
19
|
-
import
|
|
17
|
+
import { asArray, VerifiableCredentialSP, VerifiablePresentationSP } from '@sphereon/ssi-sdk.core'
|
|
20
18
|
|
|
21
19
|
const debug = Debug('sphereon:ssi-sdk:vcdm')
|
|
22
20
|
|
|
@@ -67,27 +65,8 @@ export class VcdmCredentialPlugin implements IAgentPlugin {
|
|
|
67
65
|
|
|
68
66
|
/** {@inheritdoc @veramo/core#ICredentialIssuer.createVerifiableCredential} */
|
|
69
67
|
async createVerifiableCredential(args: ICreateVerifiableCredentialLDArgs, context: IVcdmIssuerAgentContext): Promise<VerifiableCredentialSP> {
|
|
70
|
-
let {
|
|
71
|
-
const
|
|
72
|
-
const credentialType = processEntryToArray(credential.type, 'VerifiableCredential')
|
|
73
|
-
|
|
74
|
-
// only add issuanceDate for JWT
|
|
75
|
-
now = typeof now === 'number' ? new Date(now * 1000) : now
|
|
76
|
-
if (!Object.getOwnPropertyNames(credential).includes('issuanceDate')) {
|
|
77
|
-
credential.issuanceDate = (now instanceof Date ? now : new Date()).toISOString()
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
credential = {
|
|
81
|
-
...credential,
|
|
82
|
-
'@context': credentialContext,
|
|
83
|
-
type: credentialType,
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
//FIXME: if the identifier is not found, the error message should reflect that.
|
|
87
|
-
const issuer = extractIssuer(credential, { removeParameters: true })
|
|
88
|
-
if (!issuer || typeof issuer === 'undefined') {
|
|
89
|
-
throw new Error('invalid_argument: credential.issuer must not be empty')
|
|
90
|
-
}
|
|
68
|
+
let { proofFormat /* keyRef, removeOriginalFields, now , ...otherOptions */ } = args
|
|
69
|
+
const { credential, issuer, now } = preProcessCredentialPayload(args)
|
|
91
70
|
|
|
92
71
|
try {
|
|
93
72
|
await context.agent.didManagerGet({ did: issuer })
|
|
@@ -98,10 +77,12 @@ export class VcdmCredentialPlugin implements IAgentPlugin {
|
|
|
98
77
|
async function findAndIssueCredential(issuers: IVcdmCredentialProvider[]) {
|
|
99
78
|
for (const issuer of issuers) {
|
|
100
79
|
if (issuer.canIssueCredentialType({ proofFormat })) {
|
|
101
|
-
return await issuer.createVerifiableCredential(args, context)
|
|
80
|
+
return await issuer.createVerifiableCredential({ ...args, credential, now }, context)
|
|
102
81
|
}
|
|
103
82
|
}
|
|
104
|
-
throw new Error(
|
|
83
|
+
throw new Error(
|
|
84
|
+
`invalid_setup: No issuer found for the requested proof format: ${proofFormat}, supported: ${issuers.map((i) => i.getTypeProofFormat()).join(',')}`,
|
|
85
|
+
)
|
|
105
86
|
}
|
|
106
87
|
const verifiableCredential = await findAndIssueCredential(this.issuers)
|
|
107
88
|
return verifiableCredential
|
|
@@ -123,7 +104,11 @@ export class VcdmCredentialPlugin implements IAgentPlugin {
|
|
|
123
104
|
return issuer.verifyCredential(args, context)
|
|
124
105
|
}
|
|
125
106
|
}
|
|
126
|
-
return Promise.reject(
|
|
107
|
+
return Promise.reject(
|
|
108
|
+
Error(
|
|
109
|
+
`invalid_setup: No verifier found for the provided credential credential type: ${JSON.stringify(args.credential.type)} proof type ${asArray(args.credential.proof)?.[0]?.type} supported: ${issuers.map((i) => i.getTypeProofFormat()).join(',')}`,
|
|
110
|
+
),
|
|
111
|
+
)
|
|
127
112
|
}
|
|
128
113
|
verificationResult = await findAndVerifyCredential(this.issuers)
|
|
129
114
|
verifiedCredential = <VerifiableCredential>credential
|
|
@@ -143,53 +128,24 @@ export class VcdmCredentialPlugin implements IAgentPlugin {
|
|
|
143
128
|
|
|
144
129
|
/** {@inheritdoc @veramo/core#ICredentialIssuer.createVerifiablePresentation} */
|
|
145
130
|
async createVerifiablePresentation(args: ICreateVerifiablePresentationLDArgs, context: IVcdmIssuerAgentContext): Promise<VerifiablePresentationSP> {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
proofFormat,
|
|
149
|
-
/* domain,
|
|
150
|
-
challenge,
|
|
151
|
-
removeOriginalFields,
|
|
152
|
-
keyRef,*/
|
|
153
|
-
// save,
|
|
154
|
-
/*now,*/
|
|
155
|
-
/*...otherOptions*/
|
|
156
|
-
} = args
|
|
157
|
-
const presentationContext: string[] = processEntryToArray(args?.presentation?.['@context'], MANDATORY_CREDENTIAL_CONTEXT)
|
|
158
|
-
const presentationType = processEntryToArray(args?.presentation?.type, 'VerifiablePresentation')
|
|
159
|
-
presentation = {
|
|
160
|
-
...presentation,
|
|
161
|
-
'@context': presentationContext,
|
|
162
|
-
type: presentationType,
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (!isDefined(presentation.holder)) {
|
|
166
|
-
throw new Error('invalid_argument: presentation.holder must not be empty')
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (presentation.verifiableCredential) {
|
|
170
|
-
presentation.verifiableCredential = presentation.verifiableCredential.map((cred) => {
|
|
171
|
-
// map JWT credentials to their canonical form
|
|
172
|
-
if (typeof cred !== 'string' && cred.proof.jwt) {
|
|
173
|
-
return cred.proof.jwt
|
|
174
|
-
} else {
|
|
175
|
-
return cred
|
|
176
|
-
}
|
|
177
|
-
})
|
|
178
|
-
}
|
|
131
|
+
const { proofFormat } = args
|
|
132
|
+
const { presentation } = preProcessPresentation(args)
|
|
179
133
|
|
|
180
|
-
let verifiablePresentation:
|
|
134
|
+
let verifiablePresentation: VerifiablePresentationSP
|
|
181
135
|
|
|
182
136
|
async function findAndCreatePresentation(issuers: IVcdmCredentialProvider[]) {
|
|
183
137
|
for (const issuer of issuers) {
|
|
184
138
|
if (issuer.canIssueCredentialType({ proofFormat })) {
|
|
185
|
-
return await issuer.createVerifiablePresentation(args, context)
|
|
139
|
+
return await issuer.createVerifiablePresentation({ ...args, presentation }, context)
|
|
186
140
|
}
|
|
187
141
|
}
|
|
188
|
-
throw new Error(
|
|
142
|
+
throw new Error(
|
|
143
|
+
`invalid_setup: No issuer found for the requested proof format: ${proofFormat}, supported: ${issuers.map((i) => i.getTypeProofFormat()).join(',')}`,
|
|
144
|
+
)
|
|
189
145
|
}
|
|
190
146
|
|
|
191
147
|
verifiablePresentation = await findAndCreatePresentation(this.issuers)
|
|
192
|
-
return verifiablePresentation
|
|
148
|
+
return verifiablePresentation
|
|
193
149
|
}
|
|
194
150
|
|
|
195
151
|
/** {@inheritdoc @veramo/core#ICredentialVerifier.verifyPresentation} */
|