@sphereon/ssi-sdk.siopv2-oid4vp-rp-auth 0.34.1-feature.SSISDK.57.uni.client.206 → 0.34.1-feature.SSISDK.58.host.nonce.endpoint.194
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 +57 -84
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -10
- package/dist/index.d.ts +14 -10
- package/dist/index.js +57 -84
- package/dist/index.js.map +1 -1
- package/package.json +14 -14
- package/src/RPInstance.ts +26 -7
- package/src/agent/SIOPv2RP.ts +24 -55
- package/src/functions.ts +41 -40
- package/src/types/ISIOPv2RP.ts +6 -5
package/src/agent/SIOPv2RP.ts
CHANGED
|
@@ -5,12 +5,10 @@ import {
|
|
|
5
5
|
AuthorizationResponseStateStatus,
|
|
6
6
|
AuthorizationResponseStateWithVerifiedData,
|
|
7
7
|
decodeUriAsJson,
|
|
8
|
-
VerifiedAuthorizationResponse
|
|
8
|
+
VerifiedAuthorizationResponse
|
|
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'
|
|
13
|
-
|
|
14
12
|
import type { ImportDcqlQueryItem } from '@sphereon/ssi-sdk.pd-manager'
|
|
15
13
|
import {
|
|
16
14
|
AdditionalClaims,
|
|
@@ -88,11 +86,7 @@ export class SIOPv2RP implements IAgentPlugin {
|
|
|
88
86
|
|
|
89
87
|
private async createAuthorizationRequestURI(createArgs: ICreateAuthRequestArgs, context: IRequiredContext): Promise<string> {
|
|
90
88
|
return await this.getRPInstance(
|
|
91
|
-
{
|
|
92
|
-
createWhenNotPresent: true,
|
|
93
|
-
responseRedirectURI: createArgs.responseRedirectURI,
|
|
94
|
-
...(createArgs.useQueryIdInstance === true && { queryId: createArgs.queryId }),
|
|
95
|
-
},
|
|
89
|
+
{ responseRedirectURI: createArgs.responseRedirectURI, ...(createArgs.useQueryIdInstance === true && { queryId: createArgs.queryId } ) },
|
|
96
90
|
context,
|
|
97
91
|
)
|
|
98
92
|
.then((rp) => rp.createAuthorizationRequestURI(createArgs, context))
|
|
@@ -103,7 +97,7 @@ export class SIOPv2RP implements IAgentPlugin {
|
|
|
103
97
|
createArgs: ICreateAuthRequestArgs,
|
|
104
98
|
context: IRequiredContext,
|
|
105
99
|
): Promise<IAuthorizationRequestPayloads> {
|
|
106
|
-
return await this.getRPInstance({
|
|
100
|
+
return await this.getRPInstance({ queryId: createArgs.queryId }, context)
|
|
107
101
|
.then((rp) => rp.createAuthorizationRequest(createArgs, context))
|
|
108
102
|
.then(async (request) => {
|
|
109
103
|
const authRequest: IAuthorizationRequestPayloads = {
|
|
@@ -116,8 +110,10 @@ export class SIOPv2RP implements IAgentPlugin {
|
|
|
116
110
|
}
|
|
117
111
|
|
|
118
112
|
private async siopGetRequestState(args: IGetAuthRequestStateArgs, context: IRequiredContext): Promise<AuthorizationRequestState | undefined> {
|
|
119
|
-
return await this.getRPInstance({
|
|
120
|
-
rp.get(context).then((rp) =>
|
|
113
|
+
return await this.getRPInstance({ queryId: args.queryId }, context).then((rp) =>
|
|
114
|
+
rp.get(context).then((rp) =>
|
|
115
|
+
rp.sessionManager.getRequestStateByCorrelationId(args.correlationId, args.errorOnNotFound)
|
|
116
|
+
),
|
|
121
117
|
)
|
|
122
118
|
}
|
|
123
119
|
|
|
@@ -125,7 +121,7 @@ export class SIOPv2RP implements IAgentPlugin {
|
|
|
125
121
|
args: IGetAuthResponseStateArgs,
|
|
126
122
|
context: IRequiredContext,
|
|
127
123
|
): Promise<AuthorizationResponseStateWithVerifiedData | undefined> {
|
|
128
|
-
const rpInstance: RPInstance = await this.getRPInstance({
|
|
124
|
+
const rpInstance: RPInstance = await this.getRPInstance({ queryId: args.queryId }, context)
|
|
129
125
|
const authorizationResponseState: AuthorizationResponseState | undefined = await rpInstance
|
|
130
126
|
.get(context)
|
|
131
127
|
.then((rp) => rp.sessionManager.getResponseStateByCorrelationId(args.correlationId, args.errorOnNotFound))
|
|
@@ -205,7 +201,7 @@ export class SIOPv2RP implements IAgentPlugin {
|
|
|
205
201
|
if (args.state !== 'authorization_request_created') {
|
|
206
202
|
throw Error(`Only 'authorization_request_created' status is supported for this method at this point`)
|
|
207
203
|
}
|
|
208
|
-
return await this.getRPInstance({
|
|
204
|
+
return await this.getRPInstance({ queryId: args.queryId }, context)
|
|
209
205
|
// todo: In the SIOP library we need to update the signal method to be more like this method
|
|
210
206
|
.then((rp) =>
|
|
211
207
|
rp.get(context).then(async (rp) => {
|
|
@@ -219,7 +215,7 @@ export class SIOPv2RP implements IAgentPlugin {
|
|
|
219
215
|
}
|
|
220
216
|
|
|
221
217
|
private async siopDeleteState(args: IGetAuthResponseStateArgs, context: IRequiredContext): Promise<boolean> {
|
|
222
|
-
return await this.getRPInstance({
|
|
218
|
+
return await this.getRPInstance({ queryId: args.queryId }, context)
|
|
223
219
|
.then((rp) => rp.get(context).then((rp) => rp.sessionManager.deleteStateForCorrelationId(args.correlationId)))
|
|
224
220
|
.then(() => true)
|
|
225
221
|
}
|
|
@@ -232,12 +228,12 @@ export class SIOPv2RP implements IAgentPlugin {
|
|
|
232
228
|
typeof args.authorizationResponse === 'string'
|
|
233
229
|
? (decodeUriAsJson(args.authorizationResponse) as AuthorizationResponsePayload)
|
|
234
230
|
: args.authorizationResponse
|
|
235
|
-
return await this.getRPInstance({
|
|
231
|
+
return await this.getRPInstance({ queryId: args.queryId }, context).then((rp) =>
|
|
236
232
|
rp.get(context).then((rp) =>
|
|
237
233
|
rp.verifyAuthorizationResponse(authResponse, {
|
|
238
234
|
correlationId: args.correlationId,
|
|
239
|
-
|
|
240
|
-
|
|
235
|
+
...(args.dcqlQuery ? { dcqlQuery: args.dcqlQuery } : {}),
|
|
236
|
+
audience: args.audience,
|
|
241
237
|
}),
|
|
242
238
|
),
|
|
243
239
|
)
|
|
@@ -279,36 +275,9 @@ export class SIOPv2RP implements IAgentPlugin {
|
|
|
279
275
|
return undefined
|
|
280
276
|
}
|
|
281
277
|
|
|
282
|
-
async getRPInstance({
|
|
283
|
-
|
|
284
|
-
|
|
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
|
-
}
|
|
278
|
+
async getRPInstance({ queryId, responseRedirectURI }: ISiopRPInstanceArgs, context: IRequiredContext): Promise<RPInstance> {
|
|
279
|
+
const instanceId = queryId ?? SIOPv2RP._DEFAULT_OPTS_KEY
|
|
280
|
+
if (!this.instances.has(instanceId)) {
|
|
312
281
|
const instanceOpts = this.getInstanceOpts(queryId)
|
|
313
282
|
const rpOpts = await this.getRPOptions(context, { queryId, responseRedirectURI: responseRedirectURI })
|
|
314
283
|
if (!rpOpts.identifierOpts.resolveOpts?.resolver || typeof rpOpts.identifierOpts.resolveOpts.resolver.resolve !== 'function') {
|
|
@@ -323,9 +292,9 @@ export class SIOPv2RP implements IAgentPlugin {
|
|
|
323
292
|
resolverResolution: true,
|
|
324
293
|
})
|
|
325
294
|
}
|
|
326
|
-
|
|
327
|
-
this.instances.set(rpInstanceId, rpInstance)
|
|
295
|
+
this.instances.set(instanceId, new RPInstance({ rpOpts, pexOpts: instanceOpts }))
|
|
328
296
|
}
|
|
297
|
+
const rpInstance = this.instances.get(instanceId)!
|
|
329
298
|
if (responseRedirectURI) {
|
|
330
299
|
rpInstance.rpOptions.responseRedirectUri = responseRedirectURI
|
|
331
300
|
}
|
|
@@ -367,22 +336,22 @@ export class SIOPv2RP implements IAgentPlugin {
|
|
|
367
336
|
return options
|
|
368
337
|
}
|
|
369
338
|
|
|
370
|
-
getInstanceOpts(
|
|
339
|
+
getInstanceOpts(definitionId?: string): IPEXInstanceOptions | undefined {
|
|
371
340
|
if (!this.opts.instanceOpts) return undefined
|
|
372
341
|
|
|
373
|
-
const instanceOpt =
|
|
342
|
+
const instanceOpt = definitionId ? this.opts.instanceOpts.find((i) => i.queryId === definitionId) : undefined
|
|
374
343
|
|
|
375
|
-
return instanceOpt ?? this.getDefaultOptions(
|
|
344
|
+
return instanceOpt ?? this.getDefaultOptions(definitionId)
|
|
376
345
|
}
|
|
377
346
|
|
|
378
|
-
private getDefaultOptions(
|
|
347
|
+
private getDefaultOptions(definitionId: string | undefined) {
|
|
379
348
|
if (!this.opts.instanceOpts) return undefined
|
|
380
349
|
|
|
381
350
|
const defaultOptions = this.opts.instanceOpts.find((i) => i.queryId === 'default')
|
|
382
351
|
if (defaultOptions) {
|
|
383
352
|
const clonedOptions = { ...defaultOptions }
|
|
384
|
-
if (
|
|
385
|
-
clonedOptions.queryId =
|
|
353
|
+
if (definitionId !== undefined) {
|
|
354
|
+
clonedOptions.queryId = definitionId
|
|
386
355
|
}
|
|
387
356
|
return clonedOptions
|
|
388
357
|
}
|
package/src/functions.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ClientIdentifierPrefix,
|
|
3
3
|
ClientMetadataOpts,
|
|
4
|
-
DcqlQueryLookupCallback,
|
|
5
4
|
InMemoryRPSessionManager,
|
|
6
5
|
PassBy,
|
|
7
6
|
PresentationVerificationCallback,
|
|
@@ -15,7 +14,7 @@ import {
|
|
|
15
14
|
Scope,
|
|
16
15
|
SubjectType,
|
|
17
16
|
SupportedVersion,
|
|
18
|
-
VerifyJwtCallback
|
|
17
|
+
VerifyJwtCallback
|
|
19
18
|
} from '@sphereon/did-auth-siop'
|
|
20
19
|
import { CreateJwtCallback, JwtHeader, JwtIssuer, JwtPayload, SigningAlgo } from '@sphereon/oid4vc-common'
|
|
21
20
|
import { IPresentationDefinition } from '@sphereon/pex'
|
|
@@ -35,7 +34,7 @@ import { TKeyType } from '@veramo/core'
|
|
|
35
34
|
import { JWTVerifyOptions } from 'did-jwt'
|
|
36
35
|
import { Resolvable } from 'did-resolver'
|
|
37
36
|
import { EventEmitter } from 'events'
|
|
38
|
-
import { IRequiredContext, IRPOptions, ISIOPIdentifierOptions } from './types/ISIOPv2RP'
|
|
37
|
+
import { IPEXOptions, IRequiredContext, IRPOptions, ISIOPIdentifierOptions } from './types/ISIOPv2RP'
|
|
39
38
|
import { DcqlQuery } from 'dcql'
|
|
40
39
|
import { defaultHasher } from '@sphereon/ssi-sdk.core'
|
|
41
40
|
|
|
@@ -43,7 +42,7 @@ export function getRequestVersion(rpOptions: IRPOptions): SupportedVersion {
|
|
|
43
42
|
if (Array.isArray(rpOptions.supportedVersions) && rpOptions.supportedVersions.length > 0) {
|
|
44
43
|
return rpOptions.supportedVersions[0]
|
|
45
44
|
}
|
|
46
|
-
return SupportedVersion.
|
|
45
|
+
return SupportedVersion.JWT_VC_PRESENTATION_PROFILE_v1
|
|
47
46
|
}
|
|
48
47
|
|
|
49
48
|
function getWellKnownDIDVerifyCallback(siopIdentifierOpts: ISIOPIdentifierOptions, context: IRequiredContext) {
|
|
@@ -58,31 +57,6 @@ function getWellKnownDIDVerifyCallback(siopIdentifierOpts: ISIOPIdentifierOption
|
|
|
58
57
|
}
|
|
59
58
|
}
|
|
60
59
|
|
|
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
|
-
|
|
86
60
|
export function getPresentationVerificationCallback(
|
|
87
61
|
idOpts: ManagedIdentifierOptsOrResult,
|
|
88
62
|
context: IRequiredContext,
|
|
@@ -127,11 +101,34 @@ export function getPresentationVerificationCallback(
|
|
|
127
101
|
|
|
128
102
|
export async function createRPBuilder(args: {
|
|
129
103
|
rpOpts: IRPOptions
|
|
104
|
+
pexOpts?: IPEXOptions | undefined
|
|
130
105
|
definition?: IPresentationDefinition
|
|
106
|
+
dcql?: DcqlQuery
|
|
131
107
|
context: IRequiredContext
|
|
132
108
|
}): Promise<RPBuilder> {
|
|
133
|
-
const { rpOpts, context } = args
|
|
109
|
+
const { rpOpts, pexOpts, context } = args
|
|
134
110
|
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 && presentationDefinitionItem.dcqlPayload) {
|
|
128
|
+
dcqlQuery = presentationDefinitionItem.dcqlPayload.dcqlQuery as DcqlQuery // cast from DcqlQueryREST back to valibot DcqlQuery
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
135
132
|
|
|
136
133
|
const didMethods = identifierOpts.supportedDIDMethods ?? (await getAgentDIDMethods(context))
|
|
137
134
|
const eventEmitter = rpOpts.eventEmitter ?? new EventEmitter()
|
|
@@ -171,7 +168,9 @@ export async function createRPBuilder(args: {
|
|
|
171
168
|
.withResponseMode(rpOpts.responseMode ?? ResponseMode.POST)
|
|
172
169
|
.withResponseType(ResponseType.VP_TOKEN, PropertyTarget.REQUEST_OBJECT)
|
|
173
170
|
// todo: move to options fill/correct method
|
|
174
|
-
.withSupportedVersions(
|
|
171
|
+
.withSupportedVersions(
|
|
172
|
+
rpOpts.supportedVersions ?? [SupportedVersion.JWT_VC_PRESENTATION_PROFILE_v1, SupportedVersion.SIOPv2_ID1, SupportedVersion.SIOPv2_D11],
|
|
173
|
+
)
|
|
175
174
|
|
|
176
175
|
.withEventEmitter(eventEmitter)
|
|
177
176
|
.withSessionManager(rpOpts.sessionManager ?? new InMemoryRPSessionManager(eventEmitter))
|
|
@@ -190,7 +189,6 @@ export async function createRPBuilder(args: {
|
|
|
190
189
|
context,
|
|
191
190
|
),
|
|
192
191
|
)
|
|
193
|
-
.withDcqlQueryLookup(getDcqlQueryLookupCallback(context))
|
|
194
192
|
.withRevocationVerification(RevocationVerification.NEVER)
|
|
195
193
|
.withPresentationVerification(getPresentationVerificationCallback(identifierOpts.idOpts, context))
|
|
196
194
|
|
|
@@ -199,12 +197,11 @@ export async function createRPBuilder(args: {
|
|
|
199
197
|
builder.withEntityId(oidfOpts.identifier, PropertyTarget.REQUEST_OBJECT)
|
|
200
198
|
} else {
|
|
201
199
|
const resolution = await context.agent.identifierManagedGet(identifierOpts.idOpts)
|
|
202
|
-
const clientId: string =
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
builder.withClientId(clientIdPrefixed, PropertyTarget.REQUEST_OBJECT)
|
|
200
|
+
const clientId: string = rpOpts.clientMetadataOpts?.client_id ??
|
|
201
|
+
resolution.issuer ?? (isManagedIdentifierDidResult(resolution) ? resolution.did : resolution.jwkThumbprint)
|
|
202
|
+
const clientIdPrefixed = prefixClientId(clientId)
|
|
203
|
+
builder.withClientId(clientIdPrefixed, PropertyTarget.REQUEST_OBJECT
|
|
204
|
+
)
|
|
208
205
|
}
|
|
209
206
|
|
|
210
207
|
if (hasher) {
|
|
@@ -218,6 +215,10 @@ export async function createRPBuilder(args: {
|
|
|
218
215
|
//fixme: this has been removed in the new version of did-auth-siop
|
|
219
216
|
// builder.withWellknownDIDVerifyCallback(getWellKnownDIDVerifyCallback(didOpts, context))
|
|
220
217
|
|
|
218
|
+
if (dcqlQuery) {
|
|
219
|
+
builder.withDcqlQuery(dcqlQuery)
|
|
220
|
+
}
|
|
221
|
+
|
|
221
222
|
if (rpOpts.responseRedirectUri) {
|
|
222
223
|
builder.withResponseRedirectUri(rpOpts.responseRedirectUri)
|
|
223
224
|
}
|
|
@@ -302,8 +303,8 @@ export function getSigningAlgo(type: TKeyType): SigningAlgo {
|
|
|
302
303
|
export function prefixClientId(clientId: string): string {
|
|
303
304
|
// FIXME SSISDK-60
|
|
304
305
|
if (clientId.startsWith('did:')) {
|
|
305
|
-
return `${ClientIdentifierPrefix.DECENTRALIZED_IDENTIFIER}:${clientId}
|
|
306
|
+
return `${ClientIdentifierPrefix.DECENTRALIZED_IDENTIFIER}:${clientId}`;
|
|
306
307
|
}
|
|
307
308
|
|
|
308
|
-
return clientId
|
|
309
|
+
return clientId;
|
|
309
310
|
}
|
package/src/types/ISIOPv2RP.ts
CHANGED
|
@@ -32,7 +32,6 @@ import { HasherSync } from '@sphereon/ssi-types'
|
|
|
32
32
|
import { VerifyCallback } from '@sphereon/wellknown-dids-client'
|
|
33
33
|
import { IAgentContext, ICredentialVerifier, IDIDManager, IKeyManager, IPluginMethodMap, IResolver } from '@veramo/core'
|
|
34
34
|
import { DcqlQuery } from 'dcql'
|
|
35
|
-
|
|
36
35
|
import { Resolvable } from 'did-resolver'
|
|
37
36
|
import { EventEmitter } from 'events'
|
|
38
37
|
|
|
@@ -137,12 +136,11 @@ export interface IPEXDefinitionPersistArgs extends IPEXInstanceOptions {
|
|
|
137
136
|
}
|
|
138
137
|
|
|
139
138
|
export interface ISiopRPInstanceArgs {
|
|
140
|
-
createWhenNotPresent: boolean
|
|
141
139
|
queryId?: string
|
|
142
140
|
responseRedirectURI?: string
|
|
143
141
|
}
|
|
144
142
|
|
|
145
|
-
export interface IPEXInstanceOptions extends
|
|
143
|
+
export interface IPEXInstanceOptions extends IPEXOptions {
|
|
146
144
|
rpOpts?: IRPOptions
|
|
147
145
|
}
|
|
148
146
|
|
|
@@ -160,9 +158,12 @@ export interface IRPOptions {
|
|
|
160
158
|
responseRedirectUri?: string
|
|
161
159
|
}
|
|
162
160
|
|
|
163
|
-
export interface
|
|
164
|
-
queryId: string
|
|
161
|
+
export interface IPEXOptions {
|
|
165
162
|
presentationVerifyCallback?: PresentationVerificationCallback
|
|
163
|
+
// definition?: IPresentationDefinition
|
|
164
|
+
queryId: string
|
|
165
|
+
version?: string
|
|
166
|
+
tenantId?: string
|
|
166
167
|
}
|
|
167
168
|
|
|
168
169
|
export type VerificationPolicies = {
|