@sphereon/ssi-sdk.siopv2-oid4vp-rp-auth 0.34.1-next.91 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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,11 +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.dcqlQuery ? { dcqlQuery: args.dcqlQuery as DcqlQuery } : {}), // TODO BEFORE PR, check compatibility and whether we can remove local type
276
+ ...(args.dcqlQuery && { dcqlQuery: args.dcqlQuery }),
231
277
  audience: args.audience,
232
278
  }),
233
279
  ),
@@ -235,19 +281,18 @@ export class SIOPv2RP implements IAgentPlugin {
235
281
  }
236
282
 
237
283
  private async siopImportDefinitions(args: ImportDefinitionsArgs, context: IRequiredContext): Promise<void> {
238
- const { definitions, tenantId, version, versionControlMode } = args
284
+ const { importItems, tenantId, version, versionControlMode } = args
239
285
  await Promise.all(
240
- definitions.map(async (definitionPair) => {
241
- const definitionPayload = definitionPair.definitionPayload
242
- 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}`)
243
289
 
244
- console.log(`persisting definition ${definitionPayload.id} / ${definitionPayload.name} with versionControlMode ${versionControlMode}`)
245
290
  return context.agent.pdmPersistDefinition({
246
291
  definitionItem: {
292
+ queryId: importItem.queryId!,
247
293
  tenantId: tenantId,
248
294
  version: version,
249
- definitionPayload,
250
- dcqlPayload: definitionPair.dcqlPayload,
295
+ query: importItem.query,
251
296
  },
252
297
  opts: { versionControlMode: versionControlMode },
253
298
  })
@@ -256,12 +301,12 @@ export class SIOPv2RP implements IAgentPlugin {
256
301
  }
257
302
 
258
303
  private async siopGetRedirectURI(args: IGetRedirectUriArgs, context: IRequiredContext): Promise<string | undefined> {
259
- const instanceId = args.definitionId ?? SIOPv2RP._DEFAULT_OPTS_KEY
304
+ const instanceId = args.queryId ?? SIOPv2RP._DEFAULT_OPTS_KEY
260
305
  if (this.instances.has(instanceId)) {
261
306
  const rpInstance = this.instances.get(instanceId)
262
307
  if (rpInstance !== undefined) {
263
308
  const rp = await rpInstance.get(context)
264
- return rp.getResponseRedirectUri({
309
+ return await rp.getResponseRedirectUri({
265
310
  correlation_id: args.correlationId,
266
311
  correlationId: args.correlationId,
267
312
  ...(args.state && { state: args.state }),
@@ -271,37 +316,64 @@ export class SIOPv2RP implements IAgentPlugin {
271
316
  return undefined
272
317
  }
273
318
 
274
- async getRPInstance({ definitionId, responseRedirectURI }: ISiopRPInstanceArgs, context: IRequiredContext): Promise<RPInstance> {
275
- const instanceId = definitionId ?? SIOPv2RP._DEFAULT_OPTS_KEY
276
- if (!this.instances.has(instanceId)) {
277
- const instanceOpts = this.getInstanceOpts(definitionId)
278
- 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 })
279
351
  if (!rpOpts.identifierOpts.resolveOpts?.resolver || typeof rpOpts.identifierOpts.resolveOpts.resolver.resolve !== 'function') {
280
352
  if (!rpOpts.identifierOpts?.resolveOpts) {
281
353
  rpOpts.identifierOpts = { ...rpOpts.identifierOpts }
282
354
  rpOpts.identifierOpts.resolveOpts = { ...rpOpts.identifierOpts.resolveOpts }
283
355
  }
284
- 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)
285
357
  rpOpts.identifierOpts.resolveOpts.resolver = getAgentResolver(context, {
286
358
  uniresolverResolution: true,
287
359
  localResolution: true,
288
360
  resolverResolution: true,
289
361
  })
290
362
  }
291
- this.instances.set(instanceId, new RPInstance({ rpOpts, pexOpts: instanceOpts }))
363
+ rpInstance = new RPInstance({ rpOpts, pexOpts: instanceOpts })
364
+ this.instances.set(rpInstanceId, rpInstance)
292
365
  }
293
- const rpInstance = this.instances.get(instanceId)!
294
366
  if (responseRedirectURI) {
295
367
  rpInstance.rpOptions.responseRedirectUri = responseRedirectURI
296
368
  }
297
369
  return rpInstance
298
370
  }
299
371
 
300
- async getRPOptions(context: IRequiredContext, opts: { definitionId?: string; responseRedirectURI?: string }): Promise<IRPOptions> {
301
- const { definitionId, responseRedirectURI: responseRedirectURI } = opts
302
- 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
303
375
  if (!options) {
304
- 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}`)
305
377
  }
306
378
  if (this.opts.defaultOpts) {
307
379
  if (!options.identifierOpts) {
@@ -332,22 +404,22 @@ export class SIOPv2RP implements IAgentPlugin {
332
404
  return options
333
405
  }
334
406
 
335
- getInstanceOpts(definitionId?: string): IPEXInstanceOptions | undefined {
407
+ getInstanceOpts(queryId?: string): IPEXInstanceOptions | undefined {
336
408
  if (!this.opts.instanceOpts) return undefined
337
409
 
338
- 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
339
411
 
340
- return instanceOpt ?? this.getDefaultOptions(definitionId)
412
+ return instanceOpt ?? this.getDefaultOptions(queryId)
341
413
  }
342
414
 
343
- private getDefaultOptions(definitionId: string | undefined) {
415
+ private getDefaultOptions(queryId: string | undefined) {
344
416
  if (!this.opts.instanceOpts) return undefined
345
417
 
346
- const defaultOptions = this.opts.instanceOpts.find((i) => i.definitionId === 'default')
418
+ const defaultOptions = this.opts.instanceOpts.find((i) => i.queryId === 'default')
347
419
  if (defaultOptions) {
348
420
  const clonedOptions = { ...defaultOptions }
349
- if (definitionId !== undefined) {
350
- clonedOptions.definitionId = definitionId
421
+ if (queryId !== undefined) {
422
+ clonedOptions.queryId = queryId
351
423
  }
352
424
  return clonedOptions
353
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'