@sphereon/ssi-sdk.oid4vci-holder 0.32.1-feature.MWALL.715.49 → 0.32.1-feature.SDK.56.oauth.status.list.139
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.map +1 -1
- package/dist/agent/OID4VCIHolder.js +15 -14
- package/dist/agent/OID4VCIHolder.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -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 +52 -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 +47 -3
- 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 +20 -9
- 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 +24 -21
- package/src/agent/OID4VCIHolder.ts +23 -20
- package/src/index.ts +4 -2
- package/src/link-handler/index.ts +12 -5
- package/src/localization/translations/en.json +5 -1
- package/src/localization/translations/nl.json +5 -1
- package/src/machines/firstPartyMachine.ts +287 -0
- package/src/{machine → machines}/oid4vciMachine.ts +64 -3
- package/src/{agent → mappers}/OIDC4VCIBrandingMapper.ts +25 -26
- package/src/services/FirstPartyMachineServices.ts +63 -0
- package/src/{agent → services}/OID4VCIHolderService.ts +55 -4
- package/src/types/FirstPartyMachine.ts +169 -0
- package/src/types/IOID4VCIHolder.ts +41 -31
- 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
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { assign, createMachine, DoneInvokeEvent, interpret } from 'xstate'
|
|
2
|
+
import {
|
|
3
|
+
AuthorizationChallengeCodeResponse,
|
|
4
|
+
AuthorizationChallengeError,
|
|
5
|
+
AuthorizationChallengeErrorResponse
|
|
6
|
+
} from '@sphereon/oid4vci-common'
|
|
7
|
+
import { DidAuthConfig } from '@sphereon/ssi-sdk.data-store'
|
|
8
|
+
import { CreateConfigResult } from '@sphereon/ssi-sdk.siopv2-oid4vp-op-auth'
|
|
9
|
+
import {
|
|
10
|
+
createConfig,
|
|
11
|
+
getSiopRequest,
|
|
12
|
+
sendAuthorizationChallengeRequest,
|
|
13
|
+
sendAuthorizationResponse
|
|
14
|
+
} from '../services/FirstPartyMachineServices'
|
|
15
|
+
import { translate } from '../localization/Localization'
|
|
16
|
+
import { ErrorDetails } from '../types/IOID4VCIHolder'
|
|
17
|
+
import {
|
|
18
|
+
CreateConfigArgs,
|
|
19
|
+
CreateFirstPartyMachineOpts,
|
|
20
|
+
FirstPartyMachineContext,
|
|
21
|
+
FirstPartyMachineEvents,
|
|
22
|
+
FirstPartyMachineEventTypes,
|
|
23
|
+
FirstPartyMachineInterpreter,
|
|
24
|
+
FirstPartyMachineServices,
|
|
25
|
+
FirstPartyMachineState,
|
|
26
|
+
FirstPartyMachineStatesConfig,
|
|
27
|
+
FirstPartyMachineStateTypes,
|
|
28
|
+
FirstPartyMachineServiceDefinitions,
|
|
29
|
+
FirstPartyStateMachine,
|
|
30
|
+
GetSiopRequestArgs,
|
|
31
|
+
InstanceFirstPartyMachineOpts,
|
|
32
|
+
SiopV2AuthorizationRequestData,
|
|
33
|
+
SendAuthorizationResponseArgs,
|
|
34
|
+
FirstPartySelectCredentialsEvent
|
|
35
|
+
} from '../types/FirstPartyMachine'
|
|
36
|
+
|
|
37
|
+
const firstPartyMachineStates: FirstPartyMachineStatesConfig = {
|
|
38
|
+
[FirstPartyMachineStateTypes.sendAuthorizationChallengeRequest]: {
|
|
39
|
+
id: FirstPartyMachineStateTypes.sendAuthorizationChallengeRequest,
|
|
40
|
+
invoke: {
|
|
41
|
+
src: FirstPartyMachineServices.sendAuthorizationChallengeRequest,
|
|
42
|
+
onDone: {
|
|
43
|
+
target: FirstPartyMachineStateTypes.done,
|
|
44
|
+
actions: assign({
|
|
45
|
+
authorizationCodeResponse: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<AuthorizationChallengeCodeResponse>) => _event.data
|
|
46
|
+
})
|
|
47
|
+
},
|
|
48
|
+
onError: [
|
|
49
|
+
{
|
|
50
|
+
target: FirstPartyMachineStateTypes.createConfig,
|
|
51
|
+
cond: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<AuthorizationChallengeErrorResponse>): boolean => _event.data.error === AuthorizationChallengeError.insufficient_authorization,
|
|
52
|
+
actions: assign({
|
|
53
|
+
authSession: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<AuthorizationChallengeErrorResponse>) => _event.data.auth_session,
|
|
54
|
+
presentationUri: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<AuthorizationChallengeErrorResponse>) => _event.data.presentation,
|
|
55
|
+
}),
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
target: FirstPartyMachineStateTypes.error,
|
|
59
|
+
actions: assign({
|
|
60
|
+
error: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<Error>): ErrorDetails => ({
|
|
61
|
+
title: translate('oid4vci_machine_send_authorization_challenge_request_error_title'),
|
|
62
|
+
message: _event.data.message,
|
|
63
|
+
stack: _event.data.stack,
|
|
64
|
+
}),
|
|
65
|
+
}),
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
[FirstPartyMachineStateTypes.createConfig]: {
|
|
71
|
+
id: FirstPartyMachineStateTypes.createConfig,
|
|
72
|
+
invoke: {
|
|
73
|
+
src: FirstPartyMachineServices.createConfig,
|
|
74
|
+
onDone: {
|
|
75
|
+
target: FirstPartyMachineStateTypes.getSiopRequest,
|
|
76
|
+
actions: assign({
|
|
77
|
+
didAuthConfig: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<DidAuthConfig>) => _event.data,
|
|
78
|
+
}),
|
|
79
|
+
},
|
|
80
|
+
onError: {
|
|
81
|
+
target: FirstPartyMachineStateTypes.error,
|
|
82
|
+
actions: assign({
|
|
83
|
+
error: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<Error>): ErrorDetails => ({
|
|
84
|
+
title: translate('oid4vci_machine_create_config_error_title'),
|
|
85
|
+
message: _event.data.message,
|
|
86
|
+
stack: _event.data.stack,
|
|
87
|
+
}),
|
|
88
|
+
}),
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
[FirstPartyMachineStateTypes.getSiopRequest]: {
|
|
93
|
+
id: FirstPartyMachineStateTypes.getSiopRequest,
|
|
94
|
+
invoke: {
|
|
95
|
+
src: FirstPartyMachineServices.getSiopRequest,
|
|
96
|
+
onDone: {
|
|
97
|
+
target: FirstPartyMachineStateTypes.selectCredentials,
|
|
98
|
+
actions: assign({
|
|
99
|
+
authorizationRequestData: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<SiopV2AuthorizationRequestData>) => _event.data,
|
|
100
|
+
}),
|
|
101
|
+
},
|
|
102
|
+
onError: {
|
|
103
|
+
target: FirstPartyMachineStateTypes.error,
|
|
104
|
+
actions: assign({
|
|
105
|
+
error: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<Error>): ErrorDetails => ({
|
|
106
|
+
title: translate('siopV2_machine_get_request_error_title'),
|
|
107
|
+
message: _event.data.message,
|
|
108
|
+
stack: _event.data.stack,
|
|
109
|
+
}),
|
|
110
|
+
}),
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
[FirstPartyMachineStateTypes.selectCredentials]: {
|
|
115
|
+
id: FirstPartyMachineStateTypes.selectCredentials,
|
|
116
|
+
on: {
|
|
117
|
+
[FirstPartyMachineEvents.SET_SELECTED_CREDENTIALS]: {
|
|
118
|
+
actions: assign({selectedCredentials: (_ctx: FirstPartyMachineContext, _event: FirstPartySelectCredentialsEvent) => _event.data}),
|
|
119
|
+
},
|
|
120
|
+
[FirstPartyMachineEvents.NEXT]: {
|
|
121
|
+
target: FirstPartyMachineStateTypes.sendAuthorizationResponse,
|
|
122
|
+
},
|
|
123
|
+
[FirstPartyMachineEvents.DECLINE]: {
|
|
124
|
+
target: FirstPartyMachineStateTypes.declined,
|
|
125
|
+
},
|
|
126
|
+
[FirstPartyMachineEvents.PREVIOUS]: {
|
|
127
|
+
target: FirstPartyMachineStateTypes.aborted,
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
[FirstPartyMachineStateTypes.sendAuthorizationResponse]: {
|
|
132
|
+
id: FirstPartyMachineStateTypes.sendAuthorizationResponse,
|
|
133
|
+
invoke: {
|
|
134
|
+
src: FirstPartyMachineServices.sendAuthorizationResponse,
|
|
135
|
+
onDone: {
|
|
136
|
+
target: FirstPartyMachineStateTypes.sendAuthorizationChallengeRequest,
|
|
137
|
+
actions: assign({
|
|
138
|
+
presentationDuringIssuanceSession: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<string>) => _event.data,
|
|
139
|
+
}),
|
|
140
|
+
},
|
|
141
|
+
onError: {
|
|
142
|
+
target: FirstPartyMachineStateTypes.error,
|
|
143
|
+
actions: assign({
|
|
144
|
+
error: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<Error>): ErrorDetails => ({
|
|
145
|
+
title: translate('oid4vci_machine_get_request_error_title'),
|
|
146
|
+
message: _event.data.message,
|
|
147
|
+
stack: _event.data.stack,
|
|
148
|
+
}),
|
|
149
|
+
}),
|
|
150
|
+
},
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
[FirstPartyMachineStateTypes.aborted]: {
|
|
154
|
+
id: FirstPartyMachineStateTypes.aborted,
|
|
155
|
+
type: 'final'
|
|
156
|
+
},
|
|
157
|
+
[FirstPartyMachineStateTypes.declined]: {
|
|
158
|
+
id: FirstPartyMachineStateTypes.declined,
|
|
159
|
+
type: 'final'
|
|
160
|
+
},
|
|
161
|
+
[FirstPartyMachineStateTypes.error]: {
|
|
162
|
+
id: FirstPartyMachineStateTypes.error,
|
|
163
|
+
type: 'final',
|
|
164
|
+
},
|
|
165
|
+
[FirstPartyMachineStateTypes.done]: {
|
|
166
|
+
id: FirstPartyMachineStateTypes.done,
|
|
167
|
+
type: 'final',
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const createFirstPartyActivationMachine = (opts: CreateFirstPartyMachineOpts): FirstPartyStateMachine => {
|
|
172
|
+
const initialContext: FirstPartyMachineContext = {
|
|
173
|
+
openID4VCIClientState: opts.openID4VCIClientState,
|
|
174
|
+
contact: opts.contact,
|
|
175
|
+
selectedCredentials: [],
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
return createMachine<FirstPartyMachineContext, FirstPartyMachineEventTypes>(
|
|
179
|
+
{
|
|
180
|
+
id: opts?.machineId ?? 'FirstParty',
|
|
181
|
+
predictableActionArguments: true,
|
|
182
|
+
initial: FirstPartyMachineStateTypes.sendAuthorizationChallengeRequest,
|
|
183
|
+
context: initialContext,
|
|
184
|
+
states: firstPartyMachineStates,
|
|
185
|
+
schema: {
|
|
186
|
+
events: {} as FirstPartyMachineEventTypes,
|
|
187
|
+
services: {} as {
|
|
188
|
+
[FirstPartyMachineServices.sendAuthorizationChallengeRequest]: {
|
|
189
|
+
data: void
|
|
190
|
+
},
|
|
191
|
+
[FirstPartyMachineServices.createConfig]: {
|
|
192
|
+
data: CreateConfigResult
|
|
193
|
+
},
|
|
194
|
+
[FirstPartyMachineServices.getSiopRequest]: {
|
|
195
|
+
data: SiopV2AuthorizationRequestData
|
|
196
|
+
},
|
|
197
|
+
[FirstPartyMachineServices.sendAuthorizationResponse]: {
|
|
198
|
+
data: string
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
export class FirstPartyMachine {
|
|
207
|
+
private static _instance: FirstPartyMachineInterpreter | undefined;
|
|
208
|
+
|
|
209
|
+
static hasInstance(): boolean {
|
|
210
|
+
return FirstPartyMachine._instance !== undefined;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
static get instance(): FirstPartyMachineInterpreter {
|
|
214
|
+
if (!FirstPartyMachine._instance) {
|
|
215
|
+
throw Error('Please initialize ESIMActivation machine first');
|
|
216
|
+
}
|
|
217
|
+
return FirstPartyMachine._instance;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
static clearInstance(opts: {stop: boolean}) {
|
|
221
|
+
const {stop} = opts;
|
|
222
|
+
if (FirstPartyMachine.hasInstance()) {
|
|
223
|
+
if (stop) {
|
|
224
|
+
FirstPartyMachine.stopInstance();
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
FirstPartyMachine._instance = undefined;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
static stopInstance(): void {
|
|
231
|
+
if (!FirstPartyMachine.hasInstance()) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
FirstPartyMachine.instance.stop();
|
|
235
|
+
FirstPartyMachine._instance = undefined;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
public static newInstance(opts: InstanceFirstPartyMachineOpts): FirstPartyMachineInterpreter {
|
|
239
|
+
const { agentContext } = opts
|
|
240
|
+
const services: FirstPartyMachineServiceDefinitions = {
|
|
241
|
+
[FirstPartyMachineServices.sendAuthorizationChallengeRequest]: sendAuthorizationChallengeRequest,
|
|
242
|
+
[FirstPartyMachineServices.createConfig]: (args: CreateConfigArgs) => createConfig(args, agentContext),
|
|
243
|
+
[FirstPartyMachineServices.getSiopRequest]: (args: GetSiopRequestArgs) => getSiopRequest(args, agentContext),
|
|
244
|
+
[FirstPartyMachineServices.sendAuthorizationResponse]: (args: SendAuthorizationResponseArgs) => sendAuthorizationResponse(args, agentContext),
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const newInst: FirstPartyMachineInterpreter = interpret(
|
|
248
|
+
createFirstPartyActivationMachine(opts).withConfig({
|
|
249
|
+
services: {
|
|
250
|
+
...services,
|
|
251
|
+
...opts?.services,
|
|
252
|
+
},
|
|
253
|
+
guards: {
|
|
254
|
+
...opts?.guards,
|
|
255
|
+
},
|
|
256
|
+
}),
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
if (typeof opts?.subscription === 'function') {
|
|
260
|
+
newInst.onTransition(opts.subscription);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (opts?.requireCustomNavigationHook !== true) {
|
|
264
|
+
newInst.onTransition((snapshot: FirstPartyMachineState): void => {
|
|
265
|
+
if (opts?.stateNavigationListener) {
|
|
266
|
+
void opts.stateNavigationListener(newInst, snapshot)
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return newInst;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
static getInstance(
|
|
275
|
+
opts: InstanceFirstPartyMachineOpts & {
|
|
276
|
+
requireExisting?: boolean;
|
|
277
|
+
},
|
|
278
|
+
): FirstPartyMachineInterpreter {
|
|
279
|
+
if (!FirstPartyMachine._instance) {
|
|
280
|
+
if (opts?.requireExisting === true) {
|
|
281
|
+
throw Error(`Existing FirstPartyMachine instance requested, but none was created at this point!`);
|
|
282
|
+
}
|
|
283
|
+
FirstPartyMachine._instance = FirstPartyMachine.newInstance(opts);
|
|
284
|
+
}
|
|
285
|
+
return FirstPartyMachine._instance;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
AuthorizationChallengeCodeResponse,
|
|
3
|
+
AuthzFlowType,
|
|
4
|
+
toAuthorizationResponsePayload
|
|
5
|
+
} from '@sphereon/oid4vci-common'
|
|
2
6
|
import { IBasicIssuerLocaleBranding, Identity, IIssuerLocaleBranding, Party } from '@sphereon/ssi-sdk.data-store'
|
|
3
7
|
import { assign, createMachine, DoneInvokeEvent, interpret } from 'xstate'
|
|
4
8
|
import { translate } from '../localization/Localization'
|
|
@@ -29,6 +33,7 @@ import {
|
|
|
29
33
|
SetAuthorizationCodeURLEvent,
|
|
30
34
|
VerificationCodeEvent,
|
|
31
35
|
} from '../types/IOID4VCIHolder'
|
|
36
|
+
import { FirstPartyMachineStateTypes } from '../types/FirstPartyMachine'
|
|
32
37
|
|
|
33
38
|
const oid4vciHasNoContactGuard = (_ctx: OID4VCIMachineContext, _event: OID4VCIMachineEventTypes): boolean => {
|
|
34
39
|
const { contact } = _ctx
|
|
@@ -117,6 +122,10 @@ const oid4vciHasAuthorizationResponse = (ctx: OID4VCIMachineContext, _event: OID
|
|
|
117
122
|
return !!ctx.openID4VCIClientState?.authorizationCodeResponse
|
|
118
123
|
}
|
|
119
124
|
|
|
125
|
+
const oid4vciIsFirstPartyApplication = (ctx: OID4VCIMachineContext, _event: OID4VCIMachineEventTypes): boolean => {
|
|
126
|
+
return !!ctx.serverMetadata?.authorization_challenge_endpoint
|
|
127
|
+
}
|
|
128
|
+
|
|
120
129
|
const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMachine => {
|
|
121
130
|
const initialContext: OID4VCIMachineContext = {
|
|
122
131
|
// 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 +162,8 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
|
|
|
153
162
|
| { type: OID4VCIMachineGuards.hasSelectedCredentialsGuard }
|
|
154
163
|
| { type: OID4VCIMachineGuards.hasAuthorizationResponse }
|
|
155
164
|
| { type: OID4VCIMachineGuards.isOIDFOriginGuard }
|
|
156
|
-
| { type: OID4VCIMachineGuards.contactHasLowTrustGuard }
|
|
165
|
+
| { type: OID4VCIMachineGuards.contactHasLowTrustGuard }
|
|
166
|
+
| { type: OID4VCIMachineGuards.isFirstPartyApplication },
|
|
157
167
|
services: {} as {
|
|
158
168
|
[OID4VCIMachineServices.start]: {
|
|
159
169
|
data: StartResult
|
|
@@ -188,6 +198,9 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
|
|
|
188
198
|
[OID4VCIMachineServices.getIssuerBranding]: {
|
|
189
199
|
data: Array<IIssuerLocaleBranding | IBasicIssuerLocaleBranding>
|
|
190
200
|
}
|
|
201
|
+
[OID4VCIMachineServices.startFirstPartApplicationFlow]: {
|
|
202
|
+
data: void
|
|
203
|
+
}
|
|
191
204
|
},
|
|
192
205
|
},
|
|
193
206
|
context: initialContext,
|
|
@@ -332,6 +345,10 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
|
|
|
332
345
|
target: OID4VCIMachineStates.selectCredentials,
|
|
333
346
|
cond: OID4VCIMachineGuards.credentialsToSelectRequiredGuard,
|
|
334
347
|
},
|
|
348
|
+
{
|
|
349
|
+
target: OID4VCIMachineStates.startFirstPartApplicationFlow,
|
|
350
|
+
cond: OID4VCIMachineGuards.isFirstPartyApplication,
|
|
351
|
+
},
|
|
335
352
|
{
|
|
336
353
|
target: OID4VCIMachineStates.initiateAuthorizationRequest,
|
|
337
354
|
cond: OID4VCIMachineGuards.requireAuthorizationGuard,
|
|
@@ -422,6 +439,10 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
|
|
|
422
439
|
target: OID4VCIMachineStates.selectCredentials,
|
|
423
440
|
cond: OID4VCIMachineGuards.credentialsToSelectRequiredGuard,
|
|
424
441
|
},
|
|
442
|
+
{
|
|
443
|
+
target: OID4VCIMachineStates.startFirstPartApplicationFlow,
|
|
444
|
+
cond: OID4VCIMachineGuards.isFirstPartyApplication,
|
|
445
|
+
},
|
|
425
446
|
{
|
|
426
447
|
target: OID4VCIMachineStates.initiateAuthorizationRequest,
|
|
427
448
|
cond: OID4VCIMachineGuards.requireAuthorizationGuard,
|
|
@@ -435,6 +456,41 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
|
|
|
435
456
|
},
|
|
436
457
|
],
|
|
437
458
|
},
|
|
459
|
+
[OID4VCIMachineStates.startFirstPartApplicationFlow] :{
|
|
460
|
+
id: OID4VCIMachineStates.startFirstPartApplicationFlow,
|
|
461
|
+
invoke: {
|
|
462
|
+
src: OID4VCIMachineServices.startFirstPartApplicationFlow,
|
|
463
|
+
onDone: [
|
|
464
|
+
{
|
|
465
|
+
target: OID4VCIMachineStates.aborted,
|
|
466
|
+
cond: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<FirstPartyMachineStateTypes>): boolean => _event.data === FirstPartyMachineStateTypes.aborted,
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
target: OID4VCIMachineStates.declined,
|
|
470
|
+
cond: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<FirstPartyMachineStateTypes>): boolean => _event.data === FirstPartyMachineStateTypes.declined,
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
target: OID4VCIMachineStates.getCredentials,
|
|
474
|
+
actions: assign({
|
|
475
|
+
openID4VCIClientState: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<AuthorizationChallengeCodeResponse>) => {
|
|
476
|
+
const authorizationCodeResponse = toAuthorizationResponsePayload(_event.data)
|
|
477
|
+
return { ..._ctx.openID4VCIClientState!, authorizationCodeResponse }
|
|
478
|
+
}
|
|
479
|
+
})
|
|
480
|
+
}
|
|
481
|
+
],
|
|
482
|
+
onError: {
|
|
483
|
+
target: OID4VCIMachineStates.handleError,
|
|
484
|
+
actions: assign({
|
|
485
|
+
error: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<ErrorDetails>): ErrorDetails => ({
|
|
486
|
+
title: _event.data.title ?? translate('oid4vci_machine_first_party_error_title'),
|
|
487
|
+
message: _event.data.message,
|
|
488
|
+
stack: _event.data.stack,
|
|
489
|
+
}),
|
|
490
|
+
}),
|
|
491
|
+
},
|
|
492
|
+
},
|
|
493
|
+
},
|
|
438
494
|
[OID4VCIMachineStates.selectCredentials]: {
|
|
439
495
|
id: OID4VCIMachineStates.selectCredentials,
|
|
440
496
|
on: {
|
|
@@ -453,6 +509,10 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
|
|
|
453
509
|
[OID4VCIMachineStates.transitionFromSelectingCredentials]: {
|
|
454
510
|
id: OID4VCIMachineStates.transitionFromSelectingCredentials,
|
|
455
511
|
always: [
|
|
512
|
+
{
|
|
513
|
+
target: OID4VCIMachineStates.startFirstPartApplicationFlow,
|
|
514
|
+
cond: OID4VCIMachineGuards.isFirstPartyApplication,
|
|
515
|
+
},
|
|
456
516
|
{
|
|
457
517
|
target: OID4VCIMachineStates.verifyPin,
|
|
458
518
|
cond: OID4VCIMachineGuards.requirePinGuard,
|
|
@@ -726,6 +786,7 @@ export class OID4VCIMachine {
|
|
|
726
786
|
oid4vciHasAuthorizationResponse,
|
|
727
787
|
oid4vciIsOIDFOriginGuard,
|
|
728
788
|
oid4vciContactHasLowTrustGuard,
|
|
789
|
+
oid4vciIsFirstPartyApplication,
|
|
729
790
|
...opts?.guards,
|
|
730
791
|
},
|
|
731
792
|
}),
|
|
@@ -737,7 +798,7 @@ export class OID4VCIMachine {
|
|
|
737
798
|
if (opts?.requireCustomNavigationHook !== true) {
|
|
738
799
|
if (typeof opts?.stateNavigationListener === 'function') {
|
|
739
800
|
interpreter.onTransition((snapshot: OID4VCIMachineState): void => {
|
|
740
|
-
if (opts?.stateNavigationListener
|
|
801
|
+
if (opts?.stateNavigationListener) {
|
|
741
802
|
opts.stateNavigationListener(interpreter, snapshot)
|
|
742
803
|
}
|
|
743
804
|
})
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { CredentialsSupportedDisplay, NameAndLocale } from '@sphereon/oid4vci-common'
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
IBasicCredentialClaim,
|
|
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'
|
|
4
13
|
import {
|
|
5
14
|
IssuerLocaleBrandingFromArgs,
|
|
6
15
|
Oid4vciCombineDisplayLocalesFromArgs,
|
|
@@ -17,9 +26,7 @@ import {
|
|
|
17
26
|
|
|
18
27
|
// FIXME should we not move this to the branding plugin?
|
|
19
28
|
|
|
20
|
-
export const oid4vciGetCredentialBrandingFrom = async (
|
|
21
|
-
args: Oid4vciGetCredentialBrandingFromArgs,
|
|
22
|
-
): Promise<Array<IBasicCredentialLocaleBranding>> => {
|
|
29
|
+
export const oid4vciGetCredentialBrandingFrom = async (args: Oid4vciGetCredentialBrandingFromArgs): Promise<Array<IBasicCredentialLocaleBranding>> => {
|
|
23
30
|
const { credentialDisplay, issuerCredentialSubject } = args
|
|
24
31
|
|
|
25
32
|
return oid4vciCombineDisplayLocalesFrom({
|
|
@@ -28,9 +35,7 @@ export const oid4vciGetCredentialBrandingFrom = async (
|
|
|
28
35
|
})
|
|
29
36
|
}
|
|
30
37
|
|
|
31
|
-
export const oid4vciCredentialDisplayLocalesFrom = async (
|
|
32
|
-
args: Oid4vciCredentialDisplayLocalesFromArgs,
|
|
33
|
-
): Promise<Map<string, CredentialsSupportedDisplay>> => {
|
|
38
|
+
export const oid4vciCredentialDisplayLocalesFrom = async (args: Oid4vciCredentialDisplayLocalesFromArgs): Promise<Map<string, CredentialsSupportedDisplay>> => {
|
|
34
39
|
const { credentialDisplay } = args
|
|
35
40
|
return credentialDisplay.reduce((localeDisplays, display) => {
|
|
36
41
|
const localeKey = display.locale || ''
|
|
@@ -39,9 +44,7 @@ export const oid4vciCredentialDisplayLocalesFrom = async (
|
|
|
39
44
|
}, new Map<string, CredentialsSupportedDisplay>())
|
|
40
45
|
}
|
|
41
46
|
|
|
42
|
-
export const oid4vciIssuerCredentialSubjectLocalesFrom = async (
|
|
43
|
-
args: Oid4vciIssuerCredentialSubjectLocalesFromArgs,
|
|
44
|
-
): Promise<Map<string, Array<IBasicCredentialClaim>>> => {
|
|
47
|
+
export const oid4vciIssuerCredentialSubjectLocalesFrom = async (args: Oid4vciIssuerCredentialSubjectLocalesFromArgs): Promise<Map<string, Array<IBasicCredentialClaim>>> => {
|
|
45
48
|
const { issuerCredentialSubject } = args
|
|
46
49
|
const localeClaims = new Map<string, Array<IBasicCredentialClaim>>()
|
|
47
50
|
|
|
@@ -122,9 +125,7 @@ export const oid4vciCredentialLocaleBrandingFrom = async (args: Oid4vciCredentia
|
|
|
122
125
|
}
|
|
123
126
|
}
|
|
124
127
|
|
|
125
|
-
export const oid4vciCombineDisplayLocalesFrom = async (
|
|
126
|
-
args: Oid4vciCombineDisplayLocalesFromArgs,
|
|
127
|
-
): Promise<Array<IBasicCredentialLocaleBranding>> => {
|
|
128
|
+
export const oid4vciCombineDisplayLocalesFrom = async (args: Oid4vciCombineDisplayLocalesFromArgs): Promise<Array<IBasicCredentialLocaleBranding>> => {
|
|
128
129
|
const {
|
|
129
130
|
credentialDisplayLocales = new Map<string, CredentialsSupportedDisplay>(),
|
|
130
131
|
issuerCredentialSubjectLocales = new Map<string, Array<IBasicCredentialClaim>>(),
|
|
@@ -155,9 +156,7 @@ export const sdJwtGetCredentialBrandingFrom = async (args: SdJwtGetCredentialBra
|
|
|
155
156
|
})
|
|
156
157
|
}
|
|
157
158
|
|
|
158
|
-
export const sdJwtCredentialDisplayLocalesFrom = async (
|
|
159
|
-
args: SdJwtCredentialDisplayLocalesFromArgs,
|
|
160
|
-
): Promise<Map<string, SdJwtTypeDisplayMetadata>> => {
|
|
159
|
+
export const sdJwtCredentialDisplayLocalesFrom = async (args: SdJwtCredentialDisplayLocalesFromArgs): Promise<Map<string, SdJwtTypeDisplayMetadata>> => {
|
|
161
160
|
const { credentialDisplay } = args
|
|
162
161
|
return credentialDisplay.reduce((localeDisplays, display) => {
|
|
163
162
|
const localeKey = display.lang || ''
|
|
@@ -166,16 +165,14 @@ export const sdJwtCredentialDisplayLocalesFrom = async (
|
|
|
166
165
|
}, new Map<string, SdJwtTypeDisplayMetadata>())
|
|
167
166
|
}
|
|
168
167
|
|
|
169
|
-
export const sdJwtCredentialClaimLocalesFrom = async (
|
|
170
|
-
args: SdJwtCredentialClaimLocalesFromArgs,
|
|
171
|
-
): Promise<Map<string, Array<IBasicCredentialClaim>>> => {
|
|
168
|
+
export const sdJwtCredentialClaimLocalesFrom = async (args: SdJwtCredentialClaimLocalesFromArgs): Promise<Map<string, Array<IBasicCredentialClaim>>> => {
|
|
172
169
|
const { claimsMetadata } = args
|
|
173
170
|
const localeClaims = new Map<string, Array<IBasicCredentialClaim>>()
|
|
174
171
|
|
|
175
172
|
claimsMetadata.forEach((claim: SdJwtClaimMetadata): void => {
|
|
176
173
|
claim.display?.forEach((display: SdJwtClaimDisplayMetadata): void => {
|
|
177
|
-
const { lang = '', label } = display
|
|
178
|
-
const key = claim.path.map((value: SdJwtClaimPath) => String(value)).join('.')
|
|
174
|
+
const { lang = '', label } = display;
|
|
175
|
+
const key = claim.path.map((value: SdJwtClaimPath) => String(value)).join('.');
|
|
179
176
|
if (!localeClaims.has(lang)) {
|
|
180
177
|
localeClaims.set(lang, [])
|
|
181
178
|
}
|
|
@@ -183,7 +180,7 @@ export const sdJwtCredentialClaimLocalesFrom = async (
|
|
|
183
180
|
})
|
|
184
181
|
})
|
|
185
182
|
|
|
186
|
-
return localeClaims
|
|
183
|
+
return localeClaims;
|
|
187
184
|
}
|
|
188
185
|
|
|
189
186
|
export const sdJwtCredentialLocaleBrandingFrom = async (args: SdJwtCredentialLocaleBrandingFromArgs): Promise<IBasicCredentialLocaleBranding> => {
|
|
@@ -216,15 +213,17 @@ export const sdJwtCredentialLocaleBrandingFrom = async (args: SdJwtCredentialLoc
|
|
|
216
213
|
}),
|
|
217
214
|
...(credentialDisplay.rendering?.simple?.background_color && {
|
|
218
215
|
background: {
|
|
219
|
-
color: credentialDisplay.rendering.simple.background_color,
|
|
216
|
+
color: credentialDisplay.rendering.simple.background_color ,
|
|
220
217
|
},
|
|
221
218
|
}),
|
|
222
219
|
}
|
|
223
220
|
}
|
|
224
221
|
|
|
225
222
|
export const sdJwtCombineDisplayLocalesFrom = async (args: SdJwtCombineDisplayLocalesFromArgs): Promise<Array<IBasicCredentialLocaleBranding>> => {
|
|
226
|
-
const {
|
|
227
|
-
|
|
223
|
+
const {
|
|
224
|
+
credentialDisplayLocales = new Map<string, SdJwtTypeDisplayMetadata>(),
|
|
225
|
+
claimsMetadata = new Map<string, Array<IBasicCredentialClaim>>(),
|
|
226
|
+
} = args
|
|
228
227
|
|
|
229
228
|
const locales: Array<string> = Array.from(new Set([...claimsMetadata.keys(), ...credentialDisplayLocales.keys()]))
|
|
230
229
|
|
|
@@ -0,0 +1,63 @@
|
|
|
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 && openID4VCIClientState.credentialOffer?.preAuthorizedCode && { issuerState: openID4VCIClientState.credentialOffer?.preAuthorizedCode }),
|
|
23
|
+
...(!authSession && openID4VCIClientState.credentialOffer?.issuerState && { issuerState: openID4VCIClientState.credentialOffer?.issuerState }),
|
|
24
|
+
...(presentationDuringIssuanceSession && { presentationDuringIssuanceSession })
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const createConfig = async (args: CreateConfigArgs, context: RequiredContext): Promise<CreateConfigResult> => {
|
|
29
|
+
const { presentationUri } = args;
|
|
30
|
+
|
|
31
|
+
if (!presentationUri) {
|
|
32
|
+
return Promise.reject(Error('Missing presentation uri in context'));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return context.agent.siopCreateConfig({ url: presentationUri })
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const getSiopRequest = async (args: GetSiopRequestArgs, context: RequiredContext): Promise<SiopV2AuthorizationRequestData> => {
|
|
39
|
+
const {didAuthConfig, presentationUri} = args;
|
|
40
|
+
|
|
41
|
+
if (presentationUri === undefined) {
|
|
42
|
+
return Promise.reject(Error('Missing presentation uri in context'));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (didAuthConfig === undefined) {
|
|
46
|
+
return Promise.reject(Error('Missing did auth config in context'));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return context.agent.siopGetSiopRequest({ didAuthConfig, url: presentationUri })
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const sendAuthorizationResponse = async (args: SendAuthorizationResponseArgs, context: RequiredContext): Promise<string> => {
|
|
53
|
+
const { didAuthConfig, authorizationRequestData, selectedCredentials } = args
|
|
54
|
+
|
|
55
|
+
const responseData = await context.agent.siopSendResponse({
|
|
56
|
+
authorizationRequestData,
|
|
57
|
+
selectedCredentials,
|
|
58
|
+
didAuthConfig,
|
|
59
|
+
isFirstParty: true
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
return (<AuthorizationChallengeValidationResponse>responseData.body).presentation_during_issuance_session
|
|
63
|
+
}
|