@sphereon/gx-agent-cli
Version:
Gaia-X Compliance Client CLI
175 lines (174 loc) • 7.15 kB
JavaScript
import { program } from 'commander';
import { printTable } from 'console-table-printer';
import fs from 'fs';
import { asDID, convertDidWebToHost, exportToDIDDocument, getAgent, getVcType } from '@sphereon/gx-agent';
import nock from 'nock';
const vp = program.command('vp').description('Generic Verifiable Presentation commands');
vp.command('list')
.description('Lists all persisted Verifiable Presentations')
.action(async (cmd) => {
const agent = await getAgent();
try {
const uniqueVPs = await agent.dataStoreORMGetVerifiablePresentations({
order: [
{
column: 'issuanceDate',
direction: 'ASC',
},
],
});
printTable(uniqueVPs.map((vp) => {
return {
types: vp.verifiablePresentation.verifiableCredential.map((vc) => getVcType(vc)).toString(),
issuer: vp.verifiablePresentation.proof.verificationMethod,
holder: vp.verifiablePresentation.holder,
'issuance-date': vp.verifiablePresentation.proof.created,
id: vp.hash,
};
}));
}
catch (e) {
console.error(e.message);
}
});
vp.command('verify')
.description('Verify a Verifiable Presentation from file or agent id')
.option('-f, --input-file <string>', 'File containing a Verifiable Presentation')
.option('-id, --vc-id <string>', 'Use a persisted VP in the agent as input for verification')
.option('--show', 'Print the Verifiable Presentation to console')
.action(async (cmd) => {
const agent = await getAgent();
try {
if (!cmd.inputFile && !cmd.vcId) {
throw Error('Either a Verifiable Presentation input file or the id of a stored Verifiable Presentation needs to be supplied');
}
else if (cmd.inputFile && cmd.vcId) {
throw Error('Cannot both have a Verifiable Presentation input file and the id of a stored Verifiable Presentation');
}
const verifiablePresentation = cmd.inputFile
? JSON.parse(fs.readFileSync(cmd.inputFile, 'utf-8'))
: await agent.dataStoreGetVerifiablePresentation({ hash: cmd.vcId });
let id;
try {
id = await agent.didManagerGet({ did: verifiablePresentation.holder });
const didDoc = await exportToDIDDocument(id);
const url = `https://${convertDidWebToHost(verifiablePresentation.holder)}`;
nock.cleanAll();
nock(url)
.get(`/.well-known/did.json`)
.times(10)
.reply(200, {
...didDoc,
});
}
catch (e) {
// DID not hosted by us, which is fine
}
const result = await agent.checkVerifiablePresentation({ verifiablePresentation, show: cmd.show === true });
printTable([
{
types: verifiablePresentation
.verifiableCredential.map((vc) => vc.type.toString().replace('VerifiableCredential,', ''))
.toString(),
issuer: verifiablePresentation.proof.verificationMethod,
holder: verifiablePresentation.holder,
'issuance-date': verifiablePresentation.proof.created,
valid: result,
},
]);
if (cmd.show === true) {
console.log(JSON.stringify(verifiablePresentation, null, 2));
}
}
catch (e) {
console.error(e.message);
}
finally {
nock.cleanAll();
}
});
vp.command('issue')
.description('Issues a Verifiable Presentation using Credentials from input file(s) and/or stored in th eagent')
.requiredOption('-d, --did <string>', 'Use domain or did')
.option('-ids, --vc-ids <string...>', '1 or more Verifiable Credential IDS stored in the agent')
.option('-f, --vc-files <string...>', 'File(s) containing Verifiable Credentials')
.option('-c, --challenge <string>', 'Use a challenge')
.option('-t, --target-domain <string>', 'Target domain, used to protect against replay attacks')
.option('-p, --persist', 'Persist the presentation. If not provided the presentation will not be stored in the agent')
.option('--show', 'Print the Verifiable Presentation to console')
.action(async (cmd) => {
const agent = await getAgent();
if (!cmd.vcFiles && !cmd.vcIds) {
throw Error('Verifiable Credential IDs or files need to be selected. Please check parameters');
}
try {
const fileVCs = cmd.vcFiles
? cmd.vcFiles.map((file) => {
return JSON.parse(fs.readFileSync(file, 'utf-8'));
})
: [];
const agentVCs = [];
const ids = cmd.vcIds ? cmd.vcIds : [];
for (const hash of ids) {
agentVCs.push(await agent.dataStoreGetVerifiableCredential({ hash }));
}
const verifiableCredentials = fileVCs.concat(agentVCs);
if (verifiableCredentials.length === 0) {
throw Error('No verifiable credentials were found matching the critery. Did you use the --vc-files and/or --vc-ids options?');
}
const did = await asDID(cmd.did);
const id = await agent.didManagerGet({ did });
const didDoc = await exportToDIDDocument(id);
const url = `https://${convertDidWebToHost(did)}`;
nock.cleanAll();
nock(url)
.get(`/.well-known/did.json`)
.times(10)
.reply(200, {
...didDoc,
});
const uniqueVP = await agent.issueVerifiablePresentation({
challenge: cmd.challenge,
verifiableCredentials,
domain: cmd.targetDomain,
persist: cmd.persist === true,
});
const vp = uniqueVP.verifiablePresentation;
printTable([
{
types: vp.type?.toString(),
holder: vp.holder,
'issuance-date': vp.proof.created,
id: uniqueVP.hash,
persisted: cmd.persist === true,
},
]);
if (cmd.show) {
console.log(JSON.stringify(vp, null, 2));
}
}
catch (e) {
console.error(e.message);
}
finally {
nock.cleanAll();
}
});
vp.command('export')
.description('Exports a Verifiable Presentation to disk')
.argument('<id>', 'The id of the VerifiablePresentation that you want to export')
.option('-d, --did <string>', 'the DID or domain which will be used')
.option('-p, --path <string>', 'A base path to export the files to. Defaults to "exported"')
.option('--show', 'Print the Verifiable Presentation to console')
.action(async (id, cmd) => {
const agent = await getAgent();
const exportResult = await agent.exportVCsToPath({
domain: cmd.did,
hash: id,
includeVPs: true,
includeVCs: false,
exportPath: cmd.path,
});
printTable(exportResult);
console.log(`Verifiable Presentation file has been written to the above path`);
});