@sphereon/ssi-sdk.siopv2-oid4vp-rp-auth 0.34.1-feature.SSISDK.57.uni.client.169 → 0.34.1-feature.SSISDK.57.uni.client.203
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 +90 -54
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -15
- package/dist/index.d.ts +11 -15
- package/dist/index.js +91 -55
- package/dist/index.js.map +1 -1
- package/package.json +17 -17
- package/src/RPInstance.ts +7 -26
- package/src/agent/SIOPv2RP.ts +46 -14
- package/src/functions.ts +47 -38
- package/src/types/ISIOPv2RP.ts +5 -8
package/src/agent/SIOPv2RP.ts
CHANGED
|
@@ -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
|
-
{
|
|
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,
|
|
@@ -242,7 +247,7 @@ export class SIOPv2RP implements IAgentPlugin {
|
|
|
242
247
|
const { importItems, tenantId, version, versionControlMode } = args
|
|
243
248
|
await Promise.all(
|
|
244
249
|
importItems.map(async (importItem: ImportDcqlQueryItem) => {
|
|
245
|
-
DcqlQuery.validate(importItem.
|
|
250
|
+
DcqlQuery.validate(importItem.query)
|
|
246
251
|
console.log(`persisting DCQL definition ${importItem.queryId} with versionControlMode ${versionControlMode}`)
|
|
247
252
|
|
|
248
253
|
return context.agent.pdmPersistDefinition({
|
|
@@ -250,7 +255,7 @@ export class SIOPv2RP implements IAgentPlugin {
|
|
|
250
255
|
queryId: importItem.queryId!,
|
|
251
256
|
tenantId: tenantId,
|
|
252
257
|
version: version,
|
|
253
|
-
|
|
258
|
+
query: importItem.query,
|
|
254
259
|
},
|
|
255
260
|
opts: { versionControlMode: versionControlMode },
|
|
256
261
|
})
|
|
@@ -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
|
-
|
|
279
|
-
|
|
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
|
-
|
|
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,7 @@
|
|
|
1
1
|
import {
|
|
2
|
+
ClientIdentifierPrefix,
|
|
2
3
|
ClientMetadataOpts,
|
|
4
|
+
DcqlQueryLookupCallback,
|
|
3
5
|
InMemoryRPSessionManager,
|
|
4
6
|
PassBy,
|
|
5
7
|
PresentationVerificationCallback,
|
|
@@ -29,12 +31,11 @@ import { JwtCompactResult } from '@sphereon/ssi-sdk-ext.jwt-service'
|
|
|
29
31
|
import { IVerifySdJwtPresentationResult } from '@sphereon/ssi-sdk.sd-jwt'
|
|
30
32
|
import { CredentialMapper, HasherSync, OriginalVerifiableCredential, PresentationSubmission } from '@sphereon/ssi-types'
|
|
31
33
|
import { IVerifyCallbackArgs, IVerifyCredentialResult, VerifyCallback } from '@sphereon/wellknown-dids-client'
|
|
32
|
-
// import { KeyAlgo, SuppliedSigner } from '@sphereon/ssi-sdk.core'
|
|
33
34
|
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 {
|
|
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
|
|
|
@@ -42,7 +43,7 @@ export function getRequestVersion(rpOptions: IRPOptions): SupportedVersion {
|
|
|
42
43
|
if (Array.isArray(rpOptions.supportedVersions) && rpOptions.supportedVersions.length > 0) {
|
|
43
44
|
return rpOptions.supportedVersions[0]
|
|
44
45
|
}
|
|
45
|
-
return SupportedVersion.
|
|
46
|
+
return SupportedVersion.OID4VP_v1
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
function getWellKnownDIDVerifyCallback(siopIdentifierOpts: ISIOPIdentifierOptions, context: IRequiredContext) {
|
|
@@ -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,
|
|
68
|
+
...(tenantId && { tenantId }),
|
|
69
|
+
...(version && { version }),
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: queryId,
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
})
|
|
76
|
+
if (result && result.length > 0) {
|
|
77
|
+
return result[0].query
|
|
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,
|
|
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()
|
|
@@ -168,9 +171,7 @@ export async function createRPBuilder(args: {
|
|
|
168
171
|
.withResponseMode(rpOpts.responseMode ?? ResponseMode.POST)
|
|
169
172
|
.withResponseType(ResponseType.VP_TOKEN, PropertyTarget.REQUEST_OBJECT)
|
|
170
173
|
// todo: move to options fill/correct method
|
|
171
|
-
.withSupportedVersions(
|
|
172
|
-
rpOpts.supportedVersions ?? [SupportedVersion.JWT_VC_PRESENTATION_PROFILE_v1, SupportedVersion.SIOPv2_ID1, SupportedVersion.SIOPv2_D11],
|
|
173
|
-
)
|
|
174
|
+
.withSupportedVersions(rpOpts.supportedVersions ?? [SupportedVersion.OID4VP_v1, SupportedVersion.SIOPv2_OID4VP_D28])
|
|
174
175
|
|
|
175
176
|
.withEventEmitter(eventEmitter)
|
|
176
177
|
.withSessionManager(rpOpts.sessionManager ?? new InMemoryRPSessionManager(eventEmitter))
|
|
@@ -189,6 +190,7 @@ export async function createRPBuilder(args: {
|
|
|
189
190
|
context,
|
|
190
191
|
),
|
|
191
192
|
)
|
|
193
|
+
.withDcqlQueryLookup(getDcqlQueryLookupCallback(context))
|
|
192
194
|
.withRevocationVerification(RevocationVerification.NEVER)
|
|
193
195
|
.withPresentationVerification(getPresentationVerificationCallback(identifierOpts.idOpts, context))
|
|
194
196
|
|
|
@@ -197,10 +199,12 @@ export async function createRPBuilder(args: {
|
|
|
197
199
|
builder.withEntityId(oidfOpts.identifier, PropertyTarget.REQUEST_OBJECT)
|
|
198
200
|
} else {
|
|
199
201
|
const resolution = await context.agent.identifierManagedGet(identifierOpts.idOpts)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
202
|
+
const clientId: string =
|
|
203
|
+
rpOpts.clientMetadataOpts?.client_id ??
|
|
204
|
+
resolution.issuer ??
|
|
205
|
+
(isManagedIdentifierDidResult(resolution) ? resolution.did : resolution.jwkThumbprint)
|
|
206
|
+
const clientIdPrefixed = prefixClientId(clientId)
|
|
207
|
+
builder.withClientId(clientIdPrefixed, PropertyTarget.REQUEST_OBJECT)
|
|
204
208
|
}
|
|
205
209
|
|
|
206
210
|
if (hasher) {
|
|
@@ -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
|
}
|
|
@@ -298,3 +298,12 @@ export function getSigningAlgo(type: TKeyType): SigningAlgo {
|
|
|
298
298
|
throw Error('Key type not yet supported')
|
|
299
299
|
}
|
|
300
300
|
}
|
|
301
|
+
|
|
302
|
+
export function prefixClientId(clientId: string): string {
|
|
303
|
+
// FIXME SSISDK-60
|
|
304
|
+
if (clientId.startsWith('did:')) {
|
|
305
|
+
return `${ClientIdentifierPrefix.DECENTRALIZED_IDENTIFIER}:${clientId}`
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return clientId
|
|
309
|
+
}
|
package/src/types/ISIOPv2RP.ts
CHANGED
|
@@ -30,7 +30,7 @@ import { ISDJwtPlugin } from '@sphereon/ssi-sdk.sd-jwt'
|
|
|
30
30
|
import { AuthorizationRequestStateStatus } from '@sphereon/ssi-sdk.siopv2-oid4vp-common'
|
|
31
31
|
import { HasherSync } from '@sphereon/ssi-types'
|
|
32
32
|
import { VerifyCallback } from '@sphereon/wellknown-dids-client'
|
|
33
|
-
import { IAgentContext,
|
|
33
|
+
import { IAgentContext, ICredentialVerifier, IDIDManager, IKeyManager, IPluginMethodMap, IResolver } from '@veramo/core'
|
|
34
34
|
import { DcqlQuery } from 'dcql'
|
|
35
35
|
|
|
36
36
|
import { Resolvable } from 'did-resolver'
|
|
@@ -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
|
|
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
|
|
163
|
-
presentationVerifyCallback?: PresentationVerificationCallback
|
|
164
|
-
// definition?: IPresentationDefinition
|
|
163
|
+
export interface IPresentationOptions {
|
|
165
164
|
queryId: string
|
|
166
|
-
|
|
167
|
-
tenantId?: string
|
|
165
|
+
presentationVerifyCallback?: PresentationVerificationCallback
|
|
168
166
|
}
|
|
169
167
|
|
|
170
168
|
export type VerificationPolicies = {
|
|
@@ -200,7 +198,6 @@ export type IRequiredContext = IAgentContext<
|
|
|
200
198
|
IDIDManager &
|
|
201
199
|
IKeyManager &
|
|
202
200
|
IIdentifierResolution &
|
|
203
|
-
ICredentialIssuer &
|
|
204
201
|
ICredentialValidation &
|
|
205
202
|
ICredentialVerifier &
|
|
206
203
|
IPresentationExchange &
|