@sphereon/ssi-sdk.oid4vci-holder 0.33.0 → 0.33.1-feature.vcdm2.4
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.js +727 -728
- package/dist/agent/OID4VCIHolder.js.map +1 -1
- package/dist/index.js +8 -28
- package/dist/index.js.map +1 -1
- package/dist/link-handler/index.js +55 -49
- package/dist/link-handler/index.js.map +1 -1
- package/dist/listeners/headlessStateNavListener.js +7 -20
- package/dist/listeners/headlessStateNavListener.js.map +1 -1
- package/dist/localization/Localization.js +38 -43
- package/dist/localization/Localization.js.map +1 -1
- package/dist/machines/firstPartyMachine.js +79 -78
- package/dist/machines/firstPartyMachine.js.map +1 -1
- package/dist/machines/oid4vciMachine.js +304 -323
- package/dist/machines/oid4vciMachine.js.map +1 -1
- package/dist/mappers/OIDC4VCIBrandingMapper.js +163 -135
- package/dist/mappers/OIDC4VCIBrandingMapper.js.map +1 -1
- package/dist/services/FirstPartyMachineServices.js +19 -30
- package/dist/services/FirstPartyMachineServices.js.map +1 -1
- package/dist/services/OID4VCIHolderService.js +145 -153
- package/dist/services/OID4VCIHolderService.js.map +1 -1
- package/dist/types/FirstPartyMachine.js +6 -9
- package/dist/types/FirstPartyMachine.js.map +1 -1
- package/dist/types/IOID4VCIHolder.js +20 -23
- package/dist/types/IOID4VCIHolder.js.map +1 -1
- package/package.json +15 -15
|
@@ -1,54 +1,42 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
const ssi_sdk_ext_did_utils_1 = require("@sphereon/ssi-sdk-ext.did-utils");
|
|
17
|
-
const ssi_sdk_ext_identifier_resolution_1 = require("@sphereon/ssi-sdk-ext.identifier-resolution");
|
|
18
|
-
const ssi_sdk_ext_key_utils_1 = require("@sphereon/ssi-sdk-ext.key-utils");
|
|
19
|
-
const ssi_types_1 = require("@sphereon/ssi-types");
|
|
20
|
-
const utils_1 = require("@veramo/utils");
|
|
21
|
-
const Localization_1 = require("../localization/Localization");
|
|
22
|
-
const IOID4VCIHolder_1 = require("../types/IOID4VCIHolder");
|
|
23
|
-
const OIDC4VCIBrandingMapper_1 = require("../mappers/OIDC4VCIBrandingMapper");
|
|
24
|
-
const firstPartyMachine_1 = require("../machines/firstPartyMachine");
|
|
25
|
-
const FirstPartyMachine_1 = require("../types/FirstPartyMachine");
|
|
26
|
-
const ssi_sdk_core_1 = require("@sphereon/ssi-sdk.core");
|
|
27
|
-
const getCredentialBranding = (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1
|
+
import { LOG } from '@sphereon/oid4vci-client';
|
|
2
|
+
import { getSupportedCredentials, getTypesFromCredentialSupported, getTypesFromObject, OpenId4VCIVersion, } from '@sphereon/oid4vci-common';
|
|
3
|
+
import { KeyUse } from '@sphereon/ssi-sdk-ext.did-resolver-jwk';
|
|
4
|
+
import { getOrCreatePrimaryIdentifier, SupportedDidMethodEnum } from '@sphereon/ssi-sdk-ext.did-utils';
|
|
5
|
+
import { isIIdentifier, isManagedIdentifierDidResult, isManagedIdentifierResult, managedIdentifierToJwk, } from '@sphereon/ssi-sdk-ext.identifier-resolution';
|
|
6
|
+
import { keyTypeFromCryptographicSuite } from '@sphereon/ssi-sdk-ext.key-utils';
|
|
7
|
+
import { CredentialMapper, JoseSignatureAlgorithm, mdocDecodedCredentialToUniformCredential, sdJwtDecodedCredentialToUniformCredential, } from '@sphereon/ssi-types';
|
|
8
|
+
import { asArray } from '@veramo/utils';
|
|
9
|
+
import { translate } from '../localization/Localization';
|
|
10
|
+
import { OID4VCIHolderEvent, } from '../types/IOID4VCIHolder';
|
|
11
|
+
import { oid4vciGetCredentialBrandingFrom, sdJwtGetCredentialBrandingFrom, issuerLocaleBrandingFrom } from '../mappers/OIDC4VCIBrandingMapper';
|
|
12
|
+
import { FirstPartyMachine } from '../machines/firstPartyMachine';
|
|
13
|
+
import { FirstPartyMachineStateTypes } from '../types/FirstPartyMachine';
|
|
14
|
+
import { defaultHasher } from '@sphereon/ssi-sdk.core';
|
|
15
|
+
export const getCredentialBranding = async (args) => {
|
|
28
16
|
const { credentialsSupported, context } = args;
|
|
29
17
|
const credentialBranding = {};
|
|
30
|
-
|
|
18
|
+
await Promise.all(Object.entries(credentialsSupported).map(async ([configId, credentialsConfigSupported]) => {
|
|
31
19
|
let sdJwtTypeMetadata;
|
|
32
20
|
if (credentialsConfigSupported.format === 'vc+sd-jwt') {
|
|
33
21
|
const vct = credentialsConfigSupported.vct;
|
|
34
22
|
if (vct.startsWith('http')) {
|
|
35
23
|
try {
|
|
36
|
-
sdJwtTypeMetadata =
|
|
24
|
+
sdJwtTypeMetadata = await context.agent.fetchSdJwtTypeMetadataFromVctUrl({ vct });
|
|
37
25
|
}
|
|
38
|
-
catch
|
|
26
|
+
catch {
|
|
39
27
|
// For now, we are just going to ignore and continue without any branding as we still have a fallback
|
|
40
28
|
}
|
|
41
29
|
}
|
|
42
30
|
}
|
|
43
31
|
let mappedLocaleBranding = [];
|
|
44
32
|
if (sdJwtTypeMetadata) {
|
|
45
|
-
mappedLocaleBranding =
|
|
33
|
+
mappedLocaleBranding = await sdJwtGetCredentialBrandingFrom({
|
|
46
34
|
credentialDisplay: sdJwtTypeMetadata.display,
|
|
47
35
|
claimsMetadata: sdJwtTypeMetadata.claims,
|
|
48
36
|
});
|
|
49
37
|
}
|
|
50
38
|
else {
|
|
51
|
-
mappedLocaleBranding =
|
|
39
|
+
mappedLocaleBranding = await oid4vciGetCredentialBrandingFrom({
|
|
52
40
|
credentialDisplay: credentialsConfigSupported.display,
|
|
53
41
|
issuerCredentialSubject:
|
|
54
42
|
// @ts-ignore // FIXME SPRIND-123 add proper support for type recognition as claim display can be located elsewhere for v13
|
|
@@ -56,26 +44,24 @@ const getCredentialBranding = (args) => __awaiter(void 0, void 0, void 0, functi
|
|
|
56
44
|
});
|
|
57
45
|
}
|
|
58
46
|
// 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
|
|
59
|
-
const localeBranding =
|
|
47
|
+
const localeBranding = await Promise.all(mappedLocaleBranding.map(async (localeBranding) => await context.agent.ibCredentialLocaleBrandingFrom({ localeBranding })));
|
|
60
48
|
const defaultCredentialType = 'VerifiableCredential';
|
|
61
|
-
const configSupportedTypes =
|
|
62
|
-
const credentialTypes = configSupportedTypes.length === 0 ?
|
|
49
|
+
const configSupportedTypes = getTypesFromCredentialSupported(credentialsConfigSupported);
|
|
50
|
+
const credentialTypes = configSupportedTypes.length === 0 ? asArray(defaultCredentialType) : configSupportedTypes;
|
|
63
51
|
const filteredCredentialTypes = credentialTypes.filter((type) => type !== defaultCredentialType);
|
|
64
52
|
credentialBranding[filteredCredentialTypes[0]] = localeBranding; // TODO for now taking the first type
|
|
65
|
-
}))
|
|
53
|
+
}));
|
|
66
54
|
return credentialBranding;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const getBasicIssuerLocaleBranding = (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
55
|
+
};
|
|
56
|
+
export const getBasicIssuerLocaleBranding = async (args) => {
|
|
70
57
|
const { display, dynamicRegistrationClientMetadata, context } = args;
|
|
71
|
-
return
|
|
58
|
+
return await Promise.all(display.map(async (issuerDisplay) => {
|
|
72
59
|
// FIXME for now we do not have locale support for dynamicRegistrationClientMetadata, so we add all the metadata to every locale
|
|
73
|
-
const branding =
|
|
60
|
+
const branding = await issuerLocaleBrandingFrom({ issuerDisplay, dynamicRegistrationClientMetadata });
|
|
74
61
|
return context.agent.ibIssuerLocaleBrandingFrom({ localeBranding: branding });
|
|
75
|
-
}))
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const getCredentialConfigsBasedOnFormatPref = (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
62
|
+
}));
|
|
63
|
+
};
|
|
64
|
+
export const getCredentialConfigsBasedOnFormatPref = async (args) => {
|
|
79
65
|
const { vcFormatPreferences, credentials } = args;
|
|
80
66
|
const prefConfigs = {};
|
|
81
67
|
Object.entries(credentials).forEach(([key, config]) => {
|
|
@@ -85,34 +71,31 @@ const getCredentialConfigsBasedOnFormatPref = (args) => __awaiter(void 0, void 0
|
|
|
85
71
|
}
|
|
86
72
|
});
|
|
87
73
|
return prefConfigs;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const selectCredentialLocaleBranding = (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
74
|
+
};
|
|
75
|
+
export const selectCredentialLocaleBranding = async (args) => {
|
|
91
76
|
const { locale, localeBranding } = args;
|
|
92
|
-
return localeBranding
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const verifyCredentialToAccept = (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
96
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
77
|
+
return localeBranding?.find((branding) => locale ? branding.locale?.startsWith(locale) || branding.locale === undefined : branding.locale === undefined);
|
|
78
|
+
};
|
|
79
|
+
export const verifyCredentialToAccept = async (args) => {
|
|
97
80
|
const { mappedCredential, hasher, onVerifyEBSICredentialIssuer, schemaValidation, context } = args;
|
|
98
81
|
const credential = mappedCredential.credentialToAccept.credentialResponse.credential;
|
|
99
82
|
if (!credential) {
|
|
100
83
|
return Promise.reject(Error('No credential found in credential response'));
|
|
101
84
|
}
|
|
102
|
-
const wrappedVC =
|
|
103
|
-
if (
|
|
104
|
-
(typeof
|
|
105
|
-
?
|
|
106
|
-
:
|
|
85
|
+
const wrappedVC = CredentialMapper.toWrappedVerifiableCredential(credential, { hasher: hasher ?? defaultHasher });
|
|
86
|
+
if (wrappedVC.decoded?.iss?.includes('did:ebsi:') ||
|
|
87
|
+
(typeof wrappedVC.decoded?.vc?.issuer === 'string'
|
|
88
|
+
? wrappedVC.decoded?.vc?.issuer?.includes('did:ebsi:')
|
|
89
|
+
: wrappedVC.decoded?.vc?.issuer?.existingInstanceId?.includes('did:ebsi:'))) {
|
|
107
90
|
// TODO: Skipping VC validation for EBSI conformance issued credential, as their Issuer is not present in the ledger (sigh)
|
|
108
91
|
// just calling the verifySchema functionality for ebsi credentials
|
|
109
|
-
|
|
92
|
+
await context.agent.cvVerifySchema({ credential, hasher, validationPolicy: schemaValidation });
|
|
110
93
|
if (JSON.stringify(wrappedVC.decoded).includes('vc:ebsi:conformance')) {
|
|
111
94
|
return { source: wrappedVC, error: undefined, result: true, subResults: [] };
|
|
112
95
|
}
|
|
113
96
|
if (onVerifyEBSICredentialIssuer) {
|
|
114
97
|
try {
|
|
115
|
-
|
|
98
|
+
await onVerifyEBSICredentialIssuer({
|
|
116
99
|
wrappedVc: wrappedVC,
|
|
117
100
|
});
|
|
118
101
|
}
|
|
@@ -121,7 +104,7 @@ const verifyCredentialToAccept = (args) => __awaiter(void 0, void 0, void 0, fun
|
|
|
121
104
|
}
|
|
122
105
|
}
|
|
123
106
|
}
|
|
124
|
-
const verificationResult =
|
|
107
|
+
const verificationResult = await context.agent.cvVerifyCredential({
|
|
125
108
|
credential,
|
|
126
109
|
hasher,
|
|
127
110
|
// TODO WAL-675 we might want to allow these types of options as part of the context, now we have state machines. Allows us to pre-determine whether these policies apply and whether remote context should be fetched
|
|
@@ -134,98 +117,102 @@ const verifyCredentialToAccept = (args) => __awaiter(void 0, void 0, void 0, fun
|
|
|
134
117
|
},
|
|
135
118
|
});
|
|
136
119
|
if (!verificationResult.result || verificationResult.error) {
|
|
137
|
-
return Promise.reject(Error(
|
|
120
|
+
return Promise.reject(Error(verificationResult.error ?? translate('oid4vci_machine_credential_verification_failed_message')));
|
|
138
121
|
}
|
|
139
122
|
return verificationResult;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const mapCredentialToAccept = (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
123
|
+
};
|
|
124
|
+
export const mapCredentialToAccept = async (args) => {
|
|
143
125
|
const { credentialToAccept, hasher } = args;
|
|
144
126
|
const credentialResponse = credentialToAccept.credentialResponse;
|
|
145
127
|
const verifiableCredential = credentialResponse.credential;
|
|
146
128
|
if (!verifiableCredential) {
|
|
147
129
|
return Promise.reject(Error('No credential found in credential response'));
|
|
148
130
|
}
|
|
149
|
-
const wrappedVerifiableCredential =
|
|
131
|
+
const wrappedVerifiableCredential = CredentialMapper.toWrappedVerifiableCredential(verifiableCredential, { hasher });
|
|
150
132
|
let uniformVerifiableCredential;
|
|
151
|
-
if (
|
|
152
|
-
uniformVerifiableCredential =
|
|
133
|
+
if (CredentialMapper.isSdJwtDecodedCredential(wrappedVerifiableCredential.credential)) {
|
|
134
|
+
uniformVerifiableCredential = await sdJwtDecodedCredentialToUniformCredential(wrappedVerifiableCredential.credential);
|
|
153
135
|
}
|
|
154
|
-
else if (
|
|
136
|
+
else if (CredentialMapper.isSdJwtEncoded(wrappedVerifiableCredential.credential)) {
|
|
155
137
|
if (!hasher) {
|
|
156
138
|
return Promise.reject('a hasher is required for encoded SD-JWT credentials');
|
|
157
139
|
}
|
|
158
140
|
const asyncHasher = (data, algorithm) => Promise.resolve(hasher(data, algorithm));
|
|
159
|
-
const decodedSdJwt =
|
|
160
|
-
uniformVerifiableCredential =
|
|
141
|
+
const decodedSdJwt = await CredentialMapper.decodeSdJwtVcAsync(wrappedVerifiableCredential.credential, asyncHasher);
|
|
142
|
+
uniformVerifiableCredential = sdJwtDecodedCredentialToUniformCredential(decodedSdJwt);
|
|
161
143
|
}
|
|
162
|
-
else if (
|
|
163
|
-
uniformVerifiableCredential =
|
|
144
|
+
else if (CredentialMapper.isMsoMdocDecodedCredential(wrappedVerifiableCredential.credential)) {
|
|
145
|
+
uniformVerifiableCredential = mdocDecodedCredentialToUniformCredential(wrappedVerifiableCredential.credential);
|
|
164
146
|
}
|
|
165
147
|
else {
|
|
166
148
|
uniformVerifiableCredential = wrappedVerifiableCredential.credential;
|
|
167
149
|
}
|
|
168
150
|
const correlationId = typeof uniformVerifiableCredential.issuer === 'string'
|
|
169
151
|
? uniformVerifiableCredential.issuer
|
|
170
|
-
:
|
|
152
|
+
: CredentialMapper.isSdJwtDecodedCredential(uniformVerifiableCredential)
|
|
171
153
|
? uniformVerifiableCredential.decodedPayload.iss
|
|
172
154
|
: uniformVerifiableCredential.issuer.id;
|
|
173
|
-
return
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
155
|
+
return {
|
|
156
|
+
correlationId,
|
|
157
|
+
credentialToAccept,
|
|
158
|
+
types: credentialToAccept.types,
|
|
159
|
+
rawVerifiableCredential: verifiableCredential,
|
|
160
|
+
uniformVerifiableCredential,
|
|
161
|
+
...(credentialResponse.credential_subject_issuance && { credential_subject_issuance: credentialResponse.credential_subject_issuance }),
|
|
162
|
+
};
|
|
163
|
+
};
|
|
164
|
+
export const getIdentifierOpts = async (args) => {
|
|
178
165
|
const { issuanceOpt, context } = args;
|
|
179
166
|
const { identifier: identifierArg } = issuanceOpt;
|
|
180
|
-
if (identifierArg &&
|
|
167
|
+
if (identifierArg && isManagedIdentifierResult(identifierArg)) {
|
|
181
168
|
return identifierArg;
|
|
182
169
|
}
|
|
183
|
-
const { supportedPreferredDidMethod, supportedBindingMethods, keyType = 'Secp256r1', kms =
|
|
170
|
+
const { supportedPreferredDidMethod, supportedBindingMethods, keyType = 'Secp256r1', kms = await context.agent.keyManagerGetDefaultKeyManagementSystem(), } = issuanceOpt;
|
|
184
171
|
let identifier;
|
|
185
172
|
if (identifierArg) {
|
|
186
|
-
if (
|
|
187
|
-
identifier =
|
|
173
|
+
if (isIIdentifier(identifierArg.identifier)) {
|
|
174
|
+
identifier = await context.agent.identifierManagedGet(identifierArg);
|
|
188
175
|
}
|
|
189
176
|
else if (!identifierArg.method && issuanceOpt.supportedBindingMethods.includes('jwk')) {
|
|
190
|
-
identifier =
|
|
177
|
+
identifier = await managedIdentifierToJwk(identifierArg, context);
|
|
191
178
|
}
|
|
192
179
|
else if (identifierArg.method && !supportedBindingMethods.includes(identifierArg.method)) {
|
|
193
180
|
throw Error(`Supplied identifier method ${identifierArg.method} not supported by the issuer: ${supportedBindingMethods.join(',')}`);
|
|
194
181
|
}
|
|
195
182
|
else {
|
|
196
|
-
identifier =
|
|
183
|
+
identifier = await context.agent.identifierManagedGet(identifierArg);
|
|
197
184
|
}
|
|
198
185
|
}
|
|
199
|
-
const agentContext =
|
|
200
|
-
if ((!identifierArg ||
|
|
186
|
+
const agentContext = { ...context, agent: context.agent };
|
|
187
|
+
if ((!identifierArg || isIIdentifier(identifierArg.identifier)) &&
|
|
201
188
|
supportedPreferredDidMethod &&
|
|
202
189
|
(!supportedBindingMethods || supportedBindingMethods.length === 0 || supportedBindingMethods.filter((method) => method.startsWith('did')))) {
|
|
203
190
|
// previous code for managing DIDs only
|
|
204
|
-
const { result, created } =
|
|
191
|
+
const { result, created } = await getOrCreatePrimaryIdentifier(agentContext, {
|
|
205
192
|
method: supportedPreferredDidMethod,
|
|
206
193
|
createOpts: {
|
|
207
194
|
options: {
|
|
208
195
|
type: issuanceOpt.keyType,
|
|
209
|
-
use:
|
|
196
|
+
use: KeyUse.Signature,
|
|
210
197
|
codecName: issuanceOpt.codecName,
|
|
211
198
|
kms: issuanceOpt.kms,
|
|
212
199
|
},
|
|
213
200
|
},
|
|
214
201
|
});
|
|
215
|
-
identifier =
|
|
202
|
+
identifier = await context.agent.identifierManagedGetByDid({
|
|
216
203
|
identifier: result,
|
|
217
204
|
keyType,
|
|
218
205
|
offlineWhenNoDIDRegistered: result.did.startsWith('did:ebsi:'),
|
|
219
206
|
});
|
|
220
207
|
if (created) {
|
|
221
|
-
|
|
208
|
+
await agentContext.agent.emit(OID4VCIHolderEvent.IDENTIFIER_CREATED, { identifier });
|
|
222
209
|
}
|
|
223
210
|
}
|
|
224
211
|
else if (supportedBindingMethods.includes('jwk')) {
|
|
225
212
|
// todo: we probably should do something similar as with DIDs for re-use/new keys
|
|
226
|
-
const key =
|
|
213
|
+
const key = await context.agent.keyManagerCreate({ type: keyType, kms, meta: { keyAlias: `key_${keyType}_${Date.now()}` } });
|
|
227
214
|
// TODO. Create/move this to identifier service await agentContext.agent.emit(OID4VCIHolderEvent.IDENTIFIER_CREATED, { key })
|
|
228
|
-
identifier =
|
|
215
|
+
identifier = await managedIdentifierToJwk({ method: 'key', identifier: key, kmsKeyRef: key.kid }, context);
|
|
229
216
|
// } else if (supportedBindingMethods.includes('cose_key')) {
|
|
230
217
|
// // TODO COSE HERE
|
|
231
218
|
// throw Error(`Holder currently does not support binding method: ${supportedBindingMethods.join(',')}`)
|
|
@@ -235,40 +222,44 @@ const getIdentifierOpts = (args) => __awaiter(void 0, void 0, void 0, function*
|
|
|
235
222
|
}
|
|
236
223
|
args.issuanceOpt.identifier = identifier;
|
|
237
224
|
return identifier;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
const getCredentialConfigsSupportedMerged = (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
225
|
+
};
|
|
226
|
+
export const getCredentialConfigsSupportedMerged = async (args) => {
|
|
241
227
|
let result = {};
|
|
242
|
-
(
|
|
243
|
-
result =
|
|
228
|
+
(await getCredentialConfigsSupported(args)).forEach((supported) => {
|
|
229
|
+
result = { ...result, ...supported };
|
|
244
230
|
});
|
|
245
231
|
return result;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
const getCredentialConfigsSupported = (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
232
|
+
};
|
|
233
|
+
export const getCredentialConfigsSupported = async (args) => {
|
|
249
234
|
const { types, configurationIds } = args;
|
|
250
235
|
if (Array.isArray(types) && types.length > 0) {
|
|
251
|
-
return Promise.all(types.map((type) =>
|
|
236
|
+
return Promise.all(types.map((type) => getCredentialConfigsSupportedBySingleTypeOrId({ ...args, types: type })));
|
|
252
237
|
}
|
|
253
238
|
else if (Array.isArray(configurationIds) && configurationIds.length > 0) {
|
|
254
|
-
return Promise.all(configurationIds.map((configurationId) =>
|
|
255
|
-
|
|
256
|
-
|
|
239
|
+
return Promise.all(configurationIds.map((configurationId) => getCredentialConfigsSupportedBySingleTypeOrId({
|
|
240
|
+
...args,
|
|
241
|
+
configurationId,
|
|
242
|
+
types: undefined,
|
|
243
|
+
})));
|
|
244
|
+
}
|
|
245
|
+
const configs = await getCredentialConfigsSupportedBySingleTypeOrId({
|
|
246
|
+
...args,
|
|
247
|
+
types: undefined,
|
|
248
|
+
configurationId: undefined,
|
|
249
|
+
});
|
|
257
250
|
return configs && Object.keys(configs).length > 0 ? [configs] : [];
|
|
258
|
-
}
|
|
259
|
-
exports.getCredentialConfigsSupported = getCredentialConfigsSupported;
|
|
251
|
+
};
|
|
260
252
|
/**
|
|
261
253
|
* Please note that this method only returns configs supported for a single set of credential types or a single config id.
|
|
262
254
|
* If an offer contains multiple formats/types in an array or multiple config ids, you will have to call this method for all of them
|
|
263
255
|
* @param args
|
|
264
256
|
*/
|
|
265
|
-
const getCredentialConfigsSupportedBySingleTypeOrId = (args) =>
|
|
257
|
+
export const getCredentialConfigsSupportedBySingleTypeOrId = async (args) => {
|
|
266
258
|
const { client, vcFormatPreferences, configurationId } = args;
|
|
267
259
|
let { format = undefined, types = undefined } = args;
|
|
268
260
|
function createIdFromTypes(supported) {
|
|
269
|
-
var _a, _b;
|
|
270
261
|
const format = supported.format;
|
|
271
|
-
const type =
|
|
262
|
+
const type = getTypesFromObject(supported)?.join() ?? '';
|
|
272
263
|
const id = `${type}:${format}`;
|
|
273
264
|
return id;
|
|
274
265
|
}
|
|
@@ -283,18 +274,18 @@ const getCredentialConfigsSupportedBySingleTypeOrId = (args) => __awaiter(void 0
|
|
|
283
274
|
}
|
|
284
275
|
// We should always have a credential offer at this point given the above
|
|
285
276
|
if (!Array.isArray(format) && client.credentialOffer) {
|
|
286
|
-
if (client.version() >
|
|
277
|
+
if (client.version() > OpenId4VCIVersion.VER_1_0_09 &&
|
|
287
278
|
typeof client.credentialOffer.credential_offer === 'object' &&
|
|
288
279
|
'credentials' in client.credentialOffer.credential_offer) {
|
|
289
280
|
format = client.credentialOffer.credential_offer.credentials
|
|
290
281
|
.filter((cred) => typeof cred !== 'string')
|
|
291
282
|
.map((cred) => cred.format);
|
|
292
|
-
if (
|
|
283
|
+
if (format?.length === 0) {
|
|
293
284
|
format = undefined; // Otherwise we would match nothing
|
|
294
285
|
}
|
|
295
286
|
}
|
|
296
287
|
}
|
|
297
|
-
const offerSupported =
|
|
288
|
+
const offerSupported = getSupportedCredentials({
|
|
298
289
|
types: types ? [types] : client.getCredentialOfferTypes(),
|
|
299
290
|
format,
|
|
300
291
|
version: client.version(),
|
|
@@ -315,12 +306,12 @@ const getCredentialConfigsSupportedBySingleTypeOrId = (args) => __awaiter(void 0
|
|
|
315
306
|
allSupported[id] = supported;
|
|
316
307
|
});
|
|
317
308
|
}
|
|
318
|
-
let credentialConfigsSupported =
|
|
309
|
+
let credentialConfigsSupported = await getCredentialConfigsBasedOnFormatPref({
|
|
319
310
|
credentials: allSupported,
|
|
320
311
|
vcFormatPreferences,
|
|
321
312
|
});
|
|
322
313
|
if (!credentialConfigsSupported || Object.keys(credentialConfigsSupported).length === 0) {
|
|
323
|
-
|
|
314
|
+
LOG.warning(`No matching supported credential found for ${client.getIssuer()}`);
|
|
324
315
|
}
|
|
325
316
|
if (client.credentialOffer === undefined) {
|
|
326
317
|
return credentialConfigsSupported;
|
|
@@ -342,27 +333,25 @@ const getCredentialConfigsSupportedBySingleTypeOrId = (args) => __awaiter(void 0
|
|
|
342
333
|
throw new Error(`No matching supported credential configs found for offer`);
|
|
343
334
|
}
|
|
344
335
|
return credentialsToOffer;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
const getIssuanceOpts = (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
336
|
+
};
|
|
337
|
+
export const getIssuanceOpts = async (args) => {
|
|
348
338
|
const { client, credentialsSupported,
|
|
349
339
|
// serverMetadata,
|
|
350
340
|
context, didMethodPreferences, jwtCryptographicSuitePreferences, jsonldCryptographicSuitePreferences, forceIssuanceOpt, } = args;
|
|
351
341
|
if (credentialsSupported === undefined || Object.keys(credentialsSupported).length === 0) {
|
|
352
342
|
return Promise.reject(Error('No credentials supported'));
|
|
353
343
|
}
|
|
354
|
-
const getIssuanceOpts = Object.values(credentialsSupported).map((credentialSupported) =>
|
|
344
|
+
const getIssuanceOpts = Object.values(credentialsSupported).map(async (credentialSupported) => {
|
|
355
345
|
/*if (!serverMetadata?.credentialIssuerMetadata) {
|
|
356
346
|
return await getDefaultIssuanceOpts({ credentialSupported, opts: { client }, context })
|
|
357
347
|
}*/
|
|
358
|
-
|
|
359
|
-
const cryptographicSuite = yield (0, exports.getIssuanceCryptoSuite)({
|
|
348
|
+
const cryptographicSuite = await getIssuanceCryptoSuite({
|
|
360
349
|
credentialSupported,
|
|
361
350
|
client,
|
|
362
351
|
jwtCryptographicSuitePreferences,
|
|
363
352
|
jsonldCryptographicSuitePreferences,
|
|
364
353
|
});
|
|
365
|
-
const { didMethod, methods } =
|
|
354
|
+
const { didMethod, methods } = await getIssuanceMethod({
|
|
366
355
|
credentialSupported,
|
|
367
356
|
client,
|
|
368
357
|
didMethodPreferences,
|
|
@@ -372,19 +361,26 @@ const getIssuanceOpts = (args) => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
372
361
|
methods.push('did');
|
|
373
362
|
}
|
|
374
363
|
const issuanceOpt = forceIssuanceOpt
|
|
375
|
-
?
|
|
376
|
-
|
|
377
|
-
|
|
364
|
+
? { ...credentialSupported, ...forceIssuanceOpt }
|
|
365
|
+
: {
|
|
366
|
+
...credentialSupported,
|
|
367
|
+
supportedPreferredDidMethod: didMethod,
|
|
368
|
+
supportedBindingMethods: methods,
|
|
369
|
+
format: credentialSupported.format,
|
|
370
|
+
keyType: client.isEBSI() ? 'Secp256r1' : keyTypeFromCryptographicSuite({ crv: cryptographicSuite }),
|
|
371
|
+
...(client.isEBSI() && { codecName: 'EBSI' }),
|
|
372
|
+
};
|
|
373
|
+
const identifier = await getIdentifierOpts({ issuanceOpt, context });
|
|
374
|
+
if (!client.clientId && isManagedIdentifierDidResult(identifier)) {
|
|
378
375
|
// FIXME: We really should fetch server metadata. Have user select required credentials. Take the first cred to determine a kid when no clientId is present and set that.
|
|
379
376
|
// Needs a preference service for crypto, keys, dids, and clientId, with ecosystem support
|
|
380
|
-
client.clientId =
|
|
377
|
+
client.clientId = identifier.issuer ?? identifier.did;
|
|
381
378
|
}
|
|
382
|
-
return
|
|
383
|
-
})
|
|
384
|
-
return
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
const getIssuanceMethod = (opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
379
|
+
return { ...issuanceOpt, identifier };
|
|
380
|
+
});
|
|
381
|
+
return await Promise.all(getIssuanceOpts);
|
|
382
|
+
};
|
|
383
|
+
export const getIssuanceMethod = async (opts) => {
|
|
388
384
|
const { client, credentialSupported, didMethodPreferences } = opts;
|
|
389
385
|
const { format, cryptographic_binding_methods_supported } = credentialSupported;
|
|
390
386
|
let methods = []; // we use the external identifier method, as we should be supporting all values in the server metadata anyway
|
|
@@ -403,21 +399,19 @@ const getIssuanceMethod = (opts) => __awaiter(void 0, void 0, void 0, function*
|
|
|
403
399
|
console.warn(`We should have been able to determine cryptographic_binding_methods_supported, will fall back to legacy behaviour. This is likely a bug`);
|
|
404
400
|
}
|
|
405
401
|
if (client.isEBSI()) {
|
|
406
|
-
return { methods: ['did'], didMethod:
|
|
402
|
+
return { methods: ['did'], didMethod: SupportedDidMethodEnum.DID_KEY };
|
|
407
403
|
}
|
|
408
404
|
// legacy fallback
|
|
409
405
|
methods = ['did'];
|
|
410
|
-
if (!format || (format.includes('jwt') && !
|
|
406
|
+
if (!format || (format.includes('jwt') && !format?.includes('jwt_vc_json_ld'))) {
|
|
411
407
|
return { methods, didMethod: format ? didMethodPreferences[1] : didMethodPreferences[0] };
|
|
412
408
|
}
|
|
413
409
|
else {
|
|
414
410
|
// JsonLD
|
|
415
411
|
return { methods, didMethod: didMethodPreferences[0] };
|
|
416
412
|
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
const getIssuanceCryptoSuite = (opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
420
|
-
var _a, _b;
|
|
413
|
+
};
|
|
414
|
+
export const getIssuanceCryptoSuite = async (opts) => {
|
|
421
415
|
const { client, credentialSupported, jwtCryptographicSuitePreferences, jsonldCryptographicSuitePreferences } = opts;
|
|
422
416
|
let signing_algs_supported;
|
|
423
417
|
if ('proof_types_supported' in credentialSupported && credentialSupported.proof_types_supported) {
|
|
@@ -436,9 +430,9 @@ const getIssuanceCryptoSuite = (opts) => __awaiter(void 0, void 0, void 0, funct
|
|
|
436
430
|
}
|
|
437
431
|
}
|
|
438
432
|
else {
|
|
439
|
-
signing_algs_supported =
|
|
433
|
+
signing_algs_supported = asArray(
|
|
440
434
|
// @ts-ignore // legacy
|
|
441
|
-
|
|
435
|
+
credentialSupported.credential_signing_alg_values_supported ?? credentialSupported.proof_signing_alg_values_supported ?? []);
|
|
442
436
|
}
|
|
443
437
|
// TODO: Return array, so the wallet/user could choose
|
|
444
438
|
switch (credentialSupported.format) {
|
|
@@ -453,7 +447,7 @@ const getIssuanceCryptoSuite = (opts) => __awaiter(void 0, void 0, void 0, funct
|
|
|
453
447
|
return supportedPreferences[0];
|
|
454
448
|
}
|
|
455
449
|
else if (client.isEBSI()) {
|
|
456
|
-
return
|
|
450
|
+
return JoseSignatureAlgorithm.ES256;
|
|
457
451
|
}
|
|
458
452
|
// if we cannot find supported cryptographic suites, we just try with the first preference
|
|
459
453
|
const fallback = jwtCryptographicSuitePreferences[0];
|
|
@@ -477,9 +471,8 @@ const getIssuanceCryptoSuite = (opts) => __awaiter(void 0, void 0, void 0, funct
|
|
|
477
471
|
default:
|
|
478
472
|
return Promise.reject(Error(`Credential format '${credentialSupported.format}' not supported`));
|
|
479
473
|
}
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
const startFirstPartApplicationMachine = (args, context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
474
|
+
};
|
|
475
|
+
export const startFirstPartApplicationMachine = async (args, context) => {
|
|
483
476
|
const { openID4VCIClientState, stateNavigationListener, contact } = args;
|
|
484
477
|
if (!openID4VCIClientState) {
|
|
485
478
|
return Promise.reject(Error('Missing openID4VCI client state in context'));
|
|
@@ -487,7 +480,7 @@ const startFirstPartApplicationMachine = (args, context) => __awaiter(void 0, vo
|
|
|
487
480
|
if (!contact) {
|
|
488
481
|
return Promise.reject(Error('Missing contact in context'));
|
|
489
482
|
}
|
|
490
|
-
const firstPartyMachineInstance =
|
|
483
|
+
const firstPartyMachineInstance = FirstPartyMachine.newInstance({
|
|
491
484
|
openID4VCIClientState,
|
|
492
485
|
contact,
|
|
493
486
|
agentContext: context,
|
|
@@ -496,20 +489,20 @@ const startFirstPartApplicationMachine = (args, context) => __awaiter(void 0, vo
|
|
|
496
489
|
return new Promise((resolve, reject) => {
|
|
497
490
|
try {
|
|
498
491
|
firstPartyMachineInstance.onTransition((state) => {
|
|
499
|
-
if (state.matches(
|
|
492
|
+
if (state.matches(FirstPartyMachineStateTypes.done)) {
|
|
500
493
|
const authorizationCodeResponse = state.context.authorizationCodeResponse;
|
|
501
494
|
if (!authorizationCodeResponse) {
|
|
502
495
|
reject(Error('No authorizationCodeResponse acquired'));
|
|
503
496
|
}
|
|
504
497
|
resolve(authorizationCodeResponse);
|
|
505
498
|
}
|
|
506
|
-
else if (state.matches(
|
|
507
|
-
resolve(
|
|
499
|
+
else if (state.matches(FirstPartyMachineStateTypes.aborted)) {
|
|
500
|
+
resolve(FirstPartyMachineStateTypes.aborted);
|
|
508
501
|
}
|
|
509
|
-
else if (state.matches(
|
|
510
|
-
resolve(
|
|
502
|
+
else if (state.matches(FirstPartyMachineStateTypes.declined)) {
|
|
503
|
+
resolve(FirstPartyMachineStateTypes.declined);
|
|
511
504
|
}
|
|
512
|
-
else if (state.matches(
|
|
505
|
+
else if (state.matches(FirstPartyMachineStateTypes.error)) {
|
|
513
506
|
reject(state.context.error);
|
|
514
507
|
}
|
|
515
508
|
});
|
|
@@ -519,6 +512,5 @@ const startFirstPartApplicationMachine = (args, context) => __awaiter(void 0, vo
|
|
|
519
512
|
reject(error);
|
|
520
513
|
}
|
|
521
514
|
});
|
|
522
|
-
}
|
|
523
|
-
exports.startFirstPartApplicationMachine = startFirstPartApplicationMachine;
|
|
515
|
+
};
|
|
524
516
|
//# sourceMappingURL=OID4VCIHolderService.js.map
|