You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
258 lines
8.4 KiB
258 lines
8.4 KiB
// did:ssb test vector generator for DID Test Suite
|
|
|
|
const DIDSSBResolver = require('./resolver');
|
|
|
|
const dest = process.argv[2];
|
|
if (!dest) throw 'Usage: node gen-test.js <destination>';
|
|
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
|
|
const didJsonFilename = path.join(dest, 'did-ssb.json');
|
|
const resolverJsonFilename = path.join(dest, 'resolver-ssb.json');
|
|
const dereferencerJsonFilename = path.join(dest, 'dereferencer-ssb.json');
|
|
|
|
const testCommon = {
|
|
didMethod: 'did:ssb',
|
|
implementation: 'ssb-did-resolver',
|
|
implementer: 'Secure Scuttlebutt Consortium',
|
|
};
|
|
|
|
const didMethodInputs = [
|
|
{
|
|
did: 'did:ssb:ed25519:f_6sQ6d2CMxRUhLpspgGIulDxDCwYD7DzFzPNr7u5AU',
|
|
resolutionOptions: {},
|
|
representationResolutionOptions: {}
|
|
}
|
|
];
|
|
|
|
const resolverInputs = [
|
|
{
|
|
function: 'resolve',
|
|
did: 'did:ssb:ed25519:f_6sQ6d2CMxRUhLpspgGIulDxDCwYD7DzFzPNr7u5AU',
|
|
resolutionOptions: {}
|
|
},
|
|
{
|
|
function: 'resolveRepresentation',
|
|
did: 'did:ssb:ed25519:f_6sQ6d2CMxRUhLpspgGIulDxDCwYD7DzFzPNr7u5AU',
|
|
resolutionOptions: {}
|
|
},
|
|
{
|
|
function: 'resolve',
|
|
did: 'did:ssb:ed25519:6RpN4Ztw3jLwzQtHl8XpnnR58LWZTAjwq2vvfyx7zkc',
|
|
resolutionOptions: {}
|
|
}
|
|
];
|
|
|
|
const dereferencerInputs = [
|
|
{
|
|
didUrl: 'did:ssb:ed25519:f_6sQ6d2CMxRUhLpspgGIulDxDCwYD7DzFzPNr7u5AU',
|
|
dereferenceOptions: {}
|
|
},
|
|
{
|
|
didUrl: 'did:ssb:ed25519:f_6sQ6d2CMxRUhLpspgGIulDxDCwYD7DzFzPNr7u5AU?versionId=%25Vlo6kAc%2BIbGGBhD2MUi2r3ULz%2FNAGBWwGb%2FEMa4w4FI%3D.sha256',
|
|
dereferenceOptions: {}
|
|
},
|
|
{
|
|
didUrl: 'did:ssb:ed25519:f_6sQ6d2CMxRUhLpspgGIulDxDCwYD7DzFzPNr7u5AU?versionTime=2021-07-24T03:38:46Z',
|
|
dereferenceOptions: {}
|
|
}
|
|
];
|
|
|
|
let didParameters = {
|
|
versionId: 'did:ssb:ed25519:f_6sQ6d2CMxRUhLpspgGIulDxDCwYD7DzFzPNr7u5AU?versionId=%25Vlo6kAc%2BIbGGBhD2MUi2r3ULz%2FNAGBWwGb%2FEMa4w4FI%3D.sha256',
|
|
versionTime: 'did:ssb:ed25519:f_6sQ6d2CMxRUhLpspgGIulDxDCwYD7DzFzPNr7u5AU?versionTime=2021-07-24T03:38:46Z'
|
|
};
|
|
|
|
const ssbClient = require('ssb-client');
|
|
let closeSbot, resolver;
|
|
ssbClient(function (err, sbot, config) {
|
|
if (err) throw err;
|
|
closeSbot = sbot.close.bind(sbot);
|
|
resolver = new DIDSSBResolver(sbot, config);
|
|
generateReports(done)
|
|
});
|
|
|
|
function done() {
|
|
closeSbot(function (err) {
|
|
if (err && err !== true) throw err;
|
|
});
|
|
}
|
|
|
|
function generateReports(next) {
|
|
let reportWaiting = 3;
|
|
generateMethodReport(reportNext);
|
|
generateResolverReport(reportNext);
|
|
generateDereferencerReport(reportNext);
|
|
function reportNext() {
|
|
if (--reportWaiting) return;
|
|
next();
|
|
}
|
|
}
|
|
|
|
function generateMethodReport(next) {
|
|
let contentTypes = {};
|
|
let supportedContentTypes = [];
|
|
let dids = [];
|
|
let didMethodReport = {
|
|
...testCommon,
|
|
supportedContentTypes,
|
|
dids,
|
|
didParameters,
|
|
};
|
|
let methodWaiting = 0;
|
|
didMethodInputs.forEach(function (input) {
|
|
methodWaiting++;
|
|
const did = input.did;
|
|
const didReport = didMethodReport[did] = {};
|
|
dids.push(did);
|
|
let didWaiting = 2;
|
|
let resResult, resReprResult;
|
|
resolver.resolve(did, input.resolutionOptions, function (didResolutionMetadata, didDocument, didDocumentMetadata) {
|
|
if (didResolutionMetadata.error) throw didResolutionMetadata.error;
|
|
resResult = {didResolutionMetadata, didDocument, didDocumentMetadata};
|
|
didNext();
|
|
});
|
|
resolver.resolveRepresentation(did, input.representationResolutionOptions, function (didResolutionMetadata, didDocumentStream, didDocumentMetadata) {
|
|
if (didResolutionMetadata.error) throw didResolutionMetadata.error;
|
|
resReprResult = {didResolutionMetadata, didDocumentStream, didDocumentMetadata};
|
|
didNext();
|
|
});
|
|
function didNext() {
|
|
if (--didWaiting) return;
|
|
const {didDocument} = resResult;
|
|
let representationSpecificEntries = {};
|
|
let properties = {};
|
|
for (const property in didDocument) switch (property) {
|
|
case '@context':
|
|
representationSpecificEntries[property] = didDocument[property];
|
|
break;
|
|
default:
|
|
properties[property] = didDocument[property];
|
|
break;
|
|
}
|
|
didReport.didDocumentDataModel = {
|
|
properties
|
|
};
|
|
const contentType = resReprResult.didResolutionMetadata.contentType;
|
|
if (!contentType) throw new Error('Expected contentType');
|
|
if (!contentTypes[contentType]) {
|
|
contentTypes[contentType] = true
|
|
supportedContentTypes.push(contentType);
|
|
}
|
|
didReport[contentType] = {
|
|
didDocumentDataModel: {
|
|
representationSpecificEntries
|
|
},
|
|
representation: resReprResult.didDocumentStream,
|
|
didDocumentMetadata: resReprResult.didDocumentMetadata,
|
|
didResolutionMetadata: resReprResult.didResolutionMetadata
|
|
};
|
|
methodNext();
|
|
}
|
|
});
|
|
function methodNext() {
|
|
if (--methodWaiting) return;
|
|
const report = JSON.stringify(didMethodReport, null, 2);
|
|
fs.writeFileSync(didJsonFilename, report);
|
|
next();
|
|
}
|
|
}
|
|
|
|
function getOutcome(error, deactivated) {
|
|
if (error) switch (error) {
|
|
case 'invalidDid': return 'invalidDidErrorOutcome';
|
|
case 'invalidDidUrl': return 'invalidDidUrlErrorOutcome';
|
|
case 'notFound': return 'notFoundErrorOutcome';
|
|
case 'representationNotSupported': return 'representationNotSupportedErrorOutcome';
|
|
default: throw new Error('Unknown error: ' + didResolutionMetadata.error);
|
|
}
|
|
if (deactivated) return 'deactivatedOutcome';
|
|
return 'defaultOutcome';
|
|
}
|
|
|
|
function generateResolverReport(next) {
|
|
let expectedOutcomes = {};
|
|
let executions = [];
|
|
const didResolverReport = {
|
|
...testCommon,
|
|
expectedOutcomes,
|
|
executions
|
|
};
|
|
let executionWaiting = resolverInputs.length;
|
|
resolverInputs.forEach(function (input, i) {
|
|
switch (input.function) {
|
|
case 'resolve':
|
|
resolver.resolve(input.did, input.resolutionOptions, function (didResolutionMetadata, didDocument, didDocumentMetadata) {
|
|
executions[i] = {
|
|
function: input.function,
|
|
input: {did: input.did, resolutionOptions: input.resolutionOptions},
|
|
output: {didResolutionMetadata, didDocument, didDocumentMetadata}
|
|
};
|
|
const outcome = getOutcome(didResolutionMetadata.error, didDocumentMetadata.deactivated);
|
|
const idxs = expectedOutcomes[outcome] || (expectedOutcomes[outcome] = []);
|
|
idxs.push(i);
|
|
executionNext();
|
|
});
|
|
break;
|
|
case 'resolveRepresentation':
|
|
resolver.resolveRepresentation(input.did, input.resolutionOptions, function (didResolutionMetadata, didDocumentStream, didDocumentMetadata) {
|
|
executions[i] = {
|
|
function: input.function,
|
|
input: {did: input.did, resolutionOptions: input.resolutionOptions},
|
|
output: {didResolutionMetadata, didDocumentStream, didDocumentMetadata}
|
|
};
|
|
const outcome = getOutcome(didResolutionMetadata.error, didDocumentMetadata.deactivated);
|
|
const idxs = expectedOutcomes[outcome] || (expectedOutcomes[outcome] = []);
|
|
idxs.push(i);
|
|
executionNext();
|
|
});
|
|
break;
|
|
default:
|
|
throw new Error('Unknown function: ' + input.function);
|
|
}
|
|
});
|
|
function executionNext() {
|
|
if (--executionWaiting) return;
|
|
for (const outcome in expectedOutcomes) {
|
|
expectedOutcomes[outcome].sort();
|
|
}
|
|
const report = JSON.stringify(didResolverReport, null, 2);
|
|
fs.writeFileSync(resolverJsonFilename, report);
|
|
next();
|
|
}
|
|
}
|
|
|
|
function generateDereferencerReport(next) {
|
|
let expectedOutcomes = {};
|
|
let executions = [];
|
|
const didUrlDereferencerReport = {
|
|
...testCommon,
|
|
expectedOutcomes,
|
|
executions
|
|
};
|
|
let executionWaiting = dereferencerInputs.length;
|
|
dereferencerInputs.forEach(function (input, i) {
|
|
resolver.dereference(input.didUrl, input.dereferenceOptions, function (dereferencingMetadata, contentStream, contentMetadata) {
|
|
executions[i] = {
|
|
function: 'dereference',
|
|
input,
|
|
output: {dereferencingMetadata, contentStream, contentMetadata}
|
|
};
|
|
const outcome = getOutcome(dereferencingMetadata.error, contentMetadata.deactivated);
|
|
const idxs = expectedOutcomes[outcome] || (expectedOutcomes[outcome] = []);
|
|
idxs.push(i);
|
|
executionNext();
|
|
});
|
|
});
|
|
function executionNext() {
|
|
if (--executionWaiting) return;
|
|
for (const outcome in expectedOutcomes) {
|
|
expectedOutcomes[outcome].sort();
|
|
}
|
|
const report = JSON.stringify(didUrlDereferencerReport, null, 2);
|
|
fs.writeFileSync(dereferencerJsonFilename, report);
|
|
next();
|
|
}
|
|
}
|