@digitalbazaar/vc 6.3.0 → 7.0.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/lib/contexts/index.js +6 -8
- package/lib/helpers.js +103 -0
- package/lib/index.js +221 -77
- package/package.json +23 -21
package/lib/contexts/index.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Copyright (c) 2019-
|
|
2
|
+
* Copyright (c) 2019-2024 Digital Bazaar, Inc. All rights reserved.
|
|
3
3
|
*/
|
|
4
4
|
import {
|
|
5
|
-
contexts as
|
|
6
|
-
} from 'credentials-context';
|
|
5
|
+
contexts as credentialsContexts
|
|
6
|
+
} from '@digitalbazaar/credentials-context';
|
|
7
7
|
|
|
8
|
-
export const contexts = new Map(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
contexts.set(url, context);
|
|
12
|
-
}
|
|
8
|
+
export const contexts = new Map([
|
|
9
|
+
...credentialsContexts
|
|
10
|
+
]);
|
package/lib/helpers.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2023 Digital Bazaar, Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
import {named as vcNamedContexts} from '@digitalbazaar/credentials-context';
|
|
5
|
+
|
|
6
|
+
// Z and T must be uppercase
|
|
7
|
+
// xml schema date time RegExp
|
|
8
|
+
// @see https://www.w3.org/TR/xmlschema11-2/#dateTime
|
|
9
|
+
export const dateRegex = new RegExp(
|
|
10
|
+
'-?([1-9][0-9]{3,}|0[0-9]{3})' +
|
|
11
|
+
'-(0[1-9]|1[0-2])' +
|
|
12
|
+
'-(0[1-9]|[12][0-9]|3[01])' +
|
|
13
|
+
'T(([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](\.[0-9]+)?|(24:00:00(\.0+)?))' +
|
|
14
|
+
'(Z|(\\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?');
|
|
15
|
+
|
|
16
|
+
const CREDENTIALS_CONTEXT_V1_URL = vcNamedContexts.get('v1').id;
|
|
17
|
+
const CREDENTIALS_CONTEXT_V2_URL = vcNamedContexts.get('v2').id;
|
|
18
|
+
|
|
19
|
+
// mappings between credentials contexts and version numbers
|
|
20
|
+
const credentialsContextUrlToVersion = new Map([
|
|
21
|
+
[CREDENTIALS_CONTEXT_V1_URL, 1.0],
|
|
22
|
+
[CREDENTIALS_CONTEXT_V2_URL, 2.0]
|
|
23
|
+
]);
|
|
24
|
+
const credentialsVersionToContextUrl = new Map([
|
|
25
|
+
[1.0, CREDENTIALS_CONTEXT_V1_URL],
|
|
26
|
+
[2.0, CREDENTIALS_CONTEXT_V2_URL]
|
|
27
|
+
]);
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Asserts that a context array's first item is a credentials context.
|
|
31
|
+
*
|
|
32
|
+
* @param {object} options - Options.
|
|
33
|
+
* @param {Array} options.context - An array of contexts.
|
|
34
|
+
*
|
|
35
|
+
* @throws {Error} - Throws if the first context
|
|
36
|
+
* is not a credentials context.
|
|
37
|
+
*
|
|
38
|
+
* @returns {undefined}
|
|
39
|
+
*/
|
|
40
|
+
export function assertCredentialContext({context}) {
|
|
41
|
+
// ensure first context is credentials context url
|
|
42
|
+
if(!credentialsContextUrlToVersion.has(context[0])) {
|
|
43
|
+
// throw if the first context is not a credentials context
|
|
44
|
+
throw new Error(
|
|
45
|
+
`"${CREDENTIALS_CONTEXT_V1_URL}" or "${CREDENTIALS_CONTEXT_V2_URL}"` +
|
|
46
|
+
' needs to be first in the list of contexts.');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Throws if a Date is not in the correct format.
|
|
52
|
+
*
|
|
53
|
+
* @param {object} options - Options.
|
|
54
|
+
* @param {object} options.credential - A VC.
|
|
55
|
+
* @param {string} options.prop - A prop in the object.
|
|
56
|
+
*
|
|
57
|
+
* @throws {Error} Throws if the date is not a proper date string.
|
|
58
|
+
* @returns {undefined}
|
|
59
|
+
*/
|
|
60
|
+
export function assertDateString({credential, prop}) {
|
|
61
|
+
const value = credential[prop];
|
|
62
|
+
if(!dateRegex.test(value)) {
|
|
63
|
+
throw new Error(`"${prop}" must be a valid date: ${value}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Turns the first context in a VC into a numbered version.
|
|
69
|
+
*
|
|
70
|
+
* @param {object} options - Options.
|
|
71
|
+
* @param {object} options.credential - A VC.
|
|
72
|
+
*
|
|
73
|
+
* @returns {number} A number representing the version.
|
|
74
|
+
*/
|
|
75
|
+
function getContextVersion({credential} = {}) {
|
|
76
|
+
const firstContext = credential?.['@context']?.[0];
|
|
77
|
+
return credentialsContextUrlToVersion.get(firstContext);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Turns the first context in a VC into a numbered version.
|
|
82
|
+
*
|
|
83
|
+
* @param {object} options - Options.
|
|
84
|
+
* @param {number} options.version - A credentials context version.
|
|
85
|
+
*
|
|
86
|
+
* @returns {number} A number representing the version.
|
|
87
|
+
*/
|
|
88
|
+
export function getContextForVersion({version}) {
|
|
89
|
+
return credentialsVersionToContextUrl.get(version);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Checks if a VC is using a specific context version.
|
|
94
|
+
*
|
|
95
|
+
* @param {object} options - Options.
|
|
96
|
+
* @param {object} options.credential - A VC.
|
|
97
|
+
* @param {number} options.version - A VC Context version
|
|
98
|
+
*
|
|
99
|
+
* @returns {boolean} If the first context matches the version.
|
|
100
|
+
*/
|
|
101
|
+
export function checkContextVersion({credential, version}) {
|
|
102
|
+
return getContextVersion({credential}) === version;
|
|
103
|
+
}
|
package/lib/index.js
CHANGED
|
@@ -34,27 +34,22 @@
|
|
|
34
34
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
35
35
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
36
36
|
*/
|
|
37
|
+
import {
|
|
38
|
+
assertCredentialContext,
|
|
39
|
+
assertDateString,
|
|
40
|
+
checkContextVersion,
|
|
41
|
+
getContextForVersion
|
|
42
|
+
} from './helpers.js';
|
|
37
43
|
import {documentLoader as _documentLoader} from './documentLoader.js';
|
|
38
44
|
import {CredentialIssuancePurpose} from './CredentialIssuancePurpose.js';
|
|
39
45
|
import jsigs from 'jsonld-signatures';
|
|
40
46
|
import jsonld from 'jsonld';
|
|
41
|
-
export const defaultDocumentLoader =
|
|
42
|
-
jsigs.extendContextLoader(_documentLoader);
|
|
43
|
-
import * as credentialsContext from 'credentials-context';
|
|
44
47
|
|
|
45
48
|
const {AssertionProofPurpose, AuthenticationProofPurpose} = jsigs.purposes;
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
export {dateRegex} from './helpers.js';
|
|
50
|
+
export const defaultDocumentLoader = jsigs.extendContextLoader(_documentLoader);
|
|
48
51
|
export {CredentialIssuancePurpose};
|
|
49
52
|
|
|
50
|
-
// Z and T can be lowercase
|
|
51
|
-
// RFC3339 regex
|
|
52
|
-
export const dateRegex = new RegExp('^(\\d{4})-(0[1-9]|1[0-2])-' +
|
|
53
|
-
'(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):' +
|
|
54
|
-
'([0-5][0-9]):([0-5][0-9]|60)' +
|
|
55
|
-
'(\\.[0-9]+)?(Z|(\\+|-)([01][0-9]|2[0-3]):' +
|
|
56
|
-
'([0-5][0-9]))$', 'i');
|
|
57
|
-
|
|
58
53
|
/**
|
|
59
54
|
* @typedef {object} LinkedDataSignature
|
|
60
55
|
*/
|
|
@@ -131,9 +126,10 @@ export async function issue({
|
|
|
131
126
|
if(!credential) {
|
|
132
127
|
throw new TypeError('"credential" parameter is required for issuing.');
|
|
133
128
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
129
|
+
if(checkContextVersion({
|
|
130
|
+
credential,
|
|
131
|
+
version: 1.0
|
|
132
|
+
}) && !credential.issuanceDate) {
|
|
137
133
|
const now = (new Date()).toJSON();
|
|
138
134
|
credential.issuanceDate = `${now.slice(0, now.length - 5)}Z`;
|
|
139
135
|
}
|
|
@@ -343,7 +339,6 @@ async function _verifyCredential(options = {}) {
|
|
|
343
339
|
result.verified = false;
|
|
344
340
|
}
|
|
345
341
|
}
|
|
346
|
-
|
|
347
342
|
return result;
|
|
348
343
|
}
|
|
349
344
|
|
|
@@ -357,6 +352,7 @@ async function _verifyCredential(options = {}) {
|
|
|
357
352
|
* @param {string} [options.holder] - Optional presentation holder url.
|
|
358
353
|
* @param {string|Date} [options.now] - A string representing date time in
|
|
359
354
|
* ISO 8601 format or an instance of Date. Defaults to current date time.
|
|
355
|
+
* @param {number} [options.version = 2.0] - The VC context version to use.
|
|
360
356
|
*
|
|
361
357
|
* @throws {TypeError} If verifiableCredential param is missing.
|
|
362
358
|
* @throws {Error} If the credential (or the presentation params) are missing
|
|
@@ -366,10 +362,11 @@ async function _verifyCredential(options = {}) {
|
|
|
366
362
|
* VerifiablePresentation.
|
|
367
363
|
*/
|
|
368
364
|
export function createPresentation({
|
|
369
|
-
verifiableCredential, id, holder, now
|
|
365
|
+
verifiableCredential, id, holder, now, version = 2.0
|
|
370
366
|
} = {}) {
|
|
367
|
+
const initialContext = getContextForVersion({version});
|
|
371
368
|
const presentation = {
|
|
372
|
-
'@context': [
|
|
369
|
+
'@context': [initialContext],
|
|
373
370
|
type: ['VerifiablePresentation']
|
|
374
371
|
};
|
|
375
372
|
if(verifiableCredential) {
|
|
@@ -548,13 +545,7 @@ export function _checkPresentation(presentation) {
|
|
|
548
545
|
// normalize to an array to allow the common case of context being a string
|
|
549
546
|
const context = Array.isArray(presentation['@context']) ?
|
|
550
547
|
presentation['@context'] : [presentation['@context']];
|
|
551
|
-
|
|
552
|
-
// ensure first context is 'https://www.w3.org/2018/credentials/v1'
|
|
553
|
-
if(context[0] !== CREDENTIALS_CONTEXT_V1_URL) {
|
|
554
|
-
throw new Error(
|
|
555
|
-
`"${CREDENTIALS_CONTEXT_V1_URL}" needs to be first in the ` +
|
|
556
|
-
'list of contexts.');
|
|
557
|
-
}
|
|
548
|
+
assertCredentialContext({context});
|
|
558
549
|
|
|
559
550
|
const types = jsonld.getValues(presentation, 'type');
|
|
560
551
|
|
|
@@ -564,6 +555,15 @@ export function _checkPresentation(presentation) {
|
|
|
564
555
|
}
|
|
565
556
|
}
|
|
566
557
|
|
|
558
|
+
// these props of a VC must be an object with a type
|
|
559
|
+
// if present in a VC or VP
|
|
560
|
+
const mustHaveType = [
|
|
561
|
+
'proof',
|
|
562
|
+
'credentialStatus',
|
|
563
|
+
'termsOfUse',
|
|
564
|
+
'evidence'
|
|
565
|
+
];
|
|
566
|
+
|
|
567
567
|
// export for testing
|
|
568
568
|
/**
|
|
569
569
|
* @param {object} options - The options.
|
|
@@ -583,12 +583,7 @@ export function _checkCredential({
|
|
|
583
583
|
if(typeof now === 'string') {
|
|
584
584
|
now = new Date(now);
|
|
585
585
|
}
|
|
586
|
-
|
|
587
|
-
if(credential['@context'][0] !== CREDENTIALS_CONTEXT_V1_URL) {
|
|
588
|
-
throw new Error(
|
|
589
|
-
`"${CREDENTIALS_CONTEXT_V1_URL}" needs to be first in the ` +
|
|
590
|
-
'list of contexts.');
|
|
591
|
-
}
|
|
586
|
+
assertCredentialContext({context: credential['@context']});
|
|
592
587
|
|
|
593
588
|
// check type presence and cardinality
|
|
594
589
|
if(!credential.type) {
|
|
@@ -599,47 +594,71 @@ export function _checkCredential({
|
|
|
599
594
|
throw new Error('"type" must include `VerifiableCredential`.');
|
|
600
595
|
}
|
|
601
596
|
|
|
602
|
-
|
|
603
|
-
throw new Error('"credentialSubject" property is required.');
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
// If credentialSubject.id is present and is not a URI, reject it
|
|
607
|
-
if(credential.credentialSubject.id) {
|
|
608
|
-
_validateUriId({
|
|
609
|
-
id: credential.credentialSubject.id, propertyName: 'credentialSubject.id'
|
|
610
|
-
});
|
|
611
|
-
}
|
|
597
|
+
_checkCredentialSubjects({credential});
|
|
612
598
|
|
|
613
599
|
if(!credential.issuer) {
|
|
614
600
|
throw new Error('"issuer" property is required.');
|
|
615
601
|
}
|
|
602
|
+
if(checkContextVersion({credential, version: 1.0})) {
|
|
603
|
+
// check issuanceDate exists
|
|
604
|
+
if(!credential.issuanceDate) {
|
|
605
|
+
throw new Error('"issuanceDate" property is required.');
|
|
606
|
+
}
|
|
607
|
+
// check issuanceDate format on issue
|
|
608
|
+
assertDateString({credential, prop: 'issuanceDate'});
|
|
616
609
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
610
|
+
// check issuanceDate cardinality
|
|
611
|
+
if(jsonld.getValues(credential, 'issuanceDate').length > 1) {
|
|
612
|
+
throw new Error('"issuanceDate" property can only have one value.');
|
|
613
|
+
}
|
|
614
|
+
// optionally check expirationDate
|
|
615
|
+
if('expirationDate' in credential) {
|
|
616
|
+
// check if `expirationDate` property is a date
|
|
617
|
+
assertDateString({credential, prop: 'expirationDate'});
|
|
618
|
+
if(mode === 'verify') {
|
|
619
|
+
// check if `now` is after `expirationDate`
|
|
620
|
+
if(now > new Date(credential.expirationDate)) {
|
|
621
|
+
throw new Error('Credential has expired.');
|
|
622
|
+
}
|
|
623
|
+
}
|
|
631
624
|
}
|
|
632
625
|
// check if `now` is before `issuanceDate` on verification
|
|
633
626
|
if(mode === 'verify') {
|
|
634
|
-
issuanceDate = new Date(issuanceDate);
|
|
627
|
+
const issuanceDate = new Date(credential.issuanceDate);
|
|
635
628
|
if(now < issuanceDate) {
|
|
636
629
|
throw new Error(
|
|
637
630
|
`The current date time (${now.toISOString()}) is before the ` +
|
|
638
|
-
`"issuanceDate" (${issuanceDate
|
|
631
|
+
`"issuanceDate" (${credential.issuanceDate}).`);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
if(checkContextVersion({credential, version: 2.0})) {
|
|
636
|
+
// check if 'validUntil' and 'validFrom'
|
|
637
|
+
let {validUntil, validFrom} = credential;
|
|
638
|
+
if(validUntil) {
|
|
639
|
+
assertDateString({credential, prop: 'validUntil'});
|
|
640
|
+
if(mode === 'verify') {
|
|
641
|
+
validUntil = new Date(credential.validUntil);
|
|
642
|
+
if(now > validUntil) {
|
|
643
|
+
throw new Error(
|
|
644
|
+
`The current date time (${now.toISOString()}) is after ` +
|
|
645
|
+
`"validUntil" (${credential.validUntil}).`);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
if(validFrom) {
|
|
650
|
+
assertDateString({credential, prop: 'validFrom'});
|
|
651
|
+
if(mode === 'verify') {
|
|
652
|
+
// check if `now` is before `validFrom`
|
|
653
|
+
validFrom = new Date(credential.validFrom);
|
|
654
|
+
if(now < validFrom) {
|
|
655
|
+
throw new Error(
|
|
656
|
+
`The current date time (${now.toISOString()}) is before ` +
|
|
657
|
+
`"validFrom" (${credential.validFrom}).`);
|
|
658
|
+
}
|
|
639
659
|
}
|
|
640
660
|
}
|
|
641
661
|
}
|
|
642
|
-
|
|
643
662
|
// check issuer cardinality
|
|
644
663
|
if(jsonld.getValues(credential, 'issuer').length > 1) {
|
|
645
664
|
throw new Error('"issuer" property can only have one value.');
|
|
@@ -654,17 +673,18 @@ export function _checkCredential({
|
|
|
654
673
|
_validateUriId({id: issuer, propertyName: 'issuer'});
|
|
655
674
|
}
|
|
656
675
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
if
|
|
660
|
-
|
|
661
|
-
|
|
676
|
+
// check credentialStatus
|
|
677
|
+
jsonld.getValues(credential, 'credentialStatus').forEach(cs => {
|
|
678
|
+
// check if optional "id" is a URL
|
|
679
|
+
if('id' in cs) {
|
|
680
|
+
_validateUriId({id: cs.id, propertyName: 'credentialStatus.id'});
|
|
662
681
|
}
|
|
663
|
-
|
|
664
|
-
|
|
682
|
+
|
|
683
|
+
// check "type" present
|
|
684
|
+
if(!cs.type) {
|
|
665
685
|
throw new Error('"credentialStatus" must include a type.');
|
|
666
686
|
}
|
|
667
|
-
}
|
|
687
|
+
});
|
|
668
688
|
|
|
669
689
|
// check evidences are URLs
|
|
670
690
|
jsonld.getValues(credential, 'evidence').forEach(evidence => {
|
|
@@ -674,20 +694,144 @@ export function _checkCredential({
|
|
|
674
694
|
}
|
|
675
695
|
});
|
|
676
696
|
|
|
677
|
-
if
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
if(
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
697
|
+
// check if properties that require a type are
|
|
698
|
+
// defined, objects, and objects with types
|
|
699
|
+
for(const prop of mustHaveType) {
|
|
700
|
+
if(prop in credential) {
|
|
701
|
+
const _value = credential[prop];
|
|
702
|
+
if(Array.isArray(_value)) {
|
|
703
|
+
_value.forEach(entry => _checkTypedObject(entry, prop));
|
|
704
|
+
continue;
|
|
705
|
+
}
|
|
706
|
+
_checkTypedObject(_value, prop);
|
|
687
707
|
}
|
|
688
708
|
}
|
|
689
709
|
}
|
|
690
710
|
|
|
711
|
+
/**
|
|
712
|
+
* @private
|
|
713
|
+
* Checks that a property is non-empty object with
|
|
714
|
+
* property type.
|
|
715
|
+
*
|
|
716
|
+
* @param {object} obj - A potential object.
|
|
717
|
+
* @param {string} name - The name of the property.
|
|
718
|
+
*
|
|
719
|
+
* @throws {Error} if the property is not an object with a type.
|
|
720
|
+
*
|
|
721
|
+
* @returns {undefined} - Returns on success.
|
|
722
|
+
*/
|
|
723
|
+
function _checkTypedObject(obj, name) {
|
|
724
|
+
if(!isObject(obj)) {
|
|
725
|
+
throw new Error(`property "${name}" must be an object.`);
|
|
726
|
+
}
|
|
727
|
+
if(_emptyObject(obj)) {
|
|
728
|
+
throw new Error(`property "${name}" can not be an empty object.`);
|
|
729
|
+
}
|
|
730
|
+
if(!('type' in obj)) {
|
|
731
|
+
throw new Error(`property "${name}" must have property type.`);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* @private
|
|
737
|
+
* Takes in a credential and checks the credentialSubject(s)
|
|
738
|
+
*
|
|
739
|
+
* @param {object} options - Options.
|
|
740
|
+
* @param {object} options.credential - The credential to check.
|
|
741
|
+
*
|
|
742
|
+
* @throws {Error} error - Throws on errors in the credential subject.
|
|
743
|
+
*
|
|
744
|
+
* @returns {undefined} - Returns on success.
|
|
745
|
+
*/
|
|
746
|
+
function _checkCredentialSubjects({credential}) {
|
|
747
|
+
if(!credential?.credentialSubject) {
|
|
748
|
+
throw new Error('"credentialSubject" property is required.');
|
|
749
|
+
}
|
|
750
|
+
if(Array.isArray(credential?.credentialSubject)) {
|
|
751
|
+
return credential?.credentialSubject.map(
|
|
752
|
+
subject => _checkCredentialSubject({subject}));
|
|
753
|
+
}
|
|
754
|
+
return _checkCredentialSubject({subject: credential?.credentialSubject});
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
/**
|
|
758
|
+
* @private
|
|
759
|
+
*
|
|
760
|
+
* Checks a credential subject is valid.
|
|
761
|
+
*
|
|
762
|
+
* @param {object} options - Options.
|
|
763
|
+
* @param {object} options.subject - A potential credential subject.
|
|
764
|
+
*
|
|
765
|
+
* @throws {Error} If the credentialSubject is not valid.
|
|
766
|
+
*
|
|
767
|
+
* @returns {undefined} Returns on success.
|
|
768
|
+
*/
|
|
769
|
+
function _checkCredentialSubject({subject}) {
|
|
770
|
+
if(isObject(subject) === false) {
|
|
771
|
+
throw new Error('"credentialSubject" must be a non-null object.');
|
|
772
|
+
}
|
|
773
|
+
if(_emptyObject(subject)) {
|
|
774
|
+
throw new Error('"credentialSubject" must make a claim.');
|
|
775
|
+
}
|
|
776
|
+
// If credentialSubject.id is present and is not a URI, reject it
|
|
777
|
+
if(subject.id) {
|
|
778
|
+
_validateUriId({
|
|
779
|
+
id: subject.id, propertyName: 'credentialSubject.id'
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
/**
|
|
785
|
+
* @private
|
|
786
|
+
* Checks if parameter is an object.
|
|
787
|
+
*
|
|
788
|
+
* @param {object} obj - A potential object.
|
|
789
|
+
*
|
|
790
|
+
* @returns {boolean} - Returns false if not an object or null.
|
|
791
|
+
*/
|
|
792
|
+
function isObject(obj) {
|
|
793
|
+
// return false for null even though it has type object
|
|
794
|
+
if(obj === null) {
|
|
795
|
+
return false;
|
|
796
|
+
}
|
|
797
|
+
// if something has type object and is not null return true
|
|
798
|
+
if((typeof obj) === 'object') {
|
|
799
|
+
return true;
|
|
800
|
+
}
|
|
801
|
+
// return false for strings, symbols, etc.
|
|
802
|
+
return false;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* @private
|
|
807
|
+
* Is it an empty object?
|
|
808
|
+
*
|
|
809
|
+
* @param {object} obj - A potential object.
|
|
810
|
+
*
|
|
811
|
+
* @returns {boolean} - Is it empty?
|
|
812
|
+
*/
|
|
813
|
+
function _emptyObject(obj) {
|
|
814
|
+
// if the parameter is not an object return true
|
|
815
|
+
// as a non-object is an empty object
|
|
816
|
+
if(!isObject(obj)) {
|
|
817
|
+
return true;
|
|
818
|
+
}
|
|
819
|
+
return Object.keys(obj).length === 0;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
/**
|
|
823
|
+
* @private
|
|
824
|
+
*
|
|
825
|
+
* Validates if an ID is a URL.
|
|
826
|
+
*
|
|
827
|
+
* @param {object} options - Options.
|
|
828
|
+
* @param {string} options.id - the id.
|
|
829
|
+
* @param {string} options.propertyName - The property name.
|
|
830
|
+
*
|
|
831
|
+
* @throws {Error} Throws if an id is not a URL.
|
|
832
|
+
*
|
|
833
|
+
* @returns {undefined} Returns on success.
|
|
834
|
+
*/
|
|
691
835
|
function _validateUriId({id, propertyName}) {
|
|
692
836
|
let parsed;
|
|
693
837
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@digitalbazaar/vc",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"description": "Verifiable Credentials JavaScript library.",
|
|
5
5
|
"homepage": "https://github.com/digitalbazaar/vc",
|
|
6
6
|
"author": {
|
|
@@ -28,43 +28,45 @@
|
|
|
28
28
|
"lib/**/*.js"
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"credentials-context": "^
|
|
31
|
+
"@digitalbazaar/credentials-context": "^3.1.0",
|
|
32
|
+
"ed25519-signature-2018-context": "^1.1.0",
|
|
32
33
|
"jsonld": "^8.3.1",
|
|
33
34
|
"jsonld-signatures": "^11.2.1"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
36
|
-
"@digitalbazaar/bbs-2023-cryptosuite": "^1.
|
|
37
|
-
"@digitalbazaar/bls12-381-multikey": "^1.
|
|
37
|
+
"@digitalbazaar/bbs-2023-cryptosuite": "^1.2.0",
|
|
38
|
+
"@digitalbazaar/bls12-381-multikey": "^1.3.0",
|
|
38
39
|
"@digitalbazaar/credentials-examples-context": "^1.0.0",
|
|
39
|
-
"@digitalbazaar/data-integrity": "^2.
|
|
40
|
-
"@digitalbazaar/data-integrity-context": "^2.0.
|
|
41
|
-
"@digitalbazaar/ecdsa-multikey": "^1.
|
|
42
|
-
"@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.
|
|
40
|
+
"@digitalbazaar/data-integrity": "^2.2.0",
|
|
41
|
+
"@digitalbazaar/data-integrity-context": "^2.0.1",
|
|
42
|
+
"@digitalbazaar/ecdsa-multikey": "^1.7.0",
|
|
43
|
+
"@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.2.1",
|
|
43
44
|
"@digitalbazaar/ed25519-signature-2018": "^4.0.0",
|
|
44
45
|
"@digitalbazaar/ed25519-verification-key-2018": "^4.0.0",
|
|
45
|
-
"@digitalbazaar/multikey-context": "^
|
|
46
|
+
"@digitalbazaar/multikey-context": "^2.0.1",
|
|
46
47
|
"@digitalbazaar/odrl-context": "^1.0.0",
|
|
47
|
-
"c8": "^
|
|
48
|
-
"chai": "^4.
|
|
48
|
+
"c8": "^10.1.2",
|
|
49
|
+
"chai": "^4.5.0",
|
|
49
50
|
"cross-env": "^7.0.3",
|
|
50
51
|
"did-context": "^3.1.1",
|
|
51
52
|
"did-veres-one": "^16.0.0",
|
|
52
|
-
"eslint": "^8.
|
|
53
|
-
"eslint-config-digitalbazaar": "^5.0
|
|
54
|
-
"eslint-plugin-jsdoc": "^
|
|
55
|
-
"eslint-plugin-unicorn": "^
|
|
56
|
-
"karma": "^6.4.
|
|
53
|
+
"eslint": "^8.57.0",
|
|
54
|
+
"eslint-config-digitalbazaar": "^5.2.0",
|
|
55
|
+
"eslint-plugin-jsdoc": "^48.10.2",
|
|
56
|
+
"eslint-plugin-unicorn": "^55.0.0",
|
|
57
|
+
"karma": "^6.4.4",
|
|
57
58
|
"karma-chai": "^0.1.0",
|
|
58
|
-
"karma-chrome-launcher": "^3.
|
|
59
|
+
"karma-chrome-launcher": "^3.2.0",
|
|
59
60
|
"karma-mocha": "^2.0.1",
|
|
60
61
|
"karma-mocha-reporter": "^2.2.5",
|
|
61
62
|
"karma-sourcemap-loader": "^0.4.0",
|
|
62
|
-
"karma-webpack": "^5.0.
|
|
63
|
-
"
|
|
63
|
+
"karma-webpack": "^5.0.1",
|
|
64
|
+
"klona": "^2.0.6",
|
|
65
|
+
"mocha": "^10.7.0",
|
|
64
66
|
"mocha-lcov-reporter": "^1.3.0",
|
|
65
|
-
"uuid": "^
|
|
67
|
+
"uuid": "^10.0.0",
|
|
66
68
|
"veres-one-context": "^12.0.0",
|
|
67
|
-
"webpack": "^5.
|
|
69
|
+
"webpack": "^5.93.0"
|
|
68
70
|
},
|
|
69
71
|
"c8": {
|
|
70
72
|
"reporter": [
|