@sphereon/ssi-sdk.oid4vci-holder 0.32.1-next.20 → 0.32.1-next.291
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/agent/OID4VCIHolder.d.ts +1 -0
- package/dist/agent/OID4VCIHolder.d.ts.map +1 -1
- package/dist/agent/OID4VCIHolder.js +38 -24
- package/dist/agent/OID4VCIHolder.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/link-handler/index.d.ts +3 -2
- package/dist/link-handler/index.d.ts.map +1 -1
- package/dist/link-handler/index.js +2 -1
- package/dist/link-handler/index.js.map +1 -1
- package/dist/listeners/headlessStateNavListener.d.ts.map +1 -0
- package/dist/listeners/headlessStateNavListener.js.map +1 -0
- package/dist/localization/translations/en.json +5 -1
- package/dist/localization/translations/nl.json +5 -1
- package/dist/machines/firstPartyMachine.d.ts +15 -0
- package/dist/machines/firstPartyMachine.d.ts.map +1 -0
- package/dist/machines/firstPartyMachine.js +222 -0
- package/dist/machines/firstPartyMachine.js.map +1 -0
- package/dist/machines/oid4vciMachine.d.ts.map +1 -0
- package/dist/{machine → machines}/oid4vciMachine.js +58 -2
- package/dist/machines/oid4vciMachine.js.map +1 -0
- package/dist/mappers/OIDC4VCIBrandingMapper.d.ts.map +1 -0
- package/dist/{agent → mappers}/OIDC4VCIBrandingMapper.js +1 -1
- package/dist/mappers/OIDC4VCIBrandingMapper.js.map +1 -0
- package/dist/services/FirstPartyMachineServices.d.ts +9 -0
- package/dist/services/FirstPartyMachineServices.d.ts.map +1 -0
- package/dist/services/FirstPartyMachineServices.js +53 -0
- package/dist/services/FirstPartyMachineServices.js.map +1 -0
- package/dist/{agent → services}/OID4VCIHolderService.d.ts +3 -2
- package/dist/services/OID4VCIHolderService.d.ts.map +1 -0
- package/dist/{agent → services}/OID4VCIHolderService.js +49 -4
- package/dist/services/OID4VCIHolderService.js.map +1 -0
- package/dist/types/FirstPartyMachine.d.ts +112 -0
- package/dist/types/FirstPartyMachine.d.ts.map +1 -0
- package/dist/types/FirstPartyMachine.js +30 -0
- package/dist/types/FirstPartyMachine.js.map +1 -0
- package/dist/types/IOID4VCIHolder.d.ts +26 -15
- package/dist/types/IOID4VCIHolder.d.ts.map +1 -1
- package/dist/types/IOID4VCIHolder.js +3 -1
- package/dist/types/IOID4VCIHolder.js.map +1 -1
- package/package.json +26 -22
- package/src/agent/OID4VCIHolder.ts +48 -23
- package/src/index.ts +5 -2
- package/src/link-handler/index.ts +10 -5
- package/src/localization/translations/en.json +5 -1
- package/src/localization/translations/nl.json +5 -1
- package/src/machines/firstPartyMachine.ts +278 -0
- package/src/{machine → machines}/oid4vciMachine.ts +62 -3
- package/src/{agent → mappers}/OIDC4VCIBrandingMapper.ts +26 -25
- package/src/services/FirstPartyMachineServices.ts +64 -0
- package/src/{agent → services}/OID4VCIHolderService.ts +58 -10
- package/src/types/FirstPartyMachine.ts +161 -0
- package/src/types/IOID4VCIHolder.ts +52 -39
- package/dist/agent/OID4VCIHolderService.d.ts.map +0 -1
- package/dist/agent/OID4VCIHolderService.js.map +0 -1
- package/dist/agent/OIDC4VCIBrandingMapper.d.ts.map +0 -1
- package/dist/agent/OIDC4VCIBrandingMapper.js.map +0 -1
- package/dist/machine/headlessStateNavListener.d.ts.map +0 -1
- package/dist/machine/headlessStateNavListener.js.map +0 -1
- package/dist/machine/oid4vciMachine.d.ts.map +0 -1
- package/dist/machine/oid4vciMachine.js.map +0 -1
- /package/dist/{machine → listeners}/headlessStateNavListener.d.ts +0 -0
- /package/dist/{machine → listeners}/headlessStateNavListener.js +0 -0
- /package/dist/{machine → machines}/oid4vciMachine.d.ts +0 -0
- /package/dist/{agent → mappers}/OIDC4VCIBrandingMapper.d.ts +0 -0
- /package/src/{machine → listeners}/headlessStateNavListener.ts +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuthzFlowType, toAuthorizationResponsePayload } from '@sphereon/oid4vci-common'
|
|
1
|
+
import { AuthorizationChallengeCodeResponse, AuthzFlowType, toAuthorizationResponsePayload } from '@sphereon/oid4vci-common'
|
|
2
2
|
import { IBasicIssuerLocaleBranding, Identity, IIssuerLocaleBranding, Party } from '@sphereon/ssi-sdk.data-store'
|
|
3
3
|
import { assign, createMachine, DoneInvokeEvent, interpret } from 'xstate'
|
|
4
4
|
import { translate } from '../localization/Localization'
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
SetAuthorizationCodeURLEvent,
|
|
30
30
|
VerificationCodeEvent,
|
|
31
31
|
} from '../types/IOID4VCIHolder'
|
|
32
|
+
import { FirstPartyMachineStateTypes } from '../types/FirstPartyMachine'
|
|
32
33
|
|
|
33
34
|
const oid4vciHasNoContactGuard = (_ctx: OID4VCIMachineContext, _event: OID4VCIMachineEventTypes): boolean => {
|
|
34
35
|
const { contact } = _ctx
|
|
@@ -117,6 +118,10 @@ const oid4vciHasAuthorizationResponse = (ctx: OID4VCIMachineContext, _event: OID
|
|
|
117
118
|
return !!ctx.openID4VCIClientState?.authorizationCodeResponse
|
|
118
119
|
}
|
|
119
120
|
|
|
121
|
+
const oid4vciIsFirstPartyApplication = (ctx: OID4VCIMachineContext, _event: OID4VCIMachineEventTypes): boolean => {
|
|
122
|
+
return !!ctx.serverMetadata?.authorization_challenge_endpoint
|
|
123
|
+
}
|
|
124
|
+
|
|
120
125
|
const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMachine => {
|
|
121
126
|
const initialContext: OID4VCIMachineContext = {
|
|
122
127
|
// TODO WAL-671 we need to store the data from OpenIdProvider here in the context and make sure we can restart the machine with it and init the OpenIdProvider
|
|
@@ -153,7 +158,8 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
|
|
|
153
158
|
| { type: OID4VCIMachineGuards.hasSelectedCredentialsGuard }
|
|
154
159
|
| { type: OID4VCIMachineGuards.hasAuthorizationResponse }
|
|
155
160
|
| { type: OID4VCIMachineGuards.isOIDFOriginGuard }
|
|
156
|
-
| { type: OID4VCIMachineGuards.contactHasLowTrustGuard }
|
|
161
|
+
| { type: OID4VCIMachineGuards.contactHasLowTrustGuard }
|
|
162
|
+
| { type: OID4VCIMachineGuards.isFirstPartyApplication },
|
|
157
163
|
services: {} as {
|
|
158
164
|
[OID4VCIMachineServices.start]: {
|
|
159
165
|
data: StartResult
|
|
@@ -188,6 +194,9 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
|
|
|
188
194
|
[OID4VCIMachineServices.getIssuerBranding]: {
|
|
189
195
|
data: Array<IIssuerLocaleBranding | IBasicIssuerLocaleBranding>
|
|
190
196
|
}
|
|
197
|
+
[OID4VCIMachineServices.startFirstPartApplicationFlow]: {
|
|
198
|
+
data: void
|
|
199
|
+
}
|
|
191
200
|
},
|
|
192
201
|
},
|
|
193
202
|
context: initialContext,
|
|
@@ -332,6 +341,10 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
|
|
|
332
341
|
target: OID4VCIMachineStates.selectCredentials,
|
|
333
342
|
cond: OID4VCIMachineGuards.credentialsToSelectRequiredGuard,
|
|
334
343
|
},
|
|
344
|
+
{
|
|
345
|
+
target: OID4VCIMachineStates.startFirstPartApplicationFlow,
|
|
346
|
+
cond: OID4VCIMachineGuards.isFirstPartyApplication,
|
|
347
|
+
},
|
|
335
348
|
{
|
|
336
349
|
target: OID4VCIMachineStates.initiateAuthorizationRequest,
|
|
337
350
|
cond: OID4VCIMachineGuards.requireAuthorizationGuard,
|
|
@@ -422,6 +435,10 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
|
|
|
422
435
|
target: OID4VCIMachineStates.selectCredentials,
|
|
423
436
|
cond: OID4VCIMachineGuards.credentialsToSelectRequiredGuard,
|
|
424
437
|
},
|
|
438
|
+
{
|
|
439
|
+
target: OID4VCIMachineStates.startFirstPartApplicationFlow,
|
|
440
|
+
cond: OID4VCIMachineGuards.isFirstPartyApplication,
|
|
441
|
+
},
|
|
425
442
|
{
|
|
426
443
|
target: OID4VCIMachineStates.initiateAuthorizationRequest,
|
|
427
444
|
cond: OID4VCIMachineGuards.requireAuthorizationGuard,
|
|
@@ -435,6 +452,43 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
|
|
|
435
452
|
},
|
|
436
453
|
],
|
|
437
454
|
},
|
|
455
|
+
[OID4VCIMachineStates.startFirstPartApplicationFlow]: {
|
|
456
|
+
id: OID4VCIMachineStates.startFirstPartApplicationFlow,
|
|
457
|
+
invoke: {
|
|
458
|
+
src: OID4VCIMachineServices.startFirstPartApplicationFlow,
|
|
459
|
+
onDone: [
|
|
460
|
+
{
|
|
461
|
+
target: OID4VCIMachineStates.aborted,
|
|
462
|
+
cond: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<FirstPartyMachineStateTypes>): boolean =>
|
|
463
|
+
_event.data === FirstPartyMachineStateTypes.aborted,
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
target: OID4VCIMachineStates.declined,
|
|
467
|
+
cond: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<FirstPartyMachineStateTypes>): boolean =>
|
|
468
|
+
_event.data === FirstPartyMachineStateTypes.declined,
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
target: OID4VCIMachineStates.getCredentials,
|
|
472
|
+
actions: assign({
|
|
473
|
+
openID4VCIClientState: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<AuthorizationChallengeCodeResponse>) => {
|
|
474
|
+
const authorizationCodeResponse = toAuthorizationResponsePayload(_event.data)
|
|
475
|
+
return { ..._ctx.openID4VCIClientState!, authorizationCodeResponse }
|
|
476
|
+
},
|
|
477
|
+
}),
|
|
478
|
+
},
|
|
479
|
+
],
|
|
480
|
+
onError: {
|
|
481
|
+
target: OID4VCIMachineStates.handleError,
|
|
482
|
+
actions: assign({
|
|
483
|
+
error: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<ErrorDetails>): ErrorDetails => ({
|
|
484
|
+
title: _event.data.title ?? translate('oid4vci_machine_first_party_error_title'),
|
|
485
|
+
message: _event.data.message,
|
|
486
|
+
stack: _event.data.stack,
|
|
487
|
+
}),
|
|
488
|
+
}),
|
|
489
|
+
},
|
|
490
|
+
},
|
|
491
|
+
},
|
|
438
492
|
[OID4VCIMachineStates.selectCredentials]: {
|
|
439
493
|
id: OID4VCIMachineStates.selectCredentials,
|
|
440
494
|
on: {
|
|
@@ -453,6 +507,10 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
|
|
|
453
507
|
[OID4VCIMachineStates.transitionFromSelectingCredentials]: {
|
|
454
508
|
id: OID4VCIMachineStates.transitionFromSelectingCredentials,
|
|
455
509
|
always: [
|
|
510
|
+
{
|
|
511
|
+
target: OID4VCIMachineStates.startFirstPartApplicationFlow,
|
|
512
|
+
cond: OID4VCIMachineGuards.isFirstPartyApplication,
|
|
513
|
+
},
|
|
456
514
|
{
|
|
457
515
|
target: OID4VCIMachineStates.verifyPin,
|
|
458
516
|
cond: OID4VCIMachineGuards.requirePinGuard,
|
|
@@ -726,6 +784,7 @@ export class OID4VCIMachine {
|
|
|
726
784
|
oid4vciHasAuthorizationResponse,
|
|
727
785
|
oid4vciIsOIDFOriginGuard,
|
|
728
786
|
oid4vciContactHasLowTrustGuard,
|
|
787
|
+
oid4vciIsFirstPartyApplication,
|
|
729
788
|
...opts?.guards,
|
|
730
789
|
},
|
|
731
790
|
}),
|
|
@@ -737,7 +796,7 @@ export class OID4VCIMachine {
|
|
|
737
796
|
if (opts?.requireCustomNavigationHook !== true) {
|
|
738
797
|
if (typeof opts?.stateNavigationListener === 'function') {
|
|
739
798
|
interpreter.onTransition((snapshot: OID4VCIMachineState): void => {
|
|
740
|
-
if (opts?.stateNavigationListener
|
|
799
|
+
if (opts?.stateNavigationListener) {
|
|
741
800
|
opts.stateNavigationListener(interpreter, snapshot)
|
|
742
801
|
}
|
|
743
802
|
})
|
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
import { CredentialsSupportedDisplay, NameAndLocale } from '@sphereon/oid4vci-common'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
IBasicCredentialLocaleBranding,
|
|
5
|
-
IBasicIssuerLocaleBranding
|
|
6
|
-
} from '@sphereon/ssi-sdk.data-store'
|
|
7
|
-
import {
|
|
8
|
-
SdJwtClaimDisplayMetadata,
|
|
9
|
-
SdJwtClaimMetadata,
|
|
10
|
-
SdJwtClaimPath,
|
|
11
|
-
SdJwtTypeDisplayMetadata
|
|
12
|
-
} from '@sphereon/ssi-types'
|
|
2
|
+
import { IBasicCredentialClaim, IBasicCredentialLocaleBranding, IBasicIssuerLocaleBranding } from '@sphereon/ssi-sdk.data-store'
|
|
3
|
+
import { SdJwtClaimDisplayMetadata, SdJwtClaimMetadata, SdJwtClaimPath, SdJwtTypeDisplayMetadata } from '@sphereon/ssi-types'
|
|
13
4
|
import {
|
|
14
5
|
IssuerLocaleBrandingFromArgs,
|
|
15
6
|
Oid4vciCombineDisplayLocalesFromArgs,
|
|
@@ -26,7 +17,9 @@ import {
|
|
|
26
17
|
|
|
27
18
|
// FIXME should we not move this to the branding plugin?
|
|
28
19
|
|
|
29
|
-
export const oid4vciGetCredentialBrandingFrom = async (
|
|
20
|
+
export const oid4vciGetCredentialBrandingFrom = async (
|
|
21
|
+
args: Oid4vciGetCredentialBrandingFromArgs,
|
|
22
|
+
): Promise<Array<IBasicCredentialLocaleBranding>> => {
|
|
30
23
|
const { credentialDisplay, issuerCredentialSubject } = args
|
|
31
24
|
|
|
32
25
|
return oid4vciCombineDisplayLocalesFrom({
|
|
@@ -35,7 +28,9 @@ export const oid4vciGetCredentialBrandingFrom = async (args: Oid4vciGetCredentia
|
|
|
35
28
|
})
|
|
36
29
|
}
|
|
37
30
|
|
|
38
|
-
export const oid4vciCredentialDisplayLocalesFrom = async (
|
|
31
|
+
export const oid4vciCredentialDisplayLocalesFrom = async (
|
|
32
|
+
args: Oid4vciCredentialDisplayLocalesFromArgs,
|
|
33
|
+
): Promise<Map<string, CredentialsSupportedDisplay>> => {
|
|
39
34
|
const { credentialDisplay } = args
|
|
40
35
|
return credentialDisplay.reduce((localeDisplays, display) => {
|
|
41
36
|
const localeKey = display.locale || ''
|
|
@@ -44,7 +39,9 @@ export const oid4vciCredentialDisplayLocalesFrom = async (args: Oid4vciCredentia
|
|
|
44
39
|
}, new Map<string, CredentialsSupportedDisplay>())
|
|
45
40
|
}
|
|
46
41
|
|
|
47
|
-
export const oid4vciIssuerCredentialSubjectLocalesFrom = async (
|
|
42
|
+
export const oid4vciIssuerCredentialSubjectLocalesFrom = async (
|
|
43
|
+
args: Oid4vciIssuerCredentialSubjectLocalesFromArgs,
|
|
44
|
+
): Promise<Map<string, Array<IBasicCredentialClaim>>> => {
|
|
48
45
|
const { issuerCredentialSubject } = args
|
|
49
46
|
const localeClaims = new Map<string, Array<IBasicCredentialClaim>>()
|
|
50
47
|
|
|
@@ -125,7 +122,9 @@ export const oid4vciCredentialLocaleBrandingFrom = async (args: Oid4vciCredentia
|
|
|
125
122
|
}
|
|
126
123
|
}
|
|
127
124
|
|
|
128
|
-
export const oid4vciCombineDisplayLocalesFrom = async (
|
|
125
|
+
export const oid4vciCombineDisplayLocalesFrom = async (
|
|
126
|
+
args: Oid4vciCombineDisplayLocalesFromArgs,
|
|
127
|
+
): Promise<Array<IBasicCredentialLocaleBranding>> => {
|
|
129
128
|
const {
|
|
130
129
|
credentialDisplayLocales = new Map<string, CredentialsSupportedDisplay>(),
|
|
131
130
|
issuerCredentialSubjectLocales = new Map<string, Array<IBasicCredentialClaim>>(),
|
|
@@ -156,7 +155,9 @@ export const sdJwtGetCredentialBrandingFrom = async (args: SdJwtGetCredentialBra
|
|
|
156
155
|
})
|
|
157
156
|
}
|
|
158
157
|
|
|
159
|
-
export const sdJwtCredentialDisplayLocalesFrom = async (
|
|
158
|
+
export const sdJwtCredentialDisplayLocalesFrom = async (
|
|
159
|
+
args: SdJwtCredentialDisplayLocalesFromArgs,
|
|
160
|
+
): Promise<Map<string, SdJwtTypeDisplayMetadata>> => {
|
|
160
161
|
const { credentialDisplay } = args
|
|
161
162
|
return credentialDisplay.reduce((localeDisplays, display) => {
|
|
162
163
|
const localeKey = display.lang || ''
|
|
@@ -165,14 +166,16 @@ export const sdJwtCredentialDisplayLocalesFrom = async (args: SdJwtCredentialDis
|
|
|
165
166
|
}, new Map<string, SdJwtTypeDisplayMetadata>())
|
|
166
167
|
}
|
|
167
168
|
|
|
168
|
-
export const sdJwtCredentialClaimLocalesFrom = async (
|
|
169
|
+
export const sdJwtCredentialClaimLocalesFrom = async (
|
|
170
|
+
args: SdJwtCredentialClaimLocalesFromArgs,
|
|
171
|
+
): Promise<Map<string, Array<IBasicCredentialClaim>>> => {
|
|
169
172
|
const { claimsMetadata } = args
|
|
170
173
|
const localeClaims = new Map<string, Array<IBasicCredentialClaim>>()
|
|
171
174
|
|
|
172
175
|
claimsMetadata.forEach((claim: SdJwtClaimMetadata): void => {
|
|
173
176
|
claim.display?.forEach((display: SdJwtClaimDisplayMetadata): void => {
|
|
174
|
-
const { lang = '', label } = display
|
|
175
|
-
const key = claim.path.map((value: SdJwtClaimPath) => String(value)).join('.')
|
|
177
|
+
const { lang = '', label } = display
|
|
178
|
+
const key = claim.path.map((value: SdJwtClaimPath) => String(value)).join('.')
|
|
176
179
|
if (!localeClaims.has(lang)) {
|
|
177
180
|
localeClaims.set(lang, [])
|
|
178
181
|
}
|
|
@@ -180,7 +183,7 @@ export const sdJwtCredentialClaimLocalesFrom = async (args: SdJwtCredentialClaim
|
|
|
180
183
|
})
|
|
181
184
|
})
|
|
182
185
|
|
|
183
|
-
return localeClaims
|
|
186
|
+
return localeClaims
|
|
184
187
|
}
|
|
185
188
|
|
|
186
189
|
export const sdJwtCredentialLocaleBrandingFrom = async (args: SdJwtCredentialLocaleBrandingFromArgs): Promise<IBasicCredentialLocaleBranding> => {
|
|
@@ -213,17 +216,15 @@ export const sdJwtCredentialLocaleBrandingFrom = async (args: SdJwtCredentialLoc
|
|
|
213
216
|
}),
|
|
214
217
|
...(credentialDisplay.rendering?.simple?.background_color && {
|
|
215
218
|
background: {
|
|
216
|
-
color: credentialDisplay.rendering.simple.background_color
|
|
219
|
+
color: credentialDisplay.rendering.simple.background_color,
|
|
217
220
|
},
|
|
218
221
|
}),
|
|
219
222
|
}
|
|
220
223
|
}
|
|
221
224
|
|
|
222
225
|
export const sdJwtCombineDisplayLocalesFrom = async (args: SdJwtCombineDisplayLocalesFromArgs): Promise<Array<IBasicCredentialLocaleBranding>> => {
|
|
223
|
-
const {
|
|
224
|
-
|
|
225
|
-
claimsMetadata = new Map<string, Array<IBasicCredentialClaim>>(),
|
|
226
|
-
} = args
|
|
226
|
+
const { credentialDisplayLocales = new Map<string, SdJwtTypeDisplayMetadata>(), claimsMetadata = new Map<string, Array<IBasicCredentialClaim>>() } =
|
|
227
|
+
args
|
|
227
228
|
|
|
228
229
|
const locales: Array<string> = Array.from(new Set([...claimsMetadata.keys(), ...credentialDisplayLocales.keys()]))
|
|
229
230
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { OpenID4VCIClient } from '@sphereon/oid4vci-client'
|
|
2
|
+
import { AuthorizationChallengeValidationResponse } from '@sphereon/ssi-sdk.siopv2-oid4vp-common'
|
|
3
|
+
import { AuthorizationChallengeCodeResponse } from '@sphereon/oid4vci-common'
|
|
4
|
+
import { CreateConfigResult } from '@sphereon/ssi-sdk.siopv2-oid4vp-op-auth'
|
|
5
|
+
import { v4 as uuidv4 } from 'uuid'
|
|
6
|
+
import { RequiredContext } from '../types/IOID4VCIHolder'
|
|
7
|
+
import {
|
|
8
|
+
CreateConfigArgs,
|
|
9
|
+
GetSiopRequestArgs,
|
|
10
|
+
SendAuthorizationChallengeRequestArgs,
|
|
11
|
+
SendAuthorizationResponseArgs,
|
|
12
|
+
SiopV2AuthorizationRequestData,
|
|
13
|
+
} from '../types/FirstPartyMachine'
|
|
14
|
+
|
|
15
|
+
export const sendAuthorizationChallengeRequest = async (args: SendAuthorizationChallengeRequestArgs): Promise<AuthorizationChallengeCodeResponse> => {
|
|
16
|
+
const { openID4VCIClientState, authSession, presentationDuringIssuanceSession } = args
|
|
17
|
+
|
|
18
|
+
const oid4vciClient = await OpenID4VCIClient.fromState({ state: openID4VCIClientState })
|
|
19
|
+
return oid4vciClient.acquireAuthorizationChallengeCode({
|
|
20
|
+
clientId: oid4vciClient.clientId ?? uuidv4(),
|
|
21
|
+
...(authSession && { authSession }),
|
|
22
|
+
...(!authSession &&
|
|
23
|
+
openID4VCIClientState.credentialOffer?.preAuthorizedCode && { issuerState: openID4VCIClientState.credentialOffer?.preAuthorizedCode }),
|
|
24
|
+
...(!authSession && openID4VCIClientState.credentialOffer?.issuerState && { issuerState: openID4VCIClientState.credentialOffer?.issuerState }),
|
|
25
|
+
...(presentationDuringIssuanceSession && { presentationDuringIssuanceSession }),
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const createConfig = async (args: CreateConfigArgs, context: RequiredContext): Promise<CreateConfigResult> => {
|
|
30
|
+
const { presentationUri } = args
|
|
31
|
+
|
|
32
|
+
if (!presentationUri) {
|
|
33
|
+
return Promise.reject(Error('Missing presentation uri in context'))
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return context.agent.siopCreateConfig({ url: presentationUri })
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const getSiopRequest = async (args: GetSiopRequestArgs, context: RequiredContext): Promise<SiopV2AuthorizationRequestData> => {
|
|
40
|
+
const { didAuthConfig, presentationUri } = args
|
|
41
|
+
|
|
42
|
+
if (presentationUri === undefined) {
|
|
43
|
+
return Promise.reject(Error('Missing presentation uri in context'))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (didAuthConfig === undefined) {
|
|
47
|
+
return Promise.reject(Error('Missing did auth config in context'))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return context.agent.siopGetSiopRequest({ didAuthConfig, url: presentationUri })
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const sendAuthorizationResponse = async (args: SendAuthorizationResponseArgs, context: RequiredContext): Promise<string> => {
|
|
54
|
+
const { didAuthConfig, authorizationRequestData, selectedCredentials } = args
|
|
55
|
+
|
|
56
|
+
const responseData = await context.agent.siopSendResponse({
|
|
57
|
+
authorizationRequestData,
|
|
58
|
+
selectedCredentials,
|
|
59
|
+
didAuthConfig,
|
|
60
|
+
isFirstParty: true,
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
return (<AuthorizationChallengeValidationResponse>responseData.body).presentation_during_issuance_session
|
|
64
|
+
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
getTypesFromObject,
|
|
11
11
|
MetadataDisplay,
|
|
12
12
|
OpenId4VCIVersion,
|
|
13
|
+
AuthorizationChallengeCodeResponse,
|
|
13
14
|
} from '@sphereon/oid4vci-common'
|
|
14
15
|
import { KeyUse } from '@sphereon/ssi-sdk-ext.did-resolver-jwk'
|
|
15
16
|
import { getOrCreatePrimaryIdentifier, SupportedDidMethodEnum } from '@sphereon/ssi-sdk-ext.did-utils'
|
|
@@ -25,6 +26,7 @@ import { keyTypeFromCryptographicSuite } from '@sphereon/ssi-sdk-ext.key-utils'
|
|
|
25
26
|
import { IBasicCredentialLocaleBranding, IBasicIssuerLocaleBranding } from '@sphereon/ssi-sdk.data-store'
|
|
26
27
|
import {
|
|
27
28
|
CredentialMapper,
|
|
29
|
+
Hasher,
|
|
28
30
|
IVerifiableCredential,
|
|
29
31
|
JoseSignatureAlgorithm,
|
|
30
32
|
JoseSignatureAlgorithmString,
|
|
@@ -56,12 +58,13 @@ import {
|
|
|
56
58
|
SelectAppLocaleBrandingArgs,
|
|
57
59
|
VerificationResult,
|
|
58
60
|
VerifyCredentialToAcceptArgs,
|
|
61
|
+
StartFirstPartApplicationMachine,
|
|
62
|
+
RequiredContext,
|
|
59
63
|
} from '../types/IOID4VCIHolder'
|
|
60
|
-
import {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
} from './OIDC4VCIBrandingMapper'
|
|
64
|
+
import { oid4vciGetCredentialBrandingFrom, sdJwtGetCredentialBrandingFrom, issuerLocaleBrandingFrom } from '../mappers/OIDC4VCIBrandingMapper'
|
|
65
|
+
import { FirstPartyMachine } from '../machines/firstPartyMachine'
|
|
66
|
+
import { FirstPartyMachineState, FirstPartyMachineStateTypes } from '../types/FirstPartyMachine'
|
|
67
|
+
import { defaultHasher } from '@sphereon/ssi-sdk.core'
|
|
65
68
|
|
|
66
69
|
export const getCredentialBranding = async (args: GetCredentialBrandingArgs): Promise<Record<string, Array<IBasicCredentialLocaleBranding>>> => {
|
|
67
70
|
const { credentialsSupported, context } = args
|
|
@@ -83,14 +86,14 @@ export const getCredentialBranding = async (args: GetCredentialBrandingArgs): Pr
|
|
|
83
86
|
if (sdJwtTypeMetadata) {
|
|
84
87
|
mappedLocaleBranding = await sdJwtGetCredentialBrandingFrom({
|
|
85
88
|
credentialDisplay: sdJwtTypeMetadata.display,
|
|
86
|
-
claimsMetadata: sdJwtTypeMetadata.claims
|
|
89
|
+
claimsMetadata: sdJwtTypeMetadata.claims,
|
|
87
90
|
})
|
|
88
91
|
} else {
|
|
89
92
|
mappedLocaleBranding = await oid4vciGetCredentialBrandingFrom({
|
|
90
93
|
credentialDisplay: credentialsConfigSupported.display,
|
|
91
94
|
issuerCredentialSubject:
|
|
92
|
-
|
|
93
|
-
|
|
95
|
+
// @ts-ignore // FIXME SPRIND-123 add proper support for type recognition as claim display can be located elsewhere for v13
|
|
96
|
+
credentialsSupported.claims !== undefined ? credentialsConfigSupported.claims : credentialsConfigSupported.credentialSubject,
|
|
94
97
|
})
|
|
95
98
|
}
|
|
96
99
|
// TODO we should make the mapper part of the plugin, so that the logic for getting the branding becomes more clear and easier to use
|
|
@@ -155,7 +158,7 @@ export const verifyCredentialToAccept = async (args: VerifyCredentialToAcceptArg
|
|
|
155
158
|
return Promise.reject(Error('No credential found in credential response'))
|
|
156
159
|
}
|
|
157
160
|
|
|
158
|
-
const wrappedVC = CredentialMapper.toWrappedVerifiableCredential(credential, { hasher })
|
|
161
|
+
const wrappedVC = CredentialMapper.toWrappedVerifiableCredential(credential, { hasher: hasher ?? defaultHasher })
|
|
159
162
|
if (
|
|
160
163
|
wrappedVC.decoded?.iss?.includes('did:ebsi:') ||
|
|
161
164
|
(typeof wrappedVC.decoded?.vc?.issuer === 'string'
|
|
@@ -221,7 +224,7 @@ export const mapCredentialToAccept = async (args: MapCredentialToAcceptArgs): Pr
|
|
|
221
224
|
if (!hasher) {
|
|
222
225
|
return Promise.reject('a hasher is required for encoded SD-JWT credentials')
|
|
223
226
|
}
|
|
224
|
-
const asyncHasher = (data: string, algorithm: string) => Promise.resolve(hasher(data, algorithm))
|
|
227
|
+
const asyncHasher: Hasher = (data: string | ArrayBuffer, algorithm: string) => Promise.resolve(hasher(data, algorithm))
|
|
225
228
|
const decodedSdJwt = await CredentialMapper.decodeSdJwtVcAsync(wrappedVerifiableCredential.credential, asyncHasher)
|
|
226
229
|
uniformVerifiableCredential = sdJwtDecodedCredentialToUniformCredential(<SdJwtDecodedVerifiableCredential>decodedSdJwt)
|
|
227
230
|
} else if (CredentialMapper.isMsoMdocDecodedCredential(wrappedVerifiableCredential.credential)) {
|
|
@@ -615,3 +618,48 @@ export const getIssuanceCryptoSuite = async (opts: GetIssuanceCryptoSuiteArgs):
|
|
|
615
618
|
return Promise.reject(Error(`Credential format '${credentialSupported.format}' not supported`))
|
|
616
619
|
}
|
|
617
620
|
}
|
|
621
|
+
|
|
622
|
+
export const startFirstPartApplicationMachine = async (
|
|
623
|
+
args: StartFirstPartApplicationMachine,
|
|
624
|
+
context: RequiredContext,
|
|
625
|
+
): Promise<AuthorizationChallengeCodeResponse | string> => {
|
|
626
|
+
const { openID4VCIClientState, stateNavigationListener, contact } = args
|
|
627
|
+
|
|
628
|
+
if (!openID4VCIClientState) {
|
|
629
|
+
return Promise.reject(Error('Missing openID4VCI client state in context'))
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
if (!contact) {
|
|
633
|
+
return Promise.reject(Error('Missing contact in context'))
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
const firstPartyMachineInstance = FirstPartyMachine.newInstance({
|
|
637
|
+
openID4VCIClientState,
|
|
638
|
+
contact,
|
|
639
|
+
agentContext: context,
|
|
640
|
+
stateNavigationListener,
|
|
641
|
+
})
|
|
642
|
+
|
|
643
|
+
return new Promise((resolve, reject) => {
|
|
644
|
+
try {
|
|
645
|
+
firstPartyMachineInstance.onTransition((state: FirstPartyMachineState) => {
|
|
646
|
+
if (state.matches(FirstPartyMachineStateTypes.done)) {
|
|
647
|
+
const authorizationCodeResponse = state.context.authorizationCodeResponse
|
|
648
|
+
if (!authorizationCodeResponse) {
|
|
649
|
+
reject(Error('No authorizationCodeResponse acquired'))
|
|
650
|
+
}
|
|
651
|
+
resolve(authorizationCodeResponse!)
|
|
652
|
+
} else if (state.matches(FirstPartyMachineStateTypes.aborted)) {
|
|
653
|
+
resolve(FirstPartyMachineStateTypes.aborted)
|
|
654
|
+
} else if (state.matches(FirstPartyMachineStateTypes.declined)) {
|
|
655
|
+
resolve(FirstPartyMachineStateTypes.declined)
|
|
656
|
+
} else if (state.matches(FirstPartyMachineStateTypes.error)) {
|
|
657
|
+
reject(state.context.error)
|
|
658
|
+
}
|
|
659
|
+
})
|
|
660
|
+
firstPartyMachineInstance.start()
|
|
661
|
+
} catch (error) {
|
|
662
|
+
reject(error)
|
|
663
|
+
}
|
|
664
|
+
})
|
|
665
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { BaseActionObject, Interpreter, ResolveTypegenMeta, ServiceMap, State, StateMachine, StatesConfig, TypegenDisabled } from 'xstate'
|
|
2
|
+
import { OpenID4VCIClientState } from '@sphereon/oid4vci-client'
|
|
3
|
+
import { DidAuthConfig, Party } from '@sphereon/ssi-sdk.data-store'
|
|
4
|
+
import { PresentationDefinitionWithLocation, RPRegistrationMetadataPayload } from '@sphereon/did-auth-siop'
|
|
5
|
+
import { UniqueDigitalCredential } from '@sphereon/ssi-sdk.credential-store'
|
|
6
|
+
import { AuthorizationChallengeCodeResponse } from '@sphereon/oid4vci-common'
|
|
7
|
+
import { IIdentifier } from '@veramo/core'
|
|
8
|
+
import { ErrorDetails, RequiredContext } from './IOID4VCIHolder'
|
|
9
|
+
|
|
10
|
+
export enum FirstPartyMachineStateTypes {
|
|
11
|
+
sendAuthorizationChallengeRequest = 'sendAuthorizationChallengeRequest',
|
|
12
|
+
sendAuthorizationResponse = 'sendAuthorizationResponse',
|
|
13
|
+
selectCredentials = 'selectCredentials',
|
|
14
|
+
createConfig = 'createConfig',
|
|
15
|
+
getSiopRequest = 'getSiopRequest',
|
|
16
|
+
error = 'error',
|
|
17
|
+
done = 'done',
|
|
18
|
+
aborted = 'aborted',
|
|
19
|
+
declined = 'declined',
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export enum FirstPartyMachineServices {
|
|
23
|
+
sendAuthorizationChallengeRequest = 'sendAuthorizationChallengeRequest',
|
|
24
|
+
sendAuthorizationResponse = 'sendAuthorizationResponse',
|
|
25
|
+
createConfig = 'createConfig',
|
|
26
|
+
getSiopRequest = 'getSiopRequest',
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type FirstPartyMachineStates = Record<FirstPartyMachineStateTypes, {}>
|
|
30
|
+
|
|
31
|
+
export type FirstPartyMachineContext = {
|
|
32
|
+
openID4VCIClientState: OpenID4VCIClientState
|
|
33
|
+
selectedCredentials: Array<UniqueDigitalCredential>
|
|
34
|
+
contact: Party
|
|
35
|
+
authSession?: string
|
|
36
|
+
presentationUri?: string
|
|
37
|
+
identifier?: IIdentifier
|
|
38
|
+
didAuthConfig?: Omit<DidAuthConfig, 'identifier'>
|
|
39
|
+
authorizationRequestData?: SiopV2AuthorizationRequestData
|
|
40
|
+
presentationDuringIssuanceSession?: string
|
|
41
|
+
authorizationCodeResponse?: AuthorizationChallengeCodeResponse
|
|
42
|
+
error?: ErrorDetails
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export enum FirstPartyMachineEvents {
|
|
46
|
+
NEXT = 'NEXT',
|
|
47
|
+
PREVIOUS = 'PREVIOUS',
|
|
48
|
+
DECLINE = 'DECLINE',
|
|
49
|
+
SET_SELECTED_CREDENTIALS = 'SET_SELECTED_CREDENTIALS',
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export type FirstPartyNextEvent = { type: FirstPartyMachineEvents.NEXT }
|
|
53
|
+
export type FirstPartyPreviousEvent = { type: FirstPartyMachineEvents.PREVIOUS }
|
|
54
|
+
export type FirstPartyDeclineEvent = { type: FirstPartyMachineEvents.DECLINE }
|
|
55
|
+
export type FirstPartySelectCredentialsEvent = {
|
|
56
|
+
type: FirstPartyMachineEvents.SET_SELECTED_CREDENTIALS
|
|
57
|
+
data: Array<UniqueDigitalCredential>
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type FirstPartyMachineEventTypes = FirstPartyNextEvent | FirstPartyPreviousEvent | FirstPartyDeclineEvent | FirstPartySelectCredentialsEvent
|
|
61
|
+
|
|
62
|
+
export type FirstPartyMachineStatesConfig = StatesConfig<
|
|
63
|
+
FirstPartyMachineContext,
|
|
64
|
+
{
|
|
65
|
+
states: FirstPartyMachineStates
|
|
66
|
+
},
|
|
67
|
+
FirstPartyMachineEventTypes,
|
|
68
|
+
any
|
|
69
|
+
>
|
|
70
|
+
|
|
71
|
+
export type CreateFirstPartyMachineOpts = {
|
|
72
|
+
openID4VCIClientState: OpenID4VCIClientState
|
|
73
|
+
contact: Party
|
|
74
|
+
agentContext: RequiredContext
|
|
75
|
+
machineId?: string
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export type FirstPartyStateMachine = StateMachine<
|
|
79
|
+
FirstPartyMachineContext,
|
|
80
|
+
any,
|
|
81
|
+
FirstPartyMachineEventTypes,
|
|
82
|
+
{
|
|
83
|
+
value: any
|
|
84
|
+
context: FirstPartyMachineContext
|
|
85
|
+
},
|
|
86
|
+
BaseActionObject,
|
|
87
|
+
ServiceMap,
|
|
88
|
+
ResolveTypegenMeta<TypegenDisabled, FirstPartyMachineEventTypes, BaseActionObject, ServiceMap>
|
|
89
|
+
>
|
|
90
|
+
|
|
91
|
+
export type FirstPartyMachineInterpreter = Interpreter<
|
|
92
|
+
FirstPartyMachineContext,
|
|
93
|
+
any,
|
|
94
|
+
FirstPartyMachineEventTypes,
|
|
95
|
+
{
|
|
96
|
+
value: any
|
|
97
|
+
context: FirstPartyMachineContext
|
|
98
|
+
},
|
|
99
|
+
any
|
|
100
|
+
>
|
|
101
|
+
|
|
102
|
+
export type FirstPartyMachineStateNavigationListener = (
|
|
103
|
+
firstPartyMachine: FirstPartyMachineInterpreter,
|
|
104
|
+
state: FirstPartyMachineState,
|
|
105
|
+
navigation?: any,
|
|
106
|
+
) => Promise<void>
|
|
107
|
+
|
|
108
|
+
export type InstanceFirstPartyMachineOpts = {
|
|
109
|
+
services?: any
|
|
110
|
+
guards?: any
|
|
111
|
+
subscription?: () => void
|
|
112
|
+
requireCustomNavigationHook?: boolean
|
|
113
|
+
stateNavigationListener?: FirstPartyMachineStateNavigationListener
|
|
114
|
+
} & CreateFirstPartyMachineOpts
|
|
115
|
+
|
|
116
|
+
export type FirstPartyMachineState = State<
|
|
117
|
+
FirstPartyMachineContext,
|
|
118
|
+
FirstPartyMachineEventTypes,
|
|
119
|
+
any,
|
|
120
|
+
{
|
|
121
|
+
value: any
|
|
122
|
+
context: FirstPartyMachineContext
|
|
123
|
+
},
|
|
124
|
+
any
|
|
125
|
+
>
|
|
126
|
+
|
|
127
|
+
export type FirstPartyMachineServiceDefinitions = Record<keyof typeof FirstPartyMachineServices, (...args: Array<any>) => any>
|
|
128
|
+
|
|
129
|
+
export type SendAuthorizationChallengeRequestArgs = Pick<
|
|
130
|
+
FirstPartyMachineContext,
|
|
131
|
+
'openID4VCIClientState' | 'authSession' | 'presentationDuringIssuanceSession'
|
|
132
|
+
>
|
|
133
|
+
|
|
134
|
+
export type SendAuthorizationResponseArgs = Pick<
|
|
135
|
+
FirstPartyMachineContext,
|
|
136
|
+
'authSession' | 'presentationUri' | 'didAuthConfig' | 'authorizationRequestData' | 'selectedCredentials'
|
|
137
|
+
>
|
|
138
|
+
|
|
139
|
+
export type CreateConfigArgs = Pick<FirstPartyMachineContext, 'presentationUri' | 'identifier'>
|
|
140
|
+
|
|
141
|
+
export type GetSiopRequestArgs = Pick<FirstPartyMachineContext, 'didAuthConfig' | 'presentationUri'>
|
|
142
|
+
|
|
143
|
+
export type SiopV2AuthorizationRequestData = {
|
|
144
|
+
correlationId: string
|
|
145
|
+
registrationMetadataPayload: RPRegistrationMetadataPayload
|
|
146
|
+
issuer?: string
|
|
147
|
+
name?: string
|
|
148
|
+
uri?: URL
|
|
149
|
+
clientIdScheme?: string
|
|
150
|
+
clientId?: string
|
|
151
|
+
entityId?: string
|
|
152
|
+
presentationDefinitions?: PresentationDefinitionWithLocation[]
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export type FirstPartyMachineNavigationArgs = {
|
|
156
|
+
firstPartyMachine: FirstPartyMachineInterpreter
|
|
157
|
+
state: FirstPartyMachineState
|
|
158
|
+
navigation: any
|
|
159
|
+
onNext?: () => void
|
|
160
|
+
onBack?: () => void
|
|
161
|
+
}
|