@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.
- package/dist/index.cjs +432 -481
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +69 -739
- package/dist/index.d.ts +69 -739
- package/dist/index.js +424 -472
- package/dist/index.js.map +1 -1
- package/package.json +19 -19
- package/src/RPInstance.ts +29 -14
- package/src/agent/SIOPv2RP.ts +67 -138
- package/src/functions.ts +52 -49
- package/src/index.ts +1 -1
- package/src/types/ISIOPv2RP.ts +62 -32
package/src/agent/SIOPv2RP.ts
CHANGED
|
@@ -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({
|
|
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({
|
|
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({
|
|
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 (
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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
|
-
|
|
204
|
-
|
|
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
|
-
|
|
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 !== '
|
|
243
|
-
throw Error(`Only '
|
|
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({
|
|
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({
|
|
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({
|
|
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.
|
|
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 {
|
|
239
|
+
const { definitions, tenantId, version, versionControlMode } = args
|
|
285
240
|
await Promise.all(
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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({
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
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 ' +
|
|
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
|
-
|
|
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: {
|
|
373
|
-
const {
|
|
374
|
-
const options = this.getInstanceOpts(
|
|
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 ${
|
|
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(
|
|
336
|
+
getInstanceOpts(definitionId?: string): IPEXInstanceOptions | undefined {
|
|
408
337
|
if (!this.opts.instanceOpts) return undefined
|
|
409
338
|
|
|
410
|
-
const instanceOpt =
|
|
339
|
+
const instanceOpt = definitionId ? this.opts.instanceOpts.find((i) => i.definitionId === definitionId) : undefined
|
|
411
340
|
|
|
412
|
-
return instanceOpt ?? this.getDefaultOptions(
|
|
341
|
+
return instanceOpt ?? this.getDefaultOptions(definitionId)
|
|
413
342
|
}
|
|
414
343
|
|
|
415
|
-
private getDefaultOptions(
|
|
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.
|
|
347
|
+
const defaultOptions = this.opts.instanceOpts.find((i) => i.definitionId === 'default')
|
|
419
348
|
if (defaultOptions) {
|
|
420
349
|
const clonedOptions = { ...defaultOptions }
|
|
421
|
-
if (
|
|
422
|
-
clonedOptions.
|
|
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
|
-
|
|
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,
|
|
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 {
|
|
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.
|
|
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:
|
|
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(
|
|
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
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
-
}
|