Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Turn off optional tests #118

Merged
merged 5 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 91 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,100 @@ const {
property: 'verifiers'
});

// an optional parameter for
// testing optional features
const optionalTests = {
// turns on contextInjection tests
contextInjection: true,
// turns on tests related to dates
dates: true,
// turns on tests related to authentication
authentication: true
};
// an optional parameter that
// specifies a credential to test against
const credential = {
"@context": [
"https://www.w3.org/ns/credentials/v2",
{
"@protected": true,
"DriverLicenseCredential": "urn:example:DriverLicenseCredential",
"DriverLicense": {
"@id": "urn:example:DriverLicense",
"@context": {
"@protected": true,
"id": "@id",
"type": "@type",
"documentIdentifier": "urn:example:documentIdentifier",
"dateOfBirth": "urn:example:dateOfBirth",
"expirationDate": "urn:example:expiration",
"issuingAuthority": "urn:example:issuingAuthority"
}
},
"driverLicense": {
"@id": "urn:example:driverLicense",
"@type": "@id"
}
}
],
"id": "urn:uuid:36245ee9-9074-4b05-a777-febff2e69758",
"type": ["VerifiableCredential", "DriverLicenseCredential"],
"credentialSubject": {
"id": "urn:uuid:1a0e4ef5-091f-4060-842e-18e519ab9440",
"driverLicense": {
"type": "DriverLicense",
"documentIdentifier": "T21387yc328c7y32h23f23",
"dateOfBirth": "01-01-1990",
"expirationDate": "01-01-2030",
"issuingAuthority": "VA"
}
}
};
// if the suite is data integrity complaint
// cryptosuiteName is mandatory
const cryptosuiteName = 'eddsa-2022';

// an optional list of proof types VC
// issued by an implementation will have
const expectedProofTypes = [
'DataIntegrityProof',
'MyProofType'
]

checkDataIntegrityProofFormat({
implemented: matchingIssuers
implemented: matchingIssuers,
optionalTests,
credential,
cryptosuiteName,
expectedProofTypes
});

// a parameter for how the verifier
// tests will produce VCs for the verifier
const testDataOptions = {
suiteName: cryptosuiteName,
// a key the suite can issue with
key,
// the cryptosuite being tests
cryptosuite = myCryptosuite,
// optional parameter for selective disclosure tests
// using JSON pointers
mandatoryPointers,
// optional parameter for selective disclosure tests
// using JSON pointers
selectivePointers,
// an optional parameter specifying a documentLoader
// used to issue VCs
documentLoader,
// the testVector to use to produce VCs
// for the verifier
testVector: credential
};
checkDataIntegrityProofVerifyErrors({
implemented: matchingVerifiers
implemented: matchingVerifiers,
optionalTests,
// an optional parameter to specify the expected proof type
expectedProofType: 'DataIntegrityProof',
testDataOptions
});
```
10 changes: 5 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ export function checkDataIntegrityProofFormat({
cryptosuiteName, isEcdsaTests = false, credential = validVc,
testDescription = 'Data Integrity (issuer)',
optionalTests = {
dates: true,
contextInjection: true,
domain: true
dates: false,
contextInjection: false,
domain: false
}
} = {}) {
return describe(testDescription, function() {
Expand Down Expand Up @@ -105,8 +105,8 @@ export function checkDataIntegrityProofVerifyErrors({
isEcdsaTests = false, testDescription = 'Data Integrity (verifier)',
testDataOptions,
optionalTests = {
created: true,
authentication: true
dates: false,
authentication: false
}
} = {}) {
return describe(testDescription, async function() {
Expand Down
231 changes: 111 additions & 120 deletions suites/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@ const should = chai.should();
export function runDataIntegrityProofFormatTests({
endpoints, expectedProofTypes, testDescription,
vendorName, cryptosuiteName, credential,
optionalTests = {
dates: true,
contextInjection: true,
domain: true
}
optionalTests
}) {
return describe(testDescription, function() {
const columnId = testDescription;
Expand Down Expand Up @@ -310,125 +306,120 @@ export function runDataIntegrityProofFormatTests({
}
});
}
it('When an application is securing a document, if an @context ' +
'property is not provided in the document or the Data Integrity ' +
'terms used in the document are not mapped by existing values in ' +
'the @context property, implementations SHOULD inject or append an ' +
'@context property with a value of https://w3id.org/security/data' +
'-integrity/v2 or one or more contexts with at least the same ' +
'declarations, such as the Verifiable Credential Data Model v2.0 ' +
'context (https://www.w3.org/ns/credentials/v2).', async function() {
if(!issuer) {
throw new Error(`Expected ${vendorName} to have an issuer.`);
}
this.test.link = 'https://w3c.github.io/vc-data-integrity/#context-injection:~:text=if%20an%20%40context%20property%20is%20not%20provided%20in%20the%20document%20or%20the%20Data%20Integrity%20terms%20used%20in%20the%20document%20are%20not%20mapped%20by%20existing%20values%20in%20the%20%40context%20property%2C%20implementations%20SHOULD%20inject%20or%20append';
if(optionalTests.contextInjection === false) {
this.test.cell.skipMessage = 'Optional Test Skipped';
this.skip();
}
const _credential = structuredClone(credential);
const expectedContexts = [
'https://w3id.org/security/data-integrity/v2',
'https://www.w3.org/ns/credentials/v2'
];
// remove the vc's context and expect context injection to occur
delete _credential['@context'];
let err;
let data;
try {
data = await createInitialVc({issuer, credential: _credential});
} catch(e) {
err = e;
}
should.not.exist(
err,
`Expected issuer ${vendorName} to perform context injection on a ` +
`VC with out an "@context" property`);
should.exist(data, `Expected issuer ${vendorName} to return data.`);
data.should.be.an('object', 'Expected response data to be an object.');
should.exist(data['@context'],
'Expected data to have an injected "@context" property.');
if(Array.isArray(data['@context'])) {
const hasExpectedContext = expectedContexts.some(
ctx => data['@context'].includes(ctx));
return hasExpectedContext.should.equal(true,
`Expected injected context to contain one of ${expectedContexts}`);
}
data['@context'].should.be.oneOf(expectedContexts);
});
it('The date and time the proof was created is OPTIONAL and, if ' +
'included, MUST be specified as an [XMLSCHEMA11-2] dateTimeStamp ' +
'string, either in Universal Coordinated Time (UTC), denoted by a Z at ' +
'the end of the value, or with a time zone offset relative to UTC.',
function() {
this.test.link = 'https://www.w3.org/TR/vc-data-integrity/#:~:text=The%20date%20and%20time%20the%20proof%20was%20created%20is%20OPTIONAL%20and%2C%20if%20included%2C%20MUST%20be%20specified%20as%20an%20%5BXMLSCHEMA11%2D2%5D%20dateTimeStamp%20string%2C%20either%20in%20Universal%20Coordinated%20Time%20(UTC)%2C%20denoted%20by%20a%20Z%20at%20the%20end%20of%20the%20value%2C%20or%20with%20a%20time%20zone%20offset%20relative%20to%20UTC.';
if(optionalTests.dates === false) {
this.test.cell.skipMessage = 'Optional Test Skipped';
this.skip();
}
for(const proof of proofs) {
if(proof.created) {
// check if "created" is a valid XML Schema 1.1 dateTimeStamp
// value
proof.created.should.match(dateRegex);
if(optionalTests.contextInjection) {
it('When an application is securing a document, if an @context ' +
'property is not provided in the document or the Data Integrity ' +
'terms used in the document are not mapped by existing values in ' +
'the @context property, implementations SHOULD inject or append an ' +
'@context property with a value of https://w3id.org/security/data' +
'-integrity/v2 or one or more contexts with at least the same ' +
'declarations, such as the Verifiable Credential Data Model v2.0 ' +
'context (https://www.w3.org/ns/credentials/v2).', async function() {
if(!issuer) {
throw new Error(`Expected ${vendorName} to have an issuer.`);
}
}
});
it('The expires property is OPTIONAL and, if present, specifies when ' +
'the proof expires. If present, it MUST be an [XMLSCHEMA11-2] ' +
'dateTimeStamp string, either in Universal Coordinated Time (UTC), ' +
'denoted by a Z at the end of the value, or with a time zone offset ' +
'relative to UTC.', function() {
this.test.link = 'https://w3c.github.io/vc-data-integrity/#proofs:~:text=MUST%20be%20an%20%5BXMLSCHEMA11%2D2%5D%20dateTimeStamp%20string%2C%20either%20in%20Universal%20Coordinated%20Time';
if(optionalTests.dates === false) {
this.test.cell.skipMessage = 'Optional Test Skipped';
this.skip();
}
for(const proof of proofs) {
if(proof.expires) {
// check if "created" is a valid XML Schema 1.1 dateTimeStamp
// value
proof.expires.should.match(dateRegex);
this.test.link = 'https://w3c.github.io/vc-data-integrity/#context-injection:~:text=if%20an%20%40context%20property%20is%20not%20provided%20in%20the%20document%20or%20the%20Data%20Integrity%20terms%20used%20in%20the%20document%20are%20not%20mapped%20by%20existing%20values%20in%20the%20%40context%20property%2C%20implementations%20SHOULD%20inject%20or%20append';
const _credential = structuredClone(credential);
const expectedContexts = [
'https://w3id.org/security/data-integrity/v2',
'https://www.w3.org/ns/credentials/v2'
];
// remove the vc's context and expect context injection to occur
delete _credential['@context'];
let err;
let data;
try {
data = await createInitialVc({issuer, credential: _credential});
} catch(e) {
err = e;
}
}
});
it('The domain property is OPTIONAL. It conveys one or more security ' +
'domains in which the proof is meant to be used. If specified, the ' +
'associated value MUST be either a string, or an unordered set of ' +
'strings. A verifier SHOULD use the value to ensure that the proof ' +
'was intended to be used in the security domain in which the ' +
'verifier is operating.', function() {
this.test.link = 'https://w3c.github.io/vc-data-integrity/#verify-proof:~:text=The%20domain%20property%20is%20OPTIONAL.%20It%20conveys%20one%20or%20more%20security%20domains%20in%20which%20the%20proof%20is%20meant%20to%20be%20used.%20If%20specified%2C%20the%20associated%20value%20MUST';
if(optionalTests.domain === false) {
this.test.cell.skipMessage = 'Optional Test Skipped';
this.skip();
}
for(const proof of proofs) {
if(proof.domain) {
const validType = isStringOrArrayOfStrings(proof.domain);
validType.should.equal(true, 'Expected ' +
'"proof.domain" to be either a string or an unordered ' +
'set of strings.');
should.not.exist(
err,
`Expected issuer ${vendorName} to perform context injection on a ` +
`VC with out an "@context" property`);
should.exist(data, `Expected issuer ${vendorName} to return data.`);
data.should.be.an('object', 'Expected response data to be an object.');
should.exist(data['@context'],
'Expected data to have an injected "@context" property.');
if(Array.isArray(data['@context'])) {
const hasExpectedContext = expectedContexts.some(
ctx => data['@context'].includes(ctx));
return hasExpectedContext.should.equal(true,
`Expected injected context to contain one of ${expectedContexts}`);
}
}
});
it('(challenge) A string value that SHOULD be included in a proof if a ' +
'domain is specified.', function() {
this.test.link = 'https://w3c.github.io/vc-data-integrity/#verify-proof:~:text=A%20string%20value%20that%20SHOULD%20be%20included%20in%20a%20proof%20if%20a%20domain%20is%20specified.';
if(optionalTests.domain === false) {
this.test.cell.skipMessage = 'Optional Test Skipped';
this.skip();
}
for(const proof of proofs) {
if(proof.challenge) {
// domain must be specified
should.exist(proof.domain, 'Expected "proof.domain" ' +
'to be specified.');
proof.challenge.should.be.a('string', 'Expected ' +
'"proof.challenge" to be a string.');
data['@context'].should.be.oneOf(expectedContexts);
});
}
if(optionalTests.dates) {
it('The date and time the proof was created is OPTIONAL and, if ' +
'included, MUST be specified as an [XMLSCHEMA11-2] dateTimeStamp ' +
'string, either in Universal Coordinated Time (UTC), denoted by a ' +
'Z at the end of the value, or with a time zone offset relative ' +
'to UTC.',
function() {
this.test.link = 'https://www.w3.org/TR/vc-data-integrity/#:~:text=The%20date%20and%20time%20the%20proof%20was%20created%20is%20OPTIONAL%20and%2C%20if%20included%2C%20MUST%20be%20specified%20as%20an%20%5BXMLSCHEMA11%2D2%5D%20dateTimeStamp%20string%2C%20either%20in%20Universal%20Coordinated%20Time%20(UTC)%2C%20denoted%20by%20a%20Z%20at%20the%20end%20of%20the%20value%2C%20or%20with%20a%20time%20zone%20offset%20relative%20to%20UTC.';
for(const proof of proofs) {
if(proof.created) {
// check if "created" is a valid XML Schema 1.1 dateTimeStamp
// value
proof.created.should.match(dateRegex);
}
}
}
});
});
it('The expires property is OPTIONAL and, if present, specifies when ' +
'the proof expires. If present, it MUST be an [XMLSCHEMA11-2] ' +
'dateTimeStamp string, either in Universal Coordinated Time (UTC), ' +
'denoted by a Z at the end of the value, or with a time zone offset ' +
'relative to UTC.', function() {
this.test.link = 'https://w3c.github.io/vc-data-integrity/#proofs:~:text=MUST%20be%20an%20%5BXMLSCHEMA11%2D2%5D%20dateTimeStamp%20string%2C%20either%20in%20Universal%20Coordinated%20Time';
for(const proof of proofs) {
if(proof.expires) {
// check if "created" is a valid XML Schema 1.1 dateTimeStamp
// value
proof.expires.should.match(dateRegex);
}
}
});
}
if(optionalTests.domain) {
it('The domain property is OPTIONAL. It conveys one or more security ' +
'domains in which the proof is meant to be used. If specified, the ' +
'associated value MUST be either a string, or an unordered set of ' +
'strings. A verifier SHOULD use the value to ensure that the proof ' +
'was intended to be used in the security domain in which the ' +
'verifier is operating.', function() {
this.test.link = 'https://w3c.github.io/vc-data-integrity/#verify-proof:~:text=The%20domain%20property%20is%20OPTIONAL.%20It%20conveys%20one%20or%20more%20security%20domains%20in%20which%20the%20proof%20is%20meant%20to%20be%20used.%20If%20specified%2C%20the%20associated%20value%20MUST';
if(optionalTests.domain === false) {
this.test.cell.skipMessage = 'Optional Test Skipped';
this.skip();
}
for(const proof of proofs) {
if(proof.domain) {
const validType = isStringOrArrayOfStrings(proof.domain);
validType.should.equal(true, 'Expected ' +
'"proof.domain" to be either a string or an unordered ' +
'set of strings.');
}
}
});
it('(challenge) A string value that SHOULD be included in a proof if a ' +
'domain is specified.', function() {
this.test.link = 'https://w3c.github.io/vc-data-integrity/#verify-proof:~:text=A%20string%20value%20that%20SHOULD%20be%20included%20in%20a%20proof%20if%20a%20domain%20is%20specified.';
if(optionalTests.domain === false) {
this.test.cell.skipMessage = 'Optional Test Skipped';
this.skip();
}
for(const proof of proofs) {
if(proof.challenge) {
// domain must be specified
should.exist(proof.domain, 'Expected "proof.domain" ' +
'to be specified.');
proof.challenge.should.be.a('string', 'Expected ' +
'"proof.challenge" to be a string.');
}
}
});
}
});
}

Loading