@sphereon/ssi-sdk.oid4vci-issuer 0.32.1-next.18 → 0.32.1-next.287
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/IssuerInstance.d.ts +4 -5
- package/dist/IssuerInstance.d.ts.map +1 -1
- package/dist/IssuerInstance.js +3 -0
- package/dist/IssuerInstance.js.map +1 -1
- package/dist/agent/OID4VCIIssuer.d.ts +3 -2
- package/dist/agent/OID4VCIIssuer.d.ts.map +1 -1
- package/dist/agent/OID4VCIIssuer.js +30 -7
- package/dist/agent/OID4VCIIssuer.js.map +1 -1
- package/dist/functions.d.ts +12 -5
- package/dist/functions.d.ts.map +1 -1
- package/dist/functions.js +110 -13
- package/dist/functions.js.map +1 -1
- package/dist/state-manager/TypeOrmStateManager.d.ts +1 -0
- package/dist/state-manager/TypeOrmStateManager.d.ts.map +1 -0
- package/dist/state-manager/TypeOrmStateManager.js +2 -0
- package/dist/state-manager/TypeOrmStateManager.js.map +1 -0
- package/dist/state-manager/oid4vcState/IAbstractMachineStateStore.d.ts +39 -0
- package/dist/state-manager/oid4vcState/IAbstractMachineStateStore.d.ts.map +1 -0
- package/dist/state-manager/oid4vcState/IAbstractMachineStateStore.js +3 -0
- package/dist/state-manager/oid4vcState/IAbstractMachineStateStore.js.map +1 -0
- package/dist/state-manager/oid4vcState/MachineStateStore.d.ts +1 -0
- package/dist/state-manager/oid4vcState/MachineStateStore.d.ts.map +1 -0
- package/dist/state-manager/oid4vcState/MachineStateStore.js +137 -0
- package/dist/state-manager/oid4vcState/MachineStateStore.js.map +1 -0
- package/dist/types/IOID4VCIIssuer.d.ts +14 -2
- package/dist/types/IOID4VCIIssuer.d.ts.map +1 -1
- package/package.json +19 -15
- package/src/IssuerInstance.ts +8 -7
- package/src/agent/OID4VCIIssuer.ts +49 -13
- package/src/functions.ts +126 -19
- package/src/state-manager/TypeOrmStateManager.ts +0 -0
- package/src/state-manager/oid4vcState/IAbstractMachineStateStore.ts +51 -0
- package/src/state-manager/oid4vcState/MachineStateStore.ts +135 -0
- package/src/types/IOID4VCIIssuer.ts +22 -1
package/src/functions.ts
CHANGED
|
@@ -3,10 +3,12 @@ import {
|
|
|
3
3
|
CredentialRequest,
|
|
4
4
|
IssuerMetadata,
|
|
5
5
|
Jwt,
|
|
6
|
+
JWTHeader,
|
|
7
|
+
JWTPayload,
|
|
6
8
|
JwtVerifyResult,
|
|
7
9
|
OID4VCICredentialFormat,
|
|
10
|
+
StatusListOpts,
|
|
8
11
|
} from '@sphereon/oid4vci-common'
|
|
9
|
-
import { JWTHeader, JWTPayload } from '@sphereon/oid4vci-common/lib/types'
|
|
10
12
|
import { CredentialDataSupplier, CredentialIssuanceInput, CredentialSignerCallback, VcIssuer, VcIssuerBuilder } from '@sphereon/oid4vci-issuer'
|
|
11
13
|
import { getAgentResolver, IDIDOptions } from '@sphereon/ssi-sdk-ext.did-utils'
|
|
12
14
|
import { legacyKeyRefsToIdentifierOpts, ManagedIdentifierOptsOrResult } from '@sphereon/ssi-sdk-ext.identifier-resolution'
|
|
@@ -14,15 +16,17 @@ import { contextHasPlugin } from '@sphereon/ssi-sdk.agent-config'
|
|
|
14
16
|
import { SdJwtVcPayload } from '@sphereon/ssi-sdk.sd-jwt/dist'
|
|
15
17
|
import { IStatusListPlugin } from '@sphereon/ssi-sdk.vc-status-list'
|
|
16
18
|
import { CompactSdJwtVc, CredentialMapper, ICredential, W3CVerifiableCredential } from '@sphereon/ssi-types'
|
|
17
|
-
import { CredentialPayload,
|
|
19
|
+
import { CredentialPayload, ProofFormat } from '@veramo/core'
|
|
18
20
|
import { bytesToBase64 } from '@veramo/utils'
|
|
19
21
|
import { createJWT, decodeJWT, JWTVerifyOptions, verifyJWT } from 'did-jwt'
|
|
20
22
|
import { Resolvable } from 'did-resolver'
|
|
21
23
|
import { jwtDecode } from 'jwt-decode'
|
|
22
24
|
import { IIssuerOptions, IRequiredContext } from './types/IOID4VCIIssuer'
|
|
25
|
+
import fetch from 'cross-fetch'
|
|
26
|
+
import { AuthorizationResponseStateStatus } from '@sphereon/did-auth-siop'
|
|
23
27
|
|
|
24
28
|
export function getJwtVerifyCallback({ verifyOpts }: { verifyOpts?: JWTVerifyOptions }, _context: IRequiredContext) {
|
|
25
|
-
return async (args: { jwt: string; kid?: string }): Promise<JwtVerifyResult
|
|
29
|
+
return async (args: { jwt: string; kid?: string }): Promise<JwtVerifyResult> => {
|
|
26
30
|
const resolver = getAgentResolver(_context, {
|
|
27
31
|
resolverResolution: true,
|
|
28
32
|
uniresolverResolution: true,
|
|
@@ -43,17 +47,18 @@ export function getJwtVerifyCallback({ verifyOpts }: { verifyOpts?: JWTVerifyOpt
|
|
|
43
47
|
return Promise.reject(Error(`the identifier of type ${identifier.method} is missing jwks (ExternalJwkInfo)`))
|
|
44
48
|
}
|
|
45
49
|
const { alg } = jwkInfo.jwk
|
|
46
|
-
if (!alg) {
|
|
47
|
-
return Promise.reject(Error(`the ExternalJwkInfo of identifier of type ${identifier.method} is missing alg in its jwk`))
|
|
48
|
-
}
|
|
49
|
-
|
|
50
50
|
const header = jwtDecode<JWTHeader>(args.jwt, { header: true })
|
|
51
51
|
const payload = jwtDecode<JWTPayload>(args.jwt, { header: false })
|
|
52
|
+
const kid = args.kid ?? header.kid
|
|
53
|
+
//const jwk = !kid ? jwkInfo.jwk : undefined // TODO double-check if this is correct
|
|
54
|
+
const jwk = jwkInfo.jwk // FIXME workaround IATAB2B-57
|
|
52
55
|
return {
|
|
53
56
|
alg,
|
|
54
57
|
...identifier,
|
|
55
58
|
jwt: { header, payload },
|
|
56
|
-
|
|
59
|
+
...(kid && { kid }),
|
|
60
|
+
...(jwk && { jwk }),
|
|
61
|
+
} as JwtVerifyResult
|
|
57
62
|
}
|
|
58
63
|
|
|
59
64
|
const decodedJwt = (await decodeJWT(args.jwt)) as Jwt
|
|
@@ -64,7 +69,7 @@ export function getJwtVerifyCallback({ verifyOpts }: { verifyOpts?: JWTVerifyOpt
|
|
|
64
69
|
return {
|
|
65
70
|
alg: decodedJwt.header.alg,
|
|
66
71
|
jwt: decodedJwt,
|
|
67
|
-
} as JwtVerifyResult
|
|
72
|
+
} as JwtVerifyResult
|
|
68
73
|
}
|
|
69
74
|
const did = kid.split('#')[0]
|
|
70
75
|
|
|
@@ -155,11 +160,25 @@ export async function getAccessTokenSignerCallback(
|
|
|
155
160
|
}
|
|
156
161
|
|
|
157
162
|
async function accessTokenSignerCallback(jwt: Jwt, kid?: string): Promise<string> {
|
|
158
|
-
const issuer =
|
|
163
|
+
const issuer =
|
|
164
|
+
opts.idOpts?.issuer ??
|
|
165
|
+
(typeof opts.idOpts?.identifier === 'string' ? opts.idOpts.identifier : (opts.didOpts?.idOpts?.identifier?.toString() ?? opts?.iss))
|
|
159
166
|
if (!issuer) {
|
|
160
167
|
throw Error('No issuer configured for access tokens')
|
|
161
168
|
}
|
|
162
|
-
|
|
169
|
+
|
|
170
|
+
let kidHeader: string | undefined = jwt?.header?.kid ?? kid
|
|
171
|
+
if (!kidHeader) {
|
|
172
|
+
if (
|
|
173
|
+
opts.idOpts?.method === 'did' ||
|
|
174
|
+
opts.idOpts?.method === 'kid' ||
|
|
175
|
+
(typeof opts.didOpts?.idOpts.identifier === 'string' && opts.didOpts?.idOpts?.identifier?.startsWith('did:'))
|
|
176
|
+
) {
|
|
177
|
+
// @ts-ignore
|
|
178
|
+
kidHeader = opts.idOpts?.kid ?? opts.didOpts?.idOpts?.kid ?? opts?.didOpts?.identifierOpts?.kid
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return await createJWT(jwt.payload, { signer, issuer }, { ...jwt.header, ...(kidHeader && { kid: kidHeader }), typ: 'JWT' })
|
|
163
182
|
}
|
|
164
183
|
|
|
165
184
|
return accessTokenSignerCallback
|
|
@@ -170,14 +189,15 @@ export async function getCredentialSignerCallback(
|
|
|
170
189
|
crypto?: Crypto
|
|
171
190
|
},
|
|
172
191
|
context: IRequiredContext,
|
|
173
|
-
): Promise<CredentialSignerCallback
|
|
192
|
+
): Promise<CredentialSignerCallback> {
|
|
174
193
|
async function issueVCCallback(args: {
|
|
175
194
|
credentialRequest: CredentialRequest
|
|
176
195
|
credential: CredentialIssuanceInput
|
|
177
|
-
jwtVerifyResult: JwtVerifyResult
|
|
196
|
+
jwtVerifyResult: JwtVerifyResult
|
|
178
197
|
format?: OID4VCICredentialFormat
|
|
198
|
+
statusLists?: Array<StatusListOpts>
|
|
179
199
|
}): Promise<W3CVerifiableCredential | CompactSdJwtVc> {
|
|
180
|
-
const { jwtVerifyResult, format } = args
|
|
200
|
+
const { jwtVerifyResult, format, statusLists } = args
|
|
181
201
|
const credential = args.credential as ICredential // TODO: SDJWT
|
|
182
202
|
let proofFormat: ProofFormat
|
|
183
203
|
|
|
@@ -204,9 +224,10 @@ export async function getCredentialSignerCallback(
|
|
|
204
224
|
// TODO: We should extend the plugin capabilities of issuance so we do not have to tuck this into the sign callback
|
|
205
225
|
if (contextHasPlugin<IStatusListPlugin>(context, 'slAddStatusToCredential')) {
|
|
206
226
|
// Add status list if enabled (and when the input has a credentialStatus object (can be empty))
|
|
207
|
-
const credentialStatusVC = await context.agent.slAddStatusToCredential({ credential })
|
|
227
|
+
const credentialStatusVC = await context.agent.slAddStatusToCredential({ credential, statusLists })
|
|
208
228
|
if (credential.credentialStatus && !credential.credentialStatus.statusListCredential) {
|
|
209
229
|
credential.credentialStatus = credentialStatusVC.credentialStatus
|
|
230
|
+
// TODO update statusLists somehow?
|
|
210
231
|
}
|
|
211
232
|
}
|
|
212
233
|
|
|
@@ -237,6 +258,28 @@ export async function getCredentialSignerCallback(
|
|
|
237
258
|
_sd: credential['_sd'],
|
|
238
259
|
}
|
|
239
260
|
}
|
|
261
|
+
|
|
262
|
+
if (contextHasPlugin<IStatusListPlugin>(context, 'slAddStatusToSdJwtCredential')) {
|
|
263
|
+
if ((sdJwtPayload.status && sdJwtPayload.status.status_list) || (statusLists && statusLists.length > 0)) {
|
|
264
|
+
// Add status list if enabled (and when the input has a credentialStatus object (can be empty))
|
|
265
|
+
const sdJwtPayloadWithStatus = await context.agent.slAddStatusToSdJwtCredential({ credential: sdJwtPayload, statusLists })
|
|
266
|
+
if (sdJwtPayload.status?.status_list?.idx) {
|
|
267
|
+
if (!sdJwtPayloadWithStatus.status || !sdJwtPayloadWithStatus.status.status_list) {
|
|
268
|
+
// sdJwtPayload and sdJwtPayloadWithStatus is the same for now, but we should use the result anyway as this could be subject to change
|
|
269
|
+
return Promise.reject(Error('slAddStatusToSdJwtCredential did not return a status_list'))
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Update statusListId & statusListIndex back to the credential session TODO SSISDK-4 This is not a clean way to do this.
|
|
273
|
+
if (statusLists && statusLists.length > 0) {
|
|
274
|
+
const statusList = statusLists[0]
|
|
275
|
+
statusList.statusListId = sdJwtPayloadWithStatus.status.status_list.uri
|
|
276
|
+
statusList.statusListIndex = sdJwtPayloadWithStatus.status.status_list.idx
|
|
277
|
+
}
|
|
278
|
+
sdJwtPayload.status.status_list.idx = sdJwtPayloadWithStatus.status.status_list.idx
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
240
283
|
const result = await context.agent.createSdJwtVc({
|
|
241
284
|
credentialPayload: sdJwtPayload,
|
|
242
285
|
disclosureFrame: disclosureFrame,
|
|
@@ -261,10 +304,10 @@ export async function createVciIssuerBuilder(
|
|
|
261
304
|
credentialDataSupplier?: CredentialDataSupplier
|
|
262
305
|
},
|
|
263
306
|
context: IRequiredContext,
|
|
264
|
-
): Promise<VcIssuerBuilder
|
|
307
|
+
): Promise<VcIssuerBuilder> {
|
|
265
308
|
const { issuerOpts, issuerMetadata, authorizationServerMetadata } = args
|
|
266
309
|
|
|
267
|
-
const builder = new VcIssuerBuilder
|
|
310
|
+
const builder = new VcIssuerBuilder()
|
|
268
311
|
// @ts-ignore
|
|
269
312
|
const resolver =
|
|
270
313
|
args.resolver ??
|
|
@@ -285,14 +328,23 @@ export async function createVciIssuerBuilder(
|
|
|
285
328
|
builder.withAuthorizationMetadata(authorizationServerMetadata)
|
|
286
329
|
// builder.withUserPinRequired(issuerOpts.userPinRequired ?? false) was removed from implementers draft v1
|
|
287
330
|
builder.withCredentialSignerCallback(await getCredentialSignerCallback(idOpts, context))
|
|
331
|
+
|
|
332
|
+
if (issuerOpts.asClientOpts) {
|
|
333
|
+
builder.withASClientMetadata(issuerOpts.asClientOpts)
|
|
334
|
+
// @ts-ignore
|
|
335
|
+
// const authorizationServer = issuerMetadata.authorization_servers[0] as string
|
|
336
|
+
// Set the OIDC verifier
|
|
337
|
+
// builder.withJWTVerifyCallback(oidcAccessTokenVerifyCallback({clientMetadata: issuerOpts.asClientOpts, credentialIssuer: issuerMetadata.credential_issuer as string, authorizationServer}))
|
|
338
|
+
}
|
|
339
|
+
// Do not use it when asClient is used
|
|
288
340
|
builder.withJWTVerifyCallback(getJwtVerifyCallback({ verifyOpts: jwtVerifyOpts }, context))
|
|
341
|
+
|
|
289
342
|
if (args.credentialDataSupplier) {
|
|
290
343
|
builder.withCredentialDataSupplier(args.credentialDataSupplier)
|
|
291
344
|
}
|
|
292
345
|
builder.withInMemoryCNonceState()
|
|
293
346
|
builder.withInMemoryCredentialOfferState()
|
|
294
347
|
builder.withInMemoryCredentialOfferURIState()
|
|
295
|
-
builder.build()
|
|
296
348
|
|
|
297
349
|
return builder
|
|
298
350
|
}
|
|
@@ -310,7 +362,7 @@ export async function createVciIssuer(
|
|
|
310
362
|
credentialDataSupplier?: CredentialDataSupplier
|
|
311
363
|
},
|
|
312
364
|
context: IRequiredContext,
|
|
313
|
-
): Promise<VcIssuer
|
|
365
|
+
): Promise<VcIssuer> {
|
|
314
366
|
return (
|
|
315
367
|
await createVciIssuerBuilder(
|
|
316
368
|
{
|
|
@@ -323,3 +375,58 @@ export async function createVciIssuer(
|
|
|
323
375
|
)
|
|
324
376
|
).build()
|
|
325
377
|
}
|
|
378
|
+
|
|
379
|
+
export async function createAuthRequestUriCallback(opts: { path: string; presentationDefinitionId: string }): Promise<() => Promise<string>> {
|
|
380
|
+
async function authRequestUriCallback(): Promise<string> {
|
|
381
|
+
const path = opts.path.replace(':definitionId', opts.presentationDefinitionId)
|
|
382
|
+
return fetch(path, {
|
|
383
|
+
method: 'POST',
|
|
384
|
+
headers: {
|
|
385
|
+
'Content-Type': 'application/json',
|
|
386
|
+
},
|
|
387
|
+
}).then(async (response): Promise<string> => {
|
|
388
|
+
if (response.status >= 400) {
|
|
389
|
+
return Promise.reject(Error(await response.text()))
|
|
390
|
+
} else {
|
|
391
|
+
const responseData = await response.json()
|
|
392
|
+
|
|
393
|
+
if (!responseData.authRequestURI) {
|
|
394
|
+
return Promise.reject(Error('Missing auth request uri in response body'))
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return responseData.authRequestURI
|
|
398
|
+
}
|
|
399
|
+
})
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return authRequestUriCallback
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
export async function createVerifyAuthResponseCallback(opts: {
|
|
406
|
+
path: string
|
|
407
|
+
presentationDefinitionId: string
|
|
408
|
+
}): Promise<(correlationId: string) => Promise<boolean>> {
|
|
409
|
+
async function verifyAuthResponseCallback(correlationId: string): Promise<boolean> {
|
|
410
|
+
return fetch(opts.path, {
|
|
411
|
+
method: 'POST',
|
|
412
|
+
headers: {
|
|
413
|
+
'Content-Type': 'application/json',
|
|
414
|
+
},
|
|
415
|
+
body: JSON.stringify({ definitionId: opts.presentationDefinitionId, correlationId }),
|
|
416
|
+
}).then(async (response): Promise<boolean> => {
|
|
417
|
+
if (response.status >= 400) {
|
|
418
|
+
return Promise.reject(Error(await response.text()))
|
|
419
|
+
} else {
|
|
420
|
+
const responseData = await response.json()
|
|
421
|
+
|
|
422
|
+
if (!responseData.status) {
|
|
423
|
+
return Promise.reject(Error('Missing status in response body'))
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return responseData.status === AuthorizationResponseStateStatus.VERIFIED
|
|
427
|
+
}
|
|
428
|
+
})
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
return verifyAuthResponseCallback
|
|
432
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { StateType } from '@sphereon/oid4vci-common'
|
|
2
|
+
import { Oid4vcStateEntity } from '@sphereon/ssi-sdk.data-store'
|
|
3
|
+
|
|
4
|
+
export interface IOid4vcStateStore<StateType> {
|
|
5
|
+
persistOid4vcState(args: Oid4vcStateStoreParams<StateType>): Promise<Oid4vcStatePersisted<StateType>>
|
|
6
|
+
|
|
7
|
+
findOid4vcStates(args: StoreOid4vcFindActiveArgs): Promise<Array<Oid4vcStatePersisted<StateType>>>
|
|
8
|
+
|
|
9
|
+
getOid4vcState(args: StoreOid4vcGetArgs): Promise<Oid4vcStatePersisted<StateType>>
|
|
10
|
+
|
|
11
|
+
deleteOid4vcState(args: StoreOid4vcDeleteArgs): Promise<boolean>
|
|
12
|
+
|
|
13
|
+
deleteExpiredOid4vcStates(args: StoreOid4vcDeleteExpiredArgs): Promise<number>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type StoreMachineStatePersistArgs<StateType> = Omit<Oid4vcStateStoreParams<StateType>, 'createdAt' | 'updatedAt'>
|
|
17
|
+
|
|
18
|
+
export type StoreOid4vcFindActiveArgs = Partial<Pick<Oid4vcStateStoreParams<StateType>, 'expiresAt' | 'tenantId' | 'stateId'>>
|
|
19
|
+
|
|
20
|
+
export type FindMachineStatesFilterArgs = Array<Partial<Omit<Oid4vcStateStoreParams<StateType>, 'state'>>>
|
|
21
|
+
|
|
22
|
+
export type StoreFindMachineStatesArgs = {
|
|
23
|
+
filter: FindMachineStatesFilterArgs
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type StoreOid4vcGetArgs = Pick<Oid4vcStateEntity<StateType>, 'id' | 'stateId' | 'correlationId' | 'lookups' | 'tenantId'>
|
|
27
|
+
export type Oid4vcStateStore<StateType> = Pick<Oid4vcStateEntity<StateType>, 'id' | 'stateId' | 'correlationId' | 'lookups'>
|
|
28
|
+
|
|
29
|
+
export type StoreOid4vcDeleteArgs = StoreOid4vcGetArgs
|
|
30
|
+
export type StoreOid4vcDeleteExpiredArgs = {
|
|
31
|
+
id?: string
|
|
32
|
+
correlationId?: string
|
|
33
|
+
sessionId?: string
|
|
34
|
+
lookups?: Array<string>
|
|
35
|
+
tenantId?: string
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type Oid4vcStatePersisted<StateType> = {
|
|
39
|
+
id: string
|
|
40
|
+
stateId?: string
|
|
41
|
+
correlationId?: string
|
|
42
|
+
type: string
|
|
43
|
+
state: StateType
|
|
44
|
+
lookups?: Array<string>
|
|
45
|
+
createdAt: Date
|
|
46
|
+
lastUpdatedAt: Date
|
|
47
|
+
expiresAt?: Date
|
|
48
|
+
tenantId?: string
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type Oid4vcStateStoreParams<StateType> = Omit<Oid4vcStatePersisted<StateType>, 'id'>
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// import Debug from 'debug'
|
|
2
|
+
//
|
|
3
|
+
//
|
|
4
|
+
// const debug = Debug('sphereon:ssi-sdk:machine-state:store')
|
|
5
|
+
//
|
|
6
|
+
// /**
|
|
7
|
+
// * Represents a data store for managing machine states.
|
|
8
|
+
// */
|
|
9
|
+
// export class MachineStateStore extends IAbstractMachineStateStore {
|
|
10
|
+
// private readonly _dbConnection: OrPromise<DataSource>
|
|
11
|
+
//
|
|
12
|
+
// constructor(dbConnection: OrPromise<DataSource>) {
|
|
13
|
+
// super()
|
|
14
|
+
// this._dbConnection = dbConnection
|
|
15
|
+
// }
|
|
16
|
+
// async persistMachineState(state: StoreMachineStatePersistArgs): Promise<StoreMachineStateInfo> {
|
|
17
|
+
// const connection: DataSource = await this._dbConnection
|
|
18
|
+
// const { machineName, instanceId, tenantId } = state
|
|
19
|
+
// debug(`Executing persistMachineState for machine ${machineName}, instance ${instanceId}, tenantId: ${tenantId}...`)
|
|
20
|
+
// const entity = MachineStateStore.machineStateInfoEntityFrom(state)
|
|
21
|
+
// const existing = await connection.getRepository(MachineStateInfoEntity).findOne({
|
|
22
|
+
// where: {
|
|
23
|
+
// instanceId: state.instanceId,
|
|
24
|
+
// },
|
|
25
|
+
// })
|
|
26
|
+
// if (existing && existing.updatedCount > state.updatedCount) {
|
|
27
|
+
// const error = `Updating machine state with an older version is not allowed. Machine ${existing.machineName}, last count: ${
|
|
28
|
+
// existing.updatedCount
|
|
29
|
+
// }, new count: ${existing.updatedCount}, last updated: ${existing.updatedAt}, current: ${new Date()}, instance: ${existing.instanceId}`
|
|
30
|
+
// console.log(error)
|
|
31
|
+
// return Promise.reject(new Error(error))
|
|
32
|
+
// }
|
|
33
|
+
// // No need for a transaction. This is a single entity. We don't want to be surprised by an isolation level hiding the state from others
|
|
34
|
+
// const result = await connection.getRepository(MachineStateInfoEntity).save(entity, { transaction: false })
|
|
35
|
+
// debug(`Done persistMachineState machine ${machineName}, instance ${instanceId}, tenantId: ${tenantId}`)
|
|
36
|
+
// return MachineStateStore.machineInfoFrom(result)
|
|
37
|
+
// }
|
|
38
|
+
//
|
|
39
|
+
// async findActiveMachineStates(args: StoreMachineStatesFindActiveArgs): Promise<Array<StoreMachineStateInfo>> {
|
|
40
|
+
// const { tenantId, machineName, instanceId } = args
|
|
41
|
+
// const connection: DataSource = await this._dbConnection
|
|
42
|
+
// debug(`Executing findActiveMachineStates query with machineName: ${machineName}, tenantId: ${tenantId}`)
|
|
43
|
+
// const queryBuilder = connection
|
|
44
|
+
// .getRepository(MachineStateInfoEntity)
|
|
45
|
+
// .createQueryBuilder('state')
|
|
46
|
+
// .where('state.completedAt IS NULL')
|
|
47
|
+
// .andWhere(
|
|
48
|
+
// new Brackets((qb) => {
|
|
49
|
+
// qb.where('state.expiresAt IS NULL').orWhere('state.expiresAt > :now', { now: new Date() })
|
|
50
|
+
// }),
|
|
51
|
+
// )
|
|
52
|
+
//
|
|
53
|
+
// if (instanceId) {
|
|
54
|
+
// queryBuilder.andWhere('state.instanceId = :instanceId', { instanceId })
|
|
55
|
+
// }
|
|
56
|
+
// if (tenantId) {
|
|
57
|
+
// queryBuilder.andWhere('state.tenantId = :tenantId', { tenantId })
|
|
58
|
+
// }
|
|
59
|
+
// if (machineName) {
|
|
60
|
+
// queryBuilder.andWhere('state.machineName = :machineName', { machineName })
|
|
61
|
+
// }
|
|
62
|
+
//
|
|
63
|
+
// return (
|
|
64
|
+
// (await queryBuilder
|
|
65
|
+
// .orderBy('state.updatedAt', 'DESC')
|
|
66
|
+
// .getMany()
|
|
67
|
+
// .then((entities) => entities.map(MachineStateStore.machineInfoFrom))) ?? []
|
|
68
|
+
// )
|
|
69
|
+
// }
|
|
70
|
+
//
|
|
71
|
+
// async findMachineStates(args?: StoreFindMachineStatesArgs): Promise<Array<StoreMachineStateInfo>> {
|
|
72
|
+
// const connection: DataSource = await this._dbConnection
|
|
73
|
+
// debug('findMachineStates', args)
|
|
74
|
+
// const result: Array<MachineStateInfoEntity> = await connection.getRepository(MachineStateInfoEntity).find({
|
|
75
|
+
// ...(args?.filter && { where: args?.filter }),
|
|
76
|
+
// transaction: false,
|
|
77
|
+
// })
|
|
78
|
+
//
|
|
79
|
+
// return result.map((event: MachineStateInfoEntity) => MachineStateStore.machineInfoFrom(event))
|
|
80
|
+
// }
|
|
81
|
+
//
|
|
82
|
+
// async getMachineState(args: StoreMachineStateGetArgs): Promise<StoreMachineStateInfo> {
|
|
83
|
+
// const connection: DataSource = await this._dbConnection
|
|
84
|
+
// debug('getMachineState', args)
|
|
85
|
+
// return connection.getRepository(MachineStateInfoEntity).findOneOrFail({ where: { instanceId: args.instanceId } })
|
|
86
|
+
// }
|
|
87
|
+
//
|
|
88
|
+
// async deleteMachineState(args: StoreMachineStateDeleteArgs): Promise<boolean> {
|
|
89
|
+
// debug(`Executing deleteMachineState query with id: ${args.instanceId}`)
|
|
90
|
+
// if (!args.instanceId) {
|
|
91
|
+
// throw new Error('No instanceId parameter is provided.')
|
|
92
|
+
// }
|
|
93
|
+
// try {
|
|
94
|
+
// const connection: DataSource = await this._dbConnection
|
|
95
|
+
//
|
|
96
|
+
// const result = await connection.getRepository(MachineStateInfoEntity).delete(args.instanceId)
|
|
97
|
+
// return result.affected != null && result.affected > 0
|
|
98
|
+
// } catch (error) {
|
|
99
|
+
// debug(`Error deleting state: ${error}`)
|
|
100
|
+
// return false
|
|
101
|
+
// }
|
|
102
|
+
// }
|
|
103
|
+
//
|
|
104
|
+
// async deleteExpiredMachineStates(args: StoreMachineStateDeleteExpiredArgs): Promise<number> {
|
|
105
|
+
// const { machineName, tenantId, deleteDoneStates } = args
|
|
106
|
+
// debug(`Executing deleteExpiredMachineStates query with params: ${JSON.stringify(args)}`)
|
|
107
|
+
// try {
|
|
108
|
+
// const connection: DataSource = await this._dbConnection
|
|
109
|
+
//
|
|
110
|
+
// const deleteCriteria: FindOptionsWhere<MachineStateInfoEntity> = {
|
|
111
|
+
// ...(machineName && { machineName }),
|
|
112
|
+
// ...(tenantId && { tenantId }),
|
|
113
|
+
// // When deleteOnDone state is set we only look at completedAt, in other cases we compare current time with expiresAt
|
|
114
|
+
// ...(!deleteDoneStates && { expiresAt: LessThan(new Date()) }),
|
|
115
|
+
// ...(deleteDoneStates && { completedAt: Not(IsNull()) }),
|
|
116
|
+
// }
|
|
117
|
+
// const result = await connection.getRepository(MachineStateInfoEntity).delete(deleteCriteria)
|
|
118
|
+
// return result.affected ?? 0
|
|
119
|
+
// } catch (error) {
|
|
120
|
+
// debug(`Error deleting machine info: ${error}`)
|
|
121
|
+
// return Promise.reject(new Error(`Error deleting expired machine states for machine type ${machineName}`))
|
|
122
|
+
// }
|
|
123
|
+
// }
|
|
124
|
+
//
|
|
125
|
+
// protected static machineInfoFrom = (machineStateInfoEntity: MachineStateInfoEntity): StoreMachineStateInfo => {
|
|
126
|
+
// // We are making sure no entity function get copied
|
|
127
|
+
// return JSON.parse(JSON.stringify(machineStateInfoEntity))
|
|
128
|
+
// }
|
|
129
|
+
//
|
|
130
|
+
// static machineStateInfoEntityFrom = (machineStateInfo: StoreMachineStateInfo | StoreMachineStatePersistArgs): MachineStateInfoEntity => {
|
|
131
|
+
// const entity = new MachineStateInfoEntity()
|
|
132
|
+
// Object.assign(entity, machineStateInfo)
|
|
133
|
+
// return entity
|
|
134
|
+
// }
|
|
135
|
+
// }
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AccessTokenRequest,
|
|
3
3
|
AccessTokenResponse,
|
|
4
|
+
ClientMetadata,
|
|
4
5
|
CredentialConfigurationSupported,
|
|
5
6
|
CredentialDataSupplierInput,
|
|
6
7
|
CredentialIssuerMetadataOpts,
|
|
8
|
+
CredentialOfferMode,
|
|
7
9
|
CredentialOfferSession,
|
|
8
10
|
CredentialRequest,
|
|
9
11
|
CredentialResponse,
|
|
10
12
|
Grant,
|
|
11
13
|
JsonLdIssuerCredentialDefinition,
|
|
14
|
+
QRCodeOpts,
|
|
15
|
+
StatusListOpts,
|
|
12
16
|
} from '@sphereon/oid4vci-common'
|
|
13
17
|
import { CredentialDataSupplier } from '@sphereon/oid4vci-issuer'
|
|
14
18
|
import { IDIDOptions, ResolveOpts } from '@sphereon/ssi-sdk-ext.did-utils'
|
|
@@ -17,7 +21,7 @@ import { IOID4VCIStore } from '@sphereon/ssi-sdk.oid4vci-issuer-store'
|
|
|
17
21
|
import { ICredential } from '@sphereon/ssi-types/dist'
|
|
18
22
|
import { IAgentContext, ICredentialIssuer, IDIDManager, IKeyManager, IPluginMethodMap, IResolver } from '@veramo/core'
|
|
19
23
|
import { IssuerInstance } from '../IssuerInstance'
|
|
20
|
-
import { IJwtService } from '@sphereon/ssi-sdk-ext.
|
|
24
|
+
import { IJwtService } from '@sphereon/ssi-sdk-ext.jwt-service'
|
|
21
25
|
|
|
22
26
|
export type IssuerCredentialDefinition = JsonLdIssuerCredentialDefinition
|
|
23
27
|
|
|
@@ -41,6 +45,16 @@ export interface ICreateOfferArgs extends IIssuerInstanceArgs {
|
|
|
41
45
|
credentialDefinition?: IssuerCredentialDefinition
|
|
42
46
|
credentialOfferUri?: string
|
|
43
47
|
credentialDataSupplierInput?: CredentialDataSupplierInput // Optional storage that can help the credential Data Supplier. For instance to store credential input data during offer creation, if no additional data can be supplied later on
|
|
48
|
+
|
|
49
|
+
redirectUri?: string
|
|
50
|
+
// auth_session?: string; Would be a nice extension to support, to allow external systems to determine what the auth_session value should be
|
|
51
|
+
// @Deprecated use tx_code in the grant object
|
|
52
|
+
correlationId?: string
|
|
53
|
+
sessionLifeTimeInSec?: number
|
|
54
|
+
qrCodeOpts?: QRCodeOpts
|
|
55
|
+
client_id?: string
|
|
56
|
+
statusListOpts?: Array<StatusListOpts>
|
|
57
|
+
offerMode?: CredentialOfferMode
|
|
44
58
|
baseUri?: string
|
|
45
59
|
scheme?: string
|
|
46
60
|
pinLength?: number
|
|
@@ -74,6 +88,7 @@ export interface IIssuerInstanceOptions extends IMetadataOptions {
|
|
|
74
88
|
}
|
|
75
89
|
|
|
76
90
|
export interface IIssuerOptions {
|
|
91
|
+
asClientOpts?: ClientMetadata
|
|
77
92
|
idOpts?: ManagedIdentifierOptsOrResult
|
|
78
93
|
resolveOpts?: ResolveOpts
|
|
79
94
|
/**
|
|
@@ -82,6 +97,12 @@ export interface IIssuerOptions {
|
|
|
82
97
|
didOpts?: IDIDOptions
|
|
83
98
|
userPinRequired?: boolean
|
|
84
99
|
cNonceExpiresIn?: number
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Used in the callbacks for the first party flow
|
|
103
|
+
*/
|
|
104
|
+
// FIXME SPRIND-151 we need to start supporting a map with a definition id per credential, we can use the credential offer session to check which credential is being issued and then look it up in this map
|
|
105
|
+
presentationDefinitionId?: string
|
|
85
106
|
}
|
|
86
107
|
|
|
87
108
|
export interface IMetadataOptions {
|