diff --git a/packages/cicero-cli/index.js b/packages/cicero-cli/index.js index 6361b242a..2d1f497a4 100755 --- a/packages/cicero-cli/index.js +++ b/packages/cicero-cli/index.js @@ -149,11 +149,15 @@ require('yargs') } }) - .command('verify', 'verify the template signatures of the template author/developer', (yargs) => { + .command('verify', 'verify the signatures on template or contract instances', (yargs) => { yargs.option('template', { describe: 'path to the template', type: 'string' }); + yargs.option('contract', { + describe: 'path to a smart legal contract slc file', + type: 'string' + }); yargs.option('warnings', { describe: 'print warnings', type: 'boolean', @@ -169,9 +173,9 @@ require('yargs') const options = { warnings: argv.warnings, }; - return Commands.verify(argv.template, options) + return Commands.verify(argv.template, argv.contract, options) .then((result) => { - if(result) {Logger.info(`Author/developer's signature for ${argv.template} template is verified`);} + if(result) {Logger.info('all signatures verified');} }) .catch((err) => { Logger.error(err.message); @@ -671,7 +675,7 @@ require('yargs') }; return Commands.sign(argv.contract, argv.keystore, argv.passphrase, argv.signatory, argv.output, options) .then((result) => { - if(result) {Logger.info('Contract has been successfully signed');} + if(result) {Logger.info('contract has been successfully signed');} }) .catch((err) => { Logger.error(err.message); diff --git a/packages/cicero-cli/lib/commands.js b/packages/cicero-cli/lib/commands.js index 90d143300..002398c57 100644 --- a/packages/cicero-cli/lib/commands.js +++ b/packages/cicero-cli/lib/commands.js @@ -636,17 +636,6 @@ class Commands { }); } - /** - * Set default params before we verify signatures of template author/developer - * - * @param {object} argv the inbound argument values object - * @returns {object} a modfied argument object - */ - static validateVerifyArgs(argv) { - argv = Commands.validateCommonArgs(argv); - return argv; - } - /** * Set default params before we create an archive using a template * @@ -673,7 +662,7 @@ class Commands { } /** - * Create an archive using a template + * Sign a contract instance * * @param {string} slcPath - path to the slc archive * @param {string} keystore - path to the keystore @@ -703,34 +692,38 @@ class Commands { } /** - * Set default params before we create an archive using a template + * Set default params before we verify signatures of template author/developer + * * @param {object} argv the inbound argument values object * @returns {object} a modfied argument object */ static validateVerifyArgs(argv) { argv = Commands.validateCommonArgs(argv); - - if(!argv.target){ - Logger.info('Using ergo as the default target for the archive.'); - argv.target = 'ergo'; - } - return argv; } /** - * Create an archive using a template + * Verify signatures on templates or contract instances * + * @param {string} templatePath - path to the template directory or archive * @param {string} contractPath - path to the template directory or archive * @param {Object} [options] - an optional set of options * @returns {object} Promise to the code creating an archive */ - static async verify(contractPath, options) { - return Commands.loadInstance(null, contractPath, options) - .then((instance) => { - instance.verifySignatures(); - Logger.info('All signatures verified successfully'); - }); + static async verify(templatePath, contractPath, options) { + if (templatePath) { + return Commands.loadTemplate(templatePath, options) + .then(async(template) => { + const result = await template.verifyTemplateSignature(); + return result; + }); + } else { + return Commands.loadInstance(null, contractPath, options) + .then((instance) => { + instance.verifySignatures(); + Logger.info('All signatures verified successfully'); + }); + } } /** @@ -750,21 +743,6 @@ class Commands { return argv; } - /** - * Verify the template developer/author's signatures - * - * @param {string} templatePath - path to the template directory or archive - * @param {Object} [options] - an optional set of options - * @returns {object} returns true if signature is valid else false - */ - static verify(templatePath, options) { - return Commands.loadTemplate(templatePath, options) - .then(async(template) => { - const result = await template.verifyTemplateSignature(); - return result; - }); - } - /** * Create an instance archive from a template * diff --git a/packages/cicero-cli/test/cli.js b/packages/cicero-cli/test/cli.js index dd649af6c..560bacc7b 100644 --- a/packages/cicero-cli/test/cli.js +++ b/packages/cicero-cli/test/cli.js @@ -1327,7 +1327,7 @@ describe('#validateSignArgs', () => { passphrase: 'password', signatory: 'partyA', _: ['sign'] - })).should.throw('please define path of the keystore using --keystore'); + })).should.throw('Please define path of the keystore using --keystore'); }); it('passphrase not defined', () => { process.chdir(path.resolve(__dirname, 'data/contractsigning/')); @@ -1336,7 +1336,7 @@ describe('#validateSignArgs', () => { keystore: 'keystore.p12', signatory: 'partyA', _: ['sign'] - })).should.throw('please define the passphrase of the keystore using --pasphrase'); + })).should.throw('Please define the passphrase of the keystore using --pasphrase'); }); it('signatory not defined', () => { process.chdir(path.resolve(__dirname, 'data/contractsigning/')); @@ -1345,7 +1345,7 @@ describe('#validateSignArgs', () => { keystore: 'keystore.p12', passphrase: 'password', _: ['sign'] - })).should.throw('please define the signatory signing the contract using --signatory'); + })).should.throw('Please define the signatory signing the contract using --signatory'); }); it('verbose flag specified', () => { process.chdir(path.resolve(__dirname, 'data/contractsigning/')); @@ -1379,6 +1379,14 @@ describe('#sign', async () => { newInstance.contractSignatures.should.have.lengthOf(1); fs.unlinkSync(archiveName); }); + it('should sign the contract for a party/individual without specifying output path', async () => { + const slcPath = path.resolve(__dirname, 'data/contractsigning/latedeliveryandpenalty@0.17.0-d0c1a14e8a7af52e0927a23b8b30af3b5a75bee1ab788a15736e603b88a6312c.slc'); + const keystore = path.resolve(__dirname, 'data/contractsigning/keystore.p12'); + const signatory = 'partyA'; + const result = await Commands.sign(slcPath, keystore, 'password', signatory); + result.should.eql(true); + fs.unlinkSync('latedeliveryandpenalty@0.17.0-d0c1a14e8a7af52e0927a23b8b30af3b5a75bee1ab788a15736e603b88a6312c.slc'); + }); }); describe('#validateVerifyArgs', () => { @@ -1409,7 +1417,7 @@ describe('#validateVerifyArgs', () => { describe('#verify', async () => { it('should verify contract signatures', async () => { const slcPath = path.resolve(__dirname, 'data/contractsigning/latedeliveryandpenalty@0.17.0-d0c1a14e8a7af52e0927a23b8b30af3b5a75bee1ab788a15736e603b88a6312c.v1.slc'); - return Commands.verify(slcPath).should.be.fulfilled; + return Commands.verify(null, slcPath).should.be.fulfilled; }); }); diff --git a/packages/cicero-core/src/instance.js b/packages/cicero-core/src/instance.js index 605e37f79..697c68155 100644 --- a/packages/cicero-core/src/instance.js +++ b/packages/cicero-core/src/instance.js @@ -65,6 +65,7 @@ class Instance { this.data = null; this.concertoData = null; + this.authorSignature = null; this.contractSignatures = []; this.parties = []; diff --git a/packages/cicero-core/src/instanceloader.js b/packages/cicero-core/src/instanceloader.js index 35db06fc7..5466e5c78 100644 --- a/packages/cicero-core/src/instanceloader.js +++ b/packages/cicero-core/src/instanceloader.js @@ -155,13 +155,16 @@ class InstanceLoader extends FileLoader { instance.setData(data); - // grab the signatures + // grab the party signatures const signatureFiles = await InstanceLoader.loadZipFilesContents(zip, /signatures[/\\].*\.json$/, true, false); signatureFiles.forEach((signatureFile) => { let signature = JSON.parse(signatureFile.contents); instance.contractSignatures.push(signature); }); + //grab the author/developer signature + this.authorSignature = await InstanceLoader.loadZipFileContents(zip, 'signature.json', true, false); + //grab the parties const contractModel = Util.getContractModel(instance.logicManager, instance.instanceKind); const properties = contractModel.getProperties(); diff --git a/packages/cicero-core/src/instancesaver.js b/packages/cicero-core/src/instancesaver.js index df11722f6..f8a62fd2c 100644 --- a/packages/cicero-core/src/instancesaver.js +++ b/packages/cicero-core/src/instancesaver.js @@ -59,7 +59,12 @@ class InstanceSaver { zip.file('text/grammar.tem.md', instance.getParserManager().getTemplate(), options); } - //save the signatures + // save the author/developer signature + const authorSignature = JSON.stringify(instance.authorSignature); + + zip.file('signature.json', authorSignature, options); + + //save the party signatures let signatures = instance.contractSignatures; zip.file('signatures/', null, Object.assign({}, options, { dir: true