Skip to content

Commit

Permalink
Implement jwt for DB envelope tests
Browse files Browse the repository at this point in the history
Signed-off-by: PatStLouis <[email protected]>
  • Loading branch information
PatStLouis committed Dec 19, 2024
1 parent cfc1914 commit 6996312
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 53 deletions.
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"type": "module",
"scripts": {
"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",
"lint": "eslint ."
"lint": "eslint .",
"test-issuance": "node test.mjs"
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -38,6 +39,9 @@
"@digitalbazaar/data-integrity": "^2.5.0",
"@digitalbazaar/data-integrity-context": "^2.0.1",
"@digitalbazaar/ed25519-multikey": "^1.0.1",
"@digitalbazaar/did-method-key": "^5.2.0",
"@digitalbazaar/ed25519-signature-2020": "^5.4.0",
"@digitalbazaar/ezcap": "^4.1.0",
"@digitalbazaar/eddsa-rdfc-2022-cryptosuite": "^1.1.0",
"@digitalbazaar/mocha-w3c-interop-reporter": "^1.5.0",
"@digitalbazaar/vc": "^7.0.0",
Expand Down
93 changes: 51 additions & 42 deletions tests/4.13.2-envelopes.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import {
generateCredential,
generateEnvelope,
secureCredential,
setupMatrix
setupMatrix,
verifyCredential,
verifyPresentation
} from './helpers.js';
import {
vc_jwt,
Expand All @@ -18,7 +20,6 @@ import {
import assert from 'node:assert/strict';
import chai from 'chai';
import {filterByTag} from 'vc-test-suite-implementations';
import {TestEndpoints} from './TestEndpoints.js';

const should = chai.should();

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

describe(name, function() {
let envelopedCredential;
let verifiableCredential;
let negativeFixture;
before(async function() {
envelopedCredential = generateEnvelope({
verifiableCredential = generateEnvelope({
type: 'EnvelopedVerifiableCredential',
id: `data:application/vc+jwt,${vc_jwt}`
});
Expand All @@ -57,22 +57,26 @@ describe('Enveloped Verifiable Credentials', function() {
{issuer, credential: generateCredential()});
should.exist(issuedVc, 'Expected credential to be issued.');
issuedVc.should.have.property('@context');
verifiableCredential = issuedVc;
}
if(verifier) {
await assert.doesNotReject(endpoints.verify(envelopedCredential),
await assert.doesNotReject(
verifyCredential({verifier, verifiableCredential}),
'Failed to accept an enveloped VC.');

// Replace context with an empty array
negativeFixture = structuredClone(envelopedCredential);
negativeFixture = structuredClone(verifiableCredential);
negativeFixture['@context'] = [];
await assert.rejects(endpoints.verify(negativeFixture),
'Failed to reject an enveloped VC with an empty context.');
await assert.rejects(
verifyCredential({verifier, negativeFixture}),
'Failed to reject an enveloped VC with invalid context.');

// Replace context with an invalid value
negativeFixture = structuredClone(envelopedCredential);
negativeFixture = structuredClone(verifiableCredential);
negativeFixture['@context'] = 'https://www.w3.org/ns/credentials/examples/v2';
await assert.rejects(endpoints.verify(negativeFixture),
'Failed to reject an enveloped VC with an invalid context.');
await assert.rejects(
verifyCredential({verifier, negativeFixture}),
'Failed to reject an enveloped VC with invalid context.');
}
});

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

// Remove data uri portion of the id field
negativeFixture = structuredClone(envelopedCredential);
negativeFixture = structuredClone(verifiableCredential);
negativeFixture.id = negativeFixture.id.split(',').pop();
await assert.rejects(endpoints.verify(negativeFixture),
await assert.rejects(
verifyCredential({verifier, negativeFixture}),
'Failed to reject an enveloped VC with an invalid data url id.');
}
});
Expand All @@ -108,25 +113,27 @@ describe('Enveloped Verifiable Credentials', function() {
const issuedVc = await secureCredential(
{issuer, credential: generateCredential()});
should.exist(issuedVc, 'Expected credential to be issued.');
issuedVc.should.have.property('type').that.is.equal(
'EnvelopedVerifiableCredential',
`Expecting type field to be EnvelopedVerifiableCredential`);
issuedVc.should.have.property('@context');
verifiableCredential = issuedVc;
}
if(verifier) {
await assert.doesNotReject(endpoints.verify(envelopedCredential),
await assert.doesNotReject(
verifyCredential({verifier, verifiableCredential}),
'Failed to accept an enveloped VC.');

// Remove type field
negativeFixture = structuredClone(envelopedCredential);
negativeFixture = structuredClone(verifiableCredential);
delete negativeFixture.type;
await assert.rejects(endpoints.verify(negativeFixture),
await assert.rejects(
verifyCredential({verifier, negativeFixture}),
'Failed to reject an enveloped VC with an enveloped VC with a ' +
'missing `type`.');

// Replace type field
negativeFixture = structuredClone(envelopedCredential);
negativeFixture.type = ['VerifiableCredential'];
await assert.rejects(endpoints.verify(negativeFixture),
negativeFixture = structuredClone(verifiableCredential);
negativeFixture.type = 'VerifiableCredential';
await assert.rejects(
verifyCredential({verifier, negativeFixture}),
'Failed to reject an enveloped VC with an ' +
'invalid `type`.');
}
Expand All @@ -139,17 +146,16 @@ describe('Enveloped Verifiable Credentials', function() {
describe('Enveloped Verifiable Presentations', function() {
setupMatrix.call(this, match);
for(const [name, implementation] of match) {
const endpoints = new TestEndpoints({implementation, tag});
const vpVerifier = implementation.vpVerifiers?.find(
vpVerifier => vpVerifier.tags.has(tag)) || null;

describe(name, function() {
let envelopedPresentation;
let verifiablePresentation;
let negativeFixture;
before(async function() {
envelopedPresentation = generateEnvelope({
verifiablePresentation = generateEnvelope({
type: 'EnvelopedVerifiablePresentation',
id: `data:application/vp+jwt,${vp_jwt}`
id: `data:application/jwt,${vp_jwt}`
});
});
beforeEach(addPerTestMetadata);
Expand All @@ -162,21 +168,22 @@ describe('Enveloped Verifiable Presentations', function() {
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.`;

if(vpVerifier) {
await assert.doesNotReject(endpoints.verifyVp(envelopedPresentation),
await assert.doesNotReject(
verifyPresentation({vpVerifier, verifiablePresentation}),
'Failed to accept an enveloped VP.');

// Replace context field with empty array
negativeFixture = structuredClone(envelopedPresentation);
negativeFixture = structuredClone(verifiablePresentation);
negativeFixture['@context'] = [];
await assert.rejects(
endpoints.verifyVp(negativeFixture),
verifyPresentation({vpVerifier, negativeFixture}),
'Failed to reject Enveloped VP missing contexts.');

// Replace context field with invalid context
negativeFixture = structuredClone(envelopedPresentation);
negativeFixture = structuredClone(verifiablePresentation);
negativeFixture['@context'] = ['https://www.w3.org/ns/credentials/examples/v2'];
await assert.rejects(
endpoints.verifyVp(negativeFixture),
verifyPresentation({vpVerifier, negativeFixture}),
'Failed to reject Enveloped VP missing contexts.');
}
});
Expand All @@ -188,14 +195,15 @@ describe('Enveloped Verifiable Presentations', function() {
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.`;

if(vpVerifier) {
await assert.doesNotReject(endpoints.verifyVp(envelopedPresentation),
await assert.doesNotReject(
verifyPresentation({vpVerifier, verifiablePresentation}),
'Failed to accept an enveloped VP.');

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

if(vpVerifier) {
await assert.doesNotReject(endpoints.verifyVp(envelopedPresentation),
await assert.doesNotReject(
verifyPresentation({vpVerifier, verifiablePresentation}),
'Failed to accept an enveloped VP.');

// Replace type field
negativeFixture = structuredClone(envelopedPresentation);
negativeFixture = structuredClone(verifiablePresentation);
negativeFixture.type = ['VerifiablePresentation'];
await assert.rejects(
endpoints.verifyVp(negativeFixture),
verifyPresentation({vpVerifier, negativeFixture}),
'Failed to reject VP w/o type "EnvelopedVerifiablePresentation".');
}
});
Expand Down
4 changes: 2 additions & 2 deletions tests/fixtures.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

63 changes: 55 additions & 8 deletions tests/helpers.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import {challenge} from './fixtures.js';
import {makeZcapRequest} from './zcapHandler.js';

export function setupMatrix(match) {
// this will tell the report
// to make an interop matrix with this suite
Expand Down Expand Up @@ -44,15 +47,56 @@ export const secureCredential = async ({
const {settings: {id: issuerId, options = {}}} = issuer;
credential.issuer = issuerId;
const body = {credential, options};
const {data, result, error} = await issuer.post({json: body});
if(!result || !result.ok) {
console.warn(
`initial vc creation failed for ${(result || error)?.requestUrl}`,
error
);
return null;
if(issuer.settings.zcap) {
const response = await makeZcapRequest(issuer.settings, body);
return response?.data?.verifiableCredential;
} else {
const {data, result, error} = await issuer.post({json: body});
if(!result || !result.ok) {
error;
return null;
}
return data;
}
};

export const verifyCredential = async ({
verifier,
verifiableCredential,
}) => {
const {settings: {options = {}}} = verifier;
const body = {verifiableCredential, options};
if(verifier.settings.zcap) {
const response = await makeZcapRequest(verifier.settings, body);
return response?.data?.verifiableCredential;
} else {
const {data, result, error} = await verifier.post({json: body});
if(!result || !result.ok) {
error;
return null;
}
return data;
}
};

export const verifyPresentation = async ({
vpVerifier,
verifiablePresentation,
}) => {
const {settings: {options = {}}} = vpVerifier;
options.challenge = challenge;
const body = {verifiablePresentation, options};
if(vpVerifier.settings.zcap) {
const response = await makeZcapRequest(vpVerifier.settings, body);
return response?.data?.verifiableCredential;
} else {
const {data, result, error} = await vpVerifier.post({json: body});
if(!result || !result.ok) {
error;
return null;
}
return data;
}
return data;
};

export function generateCredential({
Expand Down Expand Up @@ -83,3 +127,6 @@ export function generateEnvelope({
};
return envelopeCredential;
}

export const secureEnvelope = async ({
}) => {};
29 changes: 29 additions & 0 deletions tests/zcapHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as Ed25519Multikey from '@digitalbazaar/ed25519-multikey';
import {decodeSecretKeySeed} from 'bnid';
import {Ed25519Signature2020} from '@digitalbazaar/ed25519-signature-2020';
import {ZcapClient} from '@digitalbazaar/ezcap';

export async function makeZcapRequest(settings, body) {
const capability = JSON.parse(settings.zcap.capability);
const controller = capability.controller;
// only supports did key
const id = controller + '#' + controller.slice('did:key:'.length);
const verificationKeyPair = await Ed25519Multikey.generate({
id,
controller,
seed: decodeSecretKeySeed({
secretKeySeed: process.env[settings.zcap.keySeed]
})
});
const zcapClient = new ZcapClient({
SuiteClass: Ed25519Signature2020,
invocationSigner: verificationKeyPair.signer(),
delegationSigner: verificationKeyPair.signer(),
});
const response = await zcapClient.write({
url: settings.endpoint,
json: body,
capability: JSON.parse(settings.zcap.capability)
});
return response;
}

0 comments on commit 6996312

Please sign in to comment.