@sphereon/ssi-sdk.siopv2-oid4vp-rp-auth 0.34.1-feature.SSISDK.57.uni.client.169 → 0.34.1-feature.SSISDK.57.uni.client.173

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.
@@ -9,6 +9,7 @@ import {
9
9
  } from '@sphereon/did-auth-siop'
10
10
  import { getAgentResolver } from '@sphereon/ssi-sdk-ext.did-utils'
11
11
  import { shaHasher as defaultHasher } from '@sphereon/ssi-sdk.core'
12
+ import { validate as isValidUUID } from 'uuid'
12
13
 
13
14
  import type { ImportDcqlQueryItem } from '@sphereon/ssi-sdk.pd-manager'
14
15
  import {
@@ -87,7 +88,11 @@ export class SIOPv2RP implements IAgentPlugin {
87
88
 
88
89
  private async createAuthorizationRequestURI(createArgs: ICreateAuthRequestArgs, context: IRequiredContext): Promise<string> {
89
90
  return await this.getRPInstance(
90
- { responseRedirectURI: createArgs.responseRedirectURI, ...(createArgs.useQueryIdInstance === true && { queryId: createArgs.queryId }) },
91
+ {
92
+ createWhenNotPresent: true,
93
+ responseRedirectURI: createArgs.responseRedirectURI,
94
+ ...(createArgs.useQueryIdInstance === true && { queryId: createArgs.queryId }),
95
+ },
91
96
  context,
92
97
  )
93
98
  .then((rp) => rp.createAuthorizationRequestURI(createArgs, context))
@@ -98,7 +103,7 @@ export class SIOPv2RP implements IAgentPlugin {
98
103
  createArgs: ICreateAuthRequestArgs,
99
104
  context: IRequiredContext,
100
105
  ): Promise<IAuthorizationRequestPayloads> {
101
- return await this.getRPInstance({ queryId: createArgs.queryId }, context)
106
+ return await this.getRPInstance({ createWhenNotPresent: true, queryId: createArgs.queryId }, context)
102
107
  .then((rp) => rp.createAuthorizationRequest(createArgs, context))
103
108
  .then(async (request) => {
104
109
  const authRequest: IAuthorizationRequestPayloads = {
@@ -111,7 +116,7 @@ export class SIOPv2RP implements IAgentPlugin {
111
116
  }
112
117
 
113
118
  private async siopGetRequestState(args: IGetAuthRequestStateArgs, context: IRequiredContext): Promise<AuthorizationRequestState | undefined> {
114
- return await this.getRPInstance({ queryId: args.queryId }, context).then((rp) =>
119
+ return await this.getRPInstance({ createWhenNotPresent: false, queryId: args.queryId }, context).then((rp) =>
115
120
  rp.get(context).then((rp) => rp.sessionManager.getRequestStateByCorrelationId(args.correlationId, args.errorOnNotFound)),
116
121
  )
117
122
  }
@@ -120,7 +125,7 @@ export class SIOPv2RP implements IAgentPlugin {
120
125
  args: IGetAuthResponseStateArgs,
121
126
  context: IRequiredContext,
122
127
  ): Promise<AuthorizationResponseStateWithVerifiedData | undefined> {
123
- const rpInstance: RPInstance = await this.getRPInstance({ queryId: args.queryId }, context)
128
+ const rpInstance: RPInstance = await this.getRPInstance({ createWhenNotPresent: false, queryId: args.queryId }, context)
124
129
  const authorizationResponseState: AuthorizationResponseState | undefined = await rpInstance
125
130
  .get(context)
126
131
  .then((rp) => rp.sessionManager.getResponseStateByCorrelationId(args.correlationId, args.errorOnNotFound))
@@ -200,7 +205,7 @@ export class SIOPv2RP implements IAgentPlugin {
200
205
  if (args.state !== 'authorization_request_created') {
201
206
  throw Error(`Only 'authorization_request_created' status is supported for this method at this point`)
202
207
  }
203
- return await this.getRPInstance({ queryId: args.queryId }, context)
208
+ return await this.getRPInstance({ createWhenNotPresent: false, queryId: args.queryId }, context)
204
209
  // todo: In the SIOP library we need to update the signal method to be more like this method
205
210
  .then((rp) =>
206
211
  rp.get(context).then(async (rp) => {
@@ -214,7 +219,7 @@ export class SIOPv2RP implements IAgentPlugin {
214
219
  }
215
220
 
216
221
  private async siopDeleteState(args: IGetAuthResponseStateArgs, context: IRequiredContext): Promise<boolean> {
217
- return await this.getRPInstance({ queryId: args.queryId }, context)
222
+ return await this.getRPInstance({ createWhenNotPresent: false, queryId: args.queryId }, context)
218
223
  .then((rp) => rp.get(context).then((rp) => rp.sessionManager.deleteStateForCorrelationId(args.correlationId)))
219
224
  .then(() => true)
220
225
  }
@@ -227,7 +232,7 @@ export class SIOPv2RP implements IAgentPlugin {
227
232
  typeof args.authorizationResponse === 'string'
228
233
  ? (decodeUriAsJson(args.authorizationResponse) as AuthorizationResponsePayload)
229
234
  : args.authorizationResponse
230
- return await this.getRPInstance({ queryId: args.queryId }, context).then((rp) =>
235
+ return await this.getRPInstance({ createWhenNotPresent: false, queryId: args.queryId }, context).then((rp) =>
231
236
  rp.get(context).then((rp) =>
232
237
  rp.verifyAuthorizationResponse(authResponse, {
233
238
  correlationId: args.correlationId,
@@ -274,9 +279,36 @@ export class SIOPv2RP implements IAgentPlugin {
274
279
  return undefined
275
280
  }
276
281
 
277
- async getRPInstance({ queryId, responseRedirectURI }: ISiopRPInstanceArgs, context: IRequiredContext): Promise<RPInstance> {
278
- const instanceId = queryId ?? SIOPv2RP._DEFAULT_OPTS_KEY
279
- if (!this.instances.has(instanceId)) {
282
+ async getRPInstance({ createWhenNotPresent, queryId, responseRedirectURI }: ISiopRPInstanceArgs, context: IRequiredContext): Promise<RPInstance> {
283
+ let rpInstanceId: string = SIOPv2RP._DEFAULT_OPTS_KEY
284
+ let rpInstance: RPInstance | undefined
285
+ if (queryId) {
286
+ if (this.instances.has(queryId)) {
287
+ rpInstanceId = queryId
288
+ rpInstance = this.instances.get(rpInstanceId)!
289
+ } else if (isValidUUID(queryId)) {
290
+ try {
291
+ // Check whether queryId is actually the PD item id
292
+ const pd = await context.agent.pdmGetDefinition({ itemId: queryId })
293
+ if (this.instances.has(pd.queryId)) {
294
+ rpInstanceId = pd.queryId
295
+ rpInstance = this.instances.get(rpInstanceId)!
296
+ }
297
+ } catch (ignore) {}
298
+ }
299
+ if (createWhenNotPresent) {
300
+ rpInstanceId = queryId
301
+ } else {
302
+ rpInstance = this.instances.get(rpInstanceId)
303
+ }
304
+ } else {
305
+ rpInstance = this.instances.get(rpInstanceId)
306
+ }
307
+
308
+ if (!rpInstance) {
309
+ if (!createWhenNotPresent) {
310
+ return Promise.reject(`No RP instance found for key ${rpInstanceId}`)
311
+ }
280
312
  const instanceOpts = this.getInstanceOpts(queryId)
281
313
  const rpOpts = await this.getRPOptions(context, { queryId, responseRedirectURI: responseRedirectURI })
282
314
  if (!rpOpts.identifierOpts.resolveOpts?.resolver || typeof rpOpts.identifierOpts.resolveOpts.resolver.resolve !== 'function') {
@@ -291,9 +323,9 @@ export class SIOPv2RP implements IAgentPlugin {
291
323
  resolverResolution: true,
292
324
  })
293
325
  }
294
- this.instances.set(instanceId, new RPInstance({ rpOpts, pexOpts: instanceOpts }))
326
+ rpInstance = new RPInstance({ rpOpts, pexOpts: instanceOpts })
327
+ this.instances.set(rpInstanceId, rpInstance)
295
328
  }
296
- const rpInstance = this.instances.get(instanceId)!
297
329
  if (responseRedirectURI) {
298
330
  rpInstance.rpOptions.responseRedirectUri = responseRedirectURI
299
331
  }
package/src/functions.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  ClientMetadataOpts,
3
+ DcqlQueryLookupCallback,
3
4
  InMemoryRPSessionManager,
4
5
  PassBy,
5
6
  PresentationVerificationCallback,
@@ -34,7 +35,7 @@ import { TKeyType } from '@veramo/core'
34
35
  import { JWTVerifyOptions } from 'did-jwt'
35
36
  import { Resolvable } from 'did-resolver'
36
37
  import { EventEmitter } from 'events'
37
- import { IPEXOptions, IRequiredContext, IRPOptions, ISIOPIdentifierOptions } from './types/ISIOPv2RP'
38
+ import { IRequiredContext, IRPOptions, ISIOPIdentifierOptions } from './types/ISIOPv2RP'
38
39
  import { DcqlQuery } from 'dcql'
39
40
  import { defaultHasher } from '@sphereon/ssi-sdk.core'
40
41
 
@@ -57,6 +58,31 @@ function getWellKnownDIDVerifyCallback(siopIdentifierOpts: ISIOPIdentifierOption
57
58
  }
58
59
  }
59
60
 
61
+ export function getDcqlQueryLookupCallback(context: IRequiredContext): DcqlQueryLookupCallback {
62
+ async function dcqlQueryLookup(queryId: string, version?: string, tenantId?: string): Promise<DcqlQuery> {
63
+ // TODO Add caching?
64
+ const result = await context.agent.pdmGetDefinitions({
65
+ filter: [
66
+ {
67
+ queryId: queryId,
68
+ version: version,
69
+ tenantId: tenantId,
70
+ },
71
+ {
72
+ id: queryId,
73
+ },
74
+ ],
75
+ })
76
+ if (result && result.length > 0) {
77
+ return result[0].dcqlQuery
78
+ }
79
+
80
+ return Promise.reject(Error(`No dcql query found for queryId ${queryId}`))
81
+ }
82
+
83
+ return dcqlQueryLookup
84
+ }
85
+
60
86
  export function getPresentationVerificationCallback(
61
87
  idOpts: ManagedIdentifierOptsOrResult,
62
88
  context: IRequiredContext,
@@ -101,34 +127,11 @@ export function getPresentationVerificationCallback(
101
127
 
102
128
  export async function createRPBuilder(args: {
103
129
  rpOpts: IRPOptions
104
- pexOpts?: IPEXOptions | undefined
105
130
  definition?: IPresentationDefinition
106
- dcql?: DcqlQuery
107
131
  context: IRequiredContext
108
132
  }): Promise<RPBuilder> {
109
- const { rpOpts, pexOpts, context } = args
133
+ const { rpOpts, context } = args
110
134
  const { identifierOpts } = rpOpts
111
- let definition: IPresentationDefinition | undefined = args.definition
112
- let dcqlQuery: DcqlQuery | undefined = args.dcql
113
-
114
- if (!definition && pexOpts && pexOpts.queryId) {
115
- const presentationDefinitionItems = await context.agent.pdmGetDefinitions({
116
- filter: [
117
- {
118
- queryId: pexOpts.queryId,
119
- version: pexOpts.version,
120
- tenantId: pexOpts.tenantId,
121
- },
122
- ],
123
- })
124
-
125
- if (presentationDefinitionItems.length > 0) {
126
- const presentationDefinitionItem = presentationDefinitionItems[0]
127
- if (!dcqlQuery) {
128
- dcqlQuery = presentationDefinitionItem.dcqlQuery
129
- }
130
- }
131
- }
132
135
 
133
136
  const didMethods = identifierOpts.supportedDIDMethods ?? (await getAgentDIDMethods(context))
134
137
  const eventEmitter = rpOpts.eventEmitter ?? new EventEmitter()
@@ -189,6 +192,7 @@ export async function createRPBuilder(args: {
189
192
  context,
190
193
  ),
191
194
  )
195
+ .withDcqlQueryLookup(getDcqlQueryLookupCallback(context))
192
196
  .withRevocationVerification(RevocationVerification.NEVER)
193
197
  .withPresentationVerification(getPresentationVerificationCallback(identifierOpts.idOpts, context))
194
198
 
@@ -214,10 +218,6 @@ export async function createRPBuilder(args: {
214
218
  //fixme: this has been removed in the new version of did-auth-siop
215
219
  // builder.withWellknownDIDVerifyCallback(getWellKnownDIDVerifyCallback(didOpts, context))
216
220
 
217
- if (dcqlQuery) {
218
- builder.withDcqlQuery(dcqlQuery)
219
- }
220
-
221
221
  if (rpOpts.responseRedirectUri) {
222
222
  builder.withResponseRedirectUri(rpOpts.responseRedirectUri)
223
223
  }
@@ -137,11 +137,12 @@ export interface IPEXDefinitionPersistArgs extends IPEXInstanceOptions {
137
137
  }
138
138
 
139
139
  export interface ISiopRPInstanceArgs {
140
+ createWhenNotPresent: boolean
140
141
  queryId?: string
141
142
  responseRedirectURI?: string
142
143
  }
143
144
 
144
- export interface IPEXInstanceOptions extends IPEXOptions {
145
+ export interface IPEXInstanceOptions extends IPresentationOptions {
145
146
  rpOpts?: IRPOptions
146
147
  }
147
148
 
@@ -159,12 +160,9 @@ export interface IRPOptions {
159
160
  responseRedirectUri?: string
160
161
  }
161
162
 
162
- export interface IPEXOptions {
163
- presentationVerifyCallback?: PresentationVerificationCallback
164
- // definition?: IPresentationDefinition
163
+ export interface IPresentationOptions {
165
164
  queryId: string
166
- version?: string
167
- tenantId?: string
165
+ presentationVerifyCallback?: PresentationVerificationCallback
168
166
  }
169
167
 
170
168
  export type VerificationPolicies = {