@sphereon/ssi-sdk.siopv2-oid4vp-rp-auth 0.34.1-next.3 → 0.34.1-next.323

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