@bedrock/vc-verifier 8.0.0 → 11.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/CHANGELOG.md +25 -0
- package/package.json +4 -4
- package/test/mocha/30-credential-status.js +178 -15
- package/test/mocha/helpers.js +4 -2
- package/test/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# bedrock-vc-verifier ChangeLog
|
|
2
2
|
|
|
3
|
+
## 11.0.0 - 2022-06-05
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
- **BREAKING** Use `@digitalbazaar/vc-status-list` v4.0. If `statusPurpose`
|
|
7
|
+
in credential does not match the `statusPurpose` of status list credential,
|
|
8
|
+
an error will be thrown.
|
|
9
|
+
|
|
10
|
+
## 10.0.0 - 2022-05-17
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- **BREAKING**: Use `@bedrock-service-context-store@7` to cause migration of
|
|
14
|
+
old EDV context documents to the new EDV attribute version.
|
|
15
|
+
|
|
16
|
+
## 9.0.0 - 2022-05-05
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- **BREAKING**: Update peer deps:
|
|
20
|
+
- `@bedrock/service-agent@5`
|
|
21
|
+
- `@bedrock/service-context-store@6`.
|
|
22
|
+
- **BREAKING**: The updated peer dependencies use a new EDV client with a
|
|
23
|
+
new blind attribute version. This version is incompatible with previous
|
|
24
|
+
versions and a manual migration must be performed to update all
|
|
25
|
+
EDV documents to use the new blind attribute version -- or a new
|
|
26
|
+
deployment is required.
|
|
27
|
+
|
|
3
28
|
## 8.0.0 - 2022-04-29
|
|
4
29
|
|
|
5
30
|
### Changed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bedrock/vc-verifier",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Bedrock VC Verifier",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"@digitalbazaar/ed25519-signature-2018": "^2.1.0",
|
|
25
25
|
"@digitalbazaar/ed25519-signature-2020": "^3.0.0",
|
|
26
26
|
"@digitalbazaar/vc": "^2.1.0",
|
|
27
|
-
"@digitalbazaar/vc-status-list": "^
|
|
27
|
+
"@digitalbazaar/vc-status-list": "^4.0.0",
|
|
28
28
|
"assert-plus": "^1.0.0",
|
|
29
29
|
"bnid": "^2.1.0",
|
|
30
30
|
"body-parser": "^1.19.0",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"@bedrock/jsonld-document-loader": "^3.0.0",
|
|
42
42
|
"@bedrock/mongodb": "^10.0.0",
|
|
43
43
|
"@bedrock/security-context": "^7.0.0",
|
|
44
|
-
"@bedrock/service-agent": "^
|
|
45
|
-
"@bedrock/service-context-store": "^
|
|
44
|
+
"@bedrock/service-agent": "^5.0.0",
|
|
45
|
+
"@bedrock/service-context-store": "^7.0.0",
|
|
46
46
|
"@bedrock/service-core": "^5.0.0",
|
|
47
47
|
"@bedrock/vc-status-list-context": "^4.0.0",
|
|
48
48
|
"@bedrock/vc-revocation-list-context": "^3.0.0",
|
|
@@ -39,8 +39,11 @@ const encodedList100KWith50KthRevoked =
|
|
|
39
39
|
const key = fs.readFileSync(__dirname + '/key.pem');
|
|
40
40
|
const cert = fs.readFileSync(__dirname + '/cert.pem');
|
|
41
41
|
|
|
42
|
-
let
|
|
43
|
-
let
|
|
42
|
+
let slCredentialRevocation;
|
|
43
|
+
let unsignedCredentialSl2021TypeRevocation;
|
|
44
|
+
let slCredentialSuspension;
|
|
45
|
+
let unsignedCredentialSl2021TypeSuspension;
|
|
46
|
+
let unsignedCredentialSl2021WithUnmatchingStatusPurpose;
|
|
44
47
|
let revokedSlCredential;
|
|
45
48
|
let revokedUnsignedCredential;
|
|
46
49
|
let rlCredential;
|
|
@@ -71,8 +74,8 @@ function _startServer({app}) {
|
|
|
71
74
|
testServerBaseUrl = BASE_URL;
|
|
72
75
|
console.log(`Test server listening at ${BASE_URL}`);
|
|
73
76
|
|
|
74
|
-
// Status List 2021 Credential
|
|
75
|
-
|
|
77
|
+
// Status List 2021 Credential with statusPurpose `revocation`
|
|
78
|
+
slCredentialRevocation = {
|
|
76
79
|
'@context': [
|
|
77
80
|
'https://www.w3.org/2018/credentials/v1',
|
|
78
81
|
VC_SL_CONTEXT_URL
|
|
@@ -84,12 +87,14 @@ function _startServer({app}) {
|
|
|
84
87
|
credentialSubject: {
|
|
85
88
|
id: `${BASE_URL}/status/748a7d8e-9111-11ec-a934-10bf48838a41#list`,
|
|
86
89
|
type: 'StatusList2021',
|
|
90
|
+
statusPurpose: 'revocation',
|
|
87
91
|
encodedList: encodedList100k
|
|
88
92
|
}
|
|
89
93
|
};
|
|
90
94
|
|
|
91
|
-
// Unsigned 2021 Credential
|
|
92
|
-
|
|
95
|
+
// Unsigned 2021 Credential with "credentialStatus.statusPurpose"
|
|
96
|
+
// `revocation`
|
|
97
|
+
unsignedCredentialSl2021TypeRevocation = {
|
|
93
98
|
'@context': [
|
|
94
99
|
'https://www.w3.org/2018/credentials/v1',
|
|
95
100
|
VC_SL_CONTEXT_URL,
|
|
@@ -106,13 +111,82 @@ function _startServer({app}) {
|
|
|
106
111
|
type: 'StatusList2021Entry',
|
|
107
112
|
statusPurpose: 'revocation',
|
|
108
113
|
statusListIndex: '67342',
|
|
109
|
-
statusListCredential:
|
|
114
|
+
statusListCredential: slCredentialRevocation.id
|
|
110
115
|
},
|
|
111
|
-
issuer:
|
|
116
|
+
issuer: slCredentialRevocation.issuer,
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// Status List 2021 Credential with statusPurpose `suspension`
|
|
120
|
+
slCredentialSuspension = {
|
|
121
|
+
'@context': [
|
|
122
|
+
'https://www.w3.org/2018/credentials/v1',
|
|
123
|
+
VC_SL_CONTEXT_URL
|
|
124
|
+
],
|
|
125
|
+
id: `${BASE_URL}/status/5d3e7a97-1121-11ec-9b38-10bf48838a41`,
|
|
126
|
+
issuer: 'did:key:z6Mktpn6cXks1PBKLMgZH2VaahvCtBMF6K8eCa7HzrnuYLZv',
|
|
127
|
+
issuanceDate: '2022-01-10T04:24:12.164Z',
|
|
128
|
+
type: ['VerifiableCredential', 'StatusList2021Credential'],
|
|
129
|
+
credentialSubject: {
|
|
130
|
+
id: `${BASE_URL}/status/5d3e7a97-1121-11ec-9b38-10bf48838a41#list`,
|
|
131
|
+
type: 'StatusList2021',
|
|
132
|
+
statusPurpose: 'suspension',
|
|
133
|
+
encodedList: encodedList100k
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// Unsigned 2021 Credential with "credentialStatus.statusPurpose"
|
|
138
|
+
// `suspension`
|
|
139
|
+
unsignedCredentialSl2021TypeSuspension = {
|
|
140
|
+
'@context': [
|
|
141
|
+
'https://www.w3.org/2018/credentials/v1',
|
|
142
|
+
VC_SL_CONTEXT_URL,
|
|
143
|
+
'https://w3id.org/security/suites/ed25519-2020/v1'
|
|
144
|
+
],
|
|
145
|
+
id: 'urn:uuid:a0418a78-7924-11ea-8a23-10bf48838a41',
|
|
146
|
+
type: ['VerifiableCredential', 'example:TestCredential'],
|
|
147
|
+
credentialSubject: {
|
|
148
|
+
id: 'urn:uuid:4886029a-7925-11ea-9274-10bf48838a41',
|
|
149
|
+
'example:test': 'foo'
|
|
150
|
+
},
|
|
151
|
+
credentialStatus: {
|
|
152
|
+
id: `${BASE_URL}/status/5d3e7a97-1121-11ec-9b38-10bf48838a41#67342`,
|
|
153
|
+
type: 'StatusList2021Entry',
|
|
154
|
+
statusPurpose: 'suspension',
|
|
155
|
+
statusListIndex: '67342',
|
|
156
|
+
statusListCredential: slCredentialSuspension.id
|
|
157
|
+
},
|
|
158
|
+
issuer: slCredentialSuspension.issuer,
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// Unsigned 2021 Credential with unmatching status purpose
|
|
162
|
+
unsignedCredentialSl2021WithUnmatchingStatusPurpose = {
|
|
163
|
+
'@context': [
|
|
164
|
+
'https://www.w3.org/2018/credentials/v1',
|
|
165
|
+
VC_SL_CONTEXT_URL,
|
|
166
|
+
'https://w3id.org/security/suites/ed25519-2020/v1'
|
|
167
|
+
],
|
|
168
|
+
id: 'urn:uuid:a0418a78-7924-11ea-8a23-10bf48838a41',
|
|
169
|
+
type: ['VerifiableCredential', 'example:TestCredential'],
|
|
170
|
+
credentialSubject: {
|
|
171
|
+
id: 'urn:uuid:4886029a-7925-11ea-9274-10bf48838a41',
|
|
172
|
+
'example:test': 'foo'
|
|
173
|
+
},
|
|
174
|
+
credentialStatus: {
|
|
175
|
+
id: `${BASE_URL}/status/748a7d8e-9111-11ec-a934-10bf48838a41#67342`,
|
|
176
|
+
type: 'StatusList2021Entry',
|
|
177
|
+
// intentionally set status purpose that does not match status purpose
|
|
178
|
+
// of sl credential that it fetches.
|
|
179
|
+
statusPurpose: 'suspension',
|
|
180
|
+
statusListIndex: '67342',
|
|
181
|
+
// intentionally point `statusListCredential` to a sl credential
|
|
182
|
+
// with status purpose `revocation`.
|
|
183
|
+
statusListCredential: slCredentialRevocation.id
|
|
184
|
+
},
|
|
185
|
+
issuer: slCredentialRevocation.issuer,
|
|
112
186
|
};
|
|
113
187
|
|
|
114
188
|
// Revoked Status List 2021 Credential
|
|
115
|
-
revokedSlCredential = klona(
|
|
189
|
+
revokedSlCredential = klona(slCredentialRevocation);
|
|
116
190
|
|
|
117
191
|
revokedSlCredential.id =
|
|
118
192
|
`${BASE_URL}/status/8ec30054-9111-11ec-9ab5-10bf48838a41`,
|
|
@@ -122,7 +196,7 @@ function _startServer({app}) {
|
|
|
122
196
|
`${BASE_URL}/status/8ec30054-9111-11ec-9ab5-10bf48838a41#list`;
|
|
123
197
|
|
|
124
198
|
// Revoked Unsigned 2021 Credential
|
|
125
|
-
revokedUnsignedCredential = klona(
|
|
199
|
+
revokedUnsignedCredential = klona(unsignedCredentialSl2021TypeRevocation);
|
|
126
200
|
revokedUnsignedCredential.credentialStatus.id =
|
|
127
201
|
`${revokedSlCredential.id}#50000`;
|
|
128
202
|
revokedUnsignedCredential.credentialStatus.statusListIndex = 50000;
|
|
@@ -202,7 +276,13 @@ app.get('/status/748a7d8e-9111-11ec-a934-10bf48838a41',
|
|
|
202
276
|
// eslint-disable-next-line no-unused-vars
|
|
203
277
|
(req, res, next) => {
|
|
204
278
|
// responds with a valid status list 2021 type credential
|
|
205
|
-
res.json(
|
|
279
|
+
res.json(slCredentialRevocation);
|
|
280
|
+
});
|
|
281
|
+
app.get('/status/5d3e7a97-1121-11ec-9b38-10bf48838a41',
|
|
282
|
+
// eslint-disable-next-line no-unused-vars
|
|
283
|
+
(req, res, next) => {
|
|
284
|
+
// responds with a valid status list 2021 type credential
|
|
285
|
+
res.json(slCredentialSuspension);
|
|
206
286
|
});
|
|
207
287
|
app.get('/status/8ec30054-9111-11ec-9ab5-10bf48838a41',
|
|
208
288
|
// eslint-disable-next-line no-unused-vars
|
|
@@ -301,14 +381,60 @@ describe('verify credential status', () => {
|
|
|
301
381
|
verifierId = verifierConfig.id;
|
|
302
382
|
rootZcap = `urn:zcap:root:${encodeURIComponent(verifierId)}`;
|
|
303
383
|
});
|
|
304
|
-
it('should verify "StatusList2021Credential" type
|
|
305
|
-
|
|
306
|
-
|
|
384
|
+
it('should verify "StatusList2021Credential" type with "statusPurpose" ' +
|
|
385
|
+
'revocation', async () => {
|
|
386
|
+
slCredentialRevocation = await vc.issue({
|
|
387
|
+
credential: slCredentialRevocation,
|
|
388
|
+
documentLoader: _documentLoader,
|
|
389
|
+
suite
|
|
390
|
+
});
|
|
391
|
+
const verifiableCredential = await vc.issue({
|
|
392
|
+
credential: unsignedCredentialSl2021TypeRevocation,
|
|
393
|
+
documentLoader: _documentLoader,
|
|
394
|
+
suite
|
|
395
|
+
});
|
|
396
|
+
let error;
|
|
397
|
+
let result;
|
|
398
|
+
try {
|
|
399
|
+
const zcapClient = helpers.createZcapClient({capabilityAgent});
|
|
400
|
+
result = await zcapClient.write({
|
|
401
|
+
url: `${verifierId}/credentials/verify`,
|
|
402
|
+
capability: rootZcap,
|
|
403
|
+
json: {
|
|
404
|
+
options: {
|
|
405
|
+
checks: ['proof', 'credentialStatus'],
|
|
406
|
+
},
|
|
407
|
+
verifiableCredential
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
} catch(e) {
|
|
411
|
+
error = e;
|
|
412
|
+
}
|
|
413
|
+
assertNoError(error);
|
|
414
|
+
should.exist(result.data.verified);
|
|
415
|
+
result.data.verified.should.be.a('boolean');
|
|
416
|
+
result.data.verified.should.equal(true);
|
|
417
|
+
const {checks} = result.data;
|
|
418
|
+
checks.should.be.an('array');
|
|
419
|
+
checks.should.have.length(2);
|
|
420
|
+
checks.should.be.an('array');
|
|
421
|
+
checks.should.eql(['proof', 'credentialStatus']);
|
|
422
|
+
should.exist(result.data.results);
|
|
423
|
+
result.data.results.should.be.an('array');
|
|
424
|
+
result.data.results.should.have.length(1);
|
|
425
|
+
const [r] = result.data.results;
|
|
426
|
+
r.verified.should.be.a('boolean');
|
|
427
|
+
r.verified.should.equal(true);
|
|
428
|
+
});
|
|
429
|
+
it('should verify "StatusList2021Credential" type with "statusPurpose" ' +
|
|
430
|
+
'suspension', async () => {
|
|
431
|
+
slCredentialSuspension = await vc.issue({
|
|
432
|
+
credential: slCredentialSuspension,
|
|
307
433
|
documentLoader: _documentLoader,
|
|
308
434
|
suite
|
|
309
435
|
});
|
|
310
436
|
const verifiableCredential = await vc.issue({
|
|
311
|
-
credential:
|
|
437
|
+
credential: unsignedCredentialSl2021TypeSuspension,
|
|
312
438
|
documentLoader: _documentLoader,
|
|
313
439
|
suite
|
|
314
440
|
});
|
|
@@ -345,6 +471,43 @@ describe('verify credential status', () => {
|
|
|
345
471
|
r.verified.should.be.a('boolean');
|
|
346
472
|
r.verified.should.equal(true);
|
|
347
473
|
});
|
|
474
|
+
it('should throw error if "statusPurpose" of the slCredential does not ' +
|
|
475
|
+
'match the "statusPurpose" of the credentialStatus', async () => {
|
|
476
|
+
slCredentialRevocation = await vc.issue({
|
|
477
|
+
credential: slCredentialRevocation,
|
|
478
|
+
documentLoader: _documentLoader,
|
|
479
|
+
suite
|
|
480
|
+
});
|
|
481
|
+
const verifiableCredential = await vc.issue({
|
|
482
|
+
credential: unsignedCredentialSl2021WithUnmatchingStatusPurpose,
|
|
483
|
+
documentLoader: _documentLoader,
|
|
484
|
+
suite
|
|
485
|
+
});
|
|
486
|
+
let error;
|
|
487
|
+
let result;
|
|
488
|
+
try {
|
|
489
|
+
const zcapClient = helpers.createZcapClient({capabilityAgent});
|
|
490
|
+
result = await zcapClient.write({
|
|
491
|
+
url: `${verifierId}/credentials/verify`,
|
|
492
|
+
capability: rootZcap,
|
|
493
|
+
json: {
|
|
494
|
+
options: {
|
|
495
|
+
checks: ['proof', 'credentialStatus'],
|
|
496
|
+
},
|
|
497
|
+
verifiableCredential
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
} catch(e) {
|
|
501
|
+
error = e;
|
|
502
|
+
}
|
|
503
|
+
should.exist(error);
|
|
504
|
+
should.not.exist(result);
|
|
505
|
+
error.data.verified.should.equal(false);
|
|
506
|
+
const {error: {cause: errorCause}} = error.data;
|
|
507
|
+
errorCause.should.equal(
|
|
508
|
+
'The status purpose "revocation" of the status list credential ' +
|
|
509
|
+
'does not match the status purpose "suspension" in the credential.');
|
|
510
|
+
});
|
|
348
511
|
it('should fail to verify a revoked "StatusList2021Credential" type',
|
|
349
512
|
async () => {
|
|
350
513
|
revokedSlCredential = await vc.issue({
|
package/test/mocha/helpers.js
CHANGED
|
@@ -7,16 +7,18 @@ import {createRequire} from 'module';
|
|
|
7
7
|
import {didIo} from '@bedrock/did-io';
|
|
8
8
|
import {getAppIdentity} from '@bedrock/app-identity';
|
|
9
9
|
import {mockData} from './mock.data.js';
|
|
10
|
+
import {httpClient} from '@digitalbazaar/http-client';
|
|
10
11
|
const require = createRequire(import.meta.url);
|
|
11
12
|
const {Ed25519Signature2020} = require('@digitalbazaar/ed25519-signature-2020');
|
|
12
13
|
const {EdvClient} = require('@digitalbazaar/edv-client');
|
|
13
|
-
const {httpClient} = require('@digitalbazaar/http-client');
|
|
14
14
|
const {KeystoreAgent, KmsClient} = require('@digitalbazaar/webkms-client');
|
|
15
15
|
const {ZcapClient} = require('@digitalbazaar/ezcap');
|
|
16
16
|
|
|
17
17
|
const edvBaseUrl = `${mockData.baseUrl}/edvs`;
|
|
18
18
|
const kmsBaseUrl = `${mockData.baseUrl}/kms`;
|
|
19
19
|
|
|
20
|
+
const FIVE_MINUTES = 1000 * 60 * 5;
|
|
21
|
+
|
|
20
22
|
export async function createMeter({capabilityAgent, serviceType} = {}) {
|
|
21
23
|
// create signer using the application's capability invocation key
|
|
22
24
|
const {keys: {capabilityInvocationKey}} = getAppIdentity();
|
|
@@ -204,7 +206,7 @@ export async function delegate({
|
|
|
204
206
|
}) {
|
|
205
207
|
const zcapClient = createZcapClient({capabilityAgent: delegator});
|
|
206
208
|
expires = expires || (capability && capability.expires) ||
|
|
207
|
-
new Date(Date.now() +
|
|
209
|
+
new Date(Date.now() + FIVE_MINUTES).toISOString().slice(0, -5) + 'Z';
|
|
208
210
|
return zcapClient.delegate({
|
|
209
211
|
capability, controller, expires, invocationTarget, allowedActions
|
|
210
212
|
});
|
package/test/package.json
CHANGED
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"@bedrock/package-manager": "^3.0.0",
|
|
36
36
|
"@bedrock/security-context": "^7.0.0",
|
|
37
37
|
"@bedrock/server": "^5.0.0",
|
|
38
|
-
"@bedrock/service-agent": "^
|
|
39
|
-
"@bedrock/service-context-store": "^
|
|
38
|
+
"@bedrock/service-agent": "^5.0.0",
|
|
39
|
+
"@bedrock/service-context-store": "^7.0.0",
|
|
40
40
|
"@bedrock/service-core": "5.0.0",
|
|
41
41
|
"@bedrock/ssm-mongodb": "^9.0.0",
|
|
42
42
|
"@bedrock/test": "^8.0.0",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"@digitalbazaar/did-method-key": "^2.0.0",
|
|
50
50
|
"@digitalbazaar/ed25519-signature-2020": "^3.0.0",
|
|
51
51
|
"@digitalbazaar/ed25519-verification-key-2020": "^3.2.0",
|
|
52
|
-
"@digitalbazaar/edv-client": "^
|
|
52
|
+
"@digitalbazaar/edv-client": "^14.0.0",
|
|
53
53
|
"@digitalbazaar/ezcap": "^2.0.2",
|
|
54
54
|
"@digitalbazaar/http-client": "^3.0.1",
|
|
55
55
|
"@digitalbazaar/vc": "^2.1.0",
|