@sphereon/ssi-types 0.30.2-unstable.9 → 0.31.0
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/events/index.d.ts +5 -2
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +4 -0
- package/dist/events/index.js.map +1 -1
- package/dist/logging/index.d.ts +1 -1
- package/dist/logging/index.d.ts.map +1 -1
- package/dist/logging/index.js +3 -2
- package/dist/logging/index.js.map +1 -1
- package/dist/mapper/credential-constraints.d.ts +16 -0
- package/dist/mapper/credential-constraints.d.ts.map +1 -0
- package/dist/mapper/credential-constraints.js +3 -0
- package/dist/mapper/credential-constraints.js.map +1 -0
- package/dist/mapper/credential-mapper.d.ts +3 -2
- package/dist/mapper/credential-mapper.d.ts.map +1 -1
- package/dist/mapper/credential-mapper.js +14 -10
- package/dist/mapper/credential-mapper.js.map +1 -1
- package/dist/mapper/jsonld-language-values.d.ts.map +1 -1
- package/dist/types/cose.d.ts +12 -0
- package/dist/types/cose.d.ts.map +1 -1
- package/dist/types/cose.js.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/metadata-types.d.ts +5 -0
- package/dist/types/metadata-types.d.ts.map +1 -0
- package/dist/types/metadata-types.js +3 -0
- package/dist/types/metadata-types.js.map +1 -0
- package/dist/types/mso_mdoc.d.ts +16 -8
- package/dist/types/mso_mdoc.d.ts.map +1 -1
- package/dist/types/mso_mdoc.js +29 -11
- package/dist/types/mso_mdoc.js.map +1 -1
- package/dist/types/sd-jwt-type-metadata.d.ts +147 -0
- package/dist/types/sd-jwt-type-metadata.d.ts.map +1 -0
- package/dist/types/sd-jwt-type-metadata.js +84 -0
- package/dist/types/sd-jwt-type-metadata.js.map +1 -0
- package/dist/types/sd-jwt-vc.d.ts.map +1 -1
- package/dist/types/sd-jwt-vc.js +17 -12
- package/dist/types/sd-jwt-vc.js.map +1 -1
- package/dist/types/w3c-vc.js +5 -5
- package/dist/types/w3c-vc.js.map +1 -1
- package/package.json +7 -6
- package/src/events/index.ts +8 -4
- package/src/logging/index.ts +1 -0
- package/src/mapper/credential-constraints.ts +19 -0
- package/src/mapper/credential-mapper.ts +45 -40
- package/src/types/cose.ts +13 -0
- package/src/types/index.ts +2 -0
- package/src/types/metadata-types.ts +5 -0
- package/src/types/mso_mdoc.ts +41 -7
- package/src/types/sd-jwt-type-metadata.ts +220 -0
- package/src/types/sd-jwt-vc.ts +19 -17
- package/src/types/w3c-vc.ts +2 -2
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CredentialFormat, PresentationFormat } from '../types'
|
|
2
|
+
|
|
3
|
+
export type CredentialEncoding = 'json' /*includes json-ld*/ | 'jwt' | 'cbor'
|
|
4
|
+
|
|
5
|
+
export type IssuerAttributeName = 'iss' | 'issuer' | 'issuerAuth'
|
|
6
|
+
export type SubjectAttributeName = 'subject' | 'id' | 'deviceMac' | 'TODO'
|
|
7
|
+
export type TypeAttributeName = 'type' | 'vct'
|
|
8
|
+
|
|
9
|
+
export type DataModel = 'W3C_VCDM' | 'IETF_SD_JWT' | 'ISO_MSO_MDOC'
|
|
10
|
+
|
|
11
|
+
export interface CredentialConstraint {
|
|
12
|
+
credentialFormat: CredentialFormat
|
|
13
|
+
presentationFormat: PresentationFormat
|
|
14
|
+
maxSignatures: number
|
|
15
|
+
encoding: CredentialEncoding
|
|
16
|
+
dataModel: DataModel
|
|
17
|
+
typeAttribute?: TypeAttributeName // optional since mdocs use namespace maps without an explicit type attribute
|
|
18
|
+
issuerAttributes: [IssuerAttributeName]
|
|
19
|
+
}
|
|
@@ -41,9 +41,9 @@ import {
|
|
|
41
41
|
WrappedVerifiablePresentation,
|
|
42
42
|
WrappedW3CVerifiableCredential,
|
|
43
43
|
} from '../types'
|
|
44
|
-
import { MdocDocument } from '../types/mso_mdoc'
|
|
44
|
+
import { getMdocDecodedPayload, MdocDocument } from '../types/mso_mdoc'
|
|
45
45
|
import { ObjectUtils } from '../utils'
|
|
46
|
-
import { com } from '@sphereon/kmp-
|
|
46
|
+
import { com } from '@sphereon/kmp-mdoc-core'
|
|
47
47
|
import DeviceResponseCbor = com.sphereon.mdoc.data.device.DeviceResponseCbor
|
|
48
48
|
|
|
49
49
|
export class CredentialMapper {
|
|
@@ -66,7 +66,7 @@ export class CredentialMapper {
|
|
|
66
66
|
*/
|
|
67
67
|
static decodeVerifiablePresentation(
|
|
68
68
|
presentation: OriginalVerifiablePresentation,
|
|
69
|
-
hasher?: Hasher
|
|
69
|
+
hasher?: Hasher,
|
|
70
70
|
): JwtDecodedVerifiablePresentation | IVerifiablePresentation | SdJwtDecodedVerifiableCredential | MdocOid4vpMdocVpToken | MdocDeviceResponse {
|
|
71
71
|
if (CredentialMapper.isJwtEncoded(presentation)) {
|
|
72
72
|
const payload = jwt_decode(presentation as string) as JwtDecodedVerifiablePresentation
|
|
@@ -111,7 +111,7 @@ export class CredentialMapper {
|
|
|
111
111
|
*/
|
|
112
112
|
static decodeVerifiableCredential(
|
|
113
113
|
credential: OriginalVerifiableCredential,
|
|
114
|
-
hasher?: Hasher
|
|
114
|
+
hasher?: Hasher,
|
|
115
115
|
): JwtDecodedVerifiableCredential | IVerifiableCredential | SdJwtDecodedVerifiableCredential {
|
|
116
116
|
if (CredentialMapper.isJwtEncoded(credential)) {
|
|
117
117
|
const payload = jwt_decode(credential as string) as JwtDecodedVerifiableCredential
|
|
@@ -151,7 +151,7 @@ export class CredentialMapper {
|
|
|
151
151
|
*/
|
|
152
152
|
static toWrappedVerifiablePresentation(
|
|
153
153
|
originalPresentation: OriginalVerifiablePresentation,
|
|
154
|
-
opts?: { maxTimeSkewInMS?: number; hasher?: Hasher }
|
|
154
|
+
opts?: { maxTimeSkewInMS?: number; hasher?: Hasher },
|
|
155
155
|
): WrappedVerifiablePresentation {
|
|
156
156
|
// MSO_MDOC
|
|
157
157
|
if (CredentialMapper.isMsoMdocDecodedPresentation(originalPresentation) || CredentialMapper.isMsoMdocOid4VPEncoded(originalPresentation)) {
|
|
@@ -162,19 +162,20 @@ export class CredentialMapper {
|
|
|
162
162
|
deviceResponse = originalPresentation
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
if (
|
|
169
|
-
throw Error('mdoc
|
|
165
|
+
const mdocCredentials = deviceResponse.documents?.map(
|
|
166
|
+
(doc) => CredentialMapper.toWrappedVerifiableCredential(doc, opts) as WrappedMdocCredential,
|
|
167
|
+
)
|
|
168
|
+
if (!mdocCredentials || mdocCredentials.length === 0) {
|
|
169
|
+
throw new Error('could not extract any mdoc credentials from mdoc device response')
|
|
170
170
|
}
|
|
171
|
+
|
|
171
172
|
return {
|
|
172
173
|
type: CredentialMapper.isMsoMdocDecodedPresentation(originalPresentation) ? OriginalType.MSO_MDOC_DECODED : OriginalType.MSO_MDOC_ENCODED,
|
|
173
174
|
format: 'mso_mdoc',
|
|
174
175
|
original: originalPresentation,
|
|
175
176
|
presentation: deviceResponse,
|
|
176
177
|
decoded: deviceResponse,
|
|
177
|
-
vcs:
|
|
178
|
+
vcs: mdocCredentials,
|
|
178
179
|
}
|
|
179
180
|
}
|
|
180
181
|
// SD-JWT
|
|
@@ -205,7 +206,7 @@ export class CredentialMapper {
|
|
|
205
206
|
typeof originalPresentation !== 'string' && CredentialMapper.hasJWTProofType(originalPresentation) ? proof?.jwt : originalPresentation
|
|
206
207
|
if (!original) {
|
|
207
208
|
throw Error(
|
|
208
|
-
'Could not determine original presentation, probably it was a converted JWT presentation, that is now missing the JWT value in the proof'
|
|
209
|
+
'Could not determine original presentation, probably it was a converted JWT presentation, that is now missing the JWT value in the proof',
|
|
209
210
|
)
|
|
210
211
|
}
|
|
211
212
|
const decoded = CredentialMapper.decodeVerifiablePresentation(original) as IVerifiablePresentation | JwtDecodedVerifiablePresentation
|
|
@@ -233,7 +234,7 @@ export class CredentialMapper {
|
|
|
233
234
|
? []
|
|
234
235
|
: (CredentialMapper.toWrappedVerifiableCredentials(
|
|
235
236
|
vp.verifiableCredential ?? [] /*.map(value => value.original)*/,
|
|
236
|
-
opts
|
|
237
|
+
opts,
|
|
237
238
|
) as WrappedW3CVerifiableCredential[])
|
|
238
239
|
|
|
239
240
|
const presentation = {
|
|
@@ -261,7 +262,7 @@ export class CredentialMapper {
|
|
|
261
262
|
*/
|
|
262
263
|
static toWrappedVerifiableCredentials(
|
|
263
264
|
verifiableCredentials: OriginalVerifiableCredential[],
|
|
264
|
-
opts?: { maxTimeSkewInMS?: number; hasher?: Hasher }
|
|
265
|
+
opts?: { maxTimeSkewInMS?: number; hasher?: Hasher },
|
|
265
266
|
): WrappedVerifiableCredential[] {
|
|
266
267
|
return verifiableCredentials.map((vc) => CredentialMapper.toWrappedVerifiableCredential(vc, opts))
|
|
267
268
|
}
|
|
@@ -277,10 +278,10 @@ export class CredentialMapper {
|
|
|
277
278
|
*/
|
|
278
279
|
static toWrappedVerifiableCredential(
|
|
279
280
|
verifiableCredential: OriginalVerifiableCredential,
|
|
280
|
-
opts?: { maxTimeSkewInMS?: number; hasher?: Hasher }
|
|
281
|
+
opts?: { maxTimeSkewInMS?: number; hasher?: Hasher },
|
|
281
282
|
): WrappedVerifiableCredential {
|
|
282
283
|
// MSO_MDOC
|
|
283
|
-
if (CredentialMapper.isMsoMdocDecodedCredential(verifiableCredential) || CredentialMapper.
|
|
284
|
+
if (CredentialMapper.isMsoMdocDecodedCredential(verifiableCredential) || CredentialMapper.isMsoMdocOid4VPEncoded(verifiableCredential)) {
|
|
284
285
|
let mdoc: MdocDocument
|
|
285
286
|
if (CredentialMapper.isMsoMdocOid4VPEncoded(verifiableCredential)) {
|
|
286
287
|
mdoc = decodeMdocIssuerSigned(verifiableCredential)
|
|
@@ -291,8 +292,8 @@ export class CredentialMapper {
|
|
|
291
292
|
type: CredentialMapper.isMsoMdocDecodedCredential(verifiableCredential) ? OriginalType.MSO_MDOC_DECODED : OriginalType.MSO_MDOC_ENCODED,
|
|
292
293
|
format: 'mso_mdoc',
|
|
293
294
|
original: verifiableCredential,
|
|
294
|
-
credential:
|
|
295
|
-
decoded: mdoc,
|
|
295
|
+
credential: mdoc,
|
|
296
|
+
decoded: getMdocDecodedPayload(mdoc),
|
|
296
297
|
}
|
|
297
298
|
}
|
|
298
299
|
|
|
@@ -319,10 +320,10 @@ export class CredentialMapper {
|
|
|
319
320
|
|
|
320
321
|
// If the VC is not an encoded/decoded SD-JWT, we assume it will be a W3C VC
|
|
321
322
|
const proof = CredentialMapper.getFirstProof(verifiableCredential)
|
|
322
|
-
const original = CredentialMapper.hasJWTProofType(verifiableCredential) && proof ? proof.jwt ?? verifiableCredential : verifiableCredential
|
|
323
|
+
const original = CredentialMapper.hasJWTProofType(verifiableCredential) && proof ? (proof.jwt ?? verifiableCredential) : verifiableCredential
|
|
323
324
|
if (!original) {
|
|
324
325
|
throw Error(
|
|
325
|
-
'Could not determine original credential, probably it was a converted JWT credential, that is now missing the JWT value in the proof'
|
|
326
|
+
'Could not determine original credential, probably it was a converted JWT credential, that is now missing the JWT value in the proof',
|
|
326
327
|
)
|
|
327
328
|
}
|
|
328
329
|
const decoded = CredentialMapper.decodeVerifiableCredential(original) as JwtDecodedVerifiableCredential | IVerifiableCredential
|
|
@@ -358,7 +359,7 @@ export class CredentialMapper {
|
|
|
358
359
|
return ObjectUtils.isString(original) && !original.startsWith('ey') && ObjectUtils.isBase64(original)
|
|
359
360
|
}
|
|
360
361
|
|
|
361
|
-
public static isW3cCredential(credential: ICredential | SdJwtDecodedVerifiableCredential): credential is ICredential {
|
|
362
|
+
public static isW3cCredential(credential: ICredential | SdJwtDecodedVerifiableCredential | MdocDocument): credential is ICredential {
|
|
362
363
|
return typeof credential === 'object' && '@context' in credential && ((credential as ICredential).type?.includes('VerifiableCredential') || false)
|
|
363
364
|
}
|
|
364
365
|
|
|
@@ -438,7 +439,7 @@ export class CredentialMapper {
|
|
|
438
439
|
}
|
|
439
440
|
|
|
440
441
|
public static isW3cPresentation(
|
|
441
|
-
presentation: UniformVerifiablePresentation | IPresentation | SdJwtDecodedVerifiableCredential | DeviceResponseCbor
|
|
442
|
+
presentation: UniformVerifiablePresentation | IPresentation | SdJwtDecodedVerifiableCredential | DeviceResponseCbor,
|
|
442
443
|
): presentation is IPresentation {
|
|
443
444
|
return (
|
|
444
445
|
typeof presentation === 'object' &&
|
|
@@ -448,7 +449,7 @@ export class CredentialMapper {
|
|
|
448
449
|
}
|
|
449
450
|
|
|
450
451
|
public static isSdJwtDecodedCredentialPayload(
|
|
451
|
-
credential: ICredential | SdJwtDecodedVerifiableCredentialPayload
|
|
452
|
+
credential: ICredential | SdJwtDecodedVerifiableCredentialPayload,
|
|
452
453
|
): credential is SdJwtDecodedVerifiableCredentialPayload {
|
|
453
454
|
return typeof credential === 'object' && 'vct' in credential
|
|
454
455
|
}
|
|
@@ -462,7 +463,11 @@ export class CredentialMapper {
|
|
|
462
463
|
// We are doing this over here, as the rest of the logic around it would otherwise need to be adjusted substantially
|
|
463
464
|
return false
|
|
464
465
|
}
|
|
465
|
-
|
|
466
|
+
|
|
467
|
+
// FIXME: mdoc library fails on parsing the device signed, so for now we just check whether the issuerSigned
|
|
468
|
+
// is equal, then we have a good chance it is the same credential. Once device signed parsing is fixed in mdl
|
|
469
|
+
// library we can move the .equals() to the top-level object.
|
|
470
|
+
return firstOriginal.issuerSigned.equals(secondOriginal.issuerSigned)
|
|
466
471
|
} else if (CredentialMapper.isSdJwtDecodedCredential(firstOriginal) || CredentialMapper.isSdJwtDecodedCredential(secondOriginal)) {
|
|
467
472
|
return firstOriginal.compactSdJwtVc === secondOriginal.compactSdJwtVc
|
|
468
473
|
} else {
|
|
@@ -476,7 +481,7 @@ export class CredentialMapper {
|
|
|
476
481
|
}
|
|
477
482
|
|
|
478
483
|
public static isSdJwtDecodedCredential(
|
|
479
|
-
original: OriginalVerifiableCredential | OriginalVerifiablePresentation | ICredential | IPresentation
|
|
484
|
+
original: OriginalVerifiableCredential | OriginalVerifiablePresentation | ICredential | IPresentation,
|
|
480
485
|
): original is SdJwtDecodedVerifiableCredential {
|
|
481
486
|
return (
|
|
482
487
|
typeof original === 'object' &&
|
|
@@ -485,7 +490,7 @@ export class CredentialMapper {
|
|
|
485
490
|
}
|
|
486
491
|
|
|
487
492
|
public static isMsoMdocDecodedCredential(
|
|
488
|
-
original: OriginalVerifiableCredential | OriginalVerifiablePresentation | ICredential | IPresentation
|
|
493
|
+
original: OriginalVerifiableCredential | OriginalVerifiablePresentation | ICredential | IPresentation,
|
|
489
494
|
): original is MdocDocument {
|
|
490
495
|
return typeof original === 'object' && 'issuerSigned' in original && (<MdocDocument>original).issuerSigned !== undefined
|
|
491
496
|
}
|
|
@@ -520,7 +525,7 @@ export class CredentialMapper {
|
|
|
520
525
|
static jwtEncodedPresentationToUniformPresentation(
|
|
521
526
|
jwt: string,
|
|
522
527
|
makeCredentialsUniform: boolean = true,
|
|
523
|
-
opts?: { maxTimeSkewInMS?: number }
|
|
528
|
+
opts?: { maxTimeSkewInMS?: number },
|
|
524
529
|
): IPresentation {
|
|
525
530
|
return CredentialMapper.jwtDecodedPresentationToUniformPresentation(jwt_decode(jwt), makeCredentialsUniform, opts)
|
|
526
531
|
}
|
|
@@ -528,7 +533,7 @@ export class CredentialMapper {
|
|
|
528
533
|
static jwtDecodedPresentationToUniformPresentation(
|
|
529
534
|
decoded: JwtDecodedVerifiablePresentation,
|
|
530
535
|
makeCredentialsUniform: boolean = true,
|
|
531
|
-
opts?: { maxTimeSkewInMS?: number }
|
|
536
|
+
opts?: { maxTimeSkewInMS?: number },
|
|
532
537
|
): IVerifiablePresentation {
|
|
533
538
|
const { iss, aud, jti, vp, ...rest } = decoded
|
|
534
539
|
|
|
@@ -575,7 +580,7 @@ export class CredentialMapper {
|
|
|
575
580
|
opts?: {
|
|
576
581
|
maxTimeSkewInMS?: number
|
|
577
582
|
hasher?: Hasher
|
|
578
|
-
}
|
|
583
|
+
},
|
|
579
584
|
): IVerifiableCredential {
|
|
580
585
|
if (CredentialMapper.isMsoMdocDecodedCredential(verifiableCredential)) {
|
|
581
586
|
return mdocDecodedCredentialToUniformCredential(verifiableCredential)
|
|
@@ -589,7 +594,7 @@ export class CredentialMapper {
|
|
|
589
594
|
: verifiableCredential
|
|
590
595
|
if (!original) {
|
|
591
596
|
throw Error(
|
|
592
|
-
'Could not determine original credential from passed in credential. Probably because a JWT proof type was present, but now is not available anymore'
|
|
597
|
+
'Could not determine original credential from passed in credential. Probably because a JWT proof type was present, but now is not available anymore',
|
|
593
598
|
)
|
|
594
599
|
}
|
|
595
600
|
const decoded = CredentialMapper.decodeVerifiableCredential(original, opts?.hasher)
|
|
@@ -612,7 +617,7 @@ export class CredentialMapper {
|
|
|
612
617
|
|
|
613
618
|
static toUniformPresentation(
|
|
614
619
|
presentation: OriginalVerifiablePresentation,
|
|
615
|
-
opts?: { maxTimeSkewInMS?: number; addContextIfMissing?: boolean }
|
|
620
|
+
opts?: { maxTimeSkewInMS?: number; addContextIfMissing?: boolean; hasher?: Hasher },
|
|
616
621
|
): IVerifiablePresentation {
|
|
617
622
|
if (CredentialMapper.isSdJwtDecodedCredential(presentation)) {
|
|
618
623
|
throw new Error('Converting SD-JWT VC to uniform VP is not supported.')
|
|
@@ -624,10 +629,10 @@ export class CredentialMapper {
|
|
|
624
629
|
const original = typeof presentation !== 'string' && CredentialMapper.hasJWTProofType(presentation) ? proof?.jwt : presentation
|
|
625
630
|
if (!original) {
|
|
626
631
|
throw Error(
|
|
627
|
-
'Could not determine original presentation, probably it was a converted JWT presentation, that is now missing the JWT value in the proof'
|
|
632
|
+
'Could not determine original presentation, probably it was a converted JWT presentation, that is now missing the JWT value in the proof',
|
|
628
633
|
)
|
|
629
634
|
}
|
|
630
|
-
const decoded = CredentialMapper.decodeVerifiablePresentation(original)
|
|
635
|
+
const decoded = CredentialMapper.decodeVerifiablePresentation(original, opts?.hasher)
|
|
631
636
|
const isJwtEncoded: boolean = CredentialMapper.isJwtEncoded(original)
|
|
632
637
|
const isJwtDecoded: boolean = CredentialMapper.isJwtDecodedPresentation(original)
|
|
633
638
|
const uniformPresentation =
|
|
@@ -641,7 +646,7 @@ export class CredentialMapper {
|
|
|
641
646
|
}
|
|
642
647
|
|
|
643
648
|
uniformPresentation.verifiableCredential = uniformPresentation.verifiableCredential?.map((vc) =>
|
|
644
|
-
CredentialMapper.toUniformCredential(vc, opts)
|
|
649
|
+
CredentialMapper.toUniformCredential(vc, opts),
|
|
645
650
|
) as IVerifiableCredential[] // We cast it because we IPresentation needs a VC. The internal Credential doesn't have the required Proof anymore (that is intended)
|
|
646
651
|
return uniformPresentation
|
|
647
652
|
}
|
|
@@ -650,14 +655,14 @@ export class CredentialMapper {
|
|
|
650
655
|
jwt: string,
|
|
651
656
|
opts?: {
|
|
652
657
|
maxTimeSkewInMS?: number
|
|
653
|
-
}
|
|
658
|
+
},
|
|
654
659
|
): IVerifiableCredential {
|
|
655
660
|
return CredentialMapper.jwtDecodedCredentialToUniformCredential(jwt_decode(jwt), opts)
|
|
656
661
|
}
|
|
657
662
|
|
|
658
663
|
static jwtDecodedCredentialToUniformCredential(
|
|
659
664
|
decoded: JwtDecodedVerifiableCredential,
|
|
660
|
-
opts?: { maxTimeSkewInMS?: number }
|
|
665
|
+
opts?: { maxTimeSkewInMS?: number },
|
|
661
666
|
): IVerifiableCredential {
|
|
662
667
|
const { exp, nbf, iss, vc, sub, jti, ...rest } = decoded
|
|
663
668
|
const credential: IVerifiableCredential = {
|
|
@@ -825,7 +830,7 @@ export class CredentialMapper {
|
|
|
825
830
|
}
|
|
826
831
|
|
|
827
832
|
static toCompactJWT(
|
|
828
|
-
jwtDocument: W3CVerifiableCredential | JwtDecodedVerifiableCredential | W3CVerifiablePresentation | JwtDecodedVerifiablePresentation | string
|
|
833
|
+
jwtDocument: W3CVerifiableCredential | JwtDecodedVerifiableCredential | W3CVerifiablePresentation | JwtDecodedVerifiablePresentation | string,
|
|
829
834
|
): string {
|
|
830
835
|
if (!jwtDocument || CredentialMapper.detectDocumentType(jwtDocument) !== DocumentFormat.JWT) {
|
|
831
836
|
throw Error('Cannot convert non JWT credential to JWT')
|
|
@@ -855,7 +860,7 @@ export class CredentialMapper {
|
|
|
855
860
|
| JwtDecodedVerifiablePresentation
|
|
856
861
|
| SdJwtDecodedVerifiableCredential
|
|
857
862
|
| MdocDeviceResponse
|
|
858
|
-
| MdocDocument
|
|
863
|
+
| MdocDocument,
|
|
859
864
|
): DocumentFormat {
|
|
860
865
|
if (this.isMsoMdocOid4VPEncoded(document as any) || this.isMsoMdocDecodedCredential(document as any)) {
|
|
861
866
|
return DocumentFormat.MSO_MDOC
|
|
@@ -883,7 +888,7 @@ export class CredentialMapper {
|
|
|
883
888
|
}
|
|
884
889
|
|
|
885
890
|
private static hasJWTProofType(
|
|
886
|
-
document: W3CVerifiableCredential | W3CVerifiablePresentation | JwtDecodedVerifiableCredential | JwtDecodedVerifiablePresentation
|
|
891
|
+
document: W3CVerifiableCredential | W3CVerifiablePresentation | JwtDecodedVerifiableCredential | JwtDecodedVerifiablePresentation,
|
|
887
892
|
): boolean {
|
|
888
893
|
if (typeof document === 'string') {
|
|
889
894
|
return false
|
|
@@ -892,7 +897,7 @@ export class CredentialMapper {
|
|
|
892
897
|
}
|
|
893
898
|
|
|
894
899
|
private static getFirstProof(
|
|
895
|
-
document: W3CVerifiableCredential | W3CVerifiablePresentation | JwtDecodedVerifiableCredential | JwtDecodedVerifiablePresentation
|
|
900
|
+
document: W3CVerifiableCredential | W3CVerifiablePresentation | JwtDecodedVerifiableCredential | JwtDecodedVerifiablePresentation,
|
|
896
901
|
): IProof | undefined {
|
|
897
902
|
if (!document || typeof document === 'string') {
|
|
898
903
|
return undefined
|
package/src/types/cose.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { com } from '@sphereon/kmp-mdoc-core'
|
|
2
|
+
import SignatureAlgorithm = com.sphereon.crypto.generic.SignatureAlgorithm
|
|
3
|
+
import KeyType = com.sphereon.crypto.generic.KeyType
|
|
4
|
+
import KeyOperations = com.sphereon.crypto.generic.KeyOperations
|
|
5
|
+
|
|
1
6
|
/**
|
|
2
7
|
* See our mdl-mdoc and crypto library for more information
|
|
3
8
|
* https://github.com/Sphereon-Opensource/mdoc-cbor-crypto-multiplatform
|
|
@@ -17,6 +22,14 @@ export interface ICoseKeyJson {
|
|
|
17
22
|
y?: string
|
|
18
23
|
d?: string
|
|
19
24
|
x5chain?: Array<string>
|
|
25
|
+
getSignatureAlgorithm(): SignatureAlgorithm
|
|
26
|
+
getKty(): KeyType
|
|
27
|
+
getKeyOperations(): Array<KeyOperations>
|
|
28
|
+
getX509CertificateChain(): Array<string> | undefined
|
|
29
|
+
toPublicKey(): ICoseKeyJson
|
|
30
|
+
getKidAsString(): string | undefined
|
|
31
|
+
getXAsString(): string
|
|
32
|
+
getYAsString(): string
|
|
20
33
|
|
|
21
34
|
[k: string]: unknown
|
|
22
35
|
}
|
package/src/types/index.ts
CHANGED
|
@@ -3,7 +3,9 @@ export * from './pex'
|
|
|
3
3
|
export * from './vc'
|
|
4
4
|
export * from './generic'
|
|
5
5
|
export * from './sd-jwt-vc'
|
|
6
|
+
export * from './sd-jwt-type-metadata'
|
|
6
7
|
export * from './w3c-vc'
|
|
7
8
|
export * from './jose'
|
|
8
9
|
export * from './cose'
|
|
9
10
|
export * from './mso_mdoc'
|
|
11
|
+
export * from './metadata-types'
|
package/src/types/mso_mdoc.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* for sd-jwts
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { com } from '@sphereon/kmp-
|
|
8
|
+
import { com } from '@sphereon/kmp-mdoc-core'
|
|
9
9
|
import { IProofPurpose, IProofType } from './did'
|
|
10
10
|
import { OriginalType, WrappedVerifiableCredential, WrappedVerifiablePresentation } from './vc'
|
|
11
11
|
import { IVerifiableCredential } from './w3c-vc'
|
|
@@ -25,6 +25,8 @@ export type MdocOid4vpMdocVpToken = string
|
|
|
25
25
|
export type MdocIssuerSigned = com.sphereon.mdoc.data.device.IssuerSignedCbor
|
|
26
26
|
export type MdocDocument = com.sphereon.mdoc.data.device.DocumentCbor
|
|
27
27
|
export type MdocDocumentJson = com.sphereon.mdoc.data.device.DocumentJson
|
|
28
|
+
export type IssuerSignedJson = com.sphereon.mdoc.data.device.IssuerSignedJson
|
|
29
|
+
export type DeviceSignedJson = com.sphereon.mdoc.data.device.DeviceSignedJson
|
|
28
30
|
export type MdocDeviceResponse = com.sphereon.mdoc.data.device.DeviceResponseCbor
|
|
29
31
|
|
|
30
32
|
export interface WrappedMdocCredential {
|
|
@@ -33,9 +35,10 @@ export interface WrappedMdocCredential {
|
|
|
33
35
|
*/
|
|
34
36
|
original: MdocDocument | MdocOid4vpIssuerSigned
|
|
35
37
|
/**
|
|
36
|
-
*
|
|
38
|
+
* Record where keys are the namespaces and the values are objects again with the namespace values
|
|
39
|
+
* @todo which types can be there? (it doesn't matter for matching as mdoc only matches on path)
|
|
37
40
|
*/
|
|
38
|
-
decoded:
|
|
41
|
+
decoded: MdocDecodedPayload
|
|
39
42
|
/**
|
|
40
43
|
* Type of this credential.
|
|
41
44
|
*/
|
|
@@ -47,7 +50,7 @@ export interface WrappedMdocCredential {
|
|
|
47
50
|
/**
|
|
48
51
|
* Internal stable representation of a Credential
|
|
49
52
|
*/
|
|
50
|
-
credential:
|
|
53
|
+
credential: MdocDocument
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
export interface WrappedMdocPresentation {
|
|
@@ -72,9 +75,10 @@ export interface WrappedMdocPresentation {
|
|
|
72
75
|
*/
|
|
73
76
|
presentation: MdocDeviceResponse
|
|
74
77
|
/**
|
|
75
|
-
* Wrapped Mdocs belonging to the Presentation.
|
|
78
|
+
* Wrapped Mdocs belonging to the Presentation. There can be multiple
|
|
79
|
+
* documents in a single device response
|
|
76
80
|
*/
|
|
77
|
-
vcs: [
|
|
81
|
+
vcs: WrappedMdocCredential[]
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
export function isWrappedMdocCredential(vc: WrappedVerifiableCredential): vc is WrappedMdocCredential {
|
|
@@ -84,6 +88,32 @@ export function isWrappedMdocCredential(vc: WrappedVerifiableCredential): vc is
|
|
|
84
88
|
export function isWrappedMdocPresentation(vp: WrappedVerifiablePresentation): vp is WrappedMdocPresentation {
|
|
85
89
|
return vp.format === 'mso_mdoc'
|
|
86
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Record where keys are the namespaces and the values are objects again with the namespace values
|
|
93
|
+
*/
|
|
94
|
+
export type MdocDecodedPayload = Record<string, Record<string, string | number | boolean>>
|
|
95
|
+
export function getMdocDecodedPayload(mdoc: MdocDocument): MdocDecodedPayload {
|
|
96
|
+
const mdocJson = mdoc.toJson()
|
|
97
|
+
if (!mdocJson.issuerSigned.nameSpaces) {
|
|
98
|
+
throw Error(`Cannot access Issuer Signed items from the Mdoc`)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const issuerSignedJson = mdocJson.issuerSigned.toJsonDTO<IssuerSignedJson>()
|
|
102
|
+
const namespaces = issuerSignedJson.nameSpaces as unknown as Record<string, IssuerSignedItemJson[]>
|
|
103
|
+
|
|
104
|
+
const decodedPayload: MdocDecodedPayload = {}
|
|
105
|
+
for (const [namespace, items] of Object.entries(namespaces)) {
|
|
106
|
+
decodedPayload[namespace] = items.reduce(
|
|
107
|
+
(acc, item) => ({
|
|
108
|
+
...acc,
|
|
109
|
+
[item.key]: item.value.value,
|
|
110
|
+
}),
|
|
111
|
+
{},
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return decodedPayload
|
|
116
|
+
}
|
|
87
117
|
|
|
88
118
|
/**
|
|
89
119
|
* Decode an Mdoc from its issuerSigned OID4VP Base64URL (string) to an object containing the disclosures,
|
|
@@ -98,6 +128,10 @@ export function decodeMdocIssuerSigned(oid4vpIssuerSigned: MdocOid4vpIssuerSigne
|
|
|
98
128
|
return holderMdoc
|
|
99
129
|
}
|
|
100
130
|
|
|
131
|
+
export function encodeMdocIssuerSigned(issuerSigned: MdocIssuerSigned, encoding: 'base64url' = 'base64url') {
|
|
132
|
+
return encodeTo(issuerSigned.cborEncode(), Encoding.BASE64URL)
|
|
133
|
+
}
|
|
134
|
+
|
|
101
135
|
/**
|
|
102
136
|
* Decode an Mdoc from its vp_token OID4VP Base64URL (string) to an object containing the disclosures,
|
|
103
137
|
* signed payload, decoded payload
|
|
@@ -112,7 +146,7 @@ export function decodeMdocDeviceResponse(vpToken: MdocOid4vpMdocVpToken): MdocDe
|
|
|
112
146
|
export const mdocDecodedCredentialToUniformCredential = (
|
|
113
147
|
decoded: MdocDocument,
|
|
114
148
|
// @ts-ignore
|
|
115
|
-
opts?: { maxTimeSkewInMS?: number }
|
|
149
|
+
opts?: { maxTimeSkewInMS?: number },
|
|
116
150
|
): IVerifiableCredential => {
|
|
117
151
|
const mdoc = decoded.toJson()
|
|
118
152
|
const json = mdoc.toJsonDTO<DocumentJson>()
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import * as u8a from 'uint8arrays'
|
|
2
|
+
import { AsyncHasher } from './sd-jwt-vc'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Represents the metadata associated with a specific SD-JWT VC type.
|
|
6
|
+
*/
|
|
7
|
+
interface SdJwtTypeMetadata {
|
|
8
|
+
/**
|
|
9
|
+
* REQUIRED. The VC type URI.
|
|
10
|
+
*/
|
|
11
|
+
vct: string;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* OPTIONAL. A human-readable name for the type.
|
|
15
|
+
*/
|
|
16
|
+
name?: string;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* OPTIONAL. A human-readable description for the type.
|
|
20
|
+
*/
|
|
21
|
+
description?: string;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* OPTIONAL. A URI of another type that this type extends.
|
|
25
|
+
*/
|
|
26
|
+
extends?: string;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* OPTIONAL. Integrity metadata string for the 'extends' field.
|
|
30
|
+
*/
|
|
31
|
+
['extends#integrity']?: string;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* OPTIONAL. URL pointing towards a JSON Schema document describing the VC's structure.
|
|
35
|
+
*/
|
|
36
|
+
schema_uri?: string;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* OPTIONAL. Integrity metadata string for the 'schema_uri' field.
|
|
40
|
+
*/
|
|
41
|
+
['schema_uri#integrity']?: string;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* OPTIONAL. Display metadata for various languages.
|
|
45
|
+
*/
|
|
46
|
+
display?: Array<SdJwtTypeDisplayMetadata>;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* OPTIONAL. Metadata for the claims within the VC.
|
|
50
|
+
*/
|
|
51
|
+
// TODO:
|
|
52
|
+
claims?: Array<any>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Represents display metadata for a specific language.
|
|
57
|
+
*/
|
|
58
|
+
interface SdJwtTypeDisplayMetadata {
|
|
59
|
+
/**
|
|
60
|
+
* REQUIRED. Language tag for the display information.
|
|
61
|
+
*/
|
|
62
|
+
lang: string;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* REQUIRED. Human-readable name for the type.
|
|
66
|
+
*/
|
|
67
|
+
name: string;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* OPTIONAL. Human-readable description for the type.
|
|
71
|
+
*/
|
|
72
|
+
description?: string;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* OPTIONAL. Rendering metadata for the type.
|
|
76
|
+
*/
|
|
77
|
+
rendering?: SdJwtTypeRenderingMetadata;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Contains rendering metadata for different methods.
|
|
82
|
+
*/
|
|
83
|
+
interface SdJwtTypeRenderingMetadata {
|
|
84
|
+
/**
|
|
85
|
+
* OPTIONAL. Simple rendering method metadata.
|
|
86
|
+
*/
|
|
87
|
+
simple?: SdJwtSimpleRenderingMetadata;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* OPTIONAL. Metadata for SVG templates.
|
|
91
|
+
*/
|
|
92
|
+
svg_template?: Array<SdJwtSVGTemplateMetadata>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Represents metadata for simple rendering.
|
|
97
|
+
*/
|
|
98
|
+
interface SdJwtSimpleRenderingMetadata {
|
|
99
|
+
/**
|
|
100
|
+
* OPTIONAL. Metadata for the logo image.
|
|
101
|
+
*/
|
|
102
|
+
logo?: SdJwtLogoMetadata;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* OPTIONAL. Background color for the credential.
|
|
106
|
+
*/
|
|
107
|
+
background_color?: string;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* OPTIONAL. Text color for the credential.
|
|
111
|
+
*/
|
|
112
|
+
text_color?: string;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Represents metadata for a logo.
|
|
117
|
+
*/
|
|
118
|
+
interface SdJwtLogoMetadata {
|
|
119
|
+
/**
|
|
120
|
+
* REQUIRED. URI pointing to the logo image.
|
|
121
|
+
*/
|
|
122
|
+
uri: string;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* OPTIONAL. Integrity metadata string for the 'uri' field.
|
|
126
|
+
*/
|
|
127
|
+
['uri#integrity']?: string;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* OPTIONAL. Alternative text for the logo image.
|
|
131
|
+
*/
|
|
132
|
+
alt_text?: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Represents metadata for SVG templates.
|
|
137
|
+
*/
|
|
138
|
+
interface SdJwtSVGTemplateMetadata {
|
|
139
|
+
/**
|
|
140
|
+
* REQUIRED. URI pointing to the SVG template.
|
|
141
|
+
*/
|
|
142
|
+
uri: string;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* OPTIONAL. Integrity metadata string for the 'uri' field.
|
|
146
|
+
*/
|
|
147
|
+
['uri#integrity']?: string;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* OPTIONAL. Properties for the SVG template.
|
|
151
|
+
*/
|
|
152
|
+
properties?: SdJwtSVGTemplateProperties;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Contains properties for SVG templates.
|
|
157
|
+
*/
|
|
158
|
+
interface SdJwtSVGTemplateProperties {
|
|
159
|
+
/**
|
|
160
|
+
* OPTIONAL. The orientation for which the SVG template is optimized.
|
|
161
|
+
*/
|
|
162
|
+
orientation?: string;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* OPTIONAL. The color scheme for which the SVG template is optimized.
|
|
166
|
+
*/
|
|
167
|
+
color_scheme?: string;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
// Helper function to fetch API with error handling
|
|
172
|
+
async function fetchUrlWithErrorHandling(url: string): Promise<Response> {
|
|
173
|
+
const response = await fetch(url)
|
|
174
|
+
if (!response.ok) {
|
|
175
|
+
throw new Error(`${response.status}: ${response.statusText}`)
|
|
176
|
+
}
|
|
177
|
+
return response
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export type SdJwtTypeHasher = (input: any, alg?: string) => string
|
|
181
|
+
|
|
182
|
+
async function validateIntegrity(input: any, integrityValue: string, hasher: AsyncHasher, alg?: string): Promise<boolean> {
|
|
183
|
+
const hash = await hasher(input, alg ?? 'sha256')
|
|
184
|
+
return u8a.toString(hash, 'utf-8') === integrityValue
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Fetch and validate Type Metadata
|
|
188
|
+
export async function fetchSdJwtTypeMetadataFromVctUrl(vct: string, opts?: { hasher?: AsyncHasher, integrity?: string }): Promise<SdJwtTypeMetadata> {
|
|
189
|
+
const url = new URL(vct)
|
|
190
|
+
const wellKnownUrl = `${url.origin}/.well-known/vct${url.pathname}`
|
|
191
|
+
|
|
192
|
+
const response = await fetchUrlWithErrorHandling(wellKnownUrl)
|
|
193
|
+
const metadata: SdJwtTypeMetadata = await response.json()
|
|
194
|
+
assertValidTypeMetadata(metadata, vct)
|
|
195
|
+
if (opts?.integrity && opts.hasher) {
|
|
196
|
+
if (!await validateIntegrity(metadata, opts.integrity, opts.hasher)) {
|
|
197
|
+
throw new Error('Integrity check failed')
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return metadata
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function assertValidTypeMetadata(metadata: SdJwtTypeMetadata, vct: string): void {
|
|
204
|
+
if (metadata.vct !== vct) {
|
|
205
|
+
throw new Error('VCT mismatch in metadata and credential')
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
/*
|
|
211
|
+
// Example usage
|
|
212
|
+
try {
|
|
213
|
+
const vct = 'https://betelgeuse.example.com/education_credential'
|
|
214
|
+
const typeMetadata = await fetchSdJwtTypeMetadataFromVctUrl(vct)
|
|
215
|
+
console.log('Type Metadata retrieved successfully:', typeMetadata)
|
|
216
|
+
} catch (error) {
|
|
217
|
+
console.error('Error fetching type metadata:', error.message)
|
|
218
|
+
}
|
|
219
|
+
*/
|
|
220
|
+
|