Skip to content

Commit 564d7e1

Browse files
committed
Implement jwt for DB envelope tests
Signed-off-by: PatStLouis <[email protected]>
1 parent cfc1914 commit 564d7e1

File tree

5 files changed

+142
-53
lines changed

5 files changed

+142
-53
lines changed

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
"type": "module",
1010
"scripts": {
1111
"test": "mocha tests/ --reporter @digitalbazaar/mocha-w3c-interop-reporter --reporter-options abstract=\"$PWD/abstract.hbs\",reportDir=\"$PWD/reports\",respec=\"$PWD/respecConfig.json\",suiteLog='./suite.log',templateData=\"$PWD/reports/index.json\",title=\"VC v2.0 Interoperability Report\" --timeout 15000 --preserve-symlinks",
12-
"lint": "eslint ."
12+
"lint": "eslint .",
13+
"test-issuance": "node test.mjs"
1314
},
1415
"repository": {
1516
"type": "git",
@@ -38,6 +39,9 @@
3839
"@digitalbazaar/data-integrity": "^2.5.0",
3940
"@digitalbazaar/data-integrity-context": "^2.0.1",
4041
"@digitalbazaar/ed25519-multikey": "^1.0.1",
42+
"@digitalbazaar/did-method-key": "^5.2.0",
43+
"@digitalbazaar/ed25519-signature-2020": "^5.4.0",
44+
"@digitalbazaar/ezcap": "^4.1.0",
4145
"@digitalbazaar/eddsa-rdfc-2022-cryptosuite": "^1.1.0",
4246
"@digitalbazaar/mocha-w3c-interop-reporter": "^1.5.0",
4347
"@digitalbazaar/vc": "^7.0.0",

tests/4.13.2-envelopes.js

Lines changed: 51 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import {
99
generateCredential,
1010
generateEnvelope,
1111
secureCredential,
12-
setupMatrix
12+
setupMatrix,
13+
verifyCredential,
14+
verifyPresentation
1315
} from './helpers.js';
1416
import {
1517
vc_jwt,
@@ -18,7 +20,6 @@ import {
1820
import assert from 'node:assert/strict';
1921
import chai from 'chai';
2022
import {filterByTag} from 'vc-test-suite-implementations';
21-
import {TestEndpoints} from './TestEndpoints.js';
2223

2324
const should = chai.should();
2425

@@ -29,17 +30,16 @@ const {match} = filterByTag({tags: [tag]});
2930
describe('Enveloped Verifiable Credentials', function() {
3031
setupMatrix.call(this, match);
3132
for(const [name, implementation] of match) {
32-
const endpoints = new TestEndpoints({implementation, tag});
3333
const issuer = implementation.issuers?.find(
3434
issuer => issuer.tags.has(tag)) || null;
3535
const verifier = implementation.verifiers?.find(
3636
verifier => verifier.tags.has(tag)) || null;
3737

3838
describe(name, function() {
39-
let envelopedCredential;
39+
let verifiableCredential;
4040
let negativeFixture;
4141
before(async function() {
42-
envelopedCredential = generateEnvelope({
42+
verifiableCredential = generateEnvelope({
4343
type: 'EnvelopedVerifiableCredential',
4444
id: `data:application/vc+jwt,${vc_jwt}`
4545
});
@@ -57,22 +57,26 @@ describe('Enveloped Verifiable Credentials', function() {
5757
{issuer, credential: generateCredential()});
5858
should.exist(issuedVc, 'Expected credential to be issued.');
5959
issuedVc.should.have.property('@context');
60+
verifiableCredential = issuedVc;
6061
}
6162
if(verifier) {
62-
await assert.doesNotReject(endpoints.verify(envelopedCredential),
63+
await assert.doesNotReject(
64+
verifyCredential({verifier, verifiableCredential}),
6365
'Failed to accept an enveloped VC.');
6466

6567
// Replace context with an empty array
66-
negativeFixture = structuredClone(envelopedCredential);
68+
negativeFixture = structuredClone(verifiableCredential);
6769
negativeFixture['@context'] = [];
68-
await assert.rejects(endpoints.verify(negativeFixture),
69-
'Failed to reject an enveloped VC with an empty context.');
70+
await assert.rejects(
71+
verifyCredential({verifier, negativeFixture}),
72+
'Failed to reject an enveloped VC with invalid context.');
7073

7174
// Replace context with an invalid value
72-
negativeFixture = structuredClone(envelopedCredential);
75+
negativeFixture = structuredClone(verifiableCredential);
7376
negativeFixture['@context'] = 'https://www.w3.org/ns/credentials/examples/v2';
74-
await assert.rejects(endpoints.verify(negativeFixture),
75-
'Failed to reject an enveloped VC with an invalid context.');
77+
await assert.rejects(
78+
verifyCredential({verifier, negativeFixture}),
79+
'Failed to reject an enveloped VC with invalid context.');
7680
}
7781
});
7882

@@ -85,18 +89,19 @@ describe('Enveloped Verifiable Credentials', function() {
8589
const issuedVc = await secureCredential(
8690
{issuer, credential: generateCredential()});
8791
should.exist(issuedVc, 'Expected credential to be issued.');
88-
issuedVc.should.have.property('id').that.does
89-
.include('data:',
90-
`Expecting id field to be a 'data:' scheme URL [RFC2397].`);
92+
issuedVc.should.have.property('@context');
93+
verifiableCredential = issuedVc;
9194
}
9295
if(verifier) {
93-
await assert.doesNotReject(endpoints.verify(envelopedCredential),
96+
await assert.doesNotReject(
97+
verifyCredential({verifier, verifiableCredential}),
9498
'Failed to accept an enveloped VC.');
9599

96100
// Remove data uri portion of the id field
97-
negativeFixture = structuredClone(envelopedCredential);
101+
negativeFixture = structuredClone(verifiableCredential);
98102
negativeFixture.id = negativeFixture.id.split(',').pop();
99-
await assert.rejects(endpoints.verify(negativeFixture),
103+
await assert.rejects(
104+
verifyCredential({verifier, negativeFixture}),
100105
'Failed to reject an enveloped VC with an invalid data url id.');
101106
}
102107
});
@@ -108,25 +113,27 @@ describe('Enveloped Verifiable Credentials', function() {
108113
const issuedVc = await secureCredential(
109114
{issuer, credential: generateCredential()});
110115
should.exist(issuedVc, 'Expected credential to be issued.');
111-
issuedVc.should.have.property('type').that.is.equal(
112-
'EnvelopedVerifiableCredential',
113-
`Expecting type field to be EnvelopedVerifiableCredential`);
116+
issuedVc.should.have.property('@context');
117+
verifiableCredential = issuedVc;
114118
}
115119
if(verifier) {
116-
await assert.doesNotReject(endpoints.verify(envelopedCredential),
120+
await assert.doesNotReject(
121+
verifyCredential({verifier, verifiableCredential}),
117122
'Failed to accept an enveloped VC.');
118123

119124
// Remove type field
120-
negativeFixture = structuredClone(envelopedCredential);
125+
negativeFixture = structuredClone(verifiableCredential);
121126
delete negativeFixture.type;
122-
await assert.rejects(endpoints.verify(negativeFixture),
127+
await assert.rejects(
128+
verifyCredential({verifier, negativeFixture}),
123129
'Failed to reject an enveloped VC with an enveloped VC with a ' +
124130
'missing `type`.');
125131

126132
// Replace type field
127-
negativeFixture = structuredClone(envelopedCredential);
128-
negativeFixture.type = ['VerifiableCredential'];
129-
await assert.rejects(endpoints.verify(negativeFixture),
133+
negativeFixture = structuredClone(verifiableCredential);
134+
negativeFixture.type = 'VerifiableCredential';
135+
await assert.rejects(
136+
verifyCredential({verifier, negativeFixture}),
130137
'Failed to reject an enveloped VC with an ' +
131138
'invalid `type`.');
132139
}
@@ -139,17 +146,16 @@ describe('Enveloped Verifiable Credentials', function() {
139146
describe('Enveloped Verifiable Presentations', function() {
140147
setupMatrix.call(this, match);
141148
for(const [name, implementation] of match) {
142-
const endpoints = new TestEndpoints({implementation, tag});
143149
const vpVerifier = implementation.vpVerifiers?.find(
144150
vpVerifier => vpVerifier.tags.has(tag)) || null;
145151

146152
describe(name, function() {
147-
let envelopedPresentation;
153+
let verifiablePresentation;
148154
let negativeFixture;
149155
before(async function() {
150-
envelopedPresentation = generateEnvelope({
156+
verifiablePresentation = generateEnvelope({
151157
type: 'EnvelopedVerifiablePresentation',
152-
id: `data:application/vp+jwt,${vp_jwt}`
158+
id: `data:application/jwt,${vp_jwt}`
153159
});
154160
});
155161
beforeEach(addPerTestMetadata);
@@ -162,21 +168,22 @@ describe('Enveloped Verifiable Presentations', function() {
162168
this.test.link = `https://w3c.github.io/vc-data-model/#enveloped-verifiable-presentations:~:text=The%20%40context%20property%20of%20the%20object%20MUST%20be%20present%20and%20include%20a%20context%2C%20such%20as%20the%20base%20context%20for%20this%20specification%2C%20that%20defines%20at%20least%20the%20id%2C%20type%2C%20and%20EnvelopedVerifiablePresentation%20terms%20as%20defined%20by%20the%20base%20context%20provided%20by%20this%20specification.`;
163169

164170
if(vpVerifier) {
165-
await assert.doesNotReject(endpoints.verifyVp(envelopedPresentation),
171+
await assert.doesNotReject(
172+
verifyPresentation({vpVerifier, verifiablePresentation}),
166173
'Failed to accept an enveloped VP.');
167174

168175
// Replace context field with empty array
169-
negativeFixture = structuredClone(envelopedPresentation);
176+
negativeFixture = structuredClone(verifiablePresentation);
170177
negativeFixture['@context'] = [];
171178
await assert.rejects(
172-
endpoints.verifyVp(negativeFixture),
179+
verifyPresentation({vpVerifier, negativeFixture}),
173180
'Failed to reject Enveloped VP missing contexts.');
174181

175182
// Replace context field with invalid context
176-
negativeFixture = structuredClone(envelopedPresentation);
183+
negativeFixture = structuredClone(verifiablePresentation);
177184
negativeFixture['@context'] = ['https://www.w3.org/ns/credentials/examples/v2'];
178185
await assert.rejects(
179-
endpoints.verifyVp(negativeFixture),
186+
verifyPresentation({vpVerifier, negativeFixture}),
180187
'Failed to reject Enveloped VP missing contexts.');
181188
}
182189
});
@@ -188,14 +195,15 @@ describe('Enveloped Verifiable Presentations', function() {
188195
this.test.link = `https://w3c.github.io/vc-data-model/#enveloped-verifiable-presentations:~:text=The%20id%20value%20of%20the%20object%20MUST%20be%20a%20data%3A%20URL%20%5BRFC2397%5D%20that%20expresses%20a%20secured%20verifiable%20presentation%20using%20an%20enveloping%20securing%20mechanism%2C%20such%20as%20Securing%20Verifiable%20Credentials%20using%20JOSE%20and%20COSE%20%5BVC%2DJOSE%2DCOSE%5D.`;
189196

190197
if(vpVerifier) {
191-
await assert.doesNotReject(endpoints.verifyVp(envelopedPresentation),
198+
await assert.doesNotReject(
199+
verifyPresentation({vpVerifier, verifiablePresentation}),
192200
'Failed to accept an enveloped VP.');
193201

194202
// Remove data uri portion from id field
195-
negativeFixture = structuredClone(envelopedPresentation);
203+
negativeFixture = structuredClone(verifiablePresentation);
196204
negativeFixture.id = negativeFixture.id.split(',').pop();
197205
await assert.rejects(
198-
endpoints.verifyVp(negativeFixture),
206+
verifyPresentation({vpVerifier, negativeFixture}),
199207
'Failed to reject Enveloped VP with an id that is not a data url.');
200208
}
201209
});
@@ -205,14 +213,15 @@ describe('Enveloped Verifiable Presentations', function() {
205213
this.test.link = `https://w3c.github.io/vc-data-model/#enveloped-verifiable-presentations:~:text=The%20type%20value%20of%20the%20object%20MUST%20be%20EnvelopedVerifiablePresentation.`;
206214

207215
if(vpVerifier) {
208-
await assert.doesNotReject(endpoints.verifyVp(envelopedPresentation),
216+
await assert.doesNotReject(
217+
verifyPresentation({vpVerifier, verifiablePresentation}),
209218
'Failed to accept an enveloped VP.');
210219

211220
// Replace type field
212-
negativeFixture = structuredClone(envelopedPresentation);
221+
negativeFixture = structuredClone(verifiablePresentation);
213222
negativeFixture.type = ['VerifiablePresentation'];
214223
await assert.rejects(
215-
endpoints.verifyVp(negativeFixture),
224+
verifyPresentation({vpVerifier, negativeFixture}),
216225
'Failed to reject VP w/o type "EnvelopedVerifiablePresentation".');
217226
}
218227
});

tests/fixtures.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/helpers.js

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import {challenge} from './fixtures.js';
2+
import {makeZcapRequest} from './zcapHandler.js';
3+
14
export function setupMatrix(match) {
25
// this will tell the report
36
// to make an interop matrix with this suite
@@ -44,15 +47,56 @@ export const secureCredential = async ({
4447
const {settings: {id: issuerId, options = {}}} = issuer;
4548
credential.issuer = issuerId;
4649
const body = {credential, options};
47-
const {data, result, error} = await issuer.post({json: body});
48-
if(!result || !result.ok) {
49-
console.warn(
50-
`initial vc creation failed for ${(result || error)?.requestUrl}`,
51-
error
52-
);
53-
return null;
50+
if(issuer.settings.zcap) {
51+
const response = await makeZcapRequest(issuer.settings, body);
52+
return response?.data?.verifiableCredential;
53+
} else {
54+
const {data, result, error} = await issuer.post({json: body});
55+
if(!result || !result.ok) {
56+
error;
57+
return null;
58+
}
59+
return data;
60+
}
61+
};
62+
63+
export const verifyCredential = async ({
64+
verifier,
65+
verifiableCredential,
66+
}) => {
67+
const {settings: {options = {}}} = verifier;
68+
const body = {verifiableCredential, options};
69+
if(verifier.settings.zcap) {
70+
const response = await makeZcapRequest(verifier.settings, body);
71+
return response?.data?.verifiableCredential;
72+
} else {
73+
const {data, result, error} = await verifier.post({json: body});
74+
if(!result || !result.ok) {
75+
error;
76+
return null;
77+
}
78+
return data;
79+
}
80+
};
81+
82+
export const verifyPresentation = async ({
83+
vpVerifier,
84+
verifiablePresentation,
85+
}) => {
86+
const {settings: {options = {}}} = vpVerifier;
87+
options.challenge = challenge;
88+
const body = {verifiablePresentation, options};
89+
if(vpVerifier.settings.zcap) {
90+
const response = await makeZcapRequest(vpVerifier.settings, body);
91+
return response?.data?.verifiableCredential;
92+
} else {
93+
const {data, result, error} = await vpVerifier.post({json: body});
94+
if(!result || !result.ok) {
95+
error;
96+
return null;
97+
}
98+
return data;
5499
}
55-
return data;
56100
};
57101

58102
export function generateCredential({
@@ -83,3 +127,6 @@ export function generateEnvelope({
83127
};
84128
return envelopeCredential;
85129
}
130+
131+
export const secureEnvelope = async ({
132+
}) => {};

tests/zcapHandler.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import * as Ed25519Multikey from '@digitalbazaar/ed25519-multikey';
2+
import {decodeSecretKeySeed} from 'bnid';
3+
import {Ed25519Signature2020} from '@digitalbazaar/ed25519-signature-2020';
4+
import {ZcapClient} from '@digitalbazaar/ezcap';
5+
6+
export async function makeZcapRequest(settings, body) {
7+
const capability = JSON.parse(settings.zcap.capability);
8+
const controller = capability.controller;
9+
// only supports did key
10+
const id = controller + '#' + controller.slice('did:key:'.length);
11+
const verificationKeyPair = await Ed25519Multikey.generate({
12+
id,
13+
controller,
14+
seed: decodeSecretKeySeed({
15+
secretKeySeed: process.env[settings.zcap.keySeed]
16+
})
17+
});
18+
const zcapClient = new ZcapClient({
19+
SuiteClass: Ed25519Signature2020,
20+
invocationSigner: verificationKeyPair.signer(),
21+
delegationSigner: verificationKeyPair.signer(),
22+
});
23+
const response = await zcapClient.write({
24+
url: settings.endpoint,
25+
json: body,
26+
capability: JSON.parse(settings.zcap.capability)
27+
});
28+
return response;
29+
}

0 commit comments

Comments
 (0)