@sphereon/ssi-sdk.oid4vci-issuer 0.32.1-feature.VDX.341.57 → 0.32.1-feature.new.develop.273
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 -10
- 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 -15
- 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,
|
|
@@ -49,11 +53,16 @@ export function getJwtVerifyCallback({ verifyOpts }: { verifyOpts?: JWTVerifyOpt
|
|
|
49
53
|
|
|
50
54
|
const header = jwtDecode<JWTHeader>(args.jwt, { header: true })
|
|
51
55
|
const payload = jwtDecode<JWTPayload>(args.jwt, { header: false })
|
|
56
|
+
const kid = args.kid ?? header.kid
|
|
57
|
+
//const jwk = !kid ? jwkInfo.jwk : undefined // TODO double-check if this is correct
|
|
58
|
+
const jwk = jwkInfo.jwk // FIXME workaround IATAB2B-57
|
|
52
59
|
return {
|
|
53
60
|
alg,
|
|
54
61
|
...identifier,
|
|
55
62
|
jwt: { header, payload },
|
|
56
|
-
|
|
63
|
+
...(kid && { kid }),
|
|
64
|
+
...(jwk && { jwk }),
|
|
65
|
+
} as JwtVerifyResult
|
|
57
66
|
}
|
|
58
67
|
|
|
59
68
|
const decodedJwt = (await decodeJWT(args.jwt)) as Jwt
|
|
@@ -64,7 +73,7 @@ export function getJwtVerifyCallback({ verifyOpts }: { verifyOpts?: JWTVerifyOpt
|
|
|
64
73
|
return {
|
|
65
74
|
alg: decodedJwt.header.alg,
|
|
66
75
|
jwt: decodedJwt,
|
|
67
|
-
} as JwtVerifyResult
|
|
76
|
+
} as JwtVerifyResult
|
|
68
77
|
}
|
|
69
78
|
const did = kid.split('#')[0]
|
|
70
79
|
|
|
@@ -155,11 +164,25 @@ export async function getAccessTokenSignerCallback(
|
|
|
155
164
|
}
|
|
156
165
|
|
|
157
166
|
async function accessTokenSignerCallback(jwt: Jwt, kid?: string): Promise<string> {
|
|
158
|
-
const issuer =
|
|
167
|
+
const issuer =
|
|
168
|
+
opts.idOpts?.issuer ??
|
|
169
|
+
(typeof opts.idOpts?.identifier === 'string' ? opts.idOpts.identifier : (opts.didOpts?.idOpts?.identifier?.toString() ?? opts?.iss))
|
|
159
170
|
if (!issuer) {
|
|
160
171
|
throw Error('No issuer configured for access tokens')
|
|
161
172
|
}
|
|
162
|
-
|
|
173
|
+
|
|
174
|
+
let kidHeader: string | undefined = jwt?.header?.kid ?? kid
|
|
175
|
+
if (!kidHeader) {
|
|
176
|
+
if (
|
|
177
|
+
opts.idOpts?.method === 'did' ||
|
|
178
|
+
opts.idOpts?.method === 'kid' ||
|
|
179
|
+
(typeof opts.didOpts?.idOpts.identifier === 'string' && opts.didOpts?.idOpts?.identifier?.startsWith('did:'))
|
|
180
|
+
) {
|
|
181
|
+
// @ts-ignore
|
|
182
|
+
kidHeader = opts.idOpts?.kid ?? opts.didOpts?.idOpts?.kid ?? opts?.didOpts?.identifierOpts?.kid
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return await createJWT(jwt.payload, { signer, issuer }, { ...jwt.header, ...(kidHeader && { kid: kidHeader }), typ: 'JWT' })
|
|
163
186
|
}
|
|
164
187
|
|
|
165
188
|
return accessTokenSignerCallback
|
|
@@ -170,14 +193,15 @@ export async function getCredentialSignerCallback(
|
|
|
170
193
|
crypto?: Crypto
|
|
171
194
|
},
|
|
172
195
|
context: IRequiredContext,
|
|
173
|
-
): Promise<CredentialSignerCallback
|
|
196
|
+
): Promise<CredentialSignerCallback> {
|
|
174
197
|
async function issueVCCallback(args: {
|
|
175
198
|
credentialRequest: CredentialRequest
|
|
176
199
|
credential: CredentialIssuanceInput
|
|
177
|
-
jwtVerifyResult: JwtVerifyResult
|
|
200
|
+
jwtVerifyResult: JwtVerifyResult
|
|
178
201
|
format?: OID4VCICredentialFormat
|
|
202
|
+
statusLists?: Array<StatusListOpts>
|
|
179
203
|
}): Promise<W3CVerifiableCredential | CompactSdJwtVc> {
|
|
180
|
-
const { jwtVerifyResult, format } = args
|
|
204
|
+
const { jwtVerifyResult, format, statusLists } = args
|
|
181
205
|
const credential = args.credential as ICredential // TODO: SDJWT
|
|
182
206
|
let proofFormat: ProofFormat
|
|
183
207
|
|
|
@@ -204,9 +228,10 @@ export async function getCredentialSignerCallback(
|
|
|
204
228
|
// TODO: We should extend the plugin capabilities of issuance so we do not have to tuck this into the sign callback
|
|
205
229
|
if (contextHasPlugin<IStatusListPlugin>(context, 'slAddStatusToCredential')) {
|
|
206
230
|
// Add status list if enabled (and when the input has a credentialStatus object (can be empty))
|
|
207
|
-
const credentialStatusVC = await context.agent.slAddStatusToCredential({ credential })
|
|
231
|
+
const credentialStatusVC = await context.agent.slAddStatusToCredential({ credential, statusLists })
|
|
208
232
|
if (credential.credentialStatus && !credential.credentialStatus.statusListCredential) {
|
|
209
233
|
credential.credentialStatus = credentialStatusVC.credentialStatus
|
|
234
|
+
// TODO update statusLists somehow?
|
|
210
235
|
}
|
|
211
236
|
}
|
|
212
237
|
|
|
@@ -237,6 +262,28 @@ export async function getCredentialSignerCallback(
|
|
|
237
262
|
_sd: credential['_sd'],
|
|
238
263
|
}
|
|
239
264
|
}
|
|
265
|
+
|
|
266
|
+
if (contextHasPlugin<IStatusListPlugin>(context, 'slAddStatusToSdJwtCredential')) {
|
|
267
|
+
if ((sdJwtPayload.status && sdJwtPayload.status.status_list) || (statusLists && statusLists.length > 0)) {
|
|
268
|
+
// Add status list if enabled (and when the input has a credentialStatus object (can be empty))
|
|
269
|
+
const sdJwtPayloadWithStatus = await context.agent.slAddStatusToSdJwtCredential({ credential: sdJwtPayload, statusLists })
|
|
270
|
+
if (sdJwtPayload.status?.status_list?.idx) {
|
|
271
|
+
if (!sdJwtPayloadWithStatus.status || !sdJwtPayloadWithStatus.status.status_list) {
|
|
272
|
+
// sdJwtPayload and sdJwtPayloadWithStatus is the same for now, but we should use the result anyway as this could be subject to change
|
|
273
|
+
return Promise.reject(Error('slAddStatusToSdJwtCredential did not return a status_list'))
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Update statusListId & statusListIndex back to the credential session TODO SSISDK-4 This is not a clean way to do this.
|
|
277
|
+
if (statusLists && statusLists.length > 0) {
|
|
278
|
+
const statusList = statusLists[0]
|
|
279
|
+
statusList.statusListId = sdJwtPayloadWithStatus.status.status_list.uri
|
|
280
|
+
statusList.statusListIndex = sdJwtPayloadWithStatus.status.status_list.idx
|
|
281
|
+
}
|
|
282
|
+
sdJwtPayload.status.status_list.idx = sdJwtPayloadWithStatus.status.status_list.idx
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
240
287
|
const result = await context.agent.createSdJwtVc({
|
|
241
288
|
credentialPayload: sdJwtPayload,
|
|
242
289
|
disclosureFrame: disclosureFrame,
|
|
@@ -261,10 +308,10 @@ export async function createVciIssuerBuilder(
|
|
|
261
308
|
credentialDataSupplier?: CredentialDataSupplier
|
|
262
309
|
},
|
|
263
310
|
context: IRequiredContext,
|
|
264
|
-
): Promise<VcIssuerBuilder
|
|
311
|
+
): Promise<VcIssuerBuilder> {
|
|
265
312
|
const { issuerOpts, issuerMetadata, authorizationServerMetadata } = args
|
|
266
313
|
|
|
267
|
-
const builder = new VcIssuerBuilder
|
|
314
|
+
const builder = new VcIssuerBuilder()
|
|
268
315
|
// @ts-ignore
|
|
269
316
|
const resolver =
|
|
270
317
|
args.resolver ??
|
|
@@ -285,14 +332,23 @@ export async function createVciIssuerBuilder(
|
|
|
285
332
|
builder.withAuthorizationMetadata(authorizationServerMetadata)
|
|
286
333
|
// builder.withUserPinRequired(issuerOpts.userPinRequired ?? false) was removed from implementers draft v1
|
|
287
334
|
builder.withCredentialSignerCallback(await getCredentialSignerCallback(idOpts, context))
|
|
335
|
+
|
|
336
|
+
if (issuerOpts.asClientOpts) {
|
|
337
|
+
builder.withASClientMetadata(issuerOpts.asClientOpts)
|
|
338
|
+
// @ts-ignore
|
|
339
|
+
// const authorizationServer = issuerMetadata.authorization_servers[0] as string
|
|
340
|
+
// Set the OIDC verifier
|
|
341
|
+
// builder.withJWTVerifyCallback(oidcAccessTokenVerifyCallback({clientMetadata: issuerOpts.asClientOpts, credentialIssuer: issuerMetadata.credential_issuer as string, authorizationServer}))
|
|
342
|
+
}
|
|
343
|
+
// Do not use it when asClient is used
|
|
288
344
|
builder.withJWTVerifyCallback(getJwtVerifyCallback({ verifyOpts: jwtVerifyOpts }, context))
|
|
345
|
+
|
|
289
346
|
if (args.credentialDataSupplier) {
|
|
290
347
|
builder.withCredentialDataSupplier(args.credentialDataSupplier)
|
|
291
348
|
}
|
|
292
349
|
builder.withInMemoryCNonceState()
|
|
293
350
|
builder.withInMemoryCredentialOfferState()
|
|
294
351
|
builder.withInMemoryCredentialOfferURIState()
|
|
295
|
-
builder.build()
|
|
296
352
|
|
|
297
353
|
return builder
|
|
298
354
|
}
|
|
@@ -310,7 +366,7 @@ export async function createVciIssuer(
|
|
|
310
366
|
credentialDataSupplier?: CredentialDataSupplier
|
|
311
367
|
},
|
|
312
368
|
context: IRequiredContext,
|
|
313
|
-
): Promise<VcIssuer
|
|
369
|
+
): Promise<VcIssuer> {
|
|
314
370
|
return (
|
|
315
371
|
await createVciIssuerBuilder(
|
|
316
372
|
{
|
|
@@ -323,3 +379,58 @@ export async function createVciIssuer(
|
|
|
323
379
|
)
|
|
324
380
|
).build()
|
|
325
381
|
}
|
|
382
|
+
|
|
383
|
+
export async function createAuthRequestUriCallback(opts: { path: string; presentationDefinitionId: string }): Promise<() => Promise<string>> {
|
|
384
|
+
async function authRequestUriCallback(): Promise<string> {
|
|
385
|
+
const path = opts.path.replace(':definitionId', opts.presentationDefinitionId)
|
|
386
|
+
return fetch(path, {
|
|
387
|
+
method: 'POST',
|
|
388
|
+
headers: {
|
|
389
|
+
'Content-Type': 'application/json',
|
|
390
|
+
},
|
|
391
|
+
}).then(async (response): Promise<string> => {
|
|
392
|
+
if (response.status >= 400) {
|
|
393
|
+
return Promise.reject(Error(await response.text()))
|
|
394
|
+
} else {
|
|
395
|
+
const responseData = await response.json()
|
|
396
|
+
|
|
397
|
+
if (!responseData.authRequestURI) {
|
|
398
|
+
return Promise.reject(Error('Missing auth request uri in response body'))
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return responseData.authRequestURI
|
|
402
|
+
}
|
|
403
|
+
})
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return authRequestUriCallback
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
export async function createVerifyAuthResponseCallback(opts: {
|
|
410
|
+
path: string
|
|
411
|
+
presentationDefinitionId: string
|
|
412
|
+
}): Promise<(correlationId: string) => Promise<boolean>> {
|
|
413
|
+
async function verifyAuthResponseCallback(correlationId: string): Promise<boolean> {
|
|
414
|
+
return fetch(opts.path, {
|
|
415
|
+
method: 'POST',
|
|
416
|
+
headers: {
|
|
417
|
+
'Content-Type': 'application/json',
|
|
418
|
+
},
|
|
419
|
+
body: JSON.stringify({ definitionId: opts.presentationDefinitionId, correlationId }),
|
|
420
|
+
}).then(async (response): Promise<boolean> => {
|
|
421
|
+
if (response.status >= 400) {
|
|
422
|
+
return Promise.reject(Error(await response.text()))
|
|
423
|
+
} else {
|
|
424
|
+
const responseData = await response.json()
|
|
425
|
+
|
|
426
|
+
if (!responseData.status) {
|
|
427
|
+
return Promise.reject(Error('Missing status in response body'))
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
return responseData.status === AuthorizationResponseStateStatus.VERIFIED
|
|
431
|
+
}
|
|
432
|
+
})
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return verifyAuthResponseCallback
|
|
436
|
+
}
|
|
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 {
|