@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
|
@@ -4,6 +4,8 @@ import {
|
|
|
4
4
|
AuthorizationRequestOpts,
|
|
5
5
|
AuthorizationServerClientOpts,
|
|
6
6
|
AuthorizationServerOpts,
|
|
7
|
+
CredentialConfigurationSupportedJwtVcJsonLdAndLdpVcV1_0_13,
|
|
8
|
+
CredentialDefinitionJwtVcJsonLdAndLdpVcV1_0_13,
|
|
7
9
|
CredentialOfferRequestWithBaseUrl,
|
|
8
10
|
DefaultURISchemes,
|
|
9
11
|
EndpointMetadataResult,
|
|
@@ -45,7 +47,7 @@ import {
|
|
|
45
47
|
} from '@sphereon/ssi-sdk.data-store'
|
|
46
48
|
import {
|
|
47
49
|
CredentialMapper,
|
|
48
|
-
|
|
50
|
+
HasherSync,
|
|
49
51
|
IVerifiableCredential,
|
|
50
52
|
JoseSignatureAlgorithm,
|
|
51
53
|
JoseSignatureAlgorithmString,
|
|
@@ -70,12 +72,12 @@ import {
|
|
|
70
72
|
import { asArray, computeEntryHash } from '@veramo/utils'
|
|
71
73
|
import { decodeJWT } from 'did-jwt'
|
|
72
74
|
import { v4 as uuidv4 } from 'uuid'
|
|
73
|
-
import { OID4VCIMachine } from '../
|
|
75
|
+
import { OID4VCIMachine } from '../machines/oid4vciMachine'
|
|
74
76
|
import {
|
|
75
77
|
AddContactIdentityArgs,
|
|
76
78
|
AssertValidCredentialsArgs,
|
|
77
79
|
Attribute,
|
|
78
|
-
|
|
80
|
+
CreateCredentialsToSelectFromArgs,
|
|
79
81
|
CredentialToAccept,
|
|
80
82
|
CredentialToSelectFromResult,
|
|
81
83
|
GetContactArgs,
|
|
@@ -91,6 +93,8 @@ import {
|
|
|
91
93
|
OID4VCIHolderOptions,
|
|
92
94
|
OID4VCIMachine as OID4VCIMachineId,
|
|
93
95
|
OID4VCIMachineInstanceOpts,
|
|
96
|
+
OID4VCIMachineServiceDefinitions,
|
|
97
|
+
OID4VCIMachineServices,
|
|
94
98
|
OnContactIdentityCreatedArgs,
|
|
95
99
|
OnCredentialStoredArgs,
|
|
96
100
|
OnIdentifierCreatedArgs,
|
|
@@ -98,6 +102,7 @@ import {
|
|
|
98
102
|
RequestType,
|
|
99
103
|
RequiredContext,
|
|
100
104
|
SendNotificationArgs,
|
|
105
|
+
StartFirstPartApplicationMachine,
|
|
101
106
|
StartResult,
|
|
102
107
|
StoreCredentialBrandingArgs,
|
|
103
108
|
StoreCredentialsArgs,
|
|
@@ -114,10 +119,11 @@ import {
|
|
|
114
119
|
getIssuanceOpts,
|
|
115
120
|
mapCredentialToAccept,
|
|
116
121
|
selectCredentialLocaleBranding,
|
|
122
|
+
startFirstPartApplicationMachine,
|
|
117
123
|
verifyCredentialToAccept,
|
|
118
|
-
} from '
|
|
119
|
-
|
|
124
|
+
} from '../services/OID4VCIHolderService'
|
|
120
125
|
import 'cross-fetch/polyfill'
|
|
126
|
+
import { defaultHasher } from '@sphereon/ssi-sdk.core'
|
|
121
127
|
|
|
122
128
|
/**
|
|
123
129
|
* {@inheritDoc IOID4VCIHolder}
|
|
@@ -199,7 +205,7 @@ export async function verifyEBSICredentialIssuer(args: VerifyEBSICredentialIssue
|
|
|
199
205
|
}
|
|
200
206
|
|
|
201
207
|
export class OID4VCIHolder implements IAgentPlugin {
|
|
202
|
-
private readonly hasher?:
|
|
208
|
+
private readonly hasher?: HasherSync
|
|
203
209
|
readonly eventTypes: Array<OID4VCIHolderEvent> = [
|
|
204
210
|
OID4VCIHolderEvent.CONTACT_IDENTITY_CREATED,
|
|
205
211
|
OID4VCIHolderEvent.CREDENTIAL_STORED,
|
|
@@ -261,7 +267,7 @@ export class OID4VCIHolder implements IAgentPlugin {
|
|
|
261
267
|
didMethodPreferences,
|
|
262
268
|
jwtCryptographicSuitePreferences,
|
|
263
269
|
defaultAuthorizationRequestOptions,
|
|
264
|
-
hasher,
|
|
270
|
+
hasher = defaultHasher,
|
|
265
271
|
} = { ...options }
|
|
266
272
|
|
|
267
273
|
this.hasher = hasher
|
|
@@ -307,8 +313,8 @@ export class OID4VCIHolder implements IAgentPlugin {
|
|
|
307
313
|
*/
|
|
308
314
|
private async oid4vciHolderGetMachineInterpreter(opts: OID4VCIMachineInstanceOpts, context: RequiredContext): Promise<OID4VCIMachineId> {
|
|
309
315
|
const authorizationRequestOpts = { ...this.defaultAuthorizationRequestOpts, ...opts.authorizationRequestOpts }
|
|
310
|
-
const services = {
|
|
311
|
-
start: (args: PrepareStartArgs) =>
|
|
316
|
+
const services: OID4VCIMachineServiceDefinitions = {
|
|
317
|
+
[OID4VCIMachineServices.start]: (args: PrepareStartArgs) =>
|
|
312
318
|
this.oid4vciHolderStart(
|
|
313
319
|
{
|
|
314
320
|
...args,
|
|
@@ -316,18 +322,22 @@ export class OID4VCIHolder implements IAgentPlugin {
|
|
|
316
322
|
},
|
|
317
323
|
context,
|
|
318
324
|
),
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
325
|
+
[OID4VCIMachineServices.startFirstPartApplicationFlow]: (args: StartFirstPartApplicationMachine) =>
|
|
326
|
+
startFirstPartApplicationMachine({ ...args, stateNavigationListener: opts.firstPartyStateNavigationListener }, context),
|
|
327
|
+
[OID4VCIMachineServices.createCredentialsToSelectFrom]: (args: CreateCredentialsToSelectFromArgs) =>
|
|
328
|
+
this.oid4vciHolderCreateCredentialsToSelectFrom(args, context),
|
|
329
|
+
[OID4VCIMachineServices.getContact]: (args: GetContactArgs) => this.oid4vciHolderGetContact(args, context),
|
|
330
|
+
[OID4VCIMachineServices.getCredentials]: (args: GetCredentialsArgs) =>
|
|
322
331
|
this.oid4vciHolderGetCredentials({ accessTokenOpts: args.accessTokenOpts ?? opts.accessTokenOpts, ...args }, context),
|
|
323
|
-
addContactIdentity: (args: AddContactIdentityArgs) => this.oid4vciHolderAddContactIdentity(args, context),
|
|
324
|
-
getIssuerBranding: (args: GetIssuerBrandingArgs) => this.oid4vciHolderGetIssuerBranding(args, context),
|
|
325
|
-
storeIssuerBranding: (args: StoreIssuerBrandingArgs) => this.oid4vciHolderStoreIssuerBranding(args, context),
|
|
326
|
-
assertValidCredentials: (args: AssertValidCredentialsArgs) => this.oid4vciHolderAssertValidCredentials(args, context),
|
|
327
|
-
storeCredentialBranding: (args: StoreCredentialBrandingArgs) =>
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
332
|
+
[OID4VCIMachineServices.addContactIdentity]: (args: AddContactIdentityArgs) => this.oid4vciHolderAddContactIdentity(args, context),
|
|
333
|
+
[OID4VCIMachineServices.getIssuerBranding]: (args: GetIssuerBrandingArgs) => this.oid4vciHolderGetIssuerBranding(args, context),
|
|
334
|
+
[OID4VCIMachineServices.storeIssuerBranding]: (args: StoreIssuerBrandingArgs) => this.oid4vciHolderStoreIssuerBranding(args, context),
|
|
335
|
+
[OID4VCIMachineServices.assertValidCredentials]: (args: AssertValidCredentialsArgs) => this.oid4vciHolderAssertValidCredentials(args, context),
|
|
336
|
+
[OID4VCIMachineServices.storeCredentialBranding]: (args: StoreCredentialBrandingArgs) =>
|
|
337
|
+
this.oid4vciHolderStoreCredentialBranding(args, context),
|
|
338
|
+
[OID4VCIMachineServices.storeCredentials]: (args: StoreCredentialsArgs) => this.oid4vciHolderStoreCredentials(args, context),
|
|
339
|
+
[OID4VCIMachineServices.sendNotification]: (args: SendNotificationArgs) => this.oid4vciHolderSendNotification(args, context),
|
|
340
|
+
[OID4VCIMachineServices.getFederationTrust]: (args: GetFederationTrustArgs) => this.getFederationTrust(args, context),
|
|
331
341
|
}
|
|
332
342
|
|
|
333
343
|
const oid4vciMachineInstanceArgs: OID4VCIMachineInstanceOpts = {
|
|
@@ -463,7 +473,7 @@ export class OID4VCIHolder implements IAgentPlugin {
|
|
|
463
473
|
}
|
|
464
474
|
|
|
465
475
|
private async oid4vciHolderCreateCredentialsToSelectFrom(
|
|
466
|
-
args:
|
|
476
|
+
args: CreateCredentialsToSelectFromArgs,
|
|
467
477
|
context: RequiredContext,
|
|
468
478
|
): Promise<Array<CredentialToSelectFromResult>> {
|
|
469
479
|
const { credentialBranding, locale, selectedCredentials /*, openID4VCIClientState*/, credentialsSupported } = args
|
|
@@ -629,7 +639,7 @@ export class OID4VCIHolder implements IAgentPlugin {
|
|
|
629
639
|
// The VCI lib either expects a jwk or a kid
|
|
630
640
|
const jwk = isManagedIdentifierJwkResult(identifier) ? identifier.jwk : undefined
|
|
631
641
|
|
|
632
|
-
const callbacks: ProofOfPossessionCallbacks
|
|
642
|
+
const callbacks: ProofOfPossessionCallbacks = {
|
|
633
643
|
signCallback: signCallback(identifier, context),
|
|
634
644
|
}
|
|
635
645
|
|
|
@@ -675,7 +685,10 @@ export class OID4VCIHolder implements IAgentPlugin {
|
|
|
675
685
|
if (!credentialTypes || credentialTypes.length === 0) {
|
|
676
686
|
return Promise.reject(Error('cannot determine credential id to request'))
|
|
677
687
|
}
|
|
688
|
+
|
|
689
|
+
const credentialDefinition = this.getCredentialDefinition(issuanceOpt)
|
|
678
690
|
const credentialResponse = await client.acquireCredentials({
|
|
691
|
+
...(credentialDefinition && { context: credentialDefinition['@context'] }),
|
|
679
692
|
credentialTypes,
|
|
680
693
|
proofCallbacks: callbacks,
|
|
681
694
|
format: issuanceOpt.format,
|
|
@@ -908,7 +921,7 @@ export class OID4VCIHolder implements IAgentPlugin {
|
|
|
908
921
|
: 'credential_deleted_holder_signed'
|
|
909
922
|
logger.log(`Subject issuance/signing will be used, with event`, event)
|
|
910
923
|
const issuerVC = mappedCredentialToAccept.credentialToAccept.credentialResponse.credential as OriginalVerifiableCredential
|
|
911
|
-
const wrappedIssuerVC = CredentialMapper.toWrappedVerifiableCredential(issuerVC, { hasher: this.hasher })
|
|
924
|
+
const wrappedIssuerVC = CredentialMapper.toWrappedVerifiableCredential(issuerVC, { hasher: this.hasher ?? defaultHasher })
|
|
912
925
|
console.log(`Wrapped VC: ${wrappedIssuerVC.type}, ${wrappedIssuerVC.format}`)
|
|
913
926
|
// We will use the subject of the VCI Issuer (the holder, as the issuer of the new credential, so the below is not a mistake!)
|
|
914
927
|
|
|
@@ -1075,6 +1088,11 @@ export class OID4VCIHolder implements IAgentPlugin {
|
|
|
1075
1088
|
const params = new URLSearchParams(url.search)
|
|
1076
1089
|
const openidFederation = params.get('openid_federation')
|
|
1077
1090
|
const entityIdentifier = openidFederation ?? serverMetadata.issuer
|
|
1091
|
+
if (entityIdentifier.startsWith('http://')) {
|
|
1092
|
+
console.warn(`OpenID federation does not support http://, only https:// allowed; got: (${url.toString()})`)
|
|
1093
|
+
// OIDF always needs to be https
|
|
1094
|
+
return []
|
|
1095
|
+
}
|
|
1078
1096
|
|
|
1079
1097
|
const result = await context.agent.identifierExternalResolveByOIDFEntityId({
|
|
1080
1098
|
method: 'entity_id',
|
|
@@ -1127,4 +1145,11 @@ export class OID4VCIHolder implements IAgentPlugin {
|
|
|
1127
1145
|
}
|
|
1128
1146
|
return undefined
|
|
1129
1147
|
}
|
|
1148
|
+
|
|
1149
|
+
private getCredentialDefinition(issuanceOpt: IssuanceOpts): CredentialDefinitionJwtVcJsonLdAndLdpVcV1_0_13 | undefined {
|
|
1150
|
+
if (issuanceOpt.format == 'ldp_vc' || issuanceOpt.format == 'jwt_vc_json-ld') {
|
|
1151
|
+
return (issuanceOpt as CredentialConfigurationSupportedJwtVcJsonLdAndLdpVcV1_0_13).credential_definition
|
|
1152
|
+
}
|
|
1153
|
+
return undefined
|
|
1154
|
+
}
|
|
1130
1155
|
}
|
package/src/index.ts
CHANGED
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
export { OID4VCIHolder, oid4vciHolderContextMethods, signCallback } from './agent/OID4VCIHolder'
|
|
6
|
-
export * from './
|
|
6
|
+
export * from './mappers/OIDC4VCIBrandingMapper'
|
|
7
|
+
export * from './services/OID4VCIHolderService'
|
|
8
|
+
export * from './services/FirstPartyMachineServices'
|
|
7
9
|
export * from './types/IOID4VCIHolder'
|
|
8
|
-
export * from './
|
|
10
|
+
export * from './types/FirstPartyMachine'
|
|
11
|
+
export * from './listeners/headlessStateNavListener'
|
|
9
12
|
export * from './link-handler'
|
|
@@ -3,23 +3,26 @@ import { AuthorizationRequestOpts, AuthorizationServerClientOpts, AuthzFlowType,
|
|
|
3
3
|
import { DefaultLinkPriorities, LinkHandlerAdapter } from '@sphereon/ssi-sdk.core'
|
|
4
4
|
import { IMachineStatePersistence, interpreterStartOrResume, SerializableState } from '@sphereon/ssi-sdk.xstate-machine-persistence'
|
|
5
5
|
import { IAgentContext } from '@veramo/core'
|
|
6
|
-
import { GetMachineArgs, IOID4VCIHolder, OID4VCIMachineEvents,
|
|
6
|
+
import { GetMachineArgs, IOID4VCIHolder, OID4VCIMachineEvents, OID4VCIMachineStateNavigationListener } from '../types/IOID4VCIHolder'
|
|
7
|
+
import { FirstPartyMachineStateNavigationListener } from '../types/FirstPartyMachine'
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* This handler only handles credential offer links (either by value or by reference)
|
|
10
11
|
*/
|
|
11
12
|
export class OID4VCIHolderLinkHandler extends LinkHandlerAdapter {
|
|
12
13
|
private readonly context: IAgentContext<IOID4VCIHolder & IMachineStatePersistence>
|
|
13
|
-
private readonly stateNavigationListener
|
|
14
|
-
|
|
15
|
-
| undefined
|
|
14
|
+
private readonly stateNavigationListener?: OID4VCIMachineStateNavigationListener
|
|
15
|
+
private readonly firstPartyStateNavigationListener?: FirstPartyMachineStateNavigationListener
|
|
16
16
|
private readonly noStateMachinePersistence: boolean
|
|
17
17
|
private readonly authorizationRequestOpts?: AuthorizationRequestOpts
|
|
18
18
|
private readonly clientOpts?: AuthorizationServerClientOpts
|
|
19
19
|
private readonly trustAnchors?: Array<string>
|
|
20
20
|
|
|
21
21
|
constructor(
|
|
22
|
-
args: Pick<
|
|
22
|
+
args: Pick<
|
|
23
|
+
GetMachineArgs,
|
|
24
|
+
'stateNavigationListener' | 'authorizationRequestOpts' | 'clientOpts' | 'trustAnchors' | 'firstPartyStateNavigationListener'
|
|
25
|
+
> & {
|
|
23
26
|
priority?: number | DefaultLinkPriorities
|
|
24
27
|
protocols?: Array<string | RegExp>
|
|
25
28
|
noStateMachinePersistence?: boolean
|
|
@@ -32,6 +35,7 @@ export class OID4VCIHolderLinkHandler extends LinkHandlerAdapter {
|
|
|
32
35
|
this.context = args.context
|
|
33
36
|
this.noStateMachinePersistence = args.noStateMachinePersistence === true
|
|
34
37
|
this.stateNavigationListener = args.stateNavigationListener
|
|
38
|
+
this.firstPartyStateNavigationListener = args.firstPartyStateNavigationListener
|
|
35
39
|
this.trustAnchors = args.trustAnchors
|
|
36
40
|
}
|
|
37
41
|
|
|
@@ -63,6 +67,7 @@ export class OID4VCIHolderLinkHandler extends LinkHandlerAdapter {
|
|
|
63
67
|
authorizationRequestOpts: { ...this.authorizationRequestOpts, ...opts?.authorizationRequestOpts },
|
|
64
68
|
...((clientOpts.clientId || clientOpts.clientAssertionType) && { clientOpts: clientOpts as AuthorizationServerClientOpts }),
|
|
65
69
|
stateNavigationListener: this.stateNavigationListener,
|
|
70
|
+
firstPartyStateNavigationListener: this.firstPartyStateNavigationListener,
|
|
66
71
|
})
|
|
67
72
|
|
|
68
73
|
const interpreter = oid4vciMachine.interpreter
|
|
@@ -11,5 +11,9 @@
|
|
|
11
11
|
"oid4vci_machine_initiation_error_title": "Initiate OID4VCI provider",
|
|
12
12
|
"oid4vci_machine_credential_verification_failed_message": "The credential verification resulted in an error.",
|
|
13
13
|
"oid4vci_machine_credential_verification_schema_failed_message": "The credential schema verification resulted in an error.",
|
|
14
|
-
"oid4vci_machine_retrieve_federation_trust_error_title": "Retrieve federation trust"
|
|
14
|
+
"oid4vci_machine_retrieve_federation_trust_error_title": "Retrieve federation trust",
|
|
15
|
+
"oid4vci_machine_first_party_error_title": "First party flow",
|
|
16
|
+
"oid4vci_machine_send_authorization_challenge_request_error_title": "Sending authorization challenge request",
|
|
17
|
+
"oid4vci_machine_create_config_error_title": "Creating siopV2 config",
|
|
18
|
+
"oid4vci_machine_get_request_error_title": "Getting siopV2 request"
|
|
15
19
|
}
|
|
@@ -10,5 +10,9 @@
|
|
|
10
10
|
"oid4vci_machine_credential_selection_error_title": "Credential selectie",
|
|
11
11
|
"oid4vci_machine_initiation_error_title": "Initiëren OID4VCI provider",
|
|
12
12
|
"oid4vci_machine_credential_verification_failed_message": "Verificatie van de credential leidde tot een fout.",
|
|
13
|
-
"oid4vci_machine_retrieve_federation_trust_error_title": "Ophalen federatievertrouwen"
|
|
13
|
+
"oid4vci_machine_retrieve_federation_trust_error_title": "Ophalen federatievertrouwen",
|
|
14
|
+
"oid4vci_machine_first_party_error_title": "Eerste partijstroom",
|
|
15
|
+
"oid4vci_machine_send_authorization_challenge_request_error_title": "Versturen autorisatie-uitdaging aanvraag",
|
|
16
|
+
"oid4vci_machine_create_config_error_title": "SiopV2-configuratie aanmaken",
|
|
17
|
+
"oid4vci_machine_get_request_error_title": "SiopV2-verzoek ophalen"
|
|
14
18
|
}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { assign, createMachine, DoneInvokeEvent, interpret } from 'xstate'
|
|
2
|
+
import { AuthorizationChallengeCodeResponse, AuthorizationChallengeError, AuthorizationChallengeErrorResponse } from '@sphereon/oid4vci-common'
|
|
3
|
+
import { DidAuthConfig } from '@sphereon/ssi-sdk.data-store'
|
|
4
|
+
import { CreateConfigResult } from '@sphereon/ssi-sdk.siopv2-oid4vp-op-auth'
|
|
5
|
+
import { createConfig, getSiopRequest, sendAuthorizationChallengeRequest, sendAuthorizationResponse } from '../services/FirstPartyMachineServices'
|
|
6
|
+
import { translate } from '../localization/Localization'
|
|
7
|
+
import { ErrorDetails } from '../types/IOID4VCIHolder'
|
|
8
|
+
import {
|
|
9
|
+
CreateConfigArgs,
|
|
10
|
+
CreateFirstPartyMachineOpts,
|
|
11
|
+
FirstPartyMachineContext,
|
|
12
|
+
FirstPartyMachineEvents,
|
|
13
|
+
FirstPartyMachineEventTypes,
|
|
14
|
+
FirstPartyMachineInterpreter,
|
|
15
|
+
FirstPartyMachineServices,
|
|
16
|
+
FirstPartyMachineState,
|
|
17
|
+
FirstPartyMachineStatesConfig,
|
|
18
|
+
FirstPartyMachineStateTypes,
|
|
19
|
+
FirstPartyMachineServiceDefinitions,
|
|
20
|
+
FirstPartyStateMachine,
|
|
21
|
+
GetSiopRequestArgs,
|
|
22
|
+
InstanceFirstPartyMachineOpts,
|
|
23
|
+
SiopV2AuthorizationRequestData,
|
|
24
|
+
SendAuthorizationResponseArgs,
|
|
25
|
+
FirstPartySelectCredentialsEvent,
|
|
26
|
+
} from '../types/FirstPartyMachine'
|
|
27
|
+
|
|
28
|
+
const firstPartyMachineStates: FirstPartyMachineStatesConfig = {
|
|
29
|
+
[FirstPartyMachineStateTypes.sendAuthorizationChallengeRequest]: {
|
|
30
|
+
id: FirstPartyMachineStateTypes.sendAuthorizationChallengeRequest,
|
|
31
|
+
invoke: {
|
|
32
|
+
src: FirstPartyMachineServices.sendAuthorizationChallengeRequest,
|
|
33
|
+
onDone: {
|
|
34
|
+
target: FirstPartyMachineStateTypes.done,
|
|
35
|
+
actions: assign({
|
|
36
|
+
authorizationCodeResponse: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<AuthorizationChallengeCodeResponse>) => _event.data,
|
|
37
|
+
}),
|
|
38
|
+
},
|
|
39
|
+
onError: [
|
|
40
|
+
{
|
|
41
|
+
target: FirstPartyMachineStateTypes.createConfig,
|
|
42
|
+
cond: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<AuthorizationChallengeErrorResponse>): boolean =>
|
|
43
|
+
_event.data.error === AuthorizationChallengeError.insufficient_authorization,
|
|
44
|
+
actions: assign({
|
|
45
|
+
authSession: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<AuthorizationChallengeErrorResponse>) => _event.data.auth_session,
|
|
46
|
+
presentationUri: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<AuthorizationChallengeErrorResponse>) =>
|
|
47
|
+
_event.data.presentation,
|
|
48
|
+
}),
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
target: FirstPartyMachineStateTypes.error,
|
|
52
|
+
actions: assign({
|
|
53
|
+
error: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<Error>): ErrorDetails => ({
|
|
54
|
+
title: translate('oid4vci_machine_send_authorization_challenge_request_error_title'),
|
|
55
|
+
message: _event.data.message,
|
|
56
|
+
stack: _event.data.stack,
|
|
57
|
+
}),
|
|
58
|
+
}),
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
[FirstPartyMachineStateTypes.createConfig]: {
|
|
64
|
+
id: FirstPartyMachineStateTypes.createConfig,
|
|
65
|
+
invoke: {
|
|
66
|
+
src: FirstPartyMachineServices.createConfig,
|
|
67
|
+
onDone: {
|
|
68
|
+
target: FirstPartyMachineStateTypes.getSiopRequest,
|
|
69
|
+
actions: assign({
|
|
70
|
+
didAuthConfig: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<DidAuthConfig>) => _event.data,
|
|
71
|
+
}),
|
|
72
|
+
},
|
|
73
|
+
onError: {
|
|
74
|
+
target: FirstPartyMachineStateTypes.error,
|
|
75
|
+
actions: assign({
|
|
76
|
+
error: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<Error>): ErrorDetails => ({
|
|
77
|
+
title: translate('oid4vci_machine_create_config_error_title'),
|
|
78
|
+
message: _event.data.message,
|
|
79
|
+
stack: _event.data.stack,
|
|
80
|
+
}),
|
|
81
|
+
}),
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
[FirstPartyMachineStateTypes.getSiopRequest]: {
|
|
86
|
+
id: FirstPartyMachineStateTypes.getSiopRequest,
|
|
87
|
+
invoke: {
|
|
88
|
+
src: FirstPartyMachineServices.getSiopRequest,
|
|
89
|
+
onDone: {
|
|
90
|
+
target: FirstPartyMachineStateTypes.selectCredentials,
|
|
91
|
+
actions: assign({
|
|
92
|
+
authorizationRequestData: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<SiopV2AuthorizationRequestData>) => _event.data,
|
|
93
|
+
}),
|
|
94
|
+
},
|
|
95
|
+
onError: {
|
|
96
|
+
target: FirstPartyMachineStateTypes.error,
|
|
97
|
+
actions: assign({
|
|
98
|
+
error: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<Error>): ErrorDetails => ({
|
|
99
|
+
title: translate('siopV2_machine_get_request_error_title'),
|
|
100
|
+
message: _event.data.message,
|
|
101
|
+
stack: _event.data.stack,
|
|
102
|
+
}),
|
|
103
|
+
}),
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
[FirstPartyMachineStateTypes.selectCredentials]: {
|
|
108
|
+
id: FirstPartyMachineStateTypes.selectCredentials,
|
|
109
|
+
on: {
|
|
110
|
+
[FirstPartyMachineEvents.SET_SELECTED_CREDENTIALS]: {
|
|
111
|
+
actions: assign({ selectedCredentials: (_ctx: FirstPartyMachineContext, _event: FirstPartySelectCredentialsEvent) => _event.data }),
|
|
112
|
+
},
|
|
113
|
+
[FirstPartyMachineEvents.NEXT]: {
|
|
114
|
+
target: FirstPartyMachineStateTypes.sendAuthorizationResponse,
|
|
115
|
+
},
|
|
116
|
+
[FirstPartyMachineEvents.DECLINE]: {
|
|
117
|
+
target: FirstPartyMachineStateTypes.declined,
|
|
118
|
+
},
|
|
119
|
+
[FirstPartyMachineEvents.PREVIOUS]: {
|
|
120
|
+
target: FirstPartyMachineStateTypes.aborted,
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
[FirstPartyMachineStateTypes.sendAuthorizationResponse]: {
|
|
125
|
+
id: FirstPartyMachineStateTypes.sendAuthorizationResponse,
|
|
126
|
+
invoke: {
|
|
127
|
+
src: FirstPartyMachineServices.sendAuthorizationResponse,
|
|
128
|
+
onDone: {
|
|
129
|
+
target: FirstPartyMachineStateTypes.sendAuthorizationChallengeRequest,
|
|
130
|
+
actions: assign({
|
|
131
|
+
presentationDuringIssuanceSession: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<string>) => _event.data,
|
|
132
|
+
}),
|
|
133
|
+
},
|
|
134
|
+
onError: {
|
|
135
|
+
target: FirstPartyMachineStateTypes.error,
|
|
136
|
+
actions: assign({
|
|
137
|
+
error: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<Error>): ErrorDetails => ({
|
|
138
|
+
title: translate('oid4vci_machine_get_request_error_title'),
|
|
139
|
+
message: _event.data.message,
|
|
140
|
+
stack: _event.data.stack,
|
|
141
|
+
}),
|
|
142
|
+
}),
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
[FirstPartyMachineStateTypes.aborted]: {
|
|
147
|
+
id: FirstPartyMachineStateTypes.aborted,
|
|
148
|
+
type: 'final',
|
|
149
|
+
},
|
|
150
|
+
[FirstPartyMachineStateTypes.declined]: {
|
|
151
|
+
id: FirstPartyMachineStateTypes.declined,
|
|
152
|
+
type: 'final',
|
|
153
|
+
},
|
|
154
|
+
[FirstPartyMachineStateTypes.error]: {
|
|
155
|
+
id: FirstPartyMachineStateTypes.error,
|
|
156
|
+
type: 'final',
|
|
157
|
+
},
|
|
158
|
+
[FirstPartyMachineStateTypes.done]: {
|
|
159
|
+
id: FirstPartyMachineStateTypes.done,
|
|
160
|
+
type: 'final',
|
|
161
|
+
},
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const createFirstPartyActivationMachine = (opts: CreateFirstPartyMachineOpts): FirstPartyStateMachine => {
|
|
165
|
+
const initialContext: FirstPartyMachineContext = {
|
|
166
|
+
openID4VCIClientState: opts.openID4VCIClientState,
|
|
167
|
+
contact: opts.contact,
|
|
168
|
+
selectedCredentials: [],
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return createMachine<FirstPartyMachineContext, FirstPartyMachineEventTypes>({
|
|
172
|
+
id: opts?.machineId ?? 'FirstParty',
|
|
173
|
+
predictableActionArguments: true,
|
|
174
|
+
initial: FirstPartyMachineStateTypes.sendAuthorizationChallengeRequest,
|
|
175
|
+
context: initialContext,
|
|
176
|
+
states: firstPartyMachineStates,
|
|
177
|
+
schema: {
|
|
178
|
+
events: {} as FirstPartyMachineEventTypes,
|
|
179
|
+
services: {} as {
|
|
180
|
+
[FirstPartyMachineServices.sendAuthorizationChallengeRequest]: {
|
|
181
|
+
data: void
|
|
182
|
+
}
|
|
183
|
+
[FirstPartyMachineServices.createConfig]: {
|
|
184
|
+
data: CreateConfigResult
|
|
185
|
+
}
|
|
186
|
+
[FirstPartyMachineServices.getSiopRequest]: {
|
|
187
|
+
data: SiopV2AuthorizationRequestData
|
|
188
|
+
}
|
|
189
|
+
[FirstPartyMachineServices.sendAuthorizationResponse]: {
|
|
190
|
+
data: string
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
})
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export class FirstPartyMachine {
|
|
198
|
+
private static _instance: FirstPartyMachineInterpreter | undefined
|
|
199
|
+
|
|
200
|
+
static hasInstance(): boolean {
|
|
201
|
+
return FirstPartyMachine._instance !== undefined
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
static get instance(): FirstPartyMachineInterpreter {
|
|
205
|
+
if (!FirstPartyMachine._instance) {
|
|
206
|
+
throw Error('Please initialize ESIMActivation machine first')
|
|
207
|
+
}
|
|
208
|
+
return FirstPartyMachine._instance
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
static clearInstance(opts: { stop: boolean }) {
|
|
212
|
+
const { stop } = opts
|
|
213
|
+
if (FirstPartyMachine.hasInstance()) {
|
|
214
|
+
if (stop) {
|
|
215
|
+
FirstPartyMachine.stopInstance()
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
FirstPartyMachine._instance = undefined
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
static stopInstance(): void {
|
|
222
|
+
if (!FirstPartyMachine.hasInstance()) {
|
|
223
|
+
return
|
|
224
|
+
}
|
|
225
|
+
FirstPartyMachine.instance.stop()
|
|
226
|
+
FirstPartyMachine._instance = undefined
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
public static newInstance(opts: InstanceFirstPartyMachineOpts): FirstPartyMachineInterpreter {
|
|
230
|
+
const { agentContext } = opts
|
|
231
|
+
const services: FirstPartyMachineServiceDefinitions = {
|
|
232
|
+
[FirstPartyMachineServices.sendAuthorizationChallengeRequest]: sendAuthorizationChallengeRequest,
|
|
233
|
+
[FirstPartyMachineServices.createConfig]: (args: CreateConfigArgs) => createConfig(args, agentContext),
|
|
234
|
+
[FirstPartyMachineServices.getSiopRequest]: (args: GetSiopRequestArgs) => getSiopRequest(args, agentContext),
|
|
235
|
+
[FirstPartyMachineServices.sendAuthorizationResponse]: (args: SendAuthorizationResponseArgs) => sendAuthorizationResponse(args, agentContext),
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const newInst: FirstPartyMachineInterpreter = interpret(
|
|
239
|
+
createFirstPartyActivationMachine(opts).withConfig({
|
|
240
|
+
services: {
|
|
241
|
+
...services,
|
|
242
|
+
...opts?.services,
|
|
243
|
+
},
|
|
244
|
+
guards: {
|
|
245
|
+
...opts?.guards,
|
|
246
|
+
},
|
|
247
|
+
}),
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
if (typeof opts?.subscription === 'function') {
|
|
251
|
+
newInst.onTransition(opts.subscription)
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (opts?.requireCustomNavigationHook !== true) {
|
|
255
|
+
newInst.onTransition((snapshot: FirstPartyMachineState): void => {
|
|
256
|
+
if (opts?.stateNavigationListener) {
|
|
257
|
+
void opts.stateNavigationListener(newInst, snapshot)
|
|
258
|
+
}
|
|
259
|
+
})
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return newInst
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
static getInstance(
|
|
266
|
+
opts: InstanceFirstPartyMachineOpts & {
|
|
267
|
+
requireExisting?: boolean
|
|
268
|
+
},
|
|
269
|
+
): FirstPartyMachineInterpreter {
|
|
270
|
+
if (!FirstPartyMachine._instance) {
|
|
271
|
+
if (opts?.requireExisting === true) {
|
|
272
|
+
throw Error(`Existing FirstPartyMachine instance requested, but none was created at this point!`)
|
|
273
|
+
}
|
|
274
|
+
FirstPartyMachine._instance = FirstPartyMachine.newInstance(opts)
|
|
275
|
+
}
|
|
276
|
+
return FirstPartyMachine._instance
|
|
277
|
+
}
|
|
278
|
+
}
|