@sphereon/ssi-sdk.siopv2-oid4vp-op-auth 0.34.1-feature.SSISDK.46.41 → 0.34.1-feature.SSISDK.50.98

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.
@@ -1,31 +1,21 @@
1
- import { AuthorizationRequest, SupportedVersion } from '@sphereon/did-auth-siop'
2
- import { IPresentationDefinition, PEX } from '@sphereon/pex'
3
- import { InputDescriptorV1, InputDescriptorV2, PresentationDefinitionV1, PresentationDefinitionV2 } from '@sphereon/pex-models'
1
+ import { AuthorizationRequest, Json, SupportedVersion } from '@sphereon/did-auth-siop'
4
2
  import { isOID4VCIssuerIdentifier, ManagedIdentifierOptsOrResult } from '@sphereon/ssi-sdk-ext.identifier-resolution'
5
3
  import { UniqueDigitalCredential, verifiableCredentialForRoleFilter } from '@sphereon/ssi-sdk.credential-store'
6
- import { ConnectionType, CredentialRole } from '@sphereon/ssi-sdk.data-store'
7
- import { CredentialMapper, HasherSync, Loggers, OriginalVerifiableCredential, PresentationSubmission } from '@sphereon/ssi-types'
8
- import { OID4VP, OpSession } from '../session'
9
- import {
10
- DidAgents,
11
- LOGGER_NAMESPACE,
12
- RequiredContext,
13
- SelectableCredential,
14
- SelectableCredentialsMap,
15
- Siopv2HolderEvent,
16
- SuitableCredentialAgents,
17
- VerifiableCredentialsWithDefinition,
18
- VerifiablePresentationWithDefinition,
19
- } from '../types'
4
+ import { ConnectionType } from '@sphereon/ssi-sdk.data-store'
5
+ import { CredentialRole } from '@sphereon/ssi-types'
6
+
7
+ import { CredentialMapper, HasherSync, Loggers, OriginalVerifiableCredential, SdJwtDecodedVerifiableCredential } from '@sphereon/ssi-types'
8
+ import { OpSession } from '../session'
9
+ import { LOGGER_NAMESPACE, RequiredContext, SelectableCredential, SelectableCredentialsMap, Siopv2HolderEvent } from '../types'
10
+ import { encodeJoseBlob } from '@sphereon/ssi-sdk.core'
11
+ import { DcqlPresentation, DcqlQuery } from 'dcql'
12
+ import { convertToDcqlCredentials } from '../utils/dcql'
20
13
  import { IAgentContext, IDIDManager } from '@veramo/core'
21
14
  import { getOrCreatePrimaryIdentifier, SupportedDidMethodEnum } from '@sphereon/ssi-sdk-ext.did-utils'
22
- import { defaultHasher, encodeJoseBlob } from '@sphereon/ssi-sdk.core'
23
- import { DcqlCredential, DcqlCredentialPresentation, DcqlPresentation, DcqlQuery } from 'dcql'
24
- import { convertToDcqlCredentials } from '../utils/dcql'
25
- import { getOriginalVerifiableCredential } from '../utils/CredentialUtils'
26
15
 
27
16
  export const logger = Loggers.DEFAULT.get(LOGGER_NAMESPACE)
28
17
 
18
+ // @ts-ignore
29
19
  const createEbsiIdentifier = async (agentContext: IAgentContext<IDIDManager>): Promise<ManagedIdentifierOptsOrResult> => {
30
20
  logger.log(`No EBSI key present yet. Creating a new one...`)
31
21
  const { result: newIdentifier, created } = await getOrCreatePrimaryIdentifier(agentContext, {
@@ -39,9 +29,10 @@ const createEbsiIdentifier = async (agentContext: IAgentContext<IDIDManager>): P
39
29
  return await agentContext.agent.identifierManagedGetByDid({ identifier: newIdentifier.did })
40
30
  }
41
31
 
32
+ // @ts-ignore
42
33
  const hasEbsiClient = async (authorizationRequest: AuthorizationRequest) => {
43
- const clientId = await authorizationRequest.getMergedProperty<string>('client_id')
44
- const redirectUri = await authorizationRequest.getMergedProperty<string>('redirect_uri')
34
+ const clientId = authorizationRequest.getMergedProperty<string>('client_id')
35
+ const redirectUri = authorizationRequest.getMergedProperty<string>('redirect_uri')
45
36
  return clientId?.toLowerCase().includes('.ebsi.eu') || redirectUri?.toLowerCase().includes('.ebsi.eu')
46
37
  }
47
38
 
@@ -49,293 +40,170 @@ export const siopSendAuthorizationResponse = async (
49
40
  connectionType: ConnectionType,
50
41
  args: {
51
42
  sessionId: string
52
- verifiableCredentialsWithDefinition?: VerifiableCredentialsWithDefinition[]
43
+ credentials: Array<UniqueDigitalCredential | OriginalVerifiableCredential>
53
44
  idOpts?: ManagedIdentifierOptsOrResult
54
45
  isFirstParty?: boolean
55
46
  hasher?: HasherSync
56
- dcqlQuery?: DcqlQuery
57
47
  },
58
48
  context: RequiredContext,
59
49
  ) => {
60
50
  const { agent } = context
61
- const agentContext = { ...context, agent: context.agent as DidAgents }
62
- let { idOpts, isFirstParty, hasher = defaultHasher } = args
63
-
51
+ const { credentials } = args
64
52
  if (connectionType !== ConnectionType.SIOPv2_OpenID4VP) {
65
53
  return Promise.reject(Error(`No supported authentication provider for type: ${connectionType}`))
66
54
  }
55
+
67
56
  const session: OpSession = await agent.siopGetOPSession({ sessionId: args.sessionId })
68
57
  const request = await session.getAuthorizationRequest()
69
- const aud = await request.authorizationRequest.getMergedProperty<string>('aud')
58
+ const aud = request.authorizationRequest.getMergedProperty<string>('aud')
70
59
  logger.debug(`AUD: ${aud}`)
71
60
  logger.debug(JSON.stringify(request.authorizationRequest))
72
61
 
73
- let presentationsAndDefs: VerifiablePresentationWithDefinition[] | undefined
74
- let presentationSubmission: PresentationSubmission | undefined
75
- if (await session.hasPresentationDefinitions()) {
76
- const oid4vp: OID4VP = await session.getOID4VP({ hasher })
77
-
78
- const credentialsAndDefinitions = args.verifiableCredentialsWithDefinition
79
- ? args.verifiableCredentialsWithDefinition
80
- : await oid4vp.filterCredentialsAgainstAllDefinitions(CredentialRole.HOLDER)
81
- const domain =
82
- ((await request.authorizationRequest.getMergedProperty('client_id')) as string) ??
83
- request.issuer ??
84
- (request.versions.includes(SupportedVersion.JWT_VC_PRESENTATION_PROFILE_v1)
85
- ? 'https://self-issued.me/v2/openid-vc'
86
- : 'https://self-issued.me/v2')
87
- logger.log(`NONCE: ${session.nonce}, domain: ${domain}`)
88
-
89
- const firstUniqueDC = credentialsAndDefinitions[0].credentials[0]
90
- if (typeof firstUniqueDC !== 'object' || !('digitalCredential' in firstUniqueDC)) {
91
- return Promise.reject(Error('SiopMachine only supports UniqueDigitalCredentials for now'))
92
- }
62
+ const domain =
63
+ ((await request.authorizationRequest.getMergedProperty('client_id')) as string) ??
64
+ request.issuer ??
65
+ (request.versions.includes(SupportedVersion.JWT_VC_PRESENTATION_PROFILE_v1) ? 'https://self-issued.me/v2/openid-vc' : 'https://self-issued.me/v2')
66
+ logger.debug(`NONCE: ${session.nonce}, domain: ${domain}`)
93
67
 
94
- let identifier: ManagedIdentifierOptsOrResult
95
- const digitalCredential = firstUniqueDC.digitalCredential
96
- const firstVC = firstUniqueDC.uniformVerifiableCredential
97
- const holder = CredentialMapper.isSdJwtDecodedCredential(firstVC)
98
- ? firstVC.decodedPayload.cnf?.jwk
99
- ? //TODO SDK-19: convert the JWK to hex and search for the appropriate key and associated DID
100
- //doesn't apply to did:jwk only, as you can represent any DID key as a JWK. So whenever you encounter a JWK it doesn't mean it had to come from a did:jwk in the system. It just can always be represented as a did:jwk
101
- `did:jwk:${encodeJoseBlob(firstVC.decodedPayload.cnf?.jwk)}#0`
102
- : firstVC.decodedPayload.sub
103
- : Array.isArray(firstVC.credentialSubject)
104
- ? firstVC.credentialSubject[0].id
105
- : firstVC.credentialSubject.id
106
- if (!digitalCredential.kmsKeyRef) {
107
- // In case the store does not have the kmsKeyRef lets search for the holder
68
+ const firstUniqueDC = credentials[0]
69
+ if (typeof firstUniqueDC !== 'object' || !('digitalCredential' in firstUniqueDC)) {
70
+ return Promise.reject(Error('SiopMachine only supports UniqueDigitalCredentials for now'))
71
+ }
108
72
 
109
- if (!holder) {
110
- return Promise.reject(`No holder found and no kmsKeyRef in DB. Cannot determine identifier to use`)
111
- }
112
- try {
113
- identifier = await session.context.agent.identifierManagedGet({ identifier: holder })
114
- } catch (e) {
115
- logger.debug(`Holder DID not found: ${holder}`)
116
- throw e
117
- }
118
- } else if (isOID4VCIssuerIdentifier(digitalCredential.kmsKeyRef)) {
119
- identifier = await session.context.agent.identifierManagedGetByOID4VCIssuer({
120
- identifier: firstUniqueDC.digitalCredential.kmsKeyRef,
121
- })
122
- } else {
123
- switch (digitalCredential.subjectCorrelationType) {
124
- case 'DID':
125
- identifier = await session.context.agent.identifierManagedGetByDid({
126
- identifier: digitalCredential.subjectCorrelationId ?? holder,
127
- kmsKeyRef: digitalCredential.kmsKeyRef,
128
- })
129
- break
130
- // TODO other implementations?
131
- default:
132
- if (digitalCredential.subjectCorrelationId?.startsWith('did:') || holder?.startsWith('did:')) {
133
- identifier = await session.context.agent.identifierManagedGetByDid({
134
- identifier: digitalCredential.subjectCorrelationId ?? holder,
135
- kmsKeyRef: digitalCredential.kmsKeyRef,
136
- })
137
- } else {
138
- // Since we are using the kmsKeyRef we will find the KID regardless of the identifier. We set it for later access though
139
- identifier = await session.context.agent.identifierManagedGetByKid({
140
- identifier: digitalCredential.subjectCorrelationId ?? holder ?? digitalCredential.kmsKeyRef,
141
- kmsKeyRef: digitalCredential.kmsKeyRef,
142
- })
143
- }
144
- }
73
+ let identifier: ManagedIdentifierOptsOrResult
74
+ const digitalCredential = firstUniqueDC.digitalCredential
75
+ const firstVC = firstUniqueDC.uniformVerifiableCredential
76
+ const holder = CredentialMapper.isSdJwtDecodedCredential(firstVC)
77
+ ? firstVC.decodedPayload.cnf?.jwk
78
+ ? //TODO SDK-19: convert the JWK to hex and search for the appropriate key and associated DID
79
+ //doesn't apply to did:jwk only, as you can represent any DID key as a JWK. So whenever you encounter a JWK it doesn't mean it had to come from a did:jwk in the system. It just can always be represented as a did:jwk
80
+ `did:jwk:${encodeJoseBlob(firstVC.decodedPayload.cnf?.jwk)}#0`
81
+ : firstVC.decodedPayload.sub
82
+ : Array.isArray(firstVC.credentialSubject)
83
+ ? firstVC.credentialSubject[0].id
84
+ : firstVC.credentialSubject.id
85
+ if (!digitalCredential.kmsKeyRef) {
86
+ // In case the store does not have the kmsKeyRef lets search for the holder
87
+
88
+ if (!holder) {
89
+ return Promise.reject(`No holder found and no kmsKeyRef in DB. Cannot determine identifier to use`)
145
90
  }
146
-
147
- if (identifier === undefined && idOpts !== undefined && (await hasEbsiClient(request.authorizationRequest))) {
148
- identifier = await createEbsiIdentifier(agentContext)
91
+ try {
92
+ identifier = await session.context.agent.identifierManagedGet({ identifier: holder })
93
+ } catch (e) {
94
+ logger.debug(`Holder DID not found: ${holder}`)
95
+ throw e
149
96
  }
150
- logger.debug(`Identifier`, identifier)
151
-
152
- // TODO Add mdoc support
153
-
154
- presentationsAndDefs = await oid4vp.createVerifiablePresentations(CredentialRole.HOLDER, credentialsAndDefinitions, {
155
- idOpts: identifier,
156
- proofOpts: {
157
- nonce: session.nonce,
158
- domain,
159
- },
97
+ } else if (isOID4VCIssuerIdentifier(digitalCredential.kmsKeyRef)) {
98
+ identifier = await session.context.agent.identifierManagedGetByOID4VCIssuer({
99
+ identifier: firstUniqueDC.digitalCredential.kmsKeyRef,
160
100
  })
161
- if (!presentationsAndDefs || presentationsAndDefs.length === 0) {
162
- throw Error('No verifiable presentations could be created')
163
- } else if (presentationsAndDefs.length > 1) {
164
- throw Error(`Only one verifiable presentation supported for now. Got ${presentationsAndDefs.length}`)
101
+ } else {
102
+ switch (digitalCredential.subjectCorrelationType) {
103
+ case 'DID':
104
+ identifier = await session.context.agent.identifierManagedGetByDid({
105
+ identifier: digitalCredential.subjectCorrelationId ?? holder,
106
+ kmsKeyRef: digitalCredential.kmsKeyRef,
107
+ })
108
+ break
109
+ // TODO other implementations?
110
+ default:
111
+ // Since we are using the kmsKeyRef we will find the KID regardless of the identifier. We set it for later access though
112
+ identifier = await session.context.agent.identifierManagedGetByKid({
113
+ identifier: digitalCredential.subjectCorrelationId ?? holder ?? digitalCredential.kmsKeyRef,
114
+ kmsKeyRef: digitalCredential.kmsKeyRef,
115
+ })
165
116
  }
117
+ }
166
118
 
167
- idOpts = presentationsAndDefs[0].idOpts
168
- presentationSubmission = presentationsAndDefs[0].presentationSubmission
169
-
170
- logger.log(`Definitions and locations:`, JSON.stringify(presentationsAndDefs?.[0]?.verifiablePresentations, null, 2))
171
- logger.log(`Presentation Submission:`, JSON.stringify(presentationSubmission, null, 2))
172
- const mergedVerifiablePresentations = presentationsAndDefs?.flatMap((pd) => pd.verifiablePresentations) || []
173
- return await session.sendAuthorizationResponse({
174
- ...(presentationsAndDefs && { verifiablePresentations: mergedVerifiablePresentations }),
175
- ...(presentationSubmission && { presentationSubmission }),
176
- // todo: Change issuer value in case we do not use identifier. Use key.meta.jwkThumbprint then
177
- responseSignerOpts: idOpts!,
178
- isFirstParty,
179
- })
180
- } else if (request.dcqlQuery) {
181
- if (args.verifiableCredentialsWithDefinition !== undefined && args.verifiableCredentialsWithDefinition !== null) {
182
- const vcs = args.verifiableCredentialsWithDefinition.flatMap((vcd) => vcd.credentials)
183
- const domain =
184
- ((await request.authorizationRequest.getMergedProperty('client_id')) as string) ??
185
- request.issuer ??
186
- (request.versions.includes(SupportedVersion.JWT_VC_PRESENTATION_PROFILE_v1)
187
- ? 'https://self-issued.me/v2/openid-vc'
188
- : 'https://self-issued.me/v2')
189
- logger.debug(`NONCE: ${session.nonce}, domain: ${domain}`)
119
+ const dcqlCredentialsWithCredentials = new Map(credentials.map((vc) => [convertToDcqlCredentials(vc), vc]))
190
120
 
191
- const firstUniqueDC = vcs[0]
192
- if (typeof firstUniqueDC !== 'object' || !('digitalCredential' in firstUniqueDC)) {
193
- return Promise.reject(Error('SiopMachine only supports UniqueDigitalCredentials for now'))
194
- }
121
+ const queryResult = DcqlQuery.query(request.dcqlQuery, Array.from(dcqlCredentialsWithCredentials.keys()))
195
122
 
196
- let identifier: ManagedIdentifierOptsOrResult
197
- const digitalCredential = firstUniqueDC.digitalCredential
198
- const firstVC = firstUniqueDC.uniformVerifiableCredential
199
- const holder = CredentialMapper.isSdJwtDecodedCredential(firstVC)
200
- ? firstVC.decodedPayload.cnf?.jwk
201
- ? //TODO SDK-19: convert the JWK to hex and search for the appropriate key and associated DID
202
- //doesn't apply to did:jwk only, as you can represent any DID key as a JWK. So whenever you encounter a JWK it doesn't mean it had to come from a did:jwk in the system. It just can always be represented as a did:jwk
203
- `did:jwk:${encodeJoseBlob(firstVC.decodedPayload.cnf?.jwk)}#0`
204
- : firstVC.decodedPayload.sub
205
- : Array.isArray(firstVC.credentialSubject)
206
- ? firstVC.credentialSubject[0].id
207
- : firstVC.credentialSubject.id
208
- if (!digitalCredential.kmsKeyRef) {
209
- // In case the store does not have the kmsKeyRef lets search for the holder
123
+ if (!queryResult.can_be_satisfied) {
124
+ return Promise.reject(Error('Credentials do not match required query request'))
125
+ }
210
126
 
211
- if (!holder) {
212
- return Promise.reject(`No holder found and no kmsKeyRef in DB. Cannot determine identifier to use`)
213
- }
214
- try {
215
- identifier = await session.context.agent.identifierManagedGet({ identifier: holder })
216
- } catch (e) {
217
- logger.debug(`Holder DID not found: ${holder}`)
218
- throw e
219
- }
220
- } else if (isOID4VCIssuerIdentifier(digitalCredential.kmsKeyRef)) {
221
- identifier = await session.context.agent.identifierManagedGetByOID4VCIssuer({
222
- identifier: firstUniqueDC.digitalCredential.kmsKeyRef,
223
- })
224
- } else {
225
- switch (digitalCredential.subjectCorrelationType) {
226
- case 'DID':
227
- identifier = await session.context.agent.identifierManagedGetByDid({
228
- identifier: digitalCredential.subjectCorrelationId ?? holder,
229
- kmsKeyRef: digitalCredential.kmsKeyRef,
230
- })
231
- break
232
- // TODO other implementations?
233
- default:
234
- // Since we are using the kmsKeyRef we will find the KID regardless of the identifier. We set it for later access though
235
- identifier = await session.context.agent.identifierManagedGetByKid({
236
- identifier: digitalCredential.subjectCorrelationId ?? holder ?? digitalCredential.kmsKeyRef,
237
- kmsKeyRef: digitalCredential.kmsKeyRef,
238
- })
239
- }
127
+ const presentation: DcqlPresentation.Output = {}
128
+ const uniqueCredentials = Array.from(dcqlCredentialsWithCredentials.values())
129
+ for (const [key, value] of Object.entries(queryResult.credential_matches)) {
130
+ if (value.success) {
131
+ const matchedCredentials = value.valid_credentials.map((cred) => uniqueCredentials[cred.input_credential_index])
132
+ const vc = matchedCredentials[0] // taking the first match for now //uniqueCredentials[value.input_credential_index]
133
+ if (!vc) {
134
+ continue
240
135
  }
241
- console.log(`Identifier`, identifier)
242
-
243
- const dcqlRepresentations: DcqlCredential[] = []
244
- vcs.forEach((vc: UniqueDigitalCredential | OriginalVerifiableCredential) => {
245
- const rep = convertToDcqlCredentials(vc, args.hasher)
246
- if (rep) {
247
- dcqlRepresentations.push(rep)
248
- }
249
- })
250
-
251
- const queryResult = DcqlQuery.query(request.dcqlQuery, dcqlRepresentations)
252
- const presentation: Record<string, DcqlCredentialPresentation> = {}
253
-
254
- for (const [key, value] of Object.entries(queryResult.credential_matches)) {
255
- const allMatches = Array.isArray(value) ? value : [value]
256
- allMatches.forEach((match) => {
257
- if (match.success) {
258
- const originalCredential = getOriginalVerifiableCredential(vcs[match.input_credential_index])
259
- if (!originalCredential) {
260
- throw new Error(`Index ${match.input_credential_index} out of range in credentials array`)
261
- }
262
- presentation[key] =
263
- (originalCredential as any)['compactSdJwtVc'] !== undefined ? (originalCredential as any).compactSdJwtVc : originalCredential
264
- }
265
- })
136
+ const originalVc = retrieveEncodedCredential(vc as UniqueDigitalCredential) // TODO this is not nice // also always a UniqueDigitalCredential
137
+ if (!originalVc) {
138
+ continue
266
139
  }
140
+ if (originalVc) {
141
+ presentation[key] = originalVc as string | { [x: string]: Json }
142
+ }
143
+ }
144
+ }
267
145
 
268
- const response = session.sendAuthorizationResponse({
269
- responseSignerOpts: identifier,
270
- ...{ dcqlQuery: { dcqlPresentation: DcqlPresentation.parse(presentation) } },
271
- })
146
+ const dcqlPresentation = DcqlPresentation.parse(presentation)
272
147
 
273
- logger.debug(`Response: `, response)
148
+ const response = session.sendAuthorizationResponse({
149
+ responseSignerOpts: identifier,
150
+ dcqlResponse: {
151
+ dcqlPresentation,
152
+ },
153
+ })
274
154
 
275
- return response
276
- }
277
- }
278
- throw Error('Presentation Definition or DCQL is required')
155
+ logger.debug(`Response: `, response)
156
+ return response
279
157
  }
280
158
 
281
- function buildPartialPD(
282
- inputDescriptor: InputDescriptorV1 | InputDescriptorV2,
283
- presentationDefinition: PresentationDefinitionV1 | PresentationDefinitionV2,
284
- ): IPresentationDefinition {
285
- return {
286
- ...presentationDefinition,
287
- input_descriptors: [inputDescriptor],
288
- } as IPresentationDefinition
159
+ const retrieveEncodedCredential = (credential: UniqueDigitalCredential): OriginalVerifiableCredential | undefined => {
160
+ return credential.originalVerifiableCredential !== undefined &&
161
+ credential.originalVerifiableCredential !== null &&
162
+ (credential?.originalVerifiableCredential as SdJwtDecodedVerifiableCredential)?.compactSdJwtVc !== undefined &&
163
+ (credential?.originalVerifiableCredential as SdJwtDecodedVerifiableCredential)?.compactSdJwtVc !== null
164
+ ? (credential.originalVerifiableCredential as SdJwtDecodedVerifiableCredential).compactSdJwtVc
165
+ : credential.originalVerifiableCredential
289
166
  }
290
167
 
291
- export const getSelectableCredentials = async (
292
- presentationDefinition: IPresentationDefinition,
293
- context: RequiredContext,
294
- ): Promise<SelectableCredentialsMap> => {
295
- const agentContext = { ...context, agent: context.agent as SuitableCredentialAgents }
168
+ export const getSelectableCredentials = async (dcqlQuery: DcqlQuery, context: RequiredContext): Promise<SelectableCredentialsMap> => {
169
+ const agentContext = { ...context, agent: context.agent }
296
170
  const { agent } = agentContext
297
- const pex = new PEX()
298
-
299
171
  const uniqueVerifiableCredentials = await agent.crsGetUniqueCredentials({
300
172
  filter: verifiableCredentialForRoleFilter(CredentialRole.HOLDER),
301
173
  })
302
- const credentialBranding = await agent.ibGetCredentialBranding()
303
-
174
+ const branding = await agent.ibGetCredentialBranding()
175
+ const dcqlCredentialsWithCredentials = new Map(uniqueVerifiableCredentials.map((vc) => [convertToDcqlCredentials(vc), vc]))
176
+ const queryResult = DcqlQuery.query(dcqlQuery, Array.from(dcqlCredentialsWithCredentials.keys()))
177
+ const uniqueCredentials = Array.from(dcqlCredentialsWithCredentials.values())
304
178
  const selectableCredentialsMap: SelectableCredentialsMap = new Map()
305
179
 
306
- for (const inputDescriptor of presentationDefinition.input_descriptors) {
307
- const partialPD = buildPartialPD(inputDescriptor, presentationDefinition)
308
- const originalCredentials = uniqueVerifiableCredentials.map((uniqueVC) => {
309
- return CredentialMapper.storedCredentialToOriginalFormat(uniqueVC.originalVerifiableCredential!) // ( ! is valid for verifiableCredentialForRoleFilter )
310
- })
311
- const selectionResults = pex.selectFrom(partialPD, originalCredentials)
180
+ for (const [key, value] of Object.entries(queryResult.credential_matches)) {
181
+ if (!value.valid_credentials) {
182
+ continue
183
+ }
312
184
 
313
- const selectableCredentials: Array<SelectableCredential> = []
314
- for (const selectedCredential of selectionResults.verifiableCredential || []) {
315
- const filteredUniqueVC = uniqueVerifiableCredentials.find((uniqueVC) => {
316
- const proof = uniqueVC.uniformVerifiableCredential!.proof
317
- return Array.isArray(proof) ? proof.some((proofItem) => proofItem.jwt === selectedCredential) : proof.jwt === selectedCredential
185
+ const mapSelectableCredentialPromises = value.valid_credentials.map(async (cred) => {
186
+ const matchedCredential = uniqueCredentials[cred.input_credential_index]
187
+ const credentialBranding = branding.filter((cb) => cb.vcHash === matchedCredential.hash)
188
+ const issuerPartyIdentity = await agent.cmGetContacts({
189
+ filter: [{ identities: { identifier: { correlationId: matchedCredential.uniformVerifiableCredential!.issuerDid } } }],
190
+ })
191
+ const subjectPartyIdentity = await agent.cmGetContacts({
192
+ filter: [{ identities: { identifier: { correlationId: matchedCredential.uniformVerifiableCredential!.subjectDid } } }],
318
193
  })
319
194
 
320
- if (filteredUniqueVC) {
321
- const filteredCredentialBrandings = credentialBranding.filter((cb) => cb.vcHash === filteredUniqueVC.hash)
322
- const issuerPartyIdentity = await agent.cmGetContacts({
323
- filter: [{ identities: { identifier: { correlationId: filteredUniqueVC.uniformVerifiableCredential!.issuerDid } } }],
324
- })
325
- const subjectPartyIdentity = await agent.cmGetContacts({
326
- filter: [{ identities: { identifier: { correlationId: filteredUniqueVC.uniformVerifiableCredential!.subjectDid } } }],
327
- })
328
-
329
- selectableCredentials.push({
330
- credential: filteredUniqueVC,
331
- credentialBranding: filteredCredentialBrandings[0]?.localeBranding,
332
- issuerParty: issuerPartyIdentity?.[0],
333
- subjectParty: subjectPartyIdentity?.[0],
334
- })
195
+ return {
196
+ credential: matchedCredential,
197
+ credentialBranding: credentialBranding[0]?.localeBranding,
198
+ issuerParty: issuerPartyIdentity?.[0],
199
+ subjectParty: subjectPartyIdentity?.[0],
335
200
  }
336
- }
337
- selectableCredentialsMap.set(inputDescriptor.id, selectableCredentials)
201
+ })
202
+
203
+ const selectableCredentials: Array<SelectableCredential> = await Promise.all(mapSelectableCredentialPromises)
204
+ selectableCredentialsMap.set(key, selectableCredentials)
338
205
  }
206
+
339
207
  return selectableCredentialsMap
340
208
  }
341
209