@sphereon/ssi-sdk.siopv2-oid4vp-rp-auth 0.34.1-feature.FIDES.1.274 → 0.34.1-feature.IDK.11.48

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.
@@ -3,15 +3,10 @@ import {
3
3
  AuthorizationResponsePayload,
4
4
  AuthorizationResponseState,
5
5
  AuthorizationResponseStateStatus,
6
- AuthorizationResponseStateWithVerifiedData,
7
6
  decodeUriAsJson,
8
- EncodedDcqlPresentationVpToken,
9
7
  VerifiedAuthorizationResponse,
10
8
  } from '@sphereon/did-auth-siop'
11
9
  import { getAgentResolver } from '@sphereon/ssi-sdk-ext.did-utils'
12
- import { shaHasher as defaultHasher } from '@sphereon/ssi-sdk.core'
13
- import { validate as isValidUUID } from 'uuid'
14
- import type { ImportDcqlQueryItem } from '@sphereon/ssi-sdk.pd-manager'
15
10
  import {
16
11
  AdditionalClaims,
17
12
  CredentialMapper,
@@ -27,8 +22,8 @@ import {
27
22
  SdJwtDecodedVerifiableCredential,
28
23
  } from '@sphereon/ssi-types'
29
24
  import { IAgentPlugin } from '@veramo/core'
30
- import { DcqlQuery } from 'dcql'
31
25
  import {
26
+ AuthorizationResponseStateWithVerifiedData,
32
27
  IAuthorizationRequestPayloads,
33
28
  ICreateAuthRequestArgs,
34
29
  IGetAuthRequestStateArgs,
@@ -44,9 +39,13 @@ import {
44
39
  IUpdateRequestStateArgs,
45
40
  IVerifyAuthResponseStateArgs,
46
41
  schema,
42
+ VerifiedDataMode,
47
43
  } from '../index'
48
44
  import { RPInstance } from '../RPInstance'
45
+
49
46
  import { ISIOPv2RP } from '../types/ISIOPv2RP'
47
+ import { shaHasher as defaultHasher } from '@sphereon/ssi-sdk.core'
48
+ import { DcqlQuery } from 'dcql'
50
49
 
51
50
  export class SIOPv2RP implements IAgentPlugin {
52
51
  private readonly opts: ISiopv2RPOpts
@@ -86,14 +85,7 @@ export class SIOPv2RP implements IAgentPlugin {
86
85
  }
87
86
 
88
87
  private async createAuthorizationRequestURI(createArgs: ICreateAuthRequestArgs, context: IRequiredContext): Promise<string> {
89
- return await this.getRPInstance(
90
- {
91
- createWhenNotPresent: true,
92
- responseRedirectURI: createArgs.responseRedirectURI,
93
- ...(createArgs.useQueryIdInstance === true && { queryId: createArgs.queryId }),
94
- },
95
- context,
96
- )
88
+ return await this.getRPInstance({ definitionId: createArgs.definitionId, responseRedirectURI: createArgs.responseRedirectURI }, context)
97
89
  .then((rp) => rp.createAuthorizationRequestURI(createArgs, context))
98
90
  .then((URI) => URI.encodedUri)
99
91
  }
@@ -102,20 +94,20 @@ export class SIOPv2RP implements IAgentPlugin {
102
94
  createArgs: ICreateAuthRequestArgs,
103
95
  context: IRequiredContext,
104
96
  ): Promise<IAuthorizationRequestPayloads> {
105
- return await this.getRPInstance({ createWhenNotPresent: true, queryId: createArgs.queryId }, context)
97
+ return await this.getRPInstance({ definitionId: createArgs.definitionId }, context)
106
98
  .then((rp) => rp.createAuthorizationRequest(createArgs, context))
107
99
  .then(async (request) => {
108
100
  const authRequest: IAuthorizationRequestPayloads = {
109
101
  authorizationRequest: request.payload,
110
102
  requestObject: await request.requestObjectJwt(),
111
- requestObjectDecoded: request.requestObject?.getPayload(),
103
+ requestObjectDecoded: await request.requestObject?.getPayload(),
112
104
  }
113
105
  return authRequest
114
106
  })
115
107
  }
116
108
 
117
109
  private async siopGetRequestState(args: IGetAuthRequestStateArgs, context: IRequiredContext): Promise<AuthorizationRequestState | undefined> {
118
- return await this.getRPInstance({ createWhenNotPresent: false, queryId: args.queryId }, context).then((rp) =>
110
+ return await this.getRPInstance({ definitionId: args.definitionId }, context).then((rp) =>
119
111
  rp.get(context).then((rp) => rp.sessionManager.getRequestStateByCorrelationId(args.correlationId, args.errorOnNotFound)),
120
112
  )
121
113
  }
@@ -124,7 +116,7 @@ export class SIOPv2RP implements IAgentPlugin {
124
116
  args: IGetAuthResponseStateArgs,
125
117
  context: IRequiredContext,
126
118
  ): Promise<AuthorizationResponseStateWithVerifiedData | undefined> {
127
- const rpInstance: RPInstance = await this.getRPInstance({ createWhenNotPresent: false, queryId: args.queryId }, context)
119
+ const rpInstance: RPInstance = await this.getRPInstance({ definitionId: args.definitionId }, context)
128
120
  const authorizationResponseState: AuthorizationResponseState | undefined = await rpInstance
129
121
  .get(context)
130
122
  .then((rp) => rp.sessionManager.getResponseStateByCorrelationId(args.correlationId, args.errorOnNotFound))
@@ -133,7 +125,11 @@ export class SIOPv2RP implements IAgentPlugin {
133
125
  }
134
126
 
135
127
  const responseState = authorizationResponseState as AuthorizationResponseStateWithVerifiedData
136
- if (responseState.status === AuthorizationResponseStateStatus.VERIFIED) {
128
+ if (
129
+ responseState.status === AuthorizationResponseStateStatus.VERIFIED &&
130
+ args.includeVerifiedData &&
131
+ args.includeVerifiedData !== VerifiedDataMode.NONE
132
+ ) {
137
133
  let hasher: HasherSync | undefined
138
134
  if (
139
135
  CredentialMapper.isSdJwtEncoded(responseState.response.payload.vp_token as OriginalVerifiablePresentation) &&
@@ -141,36 +137,19 @@ export class SIOPv2RP implements IAgentPlugin {
141
137
  ) {
142
138
  hasher = defaultHasher
143
139
  }
144
-
145
- // FIXME SSISDK-64 currently assuming that all vp tokens are or type EncodedDcqlPresentationVpToken as we only work with DCQL now. But the types still indicate it can be another type of vp token
146
- const vpToken = responseState.response.payload.vp_token && JSON.parse(responseState.response.payload.vp_token as EncodedDcqlPresentationVpToken)
147
- const claims = []
148
- for (const [credentialQueryId, presentationValue] of Object.entries(vpToken)) {
149
- let singleVP: OriginalVerifiablePresentation
150
- if (Array.isArray(presentationValue)) {
151
- if (presentationValue.length === 0) {
152
- throw Error(`DCQL query '${credentialQueryId}' has empty array of presentations`)
153
- }
154
- if (presentationValue.length > 1) {
155
- throw Error(`DCQL query '${credentialQueryId}' has multiple presentations (${presentationValue.length}), but only one is supported atm`)
156
- }
157
- singleVP = presentationValue[0] as OriginalVerifiablePresentation
158
- } else {
159
- singleVP = presentationValue as OriginalVerifiablePresentation
160
- }
161
-
162
- // todo this should also include mdl-mdoc
163
- const presentationDecoded = CredentialMapper.decodeVerifiablePresentation(
164
- singleVP as OriginalVerifiablePresentation,
165
- //todo: later we want to conditionally pass in options for mdl-mdoc here
166
- hasher,
167
- )
168
- console.log(`presentationDecoded: ${JSON.stringify(presentationDecoded)}`)
169
-
170
- const allClaims: AdditionalClaims = {}
171
- const presentationOrClaims = this.presentationOrClaimsFrom(presentationDecoded)
172
- if ('verifiableCredential' in presentationOrClaims) {
173
- for (const credential of presentationOrClaims.verifiableCredential) {
140
+ // todo this should also include mdl-mdoc
141
+ const presentationDecoded = CredentialMapper.decodeVerifiablePresentation(
142
+ responseState.response.payload.vp_token as OriginalVerifiablePresentation,
143
+ //todo: later we want to conditionally pass in options for mdl-mdoc here
144
+ hasher,
145
+ )
146
+ switch (args.includeVerifiedData) {
147
+ case VerifiedDataMode.VERIFIED_PRESENTATION:
148
+ responseState.response.payload.verifiedData = this.presentationOrClaimsFrom(presentationDecoded)
149
+ break
150
+ case VerifiedDataMode.CREDENTIAL_SUBJECT_FLATTENED: // TODO debug cs-flat for SD-JWT
151
+ const allClaims: AdditionalClaims = {}
152
+ for (const credential of this.presentationOrClaimsFrom(presentationDecoded).verifiableCredential || []) {
174
153
  const vc = credential as IVerifiableCredential
175
154
  const schemaValidationResult = await context.agent.cvVerifySchema({
176
155
  credential,
@@ -193,35 +172,11 @@ export class SIOPv2RP implements IAgentPlugin {
193
172
  allClaims[key] = value
194
173
  }
195
174
  })
196
-
197
- claims.push({
198
- id: credentialQueryId,
199
- type: vc.type[0],
200
- claims: allClaims,
201
- })
202
175
  }
203
- } else {
204
- claims.push({
205
- id: credentialQueryId,
206
- type: (presentationDecoded as SdJwtDecodedVerifiableCredential).decodedPayload.vct,
207
- claims: presentationOrClaims,
208
- })
209
- }
210
- }
211
-
212
- responseState.verifiedData = {
213
- ...(responseState.response.payload.vp_token && {
214
- authorization_response: {
215
- vp_token:
216
- typeof responseState.response.payload.vp_token === 'string'
217
- ? JSON.parse(responseState.response.payload.vp_token)
218
- : responseState.response.payload.vp_token,
219
- },
220
- }),
221
- ...(claims.length > 0 && { credential_claims: claims }),
176
+ responseState.verifiedData = allClaims
177
+ break
222
178
  }
223
179
  }
224
-
225
180
  return responseState
226
181
  }
227
182
 
@@ -232,17 +187,16 @@ export class SIOPv2RP implements IAgentPlugin {
232
187
  | SdJwtDecodedVerifiableCredential
233
188
  | MdocOid4vpMdocVpToken
234
189
  | MdocDeviceResponse,
235
- ): AdditionalClaims | IPresentation => {
236
- return CredentialMapper.isSdJwtDecodedCredential(presentationDecoded)
190
+ ): AdditionalClaims | IPresentation =>
191
+ CredentialMapper.isSdJwtDecodedCredential(presentationDecoded)
237
192
  ? presentationDecoded.decodedPayload
238
193
  : CredentialMapper.toUniformPresentation(presentationDecoded as OriginalVerifiablePresentation)
239
- }
240
194
 
241
195
  private async siopUpdateRequestState(args: IUpdateRequestStateArgs, context: IRequiredContext): Promise<AuthorizationRequestState> {
242
- if (args.state !== 'authorization_request_created') {
243
- throw Error(`Only 'authorization_request_created' status is supported for this method at this point`)
196
+ if (args.state !== 'sent') {
197
+ throw Error(`Only 'sent' status is supported for this method at this point`)
244
198
  }
245
- return await this.getRPInstance({ createWhenNotPresent: false, queryId: args.queryId }, context)
199
+ return await this.getRPInstance({ definitionId: args.definitionId }, context)
246
200
  // todo: In the SIOP library we need to update the signal method to be more like this method
247
201
  .then((rp) =>
248
202
  rp.get(context).then(async (rp) => {
@@ -256,7 +210,7 @@ export class SIOPv2RP implements IAgentPlugin {
256
210
  }
257
211
 
258
212
  private async siopDeleteState(args: IGetAuthResponseStateArgs, context: IRequiredContext): Promise<boolean> {
259
- return await this.getRPInstance({ createWhenNotPresent: false, queryId: args.queryId }, context)
213
+ return await this.getRPInstance({ definitionId: args.definitionId }, context)
260
214
  .then((rp) => rp.get(context).then((rp) => rp.sessionManager.deleteStateForCorrelationId(args.correlationId)))
261
215
  .then(() => true)
262
216
  }
@@ -269,11 +223,12 @@ export class SIOPv2RP implements IAgentPlugin {
269
223
  typeof args.authorizationResponse === 'string'
270
224
  ? (decodeUriAsJson(args.authorizationResponse) as AuthorizationResponsePayload)
271
225
  : args.authorizationResponse
272
- return await this.getRPInstance({ createWhenNotPresent: false, queryId: args.queryId }, context).then((rp) =>
226
+ return await this.getRPInstance({ definitionId: args.definitionId }, context).then((rp) =>
273
227
  rp.get(context).then((rp) =>
274
228
  rp.verifyAuthorizationResponse(authResponse, {
275
229
  correlationId: args.correlationId,
276
- ...(args.dcqlQuery && { dcqlQuery: args.dcqlQuery }),
230
+ ...(args.presentationDefinitions && !args.dcqlQuery ? { presentationDefinitions: args.presentationDefinitions } : {}),
231
+ ...(args.dcqlQuery ? { dcqlQuery: args.dcqlQuery as DcqlQuery } : {}), // TODO BEFORE PR, check compatibility and whether we can remove local type
277
232
  audience: args.audience,
278
233
  }),
279
234
  ),
@@ -281,18 +236,19 @@ export class SIOPv2RP implements IAgentPlugin {
281
236
  }
282
237
 
283
238
  private async siopImportDefinitions(args: ImportDefinitionsArgs, context: IRequiredContext): Promise<void> {
284
- const { importItems, tenantId, version, versionControlMode } = args
239
+ const { definitions, tenantId, version, versionControlMode } = args
285
240
  await Promise.all(
286
- importItems.map(async (importItem: ImportDcqlQueryItem) => {
287
- DcqlQuery.validate(importItem.query)
288
- console.log(`persisting DCQL definition ${importItem.queryId} with versionControlMode ${versionControlMode}`)
241
+ definitions.map(async (definitionPair) => {
242
+ const definitionPayload = definitionPair.definitionPayload
243
+ await context.agent.pexValidateDefinition({ definition: definitionPayload })
289
244
 
245
+ console.log(`persisting definition ${definitionPayload.id} / ${definitionPayload.name} with versionControlMode ${versionControlMode}`)
290
246
  return context.agent.pdmPersistDefinition({
291
247
  definitionItem: {
292
- queryId: importItem.queryId!,
293
248
  tenantId: tenantId,
294
249
  version: version,
295
- query: importItem.query,
250
+ definitionPayload,
251
+ dcqlPayload: definitionPair.dcqlPayload,
296
252
  },
297
253
  opts: { versionControlMode: versionControlMode },
298
254
  })
@@ -301,12 +257,12 @@ export class SIOPv2RP implements IAgentPlugin {
301
257
  }
302
258
 
303
259
  private async siopGetRedirectURI(args: IGetRedirectUriArgs, context: IRequiredContext): Promise<string | undefined> {
304
- const instanceId = args.queryId ?? SIOPv2RP._DEFAULT_OPTS_KEY
260
+ const instanceId = args.definitionId ?? SIOPv2RP._DEFAULT_OPTS_KEY
305
261
  if (this.instances.has(instanceId)) {
306
262
  const rpInstance = this.instances.get(instanceId)
307
263
  if (rpInstance !== undefined) {
308
264
  const rp = await rpInstance.get(context)
309
- return await rp.getResponseRedirectUri({
265
+ return rp.getResponseRedirectUri({
310
266
  correlation_id: args.correlationId,
311
267
  correlationId: args.correlationId,
312
268
  ...(args.state && { state: args.state }),
@@ -316,64 +272,37 @@ export class SIOPv2RP implements IAgentPlugin {
316
272
  return undefined
317
273
  }
318
274
 
319
- async getRPInstance({ createWhenNotPresent, queryId, responseRedirectURI }: ISiopRPInstanceArgs, context: IRequiredContext): Promise<RPInstance> {
320
- let rpInstanceId: string = SIOPv2RP._DEFAULT_OPTS_KEY
321
- let rpInstance: RPInstance | undefined
322
- if (queryId) {
323
- if (this.instances.has(queryId)) {
324
- rpInstanceId = queryId
325
- rpInstance = this.instances.get(rpInstanceId)!
326
- } else if (isValidUUID(queryId)) {
327
- try {
328
- // Check whether queryId is actually the PD item id
329
- const pd = await context.agent.pdmGetDefinition({ itemId: queryId })
330
- if (this.instances.has(pd.queryId)) {
331
- rpInstanceId = pd.queryId
332
- rpInstance = this.instances.get(rpInstanceId)!
333
- }
334
- } catch (ignore) {}
335
- }
336
- if (createWhenNotPresent) {
337
- rpInstanceId = queryId
338
- } else {
339
- rpInstance = this.instances.get(rpInstanceId)
340
- }
341
- } else {
342
- rpInstance = this.instances.get(rpInstanceId)
343
- }
344
-
345
- if (!rpInstance) {
346
- if (!createWhenNotPresent) {
347
- return Promise.reject(`No RP instance found for key ${rpInstanceId}`)
348
- }
349
- const instanceOpts = this.getInstanceOpts(queryId)
350
- const rpOpts = await this.getRPOptions(context, { queryId, responseRedirectURI: responseRedirectURI })
275
+ async getRPInstance({ definitionId, responseRedirectURI }: ISiopRPInstanceArgs, context: IRequiredContext): Promise<RPInstance> {
276
+ const instanceId = definitionId ?? SIOPv2RP._DEFAULT_OPTS_KEY
277
+ if (!this.instances.has(instanceId)) {
278
+ const instanceOpts = this.getInstanceOpts(definitionId)
279
+ const rpOpts = await this.getRPOptions(context, { definitionId, responseRedirectURI: responseRedirectURI })
351
280
  if (!rpOpts.identifierOpts.resolveOpts?.resolver || typeof rpOpts.identifierOpts.resolveOpts.resolver.resolve !== 'function') {
352
281
  if (!rpOpts.identifierOpts?.resolveOpts) {
353
282
  rpOpts.identifierOpts = { ...rpOpts.identifierOpts }
354
283
  rpOpts.identifierOpts.resolveOpts = { ...rpOpts.identifierOpts.resolveOpts }
355
284
  }
356
- console.log('Using agent DID resolver for RP instance with definition id ' + queryId)
285
+ console.log('Using agent DID resolver for RP instance with definition id ' + definitionId)
357
286
  rpOpts.identifierOpts.resolveOpts.resolver = getAgentResolver(context, {
358
287
  uniresolverResolution: true,
359
288
  localResolution: true,
360
289
  resolverResolution: true,
361
290
  })
362
291
  }
363
- rpInstance = new RPInstance({ rpOpts, pexOpts: instanceOpts })
364
- this.instances.set(rpInstanceId, rpInstance)
292
+ this.instances.set(instanceId, new RPInstance({ rpOpts, pexOpts: instanceOpts }))
365
293
  }
294
+ const rpInstance = this.instances.get(instanceId)!
366
295
  if (responseRedirectURI) {
367
296
  rpInstance.rpOptions.responseRedirectUri = responseRedirectURI
368
297
  }
369
298
  return rpInstance
370
299
  }
371
300
 
372
- async getRPOptions(context: IRequiredContext, opts: { queryId?: string; responseRedirectURI?: string }): Promise<IRPOptions> {
373
- const { queryId, responseRedirectURI: responseRedirectURI } = opts
374
- const options = this.getInstanceOpts(queryId)?.rpOpts ?? this.opts.defaultOpts
301
+ async getRPOptions(context: IRequiredContext, opts: { definitionId?: string; responseRedirectURI?: string }): Promise<IRPOptions> {
302
+ const { definitionId, responseRedirectURI: responseRedirectURI } = opts
303
+ const options = this.getInstanceOpts(definitionId)?.rpOpts ?? this.opts.defaultOpts
375
304
  if (!options) {
376
- throw Error(`Could not get specific nor default options for definition ${queryId}`)
305
+ throw Error(`Could not get specific nor default options for definition ${definitionId}`)
377
306
  }
378
307
  if (this.opts.defaultOpts) {
379
308
  if (!options.identifierOpts) {
@@ -404,22 +333,22 @@ export class SIOPv2RP implements IAgentPlugin {
404
333
  return options
405
334
  }
406
335
 
407
- getInstanceOpts(queryId?: string): IPEXInstanceOptions | undefined {
336
+ getInstanceOpts(definitionId?: string): IPEXInstanceOptions | undefined {
408
337
  if (!this.opts.instanceOpts) return undefined
409
338
 
410
- const instanceOpt = queryId ? this.opts.instanceOpts.find((i) => i.queryId === queryId) : undefined
339
+ const instanceOpt = definitionId ? this.opts.instanceOpts.find((i) => i.definitionId === definitionId) : undefined
411
340
 
412
- return instanceOpt ?? this.getDefaultOptions(queryId)
341
+ return instanceOpt ?? this.getDefaultOptions(definitionId)
413
342
  }
414
343
 
415
- private getDefaultOptions(queryId: string | undefined) {
344
+ private getDefaultOptions(definitionId: string | undefined) {
416
345
  if (!this.opts.instanceOpts) return undefined
417
346
 
418
- const defaultOptions = this.opts.instanceOpts.find((i) => i.queryId === 'default')
347
+ const defaultOptions = this.opts.instanceOpts.find((i) => i.definitionId === 'default')
419
348
  if (defaultOptions) {
420
349
  const clonedOptions = { ...defaultOptions }
421
- if (queryId !== undefined) {
422
- clonedOptions.queryId = queryId
350
+ if (definitionId !== undefined) {
351
+ clonedOptions.definitionId = definitionId
423
352
  }
424
353
  return clonedOptions
425
354
  }
package/src/functions.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import {
2
- ClientIdentifierPrefix,
2
+ ClientIdScheme,
3
3
  ClientMetadataOpts,
4
- DcqlQueryLookupCallback,
5
4
  InMemoryRPSessionManager,
6
5
  PassBy,
7
6
  PresentationVerificationCallback,
@@ -29,14 +28,14 @@ import {
29
28
  } from '@sphereon/ssi-sdk-ext.identifier-resolution'
30
29
  import { JwtCompactResult } from '@sphereon/ssi-sdk-ext.jwt-service'
31
30
  import { IVerifySdJwtPresentationResult } from '@sphereon/ssi-sdk.sd-jwt'
32
- import { CredentialMapper, HasherSync, OriginalVerifiableCredential, PresentationSubmission } from '@sphereon/ssi-types'
31
+ import { CredentialMapper, Hasher, OriginalVerifiableCredential, PresentationSubmission } from '@sphereon/ssi-types'
33
32
  import { IVerifyCallbackArgs, IVerifyCredentialResult, VerifyCallback } from '@sphereon/wellknown-dids-client'
33
+ // import { KeyAlgo, SuppliedSigner } from '@sphereon/ssi-sdk.core'
34
34
  import { TKeyType } from '@veramo/core'
35
35
  import { JWTVerifyOptions } from 'did-jwt'
36
36
  import { Resolvable } from 'did-resolver'
37
37
  import { EventEmitter } from 'events'
38
- import { validate as isValidUUID } from 'uuid'
39
- import { IRequiredContext, IRPOptions, ISIOPIdentifierOptions } from './types/ISIOPv2RP'
38
+ import { IPEXOptions, IRequiredContext, IRPOptions, ISIOPIdentifierOptions } from './types/ISIOPv2RP'
40
39
  import { DcqlQuery } from 'dcql'
41
40
  import { defaultHasher } from '@sphereon/ssi-sdk.core'
42
41
 
@@ -44,7 +43,7 @@ export function getRequestVersion(rpOptions: IRPOptions): SupportedVersion {
44
43
  if (Array.isArray(rpOptions.supportedVersions) && rpOptions.supportedVersions.length > 0) {
45
44
  return rpOptions.supportedVersions[0]
46
45
  }
47
- return SupportedVersion.OID4VP_v1
46
+ return SupportedVersion.JWT_VC_PRESENTATION_PROFILE_v1
48
47
  }
49
48
 
50
49
  function getWellKnownDIDVerifyCallback(siopIdentifierOpts: ISIOPIdentifierOptions, context: IRequiredContext) {
@@ -59,29 +58,6 @@ function getWellKnownDIDVerifyCallback(siopIdentifierOpts: ISIOPIdentifierOption
59
58
  }
60
59
  }
61
60
 
62
- export function getDcqlQueryLookupCallback(context: IRequiredContext): DcqlQueryLookupCallback {
63
- async function dcqlQueryLookup(queryId: string, version?: string, tenantId?: string): Promise<DcqlQuery> {
64
- // TODO Add caching?
65
- const result = await context.agent.pdmGetDefinitions({
66
- filter: [
67
- {
68
- queryId,
69
- ...(tenantId && { tenantId }),
70
- ...(version && { version }),
71
- },
72
- ...(isValidUUID(queryId) ? [{ id: queryId }] : []),
73
- ],
74
- })
75
- if (result && result.length > 0) {
76
- return result[0].query
77
- }
78
-
79
- return Promise.reject(Error(`No dcql query found for queryId ${queryId}`))
80
- }
81
-
82
- return dcqlQueryLookup
83
- }
84
-
85
61
  export function getPresentationVerificationCallback(
86
62
  idOpts: ManagedIdentifierOptsOrResult,
87
63
  context: IRequiredContext,
@@ -93,6 +69,7 @@ export function getPresentationVerificationCallback(
93
69
  if (CredentialMapper.isSdJwtEncoded(args)) {
94
70
  const result: IVerifySdJwtPresentationResult = await context.agent.verifySdJwtPresentation({
95
71
  presentation: args,
72
+ kb: true,
96
73
  })
97
74
  // fixme: investigate the correct way to handle this
98
75
  return { verified: !!result.payload }
@@ -126,11 +103,35 @@ export function getPresentationVerificationCallback(
126
103
 
127
104
  export async function createRPBuilder(args: {
128
105
  rpOpts: IRPOptions
106
+ pexOpts?: IPEXOptions | undefined
129
107
  definition?: IPresentationDefinition
108
+ dcql?: DcqlQuery
130
109
  context: IRequiredContext
131
110
  }): Promise<RPBuilder> {
132
- const { rpOpts, context } = args
111
+ const { rpOpts, pexOpts, context } = args
133
112
  const { identifierOpts } = rpOpts
113
+ let definition: IPresentationDefinition | undefined = args.definition
114
+ let dcqlQuery: DcqlQuery | undefined = args.dcql
115
+
116
+ if (!definition && pexOpts && pexOpts.definitionId) {
117
+ const presentationDefinitionItems = await context.agent.pdmGetDefinitions({
118
+ filter: [
119
+ {
120
+ definitionId: pexOpts.definitionId,
121
+ version: pexOpts.version,
122
+ tenantId: pexOpts.tenantId,
123
+ },
124
+ ],
125
+ })
126
+
127
+ if (presentationDefinitionItems.length > 0) {
128
+ const presentationDefinitionItem = presentationDefinitionItems[0]
129
+ definition = presentationDefinitionItem.definitionPayload
130
+ if (!dcqlQuery && presentationDefinitionItem.dcqlPayload) {
131
+ dcqlQuery = presentationDefinitionItem.dcqlPayload as DcqlQuery // cast from DcqlQueryREST back to valibot DcqlQuery
132
+ }
133
+ }
134
+ }
134
135
 
135
136
  const didMethods = identifierOpts.supportedDIDMethods ?? (await getAgentDIDMethods(context))
136
137
  const eventEmitter = rpOpts.eventEmitter ?? new EventEmitter()
@@ -160,7 +161,7 @@ export async function createRPBuilder(args: {
160
161
  uniresolverResolution: rpOpts.identifierOpts.resolveOpts?.noUniversalResolverFallback !== true,
161
162
  })
162
163
  //todo: probably wise to first look and see if we actually need the hasher to begin with
163
- let hasher: HasherSync | undefined = rpOpts.credentialOpts?.hasher
164
+ let hasher: Hasher | undefined = rpOpts.credentialOpts?.hasher
164
165
  if (!rpOpts.credentialOpts?.hasher || typeof rpOpts.credentialOpts?.hasher !== 'function') {
165
166
  hasher = defaultHasher
166
167
  }
@@ -170,7 +171,9 @@ export async function createRPBuilder(args: {
170
171
  .withResponseMode(rpOpts.responseMode ?? ResponseMode.POST)
171
172
  .withResponseType(ResponseType.VP_TOKEN, PropertyTarget.REQUEST_OBJECT)
172
173
  // todo: move to options fill/correct method
173
- .withSupportedVersions(rpOpts.supportedVersions ?? [SupportedVersion.OID4VP_v1, SupportedVersion.SIOPv2_OID4VP_D28])
174
+ .withSupportedVersions(
175
+ rpOpts.supportedVersions ?? [SupportedVersion.JWT_VC_PRESENTATION_PROFILE_v1, SupportedVersion.SIOPv2_ID1, SupportedVersion.SIOPv2_D11],
176
+ )
174
177
 
175
178
  .withEventEmitter(eventEmitter)
176
179
  .withSessionManager(rpOpts.sessionManager ?? new InMemoryRPSessionManager(eventEmitter))
@@ -189,21 +192,23 @@ export async function createRPBuilder(args: {
189
192
  context,
190
193
  ),
191
194
  )
192
- .withDcqlQueryLookup(getDcqlQueryLookupCallback(context))
193
195
  .withRevocationVerification(RevocationVerification.NEVER)
194
196
  .withPresentationVerification(getPresentationVerificationCallback(identifierOpts.idOpts, context))
195
197
 
196
198
  const oidfOpts = identifierOpts.oidfOpts
197
199
  if (oidfOpts && isExternalIdentifierOIDFEntityIdOpts(oidfOpts)) {
198
- builder.withEntityId(oidfOpts.identifier, PropertyTarget.REQUEST_OBJECT)
200
+ builder.withEntityId(oidfOpts.identifier, PropertyTarget.REQUEST_OBJECT).withClientIdScheme('entity_id', PropertyTarget.REQUEST_OBJECT)
199
201
  } else {
200
202
  const resolution = await context.agent.identifierManagedGet(identifierOpts.idOpts)
201
- const clientId: string =
202
- rpOpts.clientMetadataOpts?.client_id ??
203
- resolution.issuer ??
204
- (isManagedIdentifierDidResult(resolution) ? resolution.did : resolution.jwkThumbprint)
205
- const clientIdPrefixed = prefixClientId(clientId)
206
- builder.withClientId(clientIdPrefixed, PropertyTarget.REQUEST_OBJECT)
203
+ builder
204
+ .withClientId(
205
+ resolution.issuer ?? (isManagedIdentifierDidResult(resolution) ? resolution.did : resolution.jwkThumbprint),
206
+ PropertyTarget.REQUEST_OBJECT,
207
+ )
208
+ .withClientIdScheme(
209
+ (resolution.clientIdScheme as ClientIdScheme) ?? (identifierOpts.idOpts.clientIdScheme as ClientIdScheme),
210
+ PropertyTarget.REQUEST_OBJECT,
211
+ )
207
212
  }
208
213
 
209
214
  if (hasher) {
@@ -217,6 +222,13 @@ export async function createRPBuilder(args: {
217
222
  //fixme: this has been removed in the new version of did-auth-siop
218
223
  // builder.withWellknownDIDVerifyCallback(getWellKnownDIDVerifyCallback(didOpts, context))
219
224
 
225
+ if (definition) {
226
+ builder.withPresentationDefinition({ definition }, PropertyTarget.REQUEST_OBJECT)
227
+ }
228
+ if (dcqlQuery) {
229
+ builder.withDcqlQuery(dcqlQuery)
230
+ }
231
+
220
232
  if (rpOpts.responseRedirectUri) {
221
233
  builder.withResponseRedirectUri(rpOpts.responseRedirectUri)
222
234
  }
@@ -297,12 +309,3 @@ export function getSigningAlgo(type: TKeyType): SigningAlgo {
297
309
  throw Error('Key type not yet supported')
298
310
  }
299
311
  }
300
-
301
- export function prefixClientId(clientId: string): string {
302
- // FIXME SSISDK-60
303
- if (clientId.startsWith('did:')) {
304
- return `${ClientIdentifierPrefix.DECENTRALIZED_IDENTIFIER}:${clientId}`
305
- }
306
-
307
- return clientId
308
- }
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @public
3
3
  */
4
- import schema from '../plugin.schema.json'
4
+ const schema = require('../plugin.schema.json')
5
5
  export { schema }
6
6
  export { SIOPv2RP } from './agent/SIOPv2RP'
7
7
  export * from './types/ISIOPv2RP'