From b8dd1abbb51b24843a47b36e544d8f7448e31f83 Mon Sep 17 00:00:00 2001 From: S3bb1 Date: Fri, 14 Dec 2018 13:41:29 +0100 Subject: [PATCH 01/22] adjust tests --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 14311476..96507206 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ matrix: node_js: "8.11.3" env: - ACCOUNT_MAP='{"0xC2ee94f6cf046B02D530cf1cd16A2b32b8A4340d":"EF7012DD4D5DD6A78765C511F452F8CA641378F0DF071F9C32D506F45F31B22C","0xac46D762f0aB316105C5Cf4375bb8e380Be88658":"E29C1E4A683CC629E39CE219CFB1F35BBA898605E1B197162F0EECF0F1139630","0x35f8220bC83577458aEa4a1085A8b832DEa79b7a":"340BA316637FD01A1AFD54D4491A899F6D8EA0FB89A1D7BA94682F7D68B21B20"}' - - TESTSPECS='src/claims/*.spec.ts src/profile/*.spec.ts src/*.spec.ts' + - TESTSPECS='src/claims/*.spec.ts src/profile/*.spec.ts src/*.spec.ts !src/name-resolver.spec.ts' script: - npm run testunit $TESTSPECS @@ -40,7 +40,7 @@ matrix: node_js: "8.11.3" env: - ACCOUNT_MAP='{"0x001De828935e8c7e4cb56Fe610495cAe63fb2612":"01734663843202e2245e5796cb120510506343c67915eb4f9348ac0d8c2cf22a","0x0030C5e7394585400B1FB193DdbCb45a37Ab916E":"7d09c0873e3f8dc0c7282bb7c2ba76bfd432bff53c38ace06193d1e4faa977e7","0x00D1267B27C3A80080f9E1B6Ba01DE313b53Ab58":"a76a2b068fb715830d042ca40b1a4dab8d088b217d11af91d15b972a7afaf202"}' - - TESTSPECS='src/contracts/*.spec.ts !src/contracts/name-resolver.spec.ts src/contracts/base-contract/*.spec.ts src/contracts/business-center/*.spec.ts src/contracts/service-contract/*.spec.ts' + - TESTSPECS='src/contracts/*.spec.ts src/contracts/base-contract/*.spec.ts src/contracts/business-center/*.spec.ts src/contracts/service-contract/*.spec.ts' script: - npm run testunit $TESTSPECS @@ -48,7 +48,7 @@ matrix: node_js: "8.11.3" env: - ACCOUNT_MAP='{"0x3Be2E8D1A93139A981dc0dFe5E21B53fD6768FA6":"f42d8b97d89636b9c49d765e471f89b465df1bbb59ced554387ba4c38789fe31","0xfe825e67A8F8a0fB31496280173a3de4a6ddEc43":"5e0dbef7deafe54becbcac51f970307fe1679797cbe40f18f5dc55c9740b8d4d","0x4e61A980F2081fCAc3E1777d667B66DF0516d264":"44367a662acc6267065ce64b83a88949f5adc0249ba1cbf55309877117c2e954"}' - - TESTSPECS='src/contracts/name-resolver.spec.ts' + - TESTSPECS='src/name-resolver.spec.ts' script: - npm run testunit $TESTSPECS addons: From d921333278b0ea9125b378351ced5b9a1bffebf0 Mon Sep 17 00:00:00 2001 From: S3bb1 Date: Fri, 14 Dec 2018 13:50:54 +0100 Subject: [PATCH 02/22] remove typings (temporary) --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 96507206..4a5d13cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -66,4 +66,5 @@ before_install: install: - npm install - cd node_modules/@evan.network && rm -rf dbcp && git clone https://github.com/evannetwork/dbcp.git && cd dbcp && git checkout develop && npm i && npm run build && cd ../../../ - - cd node_modules/@evan.network && rm -rf smart-contracts-core && git clone https://github.com/evannetwork/smart-contracts-core.git && cd smart-contracts-core && git checkout develop && npm i && cd ../../../ \ No newline at end of file + - cd node_modules/@evan.network && rm -rf smart-contracts-core && git clone https://github.com/evannetwork/smart-contracts-core.git && cd smart-contracts-core && git checkout develop && npm i && cd ../../../ + - rm node_modules/web3/*.d.ts \ No newline at end of file From 79c1fb1d4f86aedd743b56be511fa54a57365332 Mon Sep 17 00:00:00 2001 From: Tobias Winkler Date: Fri, 14 Dec 2018 15:59:47 +0100 Subject: [PATCH 03/22] Adjust default profile claims; catch bcc profile create exportPrivateKey error --- src/bundles/bcc/bcc.ts | 14 +++++++++++--- src/bundles/bcc/dbcp.json | 4 ++-- src/profile/profile.ts | 2 +- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/bundles/bcc/bcc.ts b/src/bundles/bcc/bcc.ts index 8d5b5f7a..adc6c85c 100644 --- a/src/bundles/bcc/bcc.ts +++ b/src/bundles/bcc/bcc.ts @@ -376,9 +376,17 @@ const create = function(options: ProfileBundleOptions): ProfileInstance { const coreInstance = options.CoreBundle.createAndSetCore(options.coreOptions); - accountStore.getPrivateKey(options.accountId).then((pk) => { - coreInstance.dfs.setAccountAndPrivateKey(options.accountId, '0x' + pk); - }) + accountStore + .getPrivateKey(options.accountId) + .then((pk) => { + coreInstance.dfs.setAccountAndPrivateKey(options.accountId, '0x' + pk); + }) + .catch((ex) => { + executor.log( + `bcc.ProfileBundle Could not load private key from accountStore: ${ ex.message }`, + 'warning' + ); + }); coreInstance.description.cryptoProvider = new CryptoProvider({ unencrypted: new Unencrypted(), diff --git a/src/bundles/bcc/dbcp.json b/src/bundles/bcc/dbcp.json index 6a239e0d..795667da 100644 --- a/src/bundles/bcc/dbcp.json +++ b/src/bundles/bcc/dbcp.json @@ -9,7 +9,7 @@ "files": [ "bcc.js" ], - "origin": "QmRcioysUe9Q2aHiffxSx1y4T5CrT6Q2XXPFzDCeZo8WL4", + "origin": "QmSyEyRBsNPfgUBueJozayF3xoYX4UL11Ez9LfAKJ6DSU7", "type": "library" }, "description": "Contractus for loading ens entries and it's data...", @@ -33,7 +33,7 @@ "1.3.1": "QmbQ9HskNocFPNU8wf8QrweJzidMVMbJp4gqxoWEbTLyas", "1.4.0": "QmVv35DzcryDQnbmTVHJChD1enG459cUGKmqZj6xE74nHX", "1.5.0": "QmQnmbZJcUf6j6u6nsJh5jiqxwAfsBybZWPk65tVN8HZ3P", - "1.6.0": "QmY8xhXd3v7cvV42reJqqskGdQTyVHXpxh37XeVFwpVY8i" + "1.6.0": "Qmf1amzH6zaBkbbgz9MaVhq1sooZwjnPebjWijTQ9kQysb" }, "dbcpVersion": 1 } diff --git a/src/profile/profile.ts b/src/profile/profile.ts index 98823511..0d32362f 100644 --- a/src/profile/profile.ts +++ b/src/profile/profile.ts @@ -570,7 +570,7 @@ export class Profile extends Logger { */ private async loadActiveClaims() { const defaultClaims = [ - '/onboarding/agbaccepted', + '/evan/termsofuse', ]; if (!this.trees[this.treeLabels.activeClaims]) { From 20a82857b4053ac9f200679468b90808a98b0a83 Mon Sep 17 00:00:00 2001 From: wulfraem Date: Mon, 17 Dec 2018 08:53:11 +0100 Subject: [PATCH 04/22] fix docu --- docs/blockchain/name-resolver.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/blockchain/name-resolver.rst b/docs/blockchain/name-resolver.rst index 1eff50e5..ec191392 100644 --- a/docs/blockchain/name-resolver.rst +++ b/docs/blockchain/name-resolver.rst @@ -470,7 +470,7 @@ Example .. _name_resolver_setValidUntil: -setPrice +setValidUntil ================================================================================ .. code-block:: typescript From f569301dbb75156bea5adf5b5068d630e248a268 Mon Sep 17 00:00:00 2001 From: S3bb1 Date: Mon, 17 Dec 2018 15:36:59 +0100 Subject: [PATCH 05/22] add test for claims rejecting by other account --- src/claims/claims.spec.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/claims/claims.spec.ts b/src/claims/claims.spec.ts index ecb8c72e..4a15cea9 100644 --- a/src/claims/claims.spec.ts +++ b/src/claims/claims.spec.ts @@ -239,6 +239,19 @@ describe('Claims handler', function() { expect(claimsForAccount[oldLength]).to.have.deep.property('rejectReason', { reason: 'denied' }); }); + it('can reject a claim with a reason from the issuer side', async () => { + const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1])).length; + await claims.setClaim(accounts[0], accounts[0], '/company'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); + const claimId = await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo4'); + await claims.rejectClaim(accounts[0], '/company/b-s-s/employee/swo4', accounts[0], claimId, { reason: 'denied' }); + const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1]); + expect(claimsForAccount).to.have.lengthOf(oldLength + 1); + expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Rejected); + expect(claimsForAccount[oldLength]).to.have.deep.property('rejectReason', { reason: 'denied' }); + }); + it('can not re accept a rejected claim', async () => { const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1])).length; await claims.setClaim(accounts[0], accounts[0], '/company'); From 90da6e0c665296a67c6da25ba9f59c1853ba6a54 Mon Sep 17 00:00:00 2001 From: wulfraem Date: Mon, 17 Dec 2018 17:22:46 +0100 Subject: [PATCH 06/22] add support for setting claims on contracts --- VERSIONS.md | 1 + src/claims/claims.spec.ts | 566 +++++++++++++++++++++++++++----------- src/claims/claims.ts | 444 +++++++++++++++--------------- src/test/test-utils.ts | 5 +- 4 files changed, 629 insertions(+), 387 deletions(-) diff --git a/VERSIONS.md b/VERSIONS.md index d21b7d77..525a8b65 100644 --- a/VERSIONS.md +++ b/VERSIONS.md @@ -20,6 +20,7 @@ - add support for ENS registries with time limited nodes - add support for permanent ENS address on payable registrar - add support for retrieving proposals paged +- add support for setting claims on contracts ## Version 1.5.0 ### Features diff --git a/src/claims/claims.spec.ts b/src/claims/claims.spec.ts index 4a15cea9..c016f5e0 100644 --- a/src/claims/claims.spec.ts +++ b/src/claims/claims.spec.ts @@ -31,7 +31,10 @@ import { expect, use } from 'chai'; import { ContractLoader, Executor } from '@evan.network/dbcp'; import { accounts } from '../test/accounts'; +import { BaseContract } from '../contracts/base-contract/base-contract'; import { Claims, ClaimsStatus, } from './claims'; +import { config } from '../config'; +import { Description } from '../shared-description'; import { TestUtils } from '../test/test-utils'; @@ -40,9 +43,11 @@ const linker = require('solc/linker'); use(chaiAsPromised); describe('Claims handler', function() { + let baseContract: BaseContract; let claims: Claims; let claimsContracts; let contractLoader: ContractLoader; + let description: Description; let dfs: any; let executor: Executor; let nameResolver; @@ -56,6 +61,8 @@ describe('Claims handler', function() { dfs = await TestUtils.getIpfs(); claims = await TestUtils.getClaims(web3, dfs); nameResolver = await TestUtils.getNameResolver(web3); + baseContract = await TestUtils.getBaseContract(web3); + description = await TestUtils.getDescription(web3, dfs); await claims.createIdentity(accounts[0]); await claims.createIdentity(accounts[1]); }); @@ -64,202 +71,427 @@ describe('Claims handler', function() { web3.currentProvider.connection.close(); }); - // can be used for creating new libraries, but disabled by default - // it.only('can deploy a new structure', async () => { + // // // can be used for creating new libraries, but disabled by default + // it('can deploy a new structure', async () => { + // const claimsRegistryLib = await executor.createContract( + // 'ClaimsRegistryLibrary', [], { from: accounts[0], gas: 3000000, }); + // contractLoader.contracts['ClaimsRegistry'].bytecode = linker.linkBytecode( + // contractLoader.contracts['ClaimsRegistry'].bytecode, + // { 'claims/ClaimsRegistryLibrary.sol:ClaimsRegistryLibrary': claimsRegistryLib.options.address } + // ); + // const keyHolderLib = await executor.createContract( // 'KeyHolderLibrary', [], { from: accounts[0], gas: 3000000, }); // contractLoader.contracts['ClaimHolderLibrary'].bytecode = linker.linkBytecode( // contractLoader.contracts['ClaimHolderLibrary'].bytecode, // { 'claims/KeyHolderLibrary.sol:KeyHolderLibrary': keyHolderLib.options.address } // ); + // const claimHolderLib = await executor.createContract( // 'ClaimHolderLibrary', [], { from: accounts[0], gas: 3000000, }); // contractLoader.contracts['OriginIdentity'].bytecode = linker.linkBytecode( - // contractLoader.contracts['OriginIdentity'].bytecode, + // contractLoader.contracts['OriginIdentity'].bytecode, // { // 'claims/ClaimHolderLibrary.sol:ClaimHolderLibrary': claimHolderLib.options.address, // 'claims/KeyHolderLibrary.sol:KeyHolderLibrary': keyHolderLib.options.address, // }, // ) - // console.dir({keyHolderLib: keyHolderLib.options.address, claimHolderLib: claimHolderLib.options.address}); - // }) - - it('can add a claim', async () => { - const oldLength = (await claims.getClaims('/company', accounts[1])).length; - await claims.setClaim(accounts[0], accounts[1], '/company'); - const claimsForAccount = await claims.getClaims('/company', accounts[1]); - expect(claimsForAccount).to.have.lengthOf(oldLength + 1); - expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Issued); - }); + // console.dir({ + // keyHolderLib: keyHolderLib.options.address, + // claimHolderLib: claimHolderLib.options.address, + // claimsRegistryLib: claimsRegistryLib.options.address, + // }); + // process.exit(); + // }); - it('can add a claim with specific data', async () => { - const oldLength = (await claims.getClaims('/company', accounts[1])).length; - await claims.setClaim(accounts[0], accounts[1], '/company', null, {foo: 'bar'}); - const claimsForAccount = await claims.getClaims('/company', accounts[1]); - expect(claimsForAccount).to.have.lengthOf(oldLength + 1); - expect(claimsForAccount[oldLength]).to.have.property('uri', 'https://ipfs.evan.network/ipfs/Qmbjig3cZbUUufWqCEFzyCppqdnmQj3RoDjJWomnqYGy1f'); - }); + describe('when using external account based identities', () => { + it('can add a claim', async () => { + const oldLength = (await claims.getClaims('/company', accounts[1])).length; + await claims.setClaim(accounts[0], accounts[1], '/company'); + const claimsForAccount = await claims.getClaims('/company', accounts[1]); + expect(claimsForAccount).to.have.lengthOf(oldLength + 1); + expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Issued); + }); - it('can add a claim with specific expirationDate', async () => { - const oldLength = (await claims.getClaims('/company', accounts[1])).length; - const now = Math.floor(new Date().getTime() / 1000); - await claims.setClaim(accounts[0], accounts[1], '/company', now); - const claimsForAccount = await claims.getClaims('/company', accounts[1]); - expect(claimsForAccount).to.have.lengthOf(oldLength + 1); - expect(claimsForAccount[oldLength]).to.have.property('expirationDate', now.toString()); - }); + it('can add a claim with specific data', async () => { + const oldLength = (await claims.getClaims('/company', accounts[1])).length; + await claims.setClaim(accounts[0], accounts[1], '/company', null, {foo: 'bar'}); + const claimsForAccount = await claims.getClaims('/company', accounts[1]); + expect(claimsForAccount).to.have.lengthOf(oldLength + 1); + expect(claimsForAccount[oldLength]).to.have.property('uri', 'https://ipfs.evan.network/ipfs/Qmbjig3cZbUUufWqCEFzyCppqdnmQj3RoDjJWomnqYGy1f'); + }); - it('can add a claim and validate the integrity', async () => { - const oldLength = (await claims.getClaims('/company', accounts[1])).length; - await claims.setClaim(accounts[0], accounts[1], '/company'); - const claimsForAccount = await claims.getClaims('/company', accounts[1]); - expect(claimsForAccount).to.have.lengthOf(oldLength + 1); - await claims.validateClaim(claimsForAccount[oldLength].id, accounts[1]); - expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Issued); - }); + it('can add a claim with specific expirationDate', async () => { + const oldLength = (await claims.getClaims('/company', accounts[1])).length; + const now = Math.floor(new Date().getTime() / 1000); + await claims.setClaim(accounts[0], accounts[1], '/company', now); + const claimsForAccount = await claims.getClaims('/company', accounts[1]); + expect(claimsForAccount).to.have.lengthOf(oldLength + 1); + expect(claimsForAccount[oldLength]).to.have.property('expirationDate', now.toString()); + }); - it('can add subclaim paths and validate it', async () => { - const oldLength = (await claims.getClaims('/company', accounts[1])).length; - await claims.setClaim(accounts[0], accounts[0], '/company'); - await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); - await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); - await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo'); - const identity = await claims.getIdentityForAccount(accounts[1]); - const claimTree = await claims.validateClaimTree('/company/b-s-s/employee/swo', identity.options.address); - expect(claimTree).to.have.lengthOf(4); - }); + it('can add a claim and validate the integrity', async () => { + const oldLength = (await claims.getClaims('/company', accounts[1])).length; + await claims.setClaim(accounts[0], accounts[1], '/company'); + const claimsForAccount = await claims.getClaims('/company', accounts[1]); + expect(claimsForAccount).to.have.lengthOf(oldLength + 1); + await claims.validateClaim(claimsForAccount[oldLength].id, accounts[1]); + expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Issued); + }); - it('can add subclaim paths and don\'t have the needed root claims.', async () => { - const oldLength = (await claims.getClaims('/company', accounts[1])).length; - await claims.setClaim(accounts[0], accounts[0], '/company/evan/employee'); - await claims.setClaim(accounts[0], accounts[1], '/company/evan/employee/swo2'); - const identity = await claims.getIdentityForAccount(accounts[1]); - const claimTree = await claims.validateClaimTree('/company/evan/employee/swo2', identity.options.address); - expect(claimTree).to.have.lengthOf(2); - }); + it('can add subclaim paths and validate it', async () => { + const oldLength = (await claims.getClaims('/company', accounts[1])).length; + await claims.setClaim(accounts[0], accounts[0], '/company'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); + await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo'); + const identity = await claims.getIdentityForAccount(accounts[1]); + const claimTree = await claims.validateClaimTree('/company/b-s-s/employee/swo', identity.options.address); + expect(claimTree).to.have.lengthOf(4); + }); - it('can add subclaim paths', async () => { - const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo3', accounts[1])).length; - await claims.setClaim(accounts[0], accounts[0], '/company'); - await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); - await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); - await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo3'); - const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo3', accounts[1]); - expect(claimsForAccount).to.have.lengthOf(1); - expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Issued); - }); + it('can add subclaim paths and don\'t have the needed root claims.', async () => { + const oldLength = (await claims.getClaims('/company', accounts[1])).length; + await claims.setClaim(accounts[0], accounts[0], '/company/evan/employee'); + await claims.setClaim(accounts[0], accounts[1], '/company/evan/employee/swo2'); + const identity = await claims.getIdentityForAccount(accounts[1]); + const claimTree = await claims.validateClaimTree('/company/evan/employee/swo2', identity.options.address); + expect(claimTree).to.have.lengthOf(2); + }); - it('can confirm a subclaim paths with the subject user', async () => { - const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1])).length; - await claims.setClaim(accounts[0], accounts[0], '/company'); - await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); - await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); - const claimId = await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo4'); - await claims.confirmClaim(accounts[1], '/company/b-s-s/employee/swo4', accounts[0], claimId); - const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1]); - expect(claimsForAccount).to.have.lengthOf(oldLength + 1); - expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Confirmed); - }); + it('can add subclaim paths', async () => { + const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo3', accounts[1])).length; + await claims.setClaim(accounts[0], accounts[0], '/company'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); + await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo3'); + const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo3', accounts[1]); + expect(claimsForAccount).to.have.lengthOf(1); + expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Issued); + }); - it('can reject a subclaim paths with the subject user', async () => { - await claims.setClaim(accounts[0], accounts[0], '/company'); - await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); - await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); - const claimId = await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo6'); - await claims.deleteClaim(accounts[1], '/company/b-s-s/employee/swo6', accounts[0], claimId); - const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo6', accounts[1]); - expect(claimsForAccount).to.have.lengthOf(0); - }); + it('can confirm a subclaim paths with the subject user', async () => { + const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1])).length; + await claims.setClaim(accounts[0], accounts[0], '/company'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); + const claimId = await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo4'); + await claims.confirmClaim(accounts[1], accounts[1], claimId); + const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1]); + expect(claimsForAccount).to.have.lengthOf(oldLength + 1); + expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Confirmed); + }); - it('can track the creation date', async() => { - const before = Date.now() / 1000; - await claims.setClaim(accounts[0], accounts[1], '/company'); - const after = Date.now() / 1000; - const claimsForAccount = await claims.getClaims('/company', accounts[1]); - const last = claimsForAccount.length - 1; - expect(claimsForAccount[last]).to.have.property('status', ClaimsStatus.Issued); - expect(claimsForAccount[last]).to.have.property('creationDate'); - expect(parseInt(claimsForAccount[last].creationDate, 10)).to.be.gte(before); - expect(parseInt(claimsForAccount[last].creationDate, 10)).to.be.lte(after); - }); + it('can reject a subclaim paths with the subject user', async () => { + await claims.setClaim(accounts[0], accounts[0], '/company'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); + const claimId = await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo6'); + await claims.deleteClaim(accounts[1], accounts[1], claimId); + const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo6', accounts[1]); + expect(claimsForAccount).to.have.lengthOf(0); + }); - it('can track the creation block', async() => { - const before = await web3.eth.getBlockNumber(); - await claims.setClaim(accounts[0], accounts[1], '/company'); - const after = await web3.eth.getBlockNumber(); - const claimsForAccount = await claims.getClaims('/company', accounts[1]); - const last = claimsForAccount.length - 1; - expect(claimsForAccount[last]).to.have.property('status', ClaimsStatus.Issued); - expect(claimsForAccount[last]).to.have.property('creationBlock'); - expect(parseInt(claimsForAccount[last].creationBlock, 10)).to.be.gte(before); - expect(parseInt(claimsForAccount[last].creationBlock, 10)).to.be.lte(after); - }); + it('can track the creation date', async() => { + const before = Date.now() / 1000; + await claims.setClaim(accounts[0], accounts[1], '/company'); + const after = Date.now() / 1000; + const claimsForAccount = await claims.getClaims('/company', accounts[1]); + const last = claimsForAccount.length - 1; + expect(claimsForAccount[last]).to.have.property('status', ClaimsStatus.Issued); + expect(claimsForAccount[last]).to.have.property('creationDate'); + expect(parseInt(claimsForAccount[last].creationDate, 10)).to.be.gte(before); + expect(parseInt(claimsForAccount[last].creationDate, 10)).to.be.lte(after); + }); - it('can add a description to a claim', async() => { - const sampleClaimsDomain = 'sample'; - const sampleClaimTopic = '/company'; - const sampleDescription = { - name: 'sample claim', - description: 'I\'m a sample claim', - author: 'evan.network', - version: '1.0.0', - dbcpVersion: 1, - }; - await claims.setClaimDescription(accounts[0], sampleClaimTopic, sampleClaimsDomain, sampleDescription); - await claims.setClaim(accounts[0], accounts[1], sampleClaimTopic, null, null, sampleClaimsDomain); - const claimsForAccount = await claims.getClaims(sampleClaimTopic, accounts[1]); - const last = claimsForAccount.length - 1; - expect(claimsForAccount[last]).to.have.property('status', ClaimsStatus.Issued); - expect(claimsForAccount[last]).to.have.property('creationBlock'); - expect(claimsForAccount[last].description).to.deep.eq(sampleDescription); - }); + it('can track the creation block', async() => { + const before = await web3.eth.getBlockNumber(); + await claims.setClaim(accounts[0], accounts[1], '/company'); + const after = await web3.eth.getBlockNumber(); + const claimsForAccount = await claims.getClaims('/company', accounts[1]); + const last = claimsForAccount.length - 1; + expect(claimsForAccount[last]).to.have.property('status', ClaimsStatus.Issued); + expect(claimsForAccount[last]).to.have.property('creationBlock'); + expect(parseInt(claimsForAccount[last].creationBlock, 10)).to.be.gte(before); + expect(parseInt(claimsForAccount[last].creationBlock, 10)).to.be.lte(after); + }); - it('can reject a claim', async () => { - const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1])).length; - await claims.setClaim(accounts[0], accounts[0], '/company'); - await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); - await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); - const claimId = await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo4'); - await claims.rejectClaim(accounts[1], '/company/b-s-s/employee/swo4', accounts[0], claimId); - const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1]); - expect(claimsForAccount).to.have.lengthOf(oldLength + 1); - expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Rejected); - }); + it('can add a description to a claim', async() => { + const sampleClaimsDomain = 'sample'; + const sampleClaimTopic = '/company'; + const sampleDescription = { + name: 'sample claim', + description: 'I\'m a sample claim', + author: 'evan.network', + version: '1.0.0', + dbcpVersion: 1, + }; + await claims.setClaimDescription(accounts[0], sampleClaimTopic, sampleClaimsDomain, sampleDescription); + await claims.setClaim(accounts[0], accounts[1], sampleClaimTopic, null, null, sampleClaimsDomain); + const claimsForAccount = await claims.getClaims(sampleClaimTopic, accounts[1]); + const last = claimsForAccount.length - 1; + expect(claimsForAccount[last]).to.have.property('status', ClaimsStatus.Issued); + expect(claimsForAccount[last]).to.have.property('creationBlock'); + expect(claimsForAccount[last].description).to.deep.eq(sampleDescription); + }); - it('can reject a claim with a reason', async () => { - const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1])).length; - await claims.setClaim(accounts[0], accounts[0], '/company'); - await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); - await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); - const claimId = await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo4'); - await claims.rejectClaim(accounts[1], '/company/b-s-s/employee/swo4', accounts[0], claimId, { reason: 'denied' }); - const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1]); - expect(claimsForAccount).to.have.lengthOf(oldLength + 1); - expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Rejected); - expect(claimsForAccount[oldLength]).to.have.deep.property('rejectReason', { reason: 'denied' }); - }); + it('can reject a claim', async () => { + const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1])).length; + await claims.setClaim(accounts[0], accounts[0], '/company'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); + const claimId = await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo4'); + await claims.rejectClaim(accounts[1], accounts[1], claimId); + const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1]); + expect(claimsForAccount).to.have.lengthOf(oldLength + 1); + expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Rejected); + }); + + it('can reject a claim with a reason', async () => { + const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1])).length; + await claims.setClaim(accounts[0], accounts[0], '/company'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); + const claimId = await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo4'); + await claims.rejectClaim(accounts[1], accounts[1], claimId, { reason: 'denied' }); + const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1]); + expect(claimsForAccount).to.have.lengthOf(oldLength + 1); + expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Rejected); + expect(claimsForAccount[oldLength]).to.have.deep.property('rejectReason', { reason: 'denied' }); + }); + + it('can reject a claim with a reason from the issuer side', async () => { + const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1])).length; + await claims.setClaim(accounts[0], accounts[0], '/company'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); + const claimId = await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo4'); + await claims.rejectClaim(accounts[1], accounts[0], claimId, { reason: 'denied' }); + const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1]); + expect(claimsForAccount).to.have.lengthOf(oldLength + 1); + expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Rejected); + expect(claimsForAccount[oldLength]).to.have.deep.property('rejectReason', { reason: 'denied' }); + }); - it('can reject a claim with a reason from the issuer side', async () => { - const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1])).length; - await claims.setClaim(accounts[0], accounts[0], '/company'); - await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); - await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); - const claimId = await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo4'); - await claims.rejectClaim(accounts[0], '/company/b-s-s/employee/swo4', accounts[0], claimId, { reason: 'denied' }); - const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1]); - expect(claimsForAccount).to.have.lengthOf(oldLength + 1); - expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Rejected); - expect(claimsForAccount[oldLength]).to.have.deep.property('rejectReason', { reason: 'denied' }); + it('can not re accept a rejected claim', async () => { + const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1])).length; + await claims.setClaim(accounts[0], accounts[0], '/company'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); + const claimId = await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo4'); + await claims.rejectClaim(accounts[1], accounts[1], claimId); + const reacceptedP = claims.confirmClaim(accounts[1], accounts[1], claimId); + await expect(reacceptedP).to.be.rejected; + }); }); - it('can not re accept a rejected claim', async () => { - const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1])).length; - await claims.setClaim(accounts[0], accounts[0], '/company'); - await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); - await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); - const claimId = await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo4'); - await claims.rejectClaim(accounts[1], '/company/b-s-s/employee/swo4', accounts[0], claimId); - const reacceptedP = claims.confirmClaim(accounts[1], '/company/b-s-s/employee/swo4', accounts[0], claimId); - await expect(reacceptedP).to.be.rejected; + describe('when using identities for contracts', () => { + let claimsRegistry; + let contractId; + + before(async () => { + claimsRegistry = await executor.createContract( + 'ClaimsRegistry', [], { from: accounts[2], gas: 8000000 }); + claims.contracts.registry = claimsRegistry; + }); + + it('can create a new identity for a contract', async() => { + const businessCenterDomain = nameResolver.getDomainName(config.nameResolver.domains.businessCenter); + contractId = await baseContract.createUninitialized( + 'testdatacontract', + accounts[0], + businessCenterDomain, + ); + await description.setDescriptionToContract( + contractId, + { + public: { + name: 'sample claim', + description: 'I\'m a sample claim', + author: 'evan.network', + version: '1.0.0', + dbcpVersion: 1, + }, + }, + accounts[0], + ); + const identity = await claims.createIdentity(accounts[0], contractId); + expect(identity).to.match(/0x[0-9-a-f]{64}/i); + }); + + it('can add a claim', async () => { + const oldLength = (await claims.getClaims('/company', contractId)).length; + await claims.setClaim(accounts[0], contractId, '/company'); + const claimsForAccount = await claims.getClaims('/company', contractId); + expect(claimsForAccount).to.have.lengthOf(oldLength + 1); + expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Issued); + }); + + it('can add a claim with specific data', async () => { + const oldLength = (await claims.getClaims('/company', contractId)).length; + await claims.setClaim(accounts[0], contractId, '/company', null, {foo: 'bar'}); + const claimsForAccount = await claims.getClaims('/company', contractId); + expect(claimsForAccount).to.have.lengthOf(oldLength + 1); + expect(claimsForAccount[oldLength]).to.have.property('uri', 'https://ipfs.evan.network/ipfs/Qmbjig3cZbUUufWqCEFzyCppqdnmQj3RoDjJWomnqYGy1f'); + }); + + it('can add a claim with specific expirationDate', async () => { + const oldLength = (await claims.getClaims('/company', contractId)).length; + const now = Math.floor(new Date().getTime() / 1000); + await claims.setClaim(accounts[0], contractId, '/company', now); + const claimsForAccount = await claims.getClaims('/company', contractId); + expect(claimsForAccount).to.have.lengthOf(oldLength + 1); + expect(claimsForAccount[oldLength]).to.have.property('expirationDate', now.toString()); + }); + + it('can add a claim and validate the integrity', async () => { + const oldLength = (await claims.getClaims('/company', contractId)).length; + await claims.setClaim(accounts[0], contractId, '/company'); + const claimsForAccount = await claims.getClaims('/company', contractId); + expect(claimsForAccount).to.have.lengthOf(oldLength + 1); + await claims.validateClaim(claimsForAccount[oldLength].id, contractId); + expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Issued); + }); + + it('can add subclaim paths and validate it', async () => { + const oldLength = (await claims.getClaims('/company', contractId)).length; + await claims.setClaim(accounts[0], accounts[0], '/company'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); + await claims.setClaim(accounts[0], contractId, '/company/b-s-s/employee/swo'); + const identity = await claims.getIdentityForAccount(contractId); + const claimTree = await claims.validateClaimTree('/company/b-s-s/employee/swo', identity); + expect(claimTree).to.have.lengthOf(4); + }); + + it('can add subclaim paths and don\'t have the needed root claims.', async () => { + const oldLength = (await claims.getClaims('/company', contractId)).length; + await claims.setClaim(accounts[0], accounts[0], '/company/evan/employee'); + await claims.setClaim(accounts[0], contractId, '/company/evan/employee/swo2'); + const identity = await claims.getIdentityForAccount(contractId); + const claimTree = await claims.validateClaimTree('/company/evan/employee/swo2', identity); + expect(claimTree).to.have.lengthOf(2); + }); + + it('can add subclaim paths', async () => { + const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo3', contractId)).length; + await claims.setClaim(accounts[0], accounts[0], '/company'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); + await claims.setClaim(accounts[0], contractId, '/company/b-s-s/employee/swo3'); + const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo3', contractId); + expect(claimsForAccount).to.have.lengthOf(1); + expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Issued); + }); + + it('can confirm a subclaim paths with the subject user', async () => { + const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', contractId)).length; + await claims.setClaim(accounts[0], accounts[0], '/company'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); + const claimId = await claims.setClaim(accounts[0], contractId, '/company/b-s-s/employee/swo4'); + await claims.confirmClaim(contractId, accounts[0], claimId); + const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo4', contractId); + expect(claimsForAccount).to.have.lengthOf(oldLength + 1); + expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Confirmed); + }); + + it('can reject a subclaim paths with the subject user', async () => { + await claims.setClaim(accounts[0], accounts[0], '/company'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); + const claimId = await claims.setClaim(accounts[0], contractId, '/company/b-s-s/employee/swo6'); + await claims.deleteClaim(contractId, accounts[0], claimId); + const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo6', contractId); + expect(claimsForAccount).to.have.lengthOf(0); + }); + + it('can track the creation date', async() => { + const before = Date.now() / 1000; + await claims.setClaim(accounts[0], contractId, '/company'); + const after = Date.now() / 1000; + const claimsForAccount = await claims.getClaims('/company', contractId); + const last = claimsForAccount.length - 1; + expect(claimsForAccount[last]).to.have.property('status', ClaimsStatus.Issued); + expect(claimsForAccount[last]).to.have.property('creationDate'); + expect(parseInt(claimsForAccount[last].creationDate, 10)).to.be.gte(before); + expect(parseInt(claimsForAccount[last].creationDate, 10)).to.be.lte(after); + }); + + it('can track the creation block', async() => { + const before = await web3.eth.getBlockNumber(); + await claims.setClaim(accounts[0], contractId, '/company'); + const after = await web3.eth.getBlockNumber(); + const claimsForAccount = await claims.getClaims('/company', contractId); + const last = claimsForAccount.length - 1; + expect(claimsForAccount[last]).to.have.property('status', ClaimsStatus.Issued); + expect(claimsForAccount[last]).to.have.property('creationBlock'); + expect(parseInt(claimsForAccount[last].creationBlock, 10)).to.be.gte(before); + expect(parseInt(claimsForAccount[last].creationBlock, 10)).to.be.lte(after); + }); + + it('can add a description to a claim', async() => { + const sampleClaimsDomain = 'sample'; + const sampleClaimTopic = '/company'; + const sampleDescription = { + name: 'sample claim', + description: 'I\'m a sample claim', + author: 'evan.network', + version: '1.0.0', + dbcpVersion: 1, + }; + await claims.setClaimDescription(accounts[0], sampleClaimTopic, sampleClaimsDomain, sampleDescription); + await claims.setClaim(accounts[0], contractId, sampleClaimTopic, null, null, sampleClaimsDomain); + const claimsForAccount = await claims.getClaims(sampleClaimTopic, contractId); + const last = claimsForAccount.length - 1; + expect(claimsForAccount[last]).to.have.property('status', ClaimsStatus.Issued); + expect(claimsForAccount[last]).to.have.property('creationBlock'); + expect(claimsForAccount[last].description).to.deep.eq(sampleDescription); + }); + + it('can reject a claim', async () => { + const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', contractId)).length; + await claims.setClaim(accounts[0], accounts[0], '/company'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); + const claimId = await claims.setClaim(accounts[0], contractId, '/company/b-s-s/employee/swo4'); + await claims.rejectClaim(contractId, accounts[0], claimId); + const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo4', contractId); + expect(claimsForAccount).to.have.lengthOf(oldLength + 1); + expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Rejected); + }); + + it('can reject a claim with a reason', async () => { + const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', contractId)).length; + await claims.setClaim(accounts[0], accounts[0], '/company'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); + const claimId = await claims.setClaim(accounts[0], contractId, '/company/b-s-s/employee/swo4'); + await claims.rejectClaim(contractId, accounts[0], claimId, { reason: 'denied' }); + const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo4', contractId); + expect(claimsForAccount).to.have.lengthOf(oldLength + 1); + expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Rejected); + expect(claimsForAccount[oldLength]).to.have.deep.property('rejectReason', { reason: 'denied' }); + }); + + it('can not re accept a rejected claim', async () => { + const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', contractId)).length; + await claims.setClaim(accounts[0], accounts[0], '/company'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); + const claimId = await claims.setClaim(accounts[0], contractId, '/company/b-s-s/employee/swo4'); + await claims.rejectClaim(contractId, accounts[0], claimId); + const reacceptedP = claims.confirmClaim(contractId, accounts[0], claimId); + await expect(reacceptedP).to.be.rejected; + }); + + it('cannot have other users approve claims of a contract of another user', async () => { + const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', contractId)).length; + await claims.setClaim(accounts[0], accounts[0], '/company'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); + await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); + const claimId = await claims.setClaim(accounts[0], contractId, '/company/b-s-s/employee/swo4'); + await expect(claims.confirmClaim(contractId, accounts[1], claimId)).to.be.rejected; + }); }); }); diff --git a/src/claims/claims.ts b/src/claims/claims.ts index 13942084..2629c370 100644 --- a/src/claims/claims.ts +++ b/src/claims/claims.ts @@ -79,9 +79,11 @@ export interface ClaimsOptions extends LoggerOptions { * @class Claims (name) */ export class Claims extends Logger { + cachedIdentities: any = { }; contracts: any = { }; encodingEnvelope = 'binary'; options: ClaimsOptions; + subjectTypes: any = { }; constructor(options: ClaimsOptions) { super(options); @@ -97,34 +99,17 @@ export class Claims extends Logger { * confirms a claim; this can be done, if a claim has been issued for a subject and the subject * wants to confirm it * - * @param {string} subject account, that approves the claim - * @param {string} claimName name of the claim (full path) - * @param {string} issuer The issuer which has signed the claim + * @param {string} subject claim subject + * @param {string} accountId account, that performs the action * @param {string} claimId id of a claim to confirm * @return {Promise} resolved when done */ public async confirmClaim( - subject: string, claimName: string, issuer: string, claimId: string): Promise { - await this.ensureStorage(); - - const identity = await this.options.executor.executeContractCall( - this.contracts.storage, - 'users', - subject - ); - - const issuerIdentity = await this.options.executor.executeContractCall( - this.contracts.storage, - 'users', - issuer - ); - - const identityContract = this.options.contractLoader.loadContract('OriginIdentity', identity); - const sha3ClaimId = claimId; - await this.options.executor.executeContractTransaction( - identityContract, + subject: string, accountId: string, claimId: string): Promise { + await this.executeOnIdentity( + subject, 'approveClaim', - { from: subject, }, + { from: accountId }, claimId, ); } @@ -135,22 +120,40 @@ export class Claims extends Logger { * @param {string} accountId The account identifier * @return {Promise} resolves when done */ - public async createIdentity(accountId: string): Promise { - await this.ensureStorage(); - - // create Identity contract - const identityContract = await this.options.executor.createContract( - 'OriginIdentity', [], { from: accountId, gas: 3000000, }); - - const identityStorage = this.contracts.storage.options.address !== nullAddress ? - this.options.contractLoader.loadContract('V00_UserRegistry', this.contracts.storage.options.address) : null; - // register the new user in the registry - await this.options.executor.executeContractTransaction( - identityStorage, - 'registerUser', - { from: accountId, }, - identityContract.options.address, - ); + public async createIdentity(accountId: string, contractId?: string): Promise { + let identity; + if (!contractId) { + // create Identity contract + await this.ensureStorage(); + const identityContract = await this.options.executor.createContract( + 'OriginIdentity', [], { from: accountId, gas: 3000000, }); + + const identityStorage = this.contracts.storage.options.address !== nullAddress ? + this.options.contractLoader.loadContract('V00_UserRegistry', this.contracts.storage.options.address) : null; + // register the new user in the registry + await this.options.executor.executeContractTransaction( + identityStorage, + 'registerUser', + { from: accountId, }, + identityContract.options.address, + ); + identity = identityContract.options.address; + } else { + identity = await this.options.executor.executeContractTransaction( + this.contracts.registry, + 'createIdentity', + { + from: accountId, + // event IdentityCreated(bytes32 indexed identity, address indexed owner); + event: { target: 'IdentityHolder', eventName: 'IdentityCreated' }, + getEventResult: (_, args) => args.identity, + }, + ); + const description = await this.options.description.getDescription(contractId, accountId); + description.public.identity = identity; + await this.options.description.setDescriptionToContract(contractId, description, accountId); + } + return identity; } /** @@ -159,112 +162,51 @@ export class Claims extends Logger { * the issuer as well. If not, they can only react to it by confirming or rejecting the claim. * * @param {string} subject the subject of the claim - * @param {string} claimName name of the claim (full path) - * @param {string} issuer issuer of the claim; only the issuer can delete a claim + * @param {string} accountId account, that performs the action * @param {string} claimId id of a claim to delete * @return {Promise} resolved when done */ public async deleteClaim( - subject: string, claimName: string, issuer: string, claimId: string): Promise { - await this.ensureStorage(); - - const identity = await this.options.executor.executeContractCall( - this.contracts.storage, - 'users', - subject - ); - - const issuerIdentity = await this.options.executor.executeContractCall( - this.contracts.storage, - 'users', - issuer - ); - - const identityContract = this.options.contractLoader.loadContract('OriginIdentity', identity); - await this.options.executor.executeContractTransaction( - identityContract, + subject: string, accountId: string, claimId: string): Promise { + await this.executeOnIdentity( + subject, 'removeClaim', - { from: subject, }, + { from: accountId }, claimId, ); } /** - * gets claim informations for a claim name from a given account; results has the following + * gets claim information for a claim name from a given account; results has the following * properties: creationBlock, creationDate, data, description, expirationDate, id, issuer, name, * signature, status, subject, topic, uri, valid * * @param {string} claimName name (/path) of a claim * @param {string} subject the target subject - * @param {boolean} isIdentity optional indicates if the subject is already a identity * @return {Promise} claim info array */ public async getClaims(claimName: string, subject: string, isIdentity?: boolean): Promise { - await this.ensureStorage(); - - // get the target identity contract for the subject - let identity = subject; - if (!isIdentity) { - identity = await this.options.executor.executeContractCall( - this.contracts.storage, - 'users', - subject - ); - - if (identity === nullAddress) { - const msg = `trying to get claim ${claimName} with account ${subject}, ` + - `but the idendity for account ${subject} does not exist`; - this.log(msg, 'error'); - throw new Error(msg); - } - } - - const identityContract = this.options.contractLoader.loadContract('OriginIdentity', identity); const sha3ClaimName = this.options.nameResolver.soliditySha3(claimName); const uint256ClaimName = new BigNumber(sha3ClaimName).toString(10); - const claimsForTopic = await this.options.executor.executeContractCall( - identityContract, + + const claimsForTopic = await this.callOnIdentity( + subject, + isIdentity, 'getClaimIdsByTopic', - uint256ClaimName + uint256ClaimName, ); const claims = await Promise.all(claimsForTopic.map(async (claimId) => { - const claimP = this.options.executor.executeContractCall( - identityContract, + const claimDetails = [ 'getClaim', - claimId - ); - const claimStatusP = this.options.executor.executeContractCall( - identityContract, 'isClaimApproved', - claimId - ); - const claimCreationBlockP = this.options.executor.executeContractCall( - identityContract, 'claimCreationBlock', - claimId - ); - const claimCreationP = this.options.executor.executeContractCall( - identityContract, 'claimCreationDate', - claimId - ); - const claimexpirationDateP = this.options.executor.executeContractCall( - identityContract, 'getClaimExpirationDate', - claimId - ); - const claimrejectedP = this.options.executor.executeContractCall( - identityContract, 'isClaimRejected', - claimId - ); - const claimDescriptionP = (async () => { - const descriptionNodeHash = await this.options.executor.executeContractCall( - identityContract, - 'getClaimDescription', - claimId - ); + ].map(fun => this.callOnIdentity(subject, isIdentity, fun, claimId)); + claimDetails.push((async () => { + const descriptionNodeHash = await this.callOnIdentity(subject, isIdentity, 'getClaimDescription', claimId); let parsedDescription; if (descriptionNodeHash === nullBytes32) { return null; @@ -282,25 +224,10 @@ export class Claims extends Logger { return JSON.parse(envelope).public; } } - })(); - let [ - claim, - claimStatus, - creationBlock, - creationDate, - expirationDate, - description, - rejected, - ] = await Promise.all([ - claimP, - claimStatusP, - claimCreationBlockP, - claimCreationP, - claimexpirationDateP, - claimDescriptionP, - claimrejectedP - ]) - ; + })()); + + let [claim, claimStatus, creationBlock, creationDate, expirationDate, rejected, description] = + await Promise.all(claimDetails); if (claim.issuer === nullAddress) { return false; @@ -308,11 +235,11 @@ export class Claims extends Logger { let claimFlag = claimStatus ? ClaimsStatus.Confirmed : ClaimsStatus.Issued; let rejectReason; - if(rejected.rejected) { + if (rejected.rejected) { claimFlag = ClaimsStatus.Rejected; } - if(rejected.rejectReason !== nullBytes32) { + if (rejected.rejectReason !== nullBytes32) { try { const ipfsResponse = await this.options.dfs.get(rejected.rejectReason); rejectReason = JSON.parse(ipfsResponse.toString()); @@ -353,22 +280,25 @@ export class Claims extends Logger { * @return {Promise} the identity contract instance */ public async getIdentityForAccount(subject: string) { - await this.ensureStorage(); + if (!this.cachedIdentities[subject]) { + await this.ensureStorage(); - // get the target identity contract for the subject - const targetIdentity = await this.options.executor.executeContractCall( - this.contracts.storage, - 'users', - subject - ); - // check if target identity exists - if (!targetIdentity) { - const msg = `target identity for account ${subject} does not exist`; - this.log(msg, 'error'); - throw new Error(msg); - } + // get the target identity contract for the subject + const targetIdentity = await this.options.executor.executeContractCall( + this.contracts.storage, + 'users', + subject, + ); + // check if target identity exists + if (subject === nullAddress) { + const msg = `target identity for account ${subject} does not exist`; + this.log(msg, 'error'); + throw new Error(msg); + } - return this.options.contractLoader.loadContract('OriginIdentity', targetIdentity); + this.cachedIdentities[subject] = this.options.contractLoader.loadContract('OriginIdentity', targetIdentity); + } + return this.cachedIdentities[subject]; } /** @@ -399,31 +329,13 @@ export class Claims extends Logger { * wants to confirm it * * @param {string} subject account, that rejects the claim - * @param {string} claimName name of the claim (full path) - * @param {string} issuer The issuer which has signed the claim - * @param {string} claimId id of a claim to confirm + * @param {string} accountId account, that performs the action + * @param {string} claimId id of a claim to reject * @param {any} rejectReason (optional) rejectReason object * @return {Promise} resolved when done */ public async rejectClaim( - subject: string, claimName: string, issuer: string, claimId: string, rejectReason?: any): Promise { - await this.ensureStorage(); - - const identity = await this.options.executor.executeContractCall( - this.contracts.storage, - 'users', - subject - ); - - const issuerIdentity = await this.options.executor.executeContractCall( - this.contracts.storage, - 'users', - issuer - ); - - const identityContract = this.options.contractLoader.loadContract('OriginIdentity', identity); - const sha3ClaimId = claimId; - + subject: string, accountId: string, claimId: string, rejectReason?: any): Promise { if (rejectReason) { try { const stringified = JSON.stringify(rejectReason); @@ -437,12 +349,12 @@ export class Claims extends Logger { rejectReason = nullBytes32; } - await this.options.executor.executeContractTransaction( - identityContract, + await this.executeOnIdentity( + subject, 'rejectClaim', - { from: subject, }, + { from: accountId }, claimId, - rejectReason + rejectReason, ); } @@ -471,13 +383,17 @@ export class Claims extends Logger { descriptionDomain?: string, ): Promise { await this.ensureStorage(); - - // get the target identity contract for the subject - const targetIdentity = await this.options.executor.executeContractCall( - this.contracts.storage, - 'users', - subject - ); + let targetIdentity; + const subjectType = await this.getSubjectType(subject); + if (subjectType === 'contract') { + targetIdentity = (await this.options.description.getDescription(subject, issuer)).public.identity; + } else { + targetIdentity = await this.options.executor.executeContractCall( + this.contracts.storage, + 'users', + subject + ); + } // get the issuer identity contract const sourceIdentity = await this.options.executor.executeContractCall( this.contracts.storage, @@ -487,12 +403,11 @@ export class Claims extends Logger { // check if target and source identity are existing if (!targetIdentity || targetIdentity === nullAddress) { const msg = `trying to set claim ${claimName} with account ${issuer}, ` + - `but target idendity for account ${subject} does not exist`; + `but target identity for account ${subject} does not exist`; this.log(msg, 'error'); throw new Error(msg); } - const identityContract = this.options.contractLoader.loadContract('OriginIdentity', targetIdentity); // convert the claim name to a uint256 const sha3ClaimName = this.options.nameResolver.soliditySha3(claimName); const uint256ClaimName = new BigNumber(sha3ClaimName).toString(10); @@ -525,12 +440,15 @@ export class Claims extends Logger { } // add the claim to the target identity - return await this.options.executor.executeContractTransaction( - identityContract, + return await this.executeOnIdentity( + subject, 'addClaimWithMetadata', { from: issuer, - event: { target: 'ClaimHolderLibrary', eventName: 'ClaimAdded' }, + event: { + target: subjectType === 'contract' ? 'ClaimsRegistryLibrary' : 'ClaimHolderLibrary', + eventName: 'ClaimAdded', + }, getEventResult: (_, args) => { return args.claimId; }, }, uint256ClaimName, @@ -555,14 +473,14 @@ export class Claims extends Logger { * @param {any} description description of the claim; can be an Envelope but * only public properties are used * @return {Promise} resolved when done - */ - public async setClaimDescription(accountId: string, topic: string, domain: string, description: any) { - let toSet = JSON.parse(JSON.stringify(description)); - if (!toSet.hasOwnProperty('public')) { - toSet = { public: toSet }; - } - const domainWithHash = this.getFullDescriptionDomainWithHash(topic, domain); - await this.options.description.setDescription(domainWithHash, toSet, accountId); + */ + public async setClaimDescription(accountId: string, topic: string, domain: string, description: any) { + let toSet = JSON.parse(JSON.stringify(description)); + if (!toSet.hasOwnProperty('public')) { + toSet = { public: toSet }; + } + const domainWithHash = this.getFullDescriptionDomainWithHash(topic, domain); + await this.options.description.setDescription(domainWithHash, toSet, accountId); } /** @@ -577,26 +495,14 @@ export class Claims extends Logger { public async validateClaim(claimId: string, subject: string, isIdentity?: boolean) { await this.ensureStorage(); - let subjectIdentity = subject; - if (!isIdentity) { - // get the target identity contract for the subject - subjectIdentity = await this.options.executor.executeContractCall( - this.contracts.storage, - 'users', - subject - ); - - // check if target and source identity are existing - if (!subjectIdentity) { - const msg = `target idendity for account ${subject} does not exist`; - this.log(msg, 'error'); - throw new Error(msg); - } + let subjectIdentity = isIdentity ? subject : await this.getIdentityForAccount(subject); + if (subjectIdentity.options) { + subjectIdentity = subjectIdentity.options.address; } - const identityContract = this.options.contractLoader.loadContract('OriginIdentity', subjectIdentity); - const claim = await this.options.executor.executeContractCall( - identityContract, + const claim = await this.callOnIdentity( + subject, + isIdentity, 'getClaim', claimId ); @@ -639,6 +545,72 @@ export class Claims extends Logger { return treeArr; } + /** + * execute contract call on identity, checks if account or contract identity is used and if given + * subject is alraedy an identity + * + * @param {string} subject account/contract with identity or an identity of it + * @param {boolean} isIdentity true if given subject is an identity + * @param {string} fun function to call + * @param {any[]} args arguments for function (exluding the identity (for + * ClaimsRegistry functions)) + * @return {Promise} result of called function + */ + private async callOnIdentity(subject: string, isIdentity: boolean, fun: string, ...args): Promise { + const subjectType = await this.getSubjectType(subject, isIdentity); + if (subjectType === 'contract') { + // contract identity + return this.options.executor.executeContractCall( + this.contracts.registry, + fun, + isIdentity ? subject : await this.getIdentityForAccount(subject), + ...args, + ); + } else if (subjectType === 'account') { + // account identity + return this.options.executor.executeContractCall( + isIdentity ? + this.options.contractLoader.loadContract('OriginIdentity', subject) : + await this.getIdentityForAccount(subject), + fun, + ...args, + ); + } + } + + /** + * execute contract transaction on identity, checks if account or contract identity is used and if + * given subject is alraedy an identity + * + * @param {string} subject account/contract with identity or an identity of it + * @param {string} fun function to call + * @param {any} options options for transaction + * @param {any[]} args arguments for function (exluding the identity (for + * ClaimsRegistry functions)) + * @return {Promise} result of called function + */ + private async executeOnIdentity(subject: string, fun: string, options: any, ...args): Promise { + const subjectType = await this.getSubjectType(subject, false); + if (subjectType === 'contract') { + // contract identity + return this.options.executor.executeContractTransaction( + this.contracts.registry, + fun, + options, + await this.getIdentityForAccount(subject), + ...args, + ); + } else if (subjectType === 'account') { + // account identity + return this.options.executor.executeContractTransaction( + await this.getIdentityForAccount(subject), + fun, + options, + ...args, + ); + } + } + /** * Checks if a storage was initialized before, if not, load the default one. * @@ -654,13 +626,47 @@ export class Claims extends Logger { } } - private getFullDescriptionDomainWithHash(topic: string, descriptionDomain: string) { - return `${this.options.nameResolver.soliditySha3(topic).substr(2)}.${descriptionDomain}.claims.evan`; + /** + * checks if given given subject belongs to an account to a contract + * + * @param {string} subject claim subject + * @param {boolean} isIdentity true if given subject is an identity + * @return {Promise} resolves to 'account' or 'contract' + */ + private async getSubjectType(subject: string, isIdentity?: boolean): Promise { + if (isIdentity && subject.length === 66) { + return 'contract'; + } else if (isIdentity && subject.length === 42) { + return 'account'; + } else if (!this.subjectTypes[subject]) { + const targetIdentity = await this.options.executor.executeContractCall( + this.contracts.storage, + 'users', + subject, + ); + if (targetIdentity !== nullAddress) { + this.subjectTypes[subject] = 'account'; + } else { + const description = await this.options.description.getDescription(subject, null); + if (description && description.public && description.public.identity) { + this.subjectTypes[subject] = 'contract'; + this.cachedIdentities[subject] = description.public.identity; + } else { + throw new Error(`could not find identity for "${subject}"`); + } + } + } + return this.subjectTypes[subject]; } - private loadContracts(storage) { - this.contracts = { - storage: this.options.contractLoader.loadContract('V00_UserRegistry', storage), - }; + /** + * returns full domain for description + * + * @param {string} topic claim topic + * @param {string} descriptionDomain domain of description + * @return {string} full domain + */ + private getFullDescriptionDomainWithHash(topic: string, descriptionDomain: string): string { + return `${this.options.nameResolver.soliditySha3(topic).substr(2)}.${descriptionDomain}.claims.evan`; } } diff --git a/src/test/test-utils.ts b/src/test/test-utils.ts index 8c32bc8c..a7c703e7 100644 --- a/src/test/test-utils.ts +++ b/src/test/test-utils.ts @@ -113,8 +113,11 @@ export class TestUtils { } static async getBaseContract(web3): Promise { + const eventHub = await this.getEventHub(web3); + const executor = await this.getExecutor(web3); + executor.eventHub = eventHub; return new BaseContract({ - executor: await TestUtils.getExecutor(web3), + executor, loader: await TestUtils.getContractLoader(web3), log: Logger.getDefaultLog(), nameResolver: await TestUtils.getNameResolver(web3), From e56d1bbb6054dff5143ca2a047f535b0e3c2c03b Mon Sep 17 00:00:00 2001 From: wulfraem Date: Tue, 18 Dec 2018 11:09:16 +0100 Subject: [PATCH 07/22] update docu for claims --- docs/profile/claims.rst | 50 +++++++++++++++++++---------------------- src/claims/claims.ts | 43 ++++++++++++++++++++--------------- 2 files changed, 48 insertions(+), 45 deletions(-) diff --git a/docs/profile/claims.rst b/docs/profile/claims.rst index 1dacc632..ecf3dff8 100644 --- a/docs/profile/claims.rst +++ b/docs/profile/claims.rst @@ -129,9 +129,9 @@ createIdentity .. code-block:: typescript - claims.createIdentity(accountId); + claims.createIdentity(accountId[, contractId]); -Creates a new identity for Account and registers them on the storage +Creates a new identity for account or contract and registers them on the storage. Returned identity is either a 40B contract address (for account identities) or a 32B idenity hash contract identities. ---------- Parameters @@ -151,7 +151,7 @@ Example .. code-block:: typescript - await claims.createIdentity(accounts[0]); + const identity = await claims.createIdentity(accounts[0]); @@ -165,7 +165,7 @@ identityAvailable claims.identityAvailable(subject); -Checks if a account has already a identity contract. +Checks if a account has already an identity contract. ---------- Parameters @@ -208,7 +208,7 @@ getIdentityForAccount claims.getIdentityForAccount(subject); -Gets the identity contract for a given account id. +Gets the identity contract for a given account id or contract. ---------- Parameters @@ -243,8 +243,7 @@ setClaim claims.setClaim(issuer, subject, claimName[, expirationDate, claimValue, descriptionDomain]); -Sets or creates a claim; this requires the issuer to have permissions for the parent claim (if claim -name seen as a path, the parent 'folder'). +Sets or creates a claim; this requires the issuer to have permissions for the parent claim (if claim name seen as a path, the parent 'folder'). ---------- Parameters @@ -287,9 +286,9 @@ getClaims .. code-block:: typescript - claims.getClaims(claimName, subject, isIdentity); + claims.getClaims(claimName, subject[, isIdentity]); -gets claim informations for a claim name from a given account +Gets claim information for a claim name from a given account; results has the following properties: creationBlock, creationDate, data, description, expirationDate, id, issuer, name, signature, status, subject, topic, uri, valid. ---------- Parameters @@ -297,13 +296,13 @@ Parameters #. ``claimName`` - ``string``: name (/path) of a claim #. ``subject`` - ``string``: subject of the claims -#. ``isIdentity`` - ``string`` (optional): indicates if the subject is already a identity address +#. ``isIdentity`` - ``string`` (optional): indicates if the subject is already an identity ------- Returns ------- -``Promise`` returns ``any``: claim info array, contains: issuer, name, status, subject, data, uri, signature, creationDate +``Promise`` returns ``any[]``: claim info array, contains: issuer, name, status, subject, data, uri, signature, creationDate ------- Example @@ -487,17 +486,16 @@ deleteClaim .. code-block:: typescript - claims.deleteClaim(subject, claimName, issuer); + claims.deleteClaim(subject, accountId, claimId); -Delete a claim. This requires the **issuer** to have permissions for the parent claim (if claim name seen as a path, the parent 'folder'). Subjects of a claim may only delete it, if they are the issuer as well. If not, they can only react to it by confirming or rejecting the claim. +Delete a claim. This requires the **accountId** to have permissions for the parent claim (if claim name seen as a path, the parent 'folder'). Subjects of a claim may only delete it, if they are the issuer as well. If not, they can only react to it by confirming or rejecting the claim. ---------- Parameters ---------- #. ``subject`` - ``string``: the subject of the claim -#. ``claimName`` - ``string``: name of the claim (full path) -#. ``issuer`` - ``string``: issuer of the claim +#. ``accountid`` - ``string``: account, that performs the action #. ``claimId`` - ``string``: id of a claim to delete ------- @@ -512,8 +510,8 @@ Example .. code-block:: typescript - await claims.setClaim(accounts[0], accounts[1], '/company'); - await claims.deleteClaim(accounts[0], '/company', accounts[1]); + const claimId = await claims.setClaim(accounts[0], accounts[1], '/company'); + await claims.deleteClaim(accounts[1], accounts[0], claimId); @@ -535,8 +533,7 @@ Parameters ---------- #. ``subject`` - ``string``: the subject of the claim -#. ``claimName`` - ``string``: name of the claim (full path) -#. ``issuer`` - ``string``: issuer of the claim +#. ``accountid`` - ``string``: account, that performs the action #. ``claimId`` - ``string``: id of a claim to delete #. ``rejectReason`` - ``object`` (optional): JSON Object of the rejection reason @@ -552,8 +549,8 @@ Example .. code-block:: typescript - await claims.setClaim(accounts[0], accounts[1], '/company'); - await claims.rejectClaim(accounts[0], '/company', accounts[1], { rejected: "because not valid anymore"}); + const claimId = await claims.setClaim(accounts[0], accounts[1], '/company'); + await claims.rejectClaim(accounts[1], accounts[0], claimId, { rejected: "because not valid anymore"}); @@ -572,17 +569,16 @@ confirmClaim .. code-block:: typescript - claims.confirmClaim(subject, claimName[, claimValue]); + claims.confirmClaim(subject, accountId, claimId); -Confirms a claim; this can be done, it a claim has been issued for a subject and the subject wants to confirms it. +Confirms a claim; this can be done, if a claim has been issued for a subject and the subject wants to confirms it. ---------- Parameters ---------- -#. ``subject`` - ``string``: account, that approves the claim -#. ``claimName`` - ``string``: name of the claim (full path) -#. ``issuer`` - ``string``: The issuer which has signed the claim +#. ``subject`` - ``string``: claim subject +#. ``accointId`` - ``string``: account, that performs the action #. ``claimId`` - ``string``: id of a claim to confirm ------- @@ -598,7 +594,7 @@ Example .. code-block:: typescript const newClaim = await claims.setClaim(accounts[0], accounts[1], '/company'); - await claims.confirmClaim(accounts[1], '/company', accounts[0], newClaim); + await claims.confirmClaim(accounts[1], accounts[0], newClaim); diff --git a/src/claims/claims.ts b/src/claims/claims.ts index 2629c370..6e542efe 100644 --- a/src/claims/claims.ts +++ b/src/claims/claims.ts @@ -115,10 +115,13 @@ export class Claims extends Logger { } /** - * Creates a new identity for an account + * Creates a new identity for account or contract and registers them on the storage. Returned + * identity is either a 40B contract address (for account identities) or a 32B idenity hash + * contract identities * - * @param {string} accountId The account identifier - * @return {Promise} resolves when done + * @param {string} accountId The account identifier + * @param {} contractId The contract identifier + * @return {Promise} new identity */ public async createIdentity(accountId: string, contractId?: string): Promise { let identity; @@ -157,7 +160,7 @@ export class Claims extends Logger { } /** - * delete a claim. This requires the issuer to have permissions for the parent claim (if claim + * delete a claim. This requires the accountId to have permissions for the parent claim (if claim * name seen as a path, the parent 'folder'). Subjects of a claim may only delete it, if they are * the issuer as well. If not, they can only react to it by confirming or rejecting the claim. * @@ -182,10 +185,11 @@ export class Claims extends Logger { * signature, status, subject, topic, uri, valid * * @param {string} claimName name (/path) of a claim - * @param {string} subject the target subject - * @return {Promise} claim info array + * @param {string} subject subject of the claims + * @param {boolean} isIdentity (optional) indicates if the subject is already an identity + * @return {Promise} claim info array */ - public async getClaims(claimName: string, subject: string, isIdentity?: boolean): Promise { + public async getClaims(claimName: string, subject: string, isIdentity?: boolean): Promise { const sha3ClaimName = this.options.nameResolver.soliditySha3(claimName); const uint256ClaimName = new BigNumber(sha3ClaimName).toString(10); @@ -268,18 +272,17 @@ export class Claims extends Logger { }; })); - return claims.filter(function (el) { - return el; - }); + // drop null values + return claims.filter(el => el); } /** - * gets the identity contract for a given account id + * gets the identity contract for a given account id or contract * * @param {string} subject the subject for the identity contract * @return {Promise} the identity contract instance */ - public async getIdentityForAccount(subject: string) { + public async getIdentityForAccount(subject: string): Promise { if (!this.cachedIdentities[subject]) { await this.ensureStorage(); @@ -325,8 +328,9 @@ export class Claims extends Logger { } /** - * rejects a claim; this can be done, if a claim has been issued for a subject and the subject - * wants to confirm it + * reject a Claim. This claim will be marked as rejected but not deleted. This is important for + * tracking reasons. You can also optionally add a reject reason as JSON object to track + * additional informations about the rejection. Issuer and Subject can reject a special claim. * * @param {string} subject account, that rejects the claim * @param {string} accountId account, that performs the action @@ -359,7 +363,8 @@ export class Claims extends Logger { } /** - * sets or creates a claim to a given subject identity + * Sets or creates a claim; this requires the issuer to have permissions for the parent claim (if + * claim name seen as a path, the parent 'folder'). * * @param {string} issuer issuer of the claim * @param {string} subject subject of the claim and the owner of the @@ -474,7 +479,8 @@ export class Claims extends Logger { * only public properties are used * @return {Promise} resolved when done */ - public async setClaimDescription(accountId: string, topic: string, domain: string, description: any) { + public async setClaimDescription( + accountId: string, topic: string, domain: string, description: any): Promise { let toSet = JSON.parse(JSON.stringify(description)); if (!toSet.hasOwnProperty('public')) { toSet = { public: toSet }; @@ -492,7 +498,8 @@ export class Claims extends Logger { * identity * @return {Promise} resolves with true if the claim is valid, otherwise false */ - public async validateClaim(claimId: string, subject: string, isIdentity?: boolean) { + public async validateClaim( + claimId: string, subject: string, isIdentity?: boolean): Promise { await this.ensureStorage(); let subjectIdentity = isIdentity ? subject : await this.getIdentityForAccount(subject); @@ -520,7 +527,7 @@ export class Claims extends Logger { } /** - * validates a whole claim tree if the path is valid (called recursive) + * validates a whole claim tree if the path is valid (called recursively) * * @param {string} claimLabel claim topic of a claim to build the tree for * @param {string} subject subject of the claim and the owner of the claim node From d30a2ad54bf378ba6dd6c4d6fd6020533142c8a8 Mon Sep 17 00:00:00 2001 From: wulfraem Date: Tue, 18 Dec 2018 13:41:24 +0100 Subject: [PATCH 08/22] update claims function argument order --- docs/profile/claims.rst | 38 ++++++------ src/claims/claims.spec.ts | 126 +++++++++++++++++++------------------- src/claims/claims.ts | 30 ++++----- 3 files changed, 97 insertions(+), 97 deletions(-) diff --git a/docs/profile/claims.rst b/docs/profile/claims.rst index ecf3dff8..0b78ab93 100644 --- a/docs/profile/claims.rst +++ b/docs/profile/claims.rst @@ -286,7 +286,7 @@ getClaims .. code-block:: typescript - claims.getClaims(claimName, subject[, isIdentity]); + claims.getClaims(subject, claimName[, isIdentity]); Gets claim information for a claim name from a given account; results has the following properties: creationBlock, creationDate, data, description, expirationDate, id, issuer, name, signature, status, subject, topic, uri, valid. @@ -294,8 +294,8 @@ Gets claim information for a claim name from a given account; results has the fo Parameters ---------- -#. ``claimName`` - ``string``: name (/path) of a claim #. ``subject`` - ``string``: subject of the claims +#. ``claimName`` - ``string``: name (/path) of a claim #. ``isIdentity`` - ``string`` (optional): indicates if the subject is already an identity ------- @@ -311,7 +311,7 @@ Example .. code-block:: typescript await claims.setClaim(accounts[0], accounts[1], '/company'); - console.dir(await claims.getClaims('/company', accounts[1])); + console.dir(await claims.getClaims(accounts[1], '/company')); // Output: [{ creationDate: 1234567890, @@ -387,7 +387,7 @@ validateClaim .. code-block:: typescript - claims.validateClaim(claimId, subject); + claims.validateClaim(subject, claimId[, isIdentity]); validates a given claimId in case of integrity @@ -395,8 +395,8 @@ validates a given claimId in case of integrity Parameters ---------- -#. ``claimId`` - ``string``: The claim identifier #. ``subject`` - ``string``: subject of the claims +#. ``claimId`` - ``string``: The claim identifier #. ``isIdentity`` - ``boolean`` (optional): indicates if the subject is already an identity, defaults to ``false`` ------- @@ -412,8 +412,8 @@ Example .. code-block:: typescript console.dir(await claims.validateClaim( - '0x0000000000000000000000000000000000000000000000000000000000000000', accounts[1]), + '0x0000000000000000000000000000000000000000000000000000000000000000', ); // Output: true @@ -429,7 +429,7 @@ validateClaimTree .. code-block:: typescript - claims.validateClaimTree(claimLabel, subject, treeArr); + claims.validateClaimTree(subject, claimLabel, treeArr); validates a whole claim tree if the path is valid (called recursively) @@ -437,8 +437,8 @@ validates a whole claim tree if the path is valid (called recursively) Parameters ---------- -#. ``claimLabel`` - ``string``: claim topic of a claim to build the tree for #. ``subject`` - ``string``: subject of the claims +#. ``claimLabel`` - ``string``: claim topic of a claim to build the tree for #. ``treeArr`` - ``array`` (optional): result tree array, used for recursion, defaults to ``[]`` ------- @@ -453,7 +453,7 @@ Example .. code-block:: typescript - console.dir(await claims.validateClaimTree('/company/test/foo', accounts[1])); + console.dir(await claims.validateClaimTree(accounts[1], '/company/test/foo')); // Output: [{ issuer: '0x0000000000000000000000000000000000000001', name: '/company/test/foo', @@ -486,7 +486,7 @@ deleteClaim .. code-block:: typescript - claims.deleteClaim(subject, accountId, claimId); + claims.deleteClaim(accountId, subject, claimId); Delete a claim. This requires the **accountId** to have permissions for the parent claim (if claim name seen as a path, the parent 'folder'). Subjects of a claim may only delete it, if they are the issuer as well. If not, they can only react to it by confirming or rejecting the claim. @@ -494,8 +494,8 @@ Delete a claim. This requires the **accountId** to have permissions for the pare Parameters ---------- -#. ``subject`` - ``string``: the subject of the claim #. ``accountid`` - ``string``: account, that performs the action +#. ``subject`` - ``string``: the subject of the claim #. ``claimId`` - ``string``: id of a claim to delete ------- @@ -511,7 +511,7 @@ Example .. code-block:: typescript const claimId = await claims.setClaim(accounts[0], accounts[1], '/company'); - await claims.deleteClaim(accounts[1], accounts[0], claimId); + await claims.deleteClaim(accounts[0], accounts[1], claimId); @@ -524,7 +524,7 @@ rejectClaim .. code-block:: typescript - claims.rejectClaim(subject, claimName, issuer, claimId, rejectReason?); + claims.rejectClaim(accountId, subject, claimId, rejectReason?); Reject a Claim. This claim will be marked as rejected but not deleted. This is important for tracking reasons. You can also optionally add a reject reason as JSON object to track additional informations about the rejection. Issuer and Subject can reject a special claim. @@ -532,8 +532,8 @@ Reject a Claim. This claim will be marked as rejected but not deleted. This is i Parameters ---------- -#. ``subject`` - ``string``: the subject of the claim #. ``accountid`` - ``string``: account, that performs the action +#. ``subject`` - ``string``: the subject of the claim #. ``claimId`` - ``string``: id of a claim to delete #. ``rejectReason`` - ``object`` (optional): JSON Object of the rejection reason @@ -550,7 +550,7 @@ Example .. code-block:: typescript const claimId = await claims.setClaim(accounts[0], accounts[1], '/company'); - await claims.rejectClaim(accounts[1], accounts[0], claimId, { rejected: "because not valid anymore"}); + await claims.rejectClaim(accounts[0], accounts[1], claimId, { rejected: "because not valid anymore"}); @@ -569,7 +569,7 @@ confirmClaim .. code-block:: typescript - claims.confirmClaim(subject, accountId, claimId); + claims.confirmClaim(accountId, subject, claimId); Confirms a claim; this can be done, if a claim has been issued for a subject and the subject wants to confirms it. @@ -577,8 +577,8 @@ Confirms a claim; this can be done, if a claim has been issued for a subject and Parameters ---------- +#. ``accountId`` - ``string``: account, that performs the action #. ``subject`` - ``string``: claim subject -#. ``accointId`` - ``string``: account, that performs the action #. ``claimId`` - ``string``: id of a claim to confirm ------- @@ -594,7 +594,7 @@ Example .. code-block:: typescript const newClaim = await claims.setClaim(accounts[0], accounts[1], '/company'); - await claims.confirmClaim(accounts[1], accounts[0], newClaim); + await claims.confirmClaim(accounts[0], accounts[1], newClaim); @@ -659,7 +659,7 @@ Example }; await claims.setClaimDescription(accounts[0], sampleClaimTopic, sampleClaimsDomain, sampleDescription); await claims.setClaim(accounts[0], accounts[1], sampleClaimTopic, null, null, sampleClaimsDomain); - const claimsForAccount = await claims.getClaims(sampleClaimTopic, accounts[1]); + const claimsForAccount = await claims.getClaims(accounts[1], sampleClaimTopic); const last = claimsForAccount.length - 1; console.dir(claimsForAccount[last].description); // Output: diff --git a/src/claims/claims.spec.ts b/src/claims/claims.spec.ts index c016f5e0..70eafe5e 100644 --- a/src/claims/claims.spec.ts +++ b/src/claims/claims.spec.ts @@ -106,78 +106,78 @@ describe('Claims handler', function() { describe('when using external account based identities', () => { it('can add a claim', async () => { - const oldLength = (await claims.getClaims('/company', accounts[1])).length; + const oldLength = (await claims.getClaims(accounts[1], '/company')).length; await claims.setClaim(accounts[0], accounts[1], '/company'); - const claimsForAccount = await claims.getClaims('/company', accounts[1]); + const claimsForAccount = await claims.getClaims(accounts[1], '/company'); expect(claimsForAccount).to.have.lengthOf(oldLength + 1); expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Issued); }); it('can add a claim with specific data', async () => { - const oldLength = (await claims.getClaims('/company', accounts[1])).length; + const oldLength = (await claims.getClaims(accounts[1], '/company')).length; await claims.setClaim(accounts[0], accounts[1], '/company', null, {foo: 'bar'}); - const claimsForAccount = await claims.getClaims('/company', accounts[1]); + const claimsForAccount = await claims.getClaims(accounts[1], '/company'); expect(claimsForAccount).to.have.lengthOf(oldLength + 1); expect(claimsForAccount[oldLength]).to.have.property('uri', 'https://ipfs.evan.network/ipfs/Qmbjig3cZbUUufWqCEFzyCppqdnmQj3RoDjJWomnqYGy1f'); }); it('can add a claim with specific expirationDate', async () => { - const oldLength = (await claims.getClaims('/company', accounts[1])).length; + const oldLength = (await claims.getClaims(accounts[1], '/company')).length; const now = Math.floor(new Date().getTime() / 1000); await claims.setClaim(accounts[0], accounts[1], '/company', now); - const claimsForAccount = await claims.getClaims('/company', accounts[1]); + const claimsForAccount = await claims.getClaims(accounts[1], '/company'); expect(claimsForAccount).to.have.lengthOf(oldLength + 1); expect(claimsForAccount[oldLength]).to.have.property('expirationDate', now.toString()); }); it('can add a claim and validate the integrity', async () => { - const oldLength = (await claims.getClaims('/company', accounts[1])).length; + const oldLength = (await claims.getClaims(accounts[1], '/company')).length; await claims.setClaim(accounts[0], accounts[1], '/company'); - const claimsForAccount = await claims.getClaims('/company', accounts[1]); + const claimsForAccount = await claims.getClaims(accounts[1], '/company'); expect(claimsForAccount).to.have.lengthOf(oldLength + 1); - await claims.validateClaim(claimsForAccount[oldLength].id, accounts[1]); + await claims.validateClaim(accounts[1], claimsForAccount[oldLength].id); expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Issued); }); it('can add subclaim paths and validate it', async () => { - const oldLength = (await claims.getClaims('/company', accounts[1])).length; + const oldLength = (await claims.getClaims(accounts[1], '/company')).length; await claims.setClaim(accounts[0], accounts[0], '/company'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo'); const identity = await claims.getIdentityForAccount(accounts[1]); - const claimTree = await claims.validateClaimTree('/company/b-s-s/employee/swo', identity.options.address); + const claimTree = await claims.validateClaimTree(identity.options.address, '/company/b-s-s/employee/swo'); expect(claimTree).to.have.lengthOf(4); }); it('can add subclaim paths and don\'t have the needed root claims.', async () => { - const oldLength = (await claims.getClaims('/company', accounts[1])).length; + const oldLength = (await claims.getClaims(accounts[1], '/company')).length; await claims.setClaim(accounts[0], accounts[0], '/company/evan/employee'); await claims.setClaim(accounts[0], accounts[1], '/company/evan/employee/swo2'); const identity = await claims.getIdentityForAccount(accounts[1]); - const claimTree = await claims.validateClaimTree('/company/evan/employee/swo2', identity.options.address); + const claimTree = await claims.validateClaimTree(identity.options.address, '/company/evan/employee/swo2'); expect(claimTree).to.have.lengthOf(2); }); it('can add subclaim paths', async () => { - const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo3', accounts[1])).length; + const oldLength = (await claims.getClaims(accounts[1], '/company/b-s-s/employee/swo3')).length; await claims.setClaim(accounts[0], accounts[0], '/company'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo3'); - const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo3', accounts[1]); + const claimsForAccount = await claims.getClaims(accounts[1], '/company/b-s-s/employee/swo3'); expect(claimsForAccount).to.have.lengthOf(1); expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Issued); }); it('can confirm a subclaim paths with the subject user', async () => { - const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1])).length; + const oldLength = (await claims.getClaims(accounts[1], '/company/b-s-s/employee/swo4')).length; await claims.setClaim(accounts[0], accounts[0], '/company'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); const claimId = await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo4'); await claims.confirmClaim(accounts[1], accounts[1], claimId); - const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1]); + const claimsForAccount = await claims.getClaims(accounts[1], '/company/b-s-s/employee/swo4'); expect(claimsForAccount).to.have.lengthOf(oldLength + 1); expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Confirmed); }); @@ -188,7 +188,7 @@ describe('Claims handler', function() { await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); const claimId = await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo6'); await claims.deleteClaim(accounts[1], accounts[1], claimId); - const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo6', accounts[1]); + const claimsForAccount = await claims.getClaims(accounts[1], '/company/b-s-s/employee/swo6'); expect(claimsForAccount).to.have.lengthOf(0); }); @@ -196,7 +196,7 @@ describe('Claims handler', function() { const before = Date.now() / 1000; await claims.setClaim(accounts[0], accounts[1], '/company'); const after = Date.now() / 1000; - const claimsForAccount = await claims.getClaims('/company', accounts[1]); + const claimsForAccount = await claims.getClaims(accounts[1], '/company'); const last = claimsForAccount.length - 1; expect(claimsForAccount[last]).to.have.property('status', ClaimsStatus.Issued); expect(claimsForAccount[last]).to.have.property('creationDate'); @@ -208,7 +208,7 @@ describe('Claims handler', function() { const before = await web3.eth.getBlockNumber(); await claims.setClaim(accounts[0], accounts[1], '/company'); const after = await web3.eth.getBlockNumber(); - const claimsForAccount = await claims.getClaims('/company', accounts[1]); + const claimsForAccount = await claims.getClaims(accounts[1], '/company'); const last = claimsForAccount.length - 1; expect(claimsForAccount[last]).to.have.property('status', ClaimsStatus.Issued); expect(claimsForAccount[last]).to.have.property('creationBlock'); @@ -228,7 +228,7 @@ describe('Claims handler', function() { }; await claims.setClaimDescription(accounts[0], sampleClaimTopic, sampleClaimsDomain, sampleDescription); await claims.setClaim(accounts[0], accounts[1], sampleClaimTopic, null, null, sampleClaimsDomain); - const claimsForAccount = await claims.getClaims(sampleClaimTopic, accounts[1]); + const claimsForAccount = await claims.getClaims(accounts[1], sampleClaimTopic); const last = claimsForAccount.length - 1; expect(claimsForAccount[last]).to.have.property('status', ClaimsStatus.Issued); expect(claimsForAccount[last]).to.have.property('creationBlock'); @@ -236,45 +236,45 @@ describe('Claims handler', function() { }); it('can reject a claim', async () => { - const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1])).length; + const oldLength = (await claims.getClaims(accounts[1], '/company/b-s-s/employee/swo4')).length; await claims.setClaim(accounts[0], accounts[0], '/company'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); const claimId = await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo4'); await claims.rejectClaim(accounts[1], accounts[1], claimId); - const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1]); + const claimsForAccount = await claims.getClaims(accounts[1], '/company/b-s-s/employee/swo4'); expect(claimsForAccount).to.have.lengthOf(oldLength + 1); expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Rejected); }); it('can reject a claim with a reason', async () => { - const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1])).length; + const oldLength = (await claims.getClaims(accounts[1], '/company/b-s-s/employee/swo4')).length; await claims.setClaim(accounts[0], accounts[0], '/company'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); const claimId = await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo4'); await claims.rejectClaim(accounts[1], accounts[1], claimId, { reason: 'denied' }); - const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1]); + const claimsForAccount = await claims.getClaims(accounts[1], '/company/b-s-s/employee/swo4'); expect(claimsForAccount).to.have.lengthOf(oldLength + 1); expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Rejected); expect(claimsForAccount[oldLength]).to.have.deep.property('rejectReason', { reason: 'denied' }); }); it('can reject a claim with a reason from the issuer side', async () => { - const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1])).length; + const oldLength = (await claims.getClaims(accounts[1], '/company/b-s-s/employee/swo4')).length; await claims.setClaim(accounts[0], accounts[0], '/company'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); const claimId = await claims.setClaim(accounts[0], accounts[1], '/company/b-s-s/employee/swo4'); - await claims.rejectClaim(accounts[1], accounts[0], claimId, { reason: 'denied' }); - const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1]); + await claims.rejectClaim(accounts[0], accounts[1], claimId, { reason: 'denied' }); + const claimsForAccount = await claims.getClaims(accounts[1], '/company/b-s-s/employee/swo4'); expect(claimsForAccount).to.have.lengthOf(oldLength + 1); expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Rejected); expect(claimsForAccount[oldLength]).to.have.deep.property('rejectReason', { reason: 'denied' }); }); it('can not re accept a rejected claim', async () => { - const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', accounts[1])).length; + const oldLength = (await claims.getClaims(accounts[1], '/company/b-s-s/employee/swo4')).length; await claims.setClaim(accounts[0], accounts[0], '/company'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); @@ -320,78 +320,78 @@ describe('Claims handler', function() { }); it('can add a claim', async () => { - const oldLength = (await claims.getClaims('/company', contractId)).length; + const oldLength = (await claims.getClaims(contractId, '/company')).length; await claims.setClaim(accounts[0], contractId, '/company'); - const claimsForAccount = await claims.getClaims('/company', contractId); + const claimsForAccount = await claims.getClaims(contractId, '/company'); expect(claimsForAccount).to.have.lengthOf(oldLength + 1); expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Issued); }); it('can add a claim with specific data', async () => { - const oldLength = (await claims.getClaims('/company', contractId)).length; + const oldLength = (await claims.getClaims(contractId, '/company')).length; await claims.setClaim(accounts[0], contractId, '/company', null, {foo: 'bar'}); - const claimsForAccount = await claims.getClaims('/company', contractId); + const claimsForAccount = await claims.getClaims(contractId, '/company'); expect(claimsForAccount).to.have.lengthOf(oldLength + 1); expect(claimsForAccount[oldLength]).to.have.property('uri', 'https://ipfs.evan.network/ipfs/Qmbjig3cZbUUufWqCEFzyCppqdnmQj3RoDjJWomnqYGy1f'); }); it('can add a claim with specific expirationDate', async () => { - const oldLength = (await claims.getClaims('/company', contractId)).length; + const oldLength = (await claims.getClaims(contractId, '/company')).length; const now = Math.floor(new Date().getTime() / 1000); await claims.setClaim(accounts[0], contractId, '/company', now); - const claimsForAccount = await claims.getClaims('/company', contractId); + const claimsForAccount = await claims.getClaims(contractId, '/company'); expect(claimsForAccount).to.have.lengthOf(oldLength + 1); expect(claimsForAccount[oldLength]).to.have.property('expirationDate', now.toString()); }); it('can add a claim and validate the integrity', async () => { - const oldLength = (await claims.getClaims('/company', contractId)).length; + const oldLength = (await claims.getClaims(contractId, '/company')).length; await claims.setClaim(accounts[0], contractId, '/company'); - const claimsForAccount = await claims.getClaims('/company', contractId); + const claimsForAccount = await claims.getClaims(contractId, '/company'); expect(claimsForAccount).to.have.lengthOf(oldLength + 1); - await claims.validateClaim(claimsForAccount[oldLength].id, contractId); + await claims.validateClaim(contractId, claimsForAccount[oldLength].id); expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Issued); }); it('can add subclaim paths and validate it', async () => { - const oldLength = (await claims.getClaims('/company', contractId)).length; + const oldLength = (await claims.getClaims(contractId, '/company')).length; await claims.setClaim(accounts[0], accounts[0], '/company'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); await claims.setClaim(accounts[0], contractId, '/company/b-s-s/employee/swo'); const identity = await claims.getIdentityForAccount(contractId); - const claimTree = await claims.validateClaimTree('/company/b-s-s/employee/swo', identity); + const claimTree = await claims.validateClaimTree(identity, '/company/b-s-s/employee/swo'); expect(claimTree).to.have.lengthOf(4); }); it('can add subclaim paths and don\'t have the needed root claims.', async () => { - const oldLength = (await claims.getClaims('/company', contractId)).length; + const oldLength = (await claims.getClaims(contractId, '/company')).length; await claims.setClaim(accounts[0], accounts[0], '/company/evan/employee'); await claims.setClaim(accounts[0], contractId, '/company/evan/employee/swo2'); const identity = await claims.getIdentityForAccount(contractId); - const claimTree = await claims.validateClaimTree('/company/evan/employee/swo2', identity); + const claimTree = await claims.validateClaimTree(identity, '/company/evan/employee/swo2'); expect(claimTree).to.have.lengthOf(2); }); it('can add subclaim paths', async () => { - const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo3', contractId)).length; + const oldLength = (await claims.getClaims(contractId, '/company/b-s-s/employee/swo3')).length; await claims.setClaim(accounts[0], accounts[0], '/company'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); await claims.setClaim(accounts[0], contractId, '/company/b-s-s/employee/swo3'); - const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo3', contractId); + const claimsForAccount = await claims.getClaims(contractId, '/company/b-s-s/employee/swo3'); expect(claimsForAccount).to.have.lengthOf(1); expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Issued); }); it('can confirm a subclaim paths with the subject user', async () => { - const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', contractId)).length; + const oldLength = (await claims.getClaims(contractId, '/company/b-s-s/employee/swo4')).length; await claims.setClaim(accounts[0], accounts[0], '/company'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); const claimId = await claims.setClaim(accounts[0], contractId, '/company/b-s-s/employee/swo4'); - await claims.confirmClaim(contractId, accounts[0], claimId); - const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo4', contractId); + await claims.confirmClaim(accounts[0], contractId, claimId); + const claimsForAccount = await claims.getClaims(contractId, '/company/b-s-s/employee/swo4'); expect(claimsForAccount).to.have.lengthOf(oldLength + 1); expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Confirmed); }); @@ -401,8 +401,8 @@ describe('Claims handler', function() { await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); const claimId = await claims.setClaim(accounts[0], contractId, '/company/b-s-s/employee/swo6'); - await claims.deleteClaim(contractId, accounts[0], claimId); - const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo6', contractId); + await claims.deleteClaim(accounts[0], contractId, claimId); + const claimsForAccount = await claims.getClaims(contractId, '/company/b-s-s/employee/swo6'); expect(claimsForAccount).to.have.lengthOf(0); }); @@ -410,7 +410,7 @@ describe('Claims handler', function() { const before = Date.now() / 1000; await claims.setClaim(accounts[0], contractId, '/company'); const after = Date.now() / 1000; - const claimsForAccount = await claims.getClaims('/company', contractId); + const claimsForAccount = await claims.getClaims(contractId, '/company'); const last = claimsForAccount.length - 1; expect(claimsForAccount[last]).to.have.property('status', ClaimsStatus.Issued); expect(claimsForAccount[last]).to.have.property('creationDate'); @@ -422,7 +422,7 @@ describe('Claims handler', function() { const before = await web3.eth.getBlockNumber(); await claims.setClaim(accounts[0], contractId, '/company'); const after = await web3.eth.getBlockNumber(); - const claimsForAccount = await claims.getClaims('/company', contractId); + const claimsForAccount = await claims.getClaims(contractId, '/company'); const last = claimsForAccount.length - 1; expect(claimsForAccount[last]).to.have.property('status', ClaimsStatus.Issued); expect(claimsForAccount[last]).to.have.property('creationBlock'); @@ -442,7 +442,7 @@ describe('Claims handler', function() { }; await claims.setClaimDescription(accounts[0], sampleClaimTopic, sampleClaimsDomain, sampleDescription); await claims.setClaim(accounts[0], contractId, sampleClaimTopic, null, null, sampleClaimsDomain); - const claimsForAccount = await claims.getClaims(sampleClaimTopic, contractId); + const claimsForAccount = await claims.getClaims(contractId, sampleClaimTopic); const last = claimsForAccount.length - 1; expect(claimsForAccount[last]).to.have.property('status', ClaimsStatus.Issued); expect(claimsForAccount[last]).to.have.property('creationBlock'); @@ -450,48 +450,48 @@ describe('Claims handler', function() { }); it('can reject a claim', async () => { - const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', contractId)).length; + const oldLength = (await claims.getClaims(contractId, '/company/b-s-s/employee/swo4')).length; await claims.setClaim(accounts[0], accounts[0], '/company'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); const claimId = await claims.setClaim(accounts[0], contractId, '/company/b-s-s/employee/swo4'); - await claims.rejectClaim(contractId, accounts[0], claimId); - const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo4', contractId); + await claims.rejectClaim(accounts[0], contractId, claimId); + const claimsForAccount = await claims.getClaims(contractId, '/company/b-s-s/employee/swo4'); expect(claimsForAccount).to.have.lengthOf(oldLength + 1); expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Rejected); }); it('can reject a claim with a reason', async () => { - const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', contractId)).length; + const oldLength = (await claims.getClaims(contractId, '/company/b-s-s/employee/swo4')).length; await claims.setClaim(accounts[0], accounts[0], '/company'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); const claimId = await claims.setClaim(accounts[0], contractId, '/company/b-s-s/employee/swo4'); - await claims.rejectClaim(contractId, accounts[0], claimId, { reason: 'denied' }); - const claimsForAccount = await claims.getClaims('/company/b-s-s/employee/swo4', contractId); + await claims.rejectClaim(accounts[0], contractId, claimId, { reason: 'denied' }); + const claimsForAccount = await claims.getClaims(contractId, '/company/b-s-s/employee/swo4'); expect(claimsForAccount).to.have.lengthOf(oldLength + 1); expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Rejected); expect(claimsForAccount[oldLength]).to.have.deep.property('rejectReason', { reason: 'denied' }); }); it('can not re accept a rejected claim', async () => { - const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', contractId)).length; + const oldLength = (await claims.getClaims(contractId, '/company/b-s-s/employee/swo4')).length; await claims.setClaim(accounts[0], accounts[0], '/company'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); const claimId = await claims.setClaim(accounts[0], contractId, '/company/b-s-s/employee/swo4'); - await claims.rejectClaim(contractId, accounts[0], claimId); - const reacceptedP = claims.confirmClaim(contractId, accounts[0], claimId); + await claims.rejectClaim(accounts[0], contractId, claimId); + const reacceptedP = claims.confirmClaim(accounts[0], contractId, claimId); await expect(reacceptedP).to.be.rejected; }); it('cannot have other users approve claims of a contract of another user', async () => { - const oldLength = (await claims.getClaims('/company/b-s-s/employee/swo4', contractId)).length; + const oldLength = (await claims.getClaims(contractId, '/company/b-s-s/employee/swo4')).length; await claims.setClaim(accounts[0], accounts[0], '/company'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s'); await claims.setClaim(accounts[0], accounts[0], '/company/b-s-s/employee'); const claimId = await claims.setClaim(accounts[0], contractId, '/company/b-s-s/employee/swo4'); - await expect(claims.confirmClaim(contractId, accounts[1], claimId)).to.be.rejected; + await expect(claims.confirmClaim(accounts[1], contractId, claimId)).to.be.rejected; }); }); }); diff --git a/src/claims/claims.ts b/src/claims/claims.ts index 6e542efe..b5b41ad8 100644 --- a/src/claims/claims.ts +++ b/src/claims/claims.ts @@ -99,13 +99,13 @@ export class Claims extends Logger { * confirms a claim; this can be done, if a claim has been issued for a subject and the subject * wants to confirm it * - * @param {string} subject claim subject * @param {string} accountId account, that performs the action + * @param {string} subject claim subject * @param {string} claimId id of a claim to confirm * @return {Promise} resolved when done */ public async confirmClaim( - subject: string, accountId: string, claimId: string): Promise { + accountId: string, subject: string, claimId: string): Promise { await this.executeOnIdentity( subject, 'approveClaim', @@ -164,13 +164,13 @@ export class Claims extends Logger { * name seen as a path, the parent 'folder'). Subjects of a claim may only delete it, if they are * the issuer as well. If not, they can only react to it by confirming or rejecting the claim. * - * @param {string} subject the subject of the claim * @param {string} accountId account, that performs the action + * @param {string} subject the subject of the claim * @param {string} claimId id of a claim to delete * @return {Promise} resolved when done */ public async deleteClaim( - subject: string, accountId: string, claimId: string): Promise { + accountId: string, subject: string, claimId: string): Promise { await this.executeOnIdentity( subject, 'removeClaim', @@ -184,12 +184,12 @@ export class Claims extends Logger { * properties: creationBlock, creationDate, data, description, expirationDate, id, issuer, name, * signature, status, subject, topic, uri, valid * - * @param {string} claimName name (/path) of a claim * @param {string} subject subject of the claims + * @param {string} claimName name (/path) of a claim * @param {boolean} isIdentity (optional) indicates if the subject is already an identity * @return {Promise} claim info array */ - public async getClaims(claimName: string, subject: string, isIdentity?: boolean): Promise { + public async getClaims(subject: string, claimName: string, isIdentity?: boolean): Promise { const sha3ClaimName = this.options.nameResolver.soliditySha3(claimName); const uint256ClaimName = new BigNumber(sha3ClaimName).toString(10); @@ -268,7 +268,7 @@ export class Claims extends Logger { subject, topic: claim.topic, uri: (claim).uri, - valid: await this.validateClaim(claimId, subject, isIdentity) + valid: await this.validateClaim(subject, claimId, isIdentity) }; })); @@ -332,14 +332,14 @@ export class Claims extends Logger { * tracking reasons. You can also optionally add a reject reason as JSON object to track * additional informations about the rejection. Issuer and Subject can reject a special claim. * - * @param {string} subject account, that rejects the claim * @param {string} accountId account, that performs the action + * @param {string} subject account, that rejects the claim * @param {string} claimId id of a claim to reject * @param {any} rejectReason (optional) rejectReason object * @return {Promise} resolved when done */ public async rejectClaim( - subject: string, accountId: string, claimId: string, rejectReason?: any): Promise { + accountId: string, subject: string, claimId: string, rejectReason?: any): Promise { if (rejectReason) { try { const stringified = JSON.stringify(rejectReason); @@ -492,14 +492,14 @@ export class Claims extends Logger { /** * validates a given claimId in case of integrity * - * @param {string} claimId claim identifier * @param {string} subject the subject of the claim + * @param {string} claimId claim identifier * @param {boolean} isIdentity optional indicates if the subject is already an * identity * @return {Promise} resolves with true if the claim is valid, otherwise false */ public async validateClaim( - claimId: string, subject: string, isIdentity?: boolean): Promise { + subject: string, claimId: string, isIdentity?: boolean): Promise { await this.ensureStorage(); let subjectIdentity = isIdentity ? subject : await this.getIdentityForAccount(subject); @@ -529,14 +529,14 @@ export class Claims extends Logger { /** * validates a whole claim tree if the path is valid (called recursively) * - * @param {string} claimLabel claim topic of a claim to build the tree for * @param {string} subject subject of the claim and the owner of the claim node + * @param {string} claimLabel claim topic of a claim to build the tree for * @param {array} treeArr (optional) result tree array, used for recursion * @return {Promise} Array with all resolved claims for the tree */ - public async validateClaimTree(claimLabel: string, subject: string, treeArr = []) { + public async validateClaimTree(subject: string, claimLabel: string, treeArr = []) { const splittedClaimLabel = claimLabel.split('/'); - const claims = await this.getClaims(claimLabel, subject, true); + const claims = await this.getClaims(subject, claimLabel, true); // TODO: -> Add validation of more than one claim if there are more claims for the label if (claims.length > 0) { // check at the moment the first claim @@ -544,7 +544,7 @@ export class Claims extends Logger { if (splittedClaimLabel.length > 1) { splittedClaimLabel.pop(); const subClaim = splittedClaimLabel.join('/'); - await this.validateClaimTree(subClaim, claims[0].issuer, treeArr); + await this.validateClaimTree(claims[0].issuer, subClaim, treeArr); } } else { return treeArr; From 44a91be2feb87f9db1b2bf3be830e6d5bf1e1d90 Mon Sep 17 00:00:00 2001 From: S3bb1 Date: Tue, 18 Dec 2018 13:58:32 +0100 Subject: [PATCH 09/22] add transaction over identity proxy --- src/claims/claims.ts | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/claims/claims.ts b/src/claims/claims.ts index 2629c370..ba538f4a 100644 --- a/src/claims/claims.ts +++ b/src/claims/claims.ts @@ -602,12 +602,30 @@ export class Claims extends Logger { ); } else if (subjectType === 'account') { // account identity - return this.options.executor.executeContractTransaction( - await this.getIdentityForAccount(subject), - fun, + const targetIdentity = await this.getIdentityForAccount(subject); + const userIdentity = this.options.contractLoader.loadContract( + 'ClaimHolder', + targetIdentity.options.address + ); + + const abi = userIdentity.methods[fun].apply( + userIdentity.methods[fun], + args + ).encodeABI(); + + if(options.event) { + options.event.targetAddress = targetIdentity.options.address; + } + + const ret = await this.options.executor.executeContractTransaction( + await this.getIdentityForAccount(options.from), + 'execute', options, - ...args, + targetIdentity.options.address, + 0, + abi, ); + return ret; } } From e9d1898cf9b57616d8dced219f7a786c18cf03b7 Mon Sep 17 00:00:00 2001 From: wulfraem Date: Wed, 19 Dec 2018 09:46:05 +0100 Subject: [PATCH 10/22] update `setClaims` to use issuers identity for setting claims on subject --- VERSIONS.md | 3 +++ src/claims/claims.spec.ts | 3 ++- src/claims/claims.ts | 56 ++++++++++++++++++++++++++++++--------- 3 files changed, 49 insertions(+), 13 deletions(-) diff --git a/VERSIONS.md b/VERSIONS.md index 525a8b65..52285061 100644 --- a/VERSIONS.md +++ b/VERSIONS.md @@ -2,9 +2,12 @@ ## Next Version ### Features +- update `setClaims` to use issuers identity for setting claims on subject + ### Fixes ### Deprecations + ## Version 1.6.1 ### Fixes - remove web3 initialization within the `ServiceContract` diff --git a/src/claims/claims.spec.ts b/src/claims/claims.spec.ts index 70eafe5e..13c31792 100644 --- a/src/claims/claims.spec.ts +++ b/src/claims/claims.spec.ts @@ -107,7 +107,8 @@ describe('Claims handler', function() { describe('when using external account based identities', () => { it('can add a claim', async () => { const oldLength = (await claims.getClaims(accounts[1], '/company')).length; - await claims.setClaim(accounts[0], accounts[1], '/company'); + const claimId = await claims.setClaim(accounts[0], accounts[1], '/company'); + expect(claimId).to.be.ok; const claimsForAccount = await claims.getClaims(accounts[1], '/company'); expect(claimsForAccount).to.have.lengthOf(oldLength + 1); expect(claimsForAccount[oldLength]).to.have.property('status', ClaimsStatus.Issued); diff --git a/src/claims/claims.ts b/src/claims/claims.ts index 0fe4e5c8..de5e4531 100644 --- a/src/claims/claims.ts +++ b/src/claims/claims.ts @@ -615,24 +615,56 @@ export class Claims extends Logger { targetIdentity.options.address ); + // get encoded abi for passing it to identity tx const abi = userIdentity.methods[fun].apply( userIdentity.methods[fun], args ).encodeABI(); - if(options.event) { - options.event.targetAddress = targetIdentity.options.address; - } + // backup orignal event data and set event data for handling identity tx + const originalEvent = options.event; + const originalGetEventResult = options.getEventResult; + options.event = { + // event Approved(uint256 indexed executionId, bool approved); + eventName: 'Approved', + target: 'KeyHolderLibrary', // ClaimsRegistryLibrary + }; + options.getEventResult = (event, eventArgs) => { + return [eventArgs.executionId, event.blockNumber]; + }; - const ret = await this.options.executor.executeContractTransaction( - await this.getIdentityForAccount(options.from), - 'execute', - options, - targetIdentity.options.address, - 0, - abi, - ); - return ret; + const identity = await this.getIdentityForAccount(options.from); + const [executionId, blockNumber] = await this.options.executor.executeContractTransaction( + identity, 'execute', options, targetIdentity.options.address, 0, abi); + const keyHolderLibrary = this.options.contractLoader.loadContract( + 'KeyHolderLibrary', identity.options.address); + const [ executed, failed ] = await Promise.all([ + // event Executed(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data); + keyHolderLibrary.getPastEvents('Executed', { fromBlock: blockNumber, toBlock: blockNumber }), + // event ExecutionFailed(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data); + keyHolderLibrary.getPastEvents('ExecutionFailed', { fromBlock: blockNumber, toBlock: blockNumber }), + ]); + // flatten and filter events on exection id from identity tx + const filtered = [ ...executed, ...failed ].filter( + event => event.returnValues && event.returnValues.executionId === executionId); + if (filtered.length && filtered[0].event === 'Executed') { + // if execution was successfull + if (originalEvent) { + // if original options had an event property for retrieving evnet results + const targetIdentityEvents = await targetIdentity.getPastEvents( + originalEvent.eventName, { fromBlock: blockNumber, toBlock: blockNumber }); + if (targetIdentityEvents.length) { + return originalGetEventResult(targetIdentityEvents[0], targetIdentityEvents[0].returnValues); + } + } + } else if (filtered.length && filtered[0].event === 'ExecutionFailed') { + const values = filtered[0].returnValues; + throw new Error('executeOnIdentity failed; ExecutionFailed event was triggered: ' + + `executionId: "${values.executionId}", to: "${values.to}", value: "${values.value}"`); + } else { + throw new Error('executeOnIdentity failed; subject type was \'account\', ' + + 'but no proper identity tx status event could be retrieved'); + } } } From 93dcee6f428a05b869ddb3a7b2d541eb32cd9a69 Mon Sep 17 00:00:00 2001 From: wulfraem Date: Thu, 20 Dec 2018 10:25:00 +0100 Subject: [PATCH 11/22] code cleanup --- src/claims/claims.ts | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/claims/claims.ts b/src/claims/claims.ts index de5e4531..f32aa20f 100644 --- a/src/claims/claims.ts +++ b/src/claims/claims.ts @@ -585,6 +585,21 @@ export class Claims extends Logger { } } + /** + * Checks if a storage was initialized before, if not, load the default one. + * + * @return {Promise} resolved when storage exists or storage was loaded + */ + private async ensureStorage() { + if (!this.contracts.storage) { + const storageAddress = await this.options.nameResolver + .getAddress(`identities.${ this.options.nameResolver.config.labels.ensRoot }`); + + this.contracts.storage = this.options.contractLoader.loadContract('V00_UserRegistry', + storageAddress); + } + } + /** * execute contract transaction on identity, checks if account or contract identity is used and if * given subject is alraedy an identity @@ -669,18 +684,14 @@ export class Claims extends Logger { } /** - * Checks if a storage was initialized before, if not, load the default one. + * returns full domain for description * - * @return {Promise} resolved when storage exists or storage was loaded + * @param {string} topic claim topic + * @param {string} descriptionDomain domain of description + * @return {string} full domain */ - private async ensureStorage() { - if (!this.contracts.storage) { - const storageAddress = await this.options.nameResolver - .getAddress(`identities.${ this.options.nameResolver.config.labels.ensRoot }`); - - this.contracts.storage = this.options.contractLoader.loadContract('V00_UserRegistry', - storageAddress); - } + private getFullDescriptionDomainWithHash(topic: string, descriptionDomain: string): string { + return `${this.options.nameResolver.soliditySha3(topic).substr(2)}.${descriptionDomain}.claims.evan`; } /** @@ -715,15 +726,4 @@ export class Claims extends Logger { } return this.subjectTypes[subject]; } - - /** - * returns full domain for description - * - * @param {string} topic claim topic - * @param {string} descriptionDomain domain of description - * @return {string} full domain - */ - private getFullDescriptionDomainWithHash(topic: string, descriptionDomain: string): string { - return `${this.options.nameResolver.soliditySha3(topic).substr(2)}.${descriptionDomain}.claims.evan`; - } } From 1689322625a414a5fd5153c1a8051c603959ba1b Mon Sep 17 00:00:00 2001 From: wulfraem Date: Thu, 20 Dec 2018 15:35:51 +0100 Subject: [PATCH 12/22] add linking and checks for contract identities --- VERSIONS.md | 1 + src/claims/claims.spec.ts | 47 ++++++++++++++++++++++++++++++- src/claims/claims.ts | 59 ++++++++++++++++++++++++--------------- 3 files changed, 83 insertions(+), 24 deletions(-) diff --git a/VERSIONS.md b/VERSIONS.md index 52285061..221be2e1 100644 --- a/VERSIONS.md +++ b/VERSIONS.md @@ -3,6 +3,7 @@ ## Next Version ### Features - update `setClaims` to use issuers identity for setting claims on subject +- add linking and checks for contract identities ### Fixes ### Deprecations diff --git a/src/claims/claims.spec.ts b/src/claims/claims.spec.ts index 13c31792..4c828716 100644 --- a/src/claims/claims.spec.ts +++ b/src/claims/claims.spec.ts @@ -311,7 +311,7 @@ describe('Claims handler', function() { description: 'I\'m a sample claim', author: 'evan.network', version: '1.0.0', - dbcpVersion: 1, + dbcpVersion: 2, }, }, accounts[0], @@ -494,5 +494,50 @@ describe('Claims handler', function() { const claimId = await claims.setClaim(accounts[0], contractId, '/company/b-s-s/employee/swo4'); await expect(claims.confirmClaim(accounts[1], contractId, claimId)).to.be.rejected; }); + + it('does not return claim data, when identity and contract id mismatch', async () => { + const businessCenterDomain = nameResolver.getDomainName(config.nameResolver.domains.businessCenter); + // create two contracts with a claim + const [ contractId1, contractId2 ] = await Promise.all([...Array(2)].map(async () => { + const localContractId = await baseContract.createUninitialized( + 'testdatacontract', + accounts[0], + businessCenterDomain, + ); + await description.setDescriptionToContract( + localContractId, + { + public: { + name: 'sample claim', + description: 'I\'m a sample claim', + author: 'evan.network', + version: '1.0.0', + dbcpVersion: 2, + }, + }, + accounts[0], + ); + const identity = await claims.createIdentity(accounts[0], localContractId); + await claims.setClaim(accounts[0], localContractId, '/company'); + + // each contract should have one claim + const contractClaims = await claims.getClaims(localContractId, '/company'); + expect(contractClaims).to.have.lengthOf(1); + expect(contractClaims[0]).to.have.property('status', ClaimsStatus.Issued); + + return localContractId; + })); + + // point contract1s description to contract2s identity + const description1 = await description.getDescription(contractId1, accounts[0]); + const description2 = await description.getDescription(contractId2, accounts[0]); + description1.public.identity = description2.public.identity; + await description.setDescriptionToContract(contractId1, description1, accounts[0]); + + claims.cachedIdentities = {}; + claims.subjectTypes = {}; + await expect(claims.getClaims(contractId1, '/company')).to.be.rejected; + }); }); }); + diff --git a/src/claims/claims.ts b/src/claims/claims.ts index f32aa20f..18d06488 100644 --- a/src/claims/claims.ts +++ b/src/claims/claims.ts @@ -142,6 +142,7 @@ export class Claims extends Logger { ); identity = identityContract.options.address; } else { + // create identity hash from registry identity = await this.options.executor.executeContractTransaction( this.contracts.registry, 'createIdentity', @@ -152,9 +153,18 @@ export class Claims extends Logger { getEventResult: (_, args) => args.identity, }, ); + // write identity to description const description = await this.options.description.getDescription(contractId, accountId); description.public.identity = identity; await this.options.description.setDescriptionToContract(contractId, description, accountId); + // write identity to contract + await this.options.executor.executeContractTransaction( + this.contracts.registry, + 'linkIdentity', + { from: accountId }, + identity, + contractId, + ); } return identity; } @@ -293,13 +303,30 @@ export class Claims extends Logger { subject, ); // check if target identity exists - if (subject === nullAddress) { - const msg = `target identity for account ${subject} does not exist`; - this.log(msg, 'error'); - throw new Error(msg); - } + if (targetIdentity !== nullAddress) { + this.subjectTypes[subject] = 'account'; + this.cachedIdentities[subject] = this.options.contractLoader.loadContract('OriginIdentity', targetIdentity); + } else { + const description = await this.options.description.getDescription(subject, null); + if (description && description.public && description.public.identity) { + // we got an identity from description, now check, that contract id matches linked address + const linked = await this.options.executor.executeContractCall( + this.contracts.registry, 'getLink', description.public.identity); + if (linked !== subject) { + const msg = `subject description of "${subject}" points to identity ` + + `"${description.public.identity}", but this identity is linked to address "${linked}"`; + this.log(msg, 'error'); + throw new Error(msg); + } + this.subjectTypes[subject] = 'contract'; + this.cachedIdentities[subject] = description.public.identity; + } else { + const msg = `could not find identity for "${subject}"`; + this.log(msg, 'error'); + throw new Error(msg); + } - this.cachedIdentities[subject] = this.options.contractLoader.loadContract('OriginIdentity', targetIdentity); + } } return this.cachedIdentities[subject]; } @@ -659,7 +686,7 @@ export class Claims extends Logger { // event ExecutionFailed(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data); keyHolderLibrary.getPastEvents('ExecutionFailed', { fromBlock: blockNumber, toBlock: blockNumber }), ]); - // flatten and filter events on exection id from identity tx + // flatten and filter eventso n exection id from identity tx const filtered = [ ...executed, ...failed ].filter( event => event.returnValues && event.returnValues.executionId === executionId); if (filtered.length && filtered[0].event === 'Executed') { @@ -707,22 +734,8 @@ export class Claims extends Logger { } else if (isIdentity && subject.length === 42) { return 'account'; } else if (!this.subjectTypes[subject]) { - const targetIdentity = await this.options.executor.executeContractCall( - this.contracts.storage, - 'users', - subject, - ); - if (targetIdentity !== nullAddress) { - this.subjectTypes[subject] = 'account'; - } else { - const description = await this.options.description.getDescription(subject, null); - if (description && description.public && description.public.identity) { - this.subjectTypes[subject] = 'contract'; - this.cachedIdentities[subject] = description.public.identity; - } else { - throw new Error(`could not find identity for "${subject}"`); - } - } + // fills subject type upon retrieval + await this.getIdentityForAccount(subject); } return this.subjectTypes[subject]; } From 5ae5c0f87bccd8a483c94a50d63b4c0efaf881f6 Mon Sep 17 00:00:00 2001 From: wulfraem Date: Thu, 20 Dec 2018 15:56:09 +0100 Subject: [PATCH 13/22] remove parts from readme, that have moved into API documentation --- README.md | 1055 +---------------------------------------------------- 1 file changed, 7 insertions(+), 1048 deletions(-) diff --git a/README.md b/README.md index c8b73832..19685e46 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,7 @@ -# blockchain-core +# api-blockchain-core [![Build Status](https://travis-ci.org/evannetwork/api-blockchain-core.svg?branch=develop)](https://travis-ci.org/evannetwork/api-blockchain-core) -## Table of Contents - - -- [About](#about) -- [Tests](#tests) -- [Module Initialization](#module-initialization) -- [Handling Profiles](#handling-profiles) - - [Structure](#structure) - - [Example](#example) -- [BaseContract](#basecontract) - - [Create Contracts](#create-contracts) - - [Managing Contract Members](#managing-contract-members) - - [Change Contract State](#change-contract-state) - - [Updating a Members State](#updating-a-members-state) -- [DataContract](#datacontract) - - [Creating DataContracts](#creating-datacontracts) - - [Entries](#entries) - - [List Entries](#list-entries) -- [Encryption](#encryption) - - [Usage](#usage) - - [Examples](#examples) -- [Sharings / Multikeys](#sharings--multikeys) - - [The Sharing Concept](#the-sharing-concept) - - [How to use](#how-to-use) - - [Example](#example-1) -- [Rights and Roles](#rights-and-roles) - - [Add Accounts to Role](#add-accounts-to-role) - - [Get Members of Roles a Contract](#get-members-of-roles-a-contract) - - [Setting Function Permissions](#setting-function-permissions) - - [Setting Operation Permissions](#setting-operation-permissions) -- [IPLD](#ipld) - - [Adding Trees to IPLD](#adding-trees-to-ipld) - - [Retrieving Trees from IPLD](#retrieving-trees-from-ipld) - - [Subtrees](#subtrees) - - [Extending trees](#extending-trees) - - [Getting Values from Subtrees](#getting-values-from-subtrees) - - [About Encryption in IPLD Trees](#about-encryption-in-ipld-trees) -- [Mailbox](#mailbox) - - [Send a Mail](#send-a-mail) - - [Retrieving bmails](#retrieving-bmails) - - [Answering to a bmail](#answering-to-a-bmail) - - [Bmails and EVEs](#bmails-and-eves) - - [Checking a bmails balance](#checking-a-bmails-balance) - - [Withdrawing funds from bmails](#withdrawing-funds-from-bmails) -- [Key Exchange](#key-exchange) - - [Start the Key Exchange Process](#start-the-key-exchange-process) - - [Finishing the Key Exchange Process](#finishing-the-key-exchange-process) -- [Onboarding](#onboarding) - - - ## About The blockchain core is a helper library, that offers helpers for interacting with the blockchain. It is written in TypeScript and offers several (up to a certain degree) stand-alone modules, that can be used for @@ -65,6 +14,12 @@ The blockchain core is a helper library, that offers helpers for interacting wit - sending and receiving bmails +## Documentation +- API documentation can be found here [here](https://ipfs.evan.network/ipns/QmYmsPTdPPDLig6gKB1wu1De4KJtTqAXFLF1498umYs4M6/getting-started.html)[+] +- if you want to know about where the API is used, you can have a look at our [wiki](https://evannetwork.github.io/)[+] +- updates, develop HowTos and more cool stuff about what evan.network is doing can be found on our [Medium channel](https://medium.com/evan-network)[+] + + ## Tests The tests are written with mocha and chai and the files (`*.spec.js`) are located next to the files, they contain tests for. The tests are in between unit tests and integration tests. They each cover a single class but do not mock external dependencies and use the live blockchain for its contract and transaction related components. They act as a living documentation and examples for using the modules can be found in them. @@ -78,999 +33,3 @@ There are multiple scripts for running tests: - `npm run testunitbrk ${PATH_TO_SPEC_FILE}` - runs a single `*.spec.js` file, steps into breakpoint on first line, can be used when facing startup issues All tests are run with the `--inspect` flag for debugging. - - -## Module Initialization -The modules take 1 argument in their constructor, that is (in most modules) an interface with the required dependencies, for example in the [`BaseContract`](./src/contracts/base-contract/base-contract.ts) class: - -```typescript -// ... - -/** - * options for BaseContract constructor - */ -export interface BaseContractOptions { - executor: Executor, - loader: ContractLoader, - log?: Function, - nameResolver: NameResolver, -} - - -/** - * wrapper for BaseContract interactions - * - * @class BaseContract (name) - */ -export class BaseContract extends Logger { - protected options: BaseContractOptions; - - constructor(optionsInput: BaseContractOptions) { - super(optionsInput); - this.options = optionsInput; - } - - // ... -} -``` - -Some of the modules have circular depenencies, as many modules require basic modules like the `Executor` or the `NameResolver` (from [DBCP](https://github.com/evannetwork/dbcp)[+]) and in reverse those two modules need functionalities from their dependents. For example the `Executor` from the sample above needs the `EventHub` (which requires the `Executor` itself) for transactions, that use an events for returning results. These modules -need further initialization steps before they can be used, which are described in their constructors comment and can be seen in their tests. - - -## Handling Profiles -### Structure -A users profile is its personal storage for -- contacts -- encryption keys exchanged with contacts -- an own public key for exchanging keys with new contacts -- bookmarked ÐAPPs -- created contracts - -This data is stored as an [IPLD Graphs](https://github.com/ipld/ipld)[+] per type and stored in a users profile contract. These graphs are independant from each other and have to be saved separately. - -This contract is a [`DataContract`](./src/contracts/database-contract/data-contract.ts) and can be created via the factory at `profile.factory.evan` and looked up at the global profile index `profile.evan`. The creation process and landmap looks like this: - -![profile landmap](https://user-images.githubusercontent.com/1394421/38298221-1938d006-37f7-11e8-9a84-abfd311c97f0.png) - -### Example -This example shows how to create a profile and store a bookmark in it. For abbreviation the creation of the profile helper has been omitted and an existing instance called `profile` is used. -```typescript -// the bookmark we want to store -const sampleDesc = { - title: 'sampleTest', - description: 'desc', - img: 'img', - primaryColor: '#FFFFFF', -}; - -// create new profile, set private key and keyexchange partial key -await profile.createProfile(keyExchange.getDiffieHellmanKeys()); - -// add a bookmark -await profile.addDappBookmark('sample1.test', sampleDesc); - -// store tree to contract -await profile.storeForAccount(profile.treeLabels.bookmarkedDapps); -``` - - -## BaseContract -The [`BaseContract`](./src/contracts/base-contract/base-contract.ts) is the base contract class used for -- [DataContracts](#datacontract) -- [ServiceContractss](#servicecontract) - -Contracts, that inherit from `BaseContracts`, are able to: -- manage a list of contract participants (called "members") -- manage the own state (a flag, that indicate its own life cycle status) -- manage members state (a flag, that indicate the members state in the contract) - -What members can do, what non-members cannot do depends of the - - -### Create Contracts -The API supports creating contracts, that inhering from `BaseContract`. This is done by calling the respective factory. The factory calls are done via a function with this interface: -```solidity -/// @notice create new contract instance -/// @param businessCenter address of the BusinessCenter to use or 0x0 -/// @param provider future owner of the contract -/// @param _contractDescription DBCP definition of the contract -/// @param ensAddress address of the ENS contract -function createContract( - address businessCenter, - address provider, - bytes32 _contractDescription, - address ensAddress) public returns (address); -``` - -The API supports creating contracts with this function. Contracts created this way may not be ready to use and require an additional function at the contract to be called before usage. This function is usually called `init` and its arguments and implementation depends of the specific contract. - -The `createUninitialized` function performs a lookup for the respective factory contract and calls the `createContract` function at it. - -```typescript -const contractOwner = '0x...'; -const businessCenterDomain = 'testbc.evan'; -const contractId = await baseContract.createUninitialized( - 'testdatacontract', // factory name - contractOwner, // account, that will be owner of the new contract - businessCenterDomain, // business center, where the new contract will be created -); -``` - - -### Managing Contract Members -To allow accounts to work with contract resources, they have to be added as members to the contract. This can be can be done with: -```typescript -const contractOwner = '0x0000000000000000000000000000000000000001'; -const invitee = '0x0000000000000000000000000000000000000002'; -const businessCenterDomain = 'testbc.evan'; -const contract = loader.loadContract('BaseContractInterface', contractId); -await baseContract.inviteToContract( - businessCenterDomain, - contractId, - contractOwner, - invitee, -); -``` - -To check if an account is a member of a contract, the contract function `isMember` can be used: -```typescript -const isMember = await executor.executeContractCall(contract, 'isConsumer', invitee); -console.log(isMember); -// Output: -// true -``` - - -### Change Contract State -The contracts state reflects the current state and how other members may be able to interact with it. So for example, a contract for tasks cannot have its tasks resolved, when the contract is still in Draft state. State transitions are limited to configured roles and allow going from one state to another only if configured for this role. - -The contract state can be set via: `function changeContractState(ContractState newState);`. -```typescript -await baseContract.changeContractState(contractId, contractOwner, ContractState.Active); -``` - -`ContractState` is an enum in the BaseContract class, that holds the same state values as the `[BaseContract.sol`](https://github.com/evannetwork/smart-contracts/blob/master/contracts/BaseContract.sol). Alternatively integer values matching the enums in [`BaseContractInterface.sol`](https://github.com/evannetwork/smart-contracts/blob/master/contracts/BaseContractInterface.sol) can be used. - - -### Updating a Members State -A members state reflects this members status in the contract. These status values can for example be be Active, Draft or Terminated. - -Consumer state can be set via: -```solidity -function changeConsumerState(address consumer, ConsumerState state); -``` - -`ConsumerState` is an enum in the BaseContract class, that holds the same state values as the [`BaseContract.sol`](https://github.com/evannetwork/smart-contracts/blob/master/contracts/BaseContract.sol). Alternatively integer values matching the enums in [`BaseContractInterface.sol`](https://github.com/evannetwork/smart-contracts/blob/master/contracts/BaseContractInterface.sol) can be used. - - -## DataContract -The DataContract is a secured data storage contract for single properties and lists. If created on its own, DataContracts cannot do very much. They rely on their authority to check which entries or lists can be used. - -For more information about DataContracts purpose and their authorities see [Data Contract](https://evannetwork.github.io/dev/data-contract)[+] in the evan.network wiki. - -For abbreviation the creation of the data contract helper has been omitted and an existing instance called `dc` is used. - -### Creating DataContracts -Let's say, we want to create a DataContract for a business center at the domain "samplebc.evan" and this business center has a DataContractFactory named "testdatacontract". We want to have two users working in our DataContract, so we get these sample values: -```typescript -const factoryName = 'testdatacontract'; -const businessCenterDomain = 'samplebc.evan'; -const accounts = [ - '0x0000000000000000000000000000000000000001', - '0x0000000000000000000000000000000000000002', -]; -``` - -Now create a contract with: -```typescript -const contract = await dc.create(factoryName, accounts[0], businessCenterDomain); -``` - -Okay, that was pretty anticlimatic. And boring. And does not provide a description for the contract. Let's add a description to the process. The definition is a [DBCP](https://github.com/evannetwork/dbcp/wiki)[+] contract definition and is stored in an `Envelope` (see section "Encryption"): -```typescript -const definition: Envelope = { - "public": { - "name": "Data Contract Sample", - "description": "reiterance oxynitrate sat alternize acurative", - "version": "0.1.0", - "author": "evan GmbH", - "dataSchema": { - "list_settable_by_member": { - "$id": "list_settable_by_member_schema", - "type": "object", - "additionalProperties": false, - "properties": { - "foo": { "type": "string" }, - "bar": { "type": "integer" } - } - }, - "entry_settable_by_member": { - "$id": "entry_settable_by_member_schema", - "type": "integer", - } - } - } -}; -definition.cryptoInfo = cryptoProvider.getCryptorByCryptoAlgo('aes').getCryptoInfo(accounts[0]); -const contract = await dc.create('testdatacontract', accounts[0], businessCenterDomain, definition); -``` - -Now we have a nice little DataContract with a description. This contract is now able to be understood by other components, that understand the dbcp. And on top of that, we provided data schemas for the two properties `list_settable_by_member` and `entry_settable_by_member` (written for [ajv](https://github.com/epoberezkin/ajv)[+]). This means, that when someone adds or sets entries to or in those properties, the incoming data is validated before actually encrypting and storing it. - -To allow other users to work on the contract, they have to be invited with: -```typescript -await dc.inviteToContract(businessCenterDomain, contract.options.address, accounts[0], accounts[1]); -``` - -Now the user `accounts[1]` can use functions from the contract, but to actually store data, the user needs access to the data key for the DataContract. This can be done via updating the contracts sharing: -```typescript -const blockNr = await web3.eth.getBlockNumber(); -const contentKey = await sharing.getKey(contract.options.address, accounts[0], '*', blockNr); -await sharing.addSharing(contract.options.address, accounts[0], accounts[1], '*', blockNr, contentKey); -``` - -This function, used in `data-contract.spec.js` test file, combines the last steps and will be used in later examples in this section. -```typescript -async function createContract(addSharing = false, schema?) { - let definition; - if (schema) { - definition = JSON.parse(JSON.stringify(sampleDefinition)); - definition.public.dataSchema = schema; - definition.cryptoInfo = cryptoProvider.getCryptorByCryptoAlgo('aes').getCryptoInfo(accounts[0]); - } - const contract = await dc.create('testdatacontract', accounts[0], businessCenterDomain, definition); - await dc.inviteToContract(businessCenterDomain, contract.options.address, accounts[0], accounts[1]); - if (addSharing) { - const blockNr = await web3.eth.getBlockNumber(); - const contentKey = await sharing.getKey(contract.options.address, accounts[0], '*', blockNr); - await sharing.addSharing(contract.options.address, accounts[0], accounts[1], '*', blockNr, contentKey); - } - return contract; -} -``` - - -### Entries -Entries can be set with: -```typescript -const sampleValue = 123; -await dc.setEntry(contract, 'entry_settable_by_owner', sampleValue, accounts[0]); -``` - -Entries are automatically encrypted before setting it in the contract. If you want to use values as is, without encrypting them, you can add them in raw mode, which sets them as `bytes32` values: -```typescript -const sampleValue = '0x000000000000000000000000000000000000007b'; -await dc.setEntry(contract, 'entry_settable_by_owner', sampleValue, accounts[0], true); -``` - -Entries can be retrieved with: -```typescript -const retrieved = await dc.getEntry(contract, 'entry_settable_by_owner', accounts[0]); -``` - -Raw values can be retrieved in the same way: -```typescript -const retrieved = await dc.getEntry(contract, 'entry_settable_by_owner', accounts[0], true); -``` - - -### List Entries -List entries support the raw mode as well. To use raw values, pass `true` in the same way as wehn using the entries functions. - -List entries can be added in bulk, so the value argument is an array with values. This array can be arbitrarily large **up to a certain degree**. Values are inserted on the blockchain side and adding very large arrays this way may take more gas during the contract transaction, than may fit into a single transaction. If this is the case, values can be added in chunks (multiple transactions). Values can be added with: -```typescript -const sampleValue = { - foo: 'sample', - bar: 123, -}; -await dc.addListEntries(contract, 'list_settable_by_member', [sampleValue], accounts[0]); -``` - -When using lists similar to tagging list entries with metadata, entries can be added in multiple lists at once by passing an array of list names: -```typescript -const sampleValue = { - foo: 'sample', - bar: 123, -}; -await dc.addListEntries(contract, ['list_1', 'list_2'], [sampleValue], accounts[0]); -``` - -List entries can be retrieved one at a time: -```typescript -const itemIndex = 0; -await dc.getListEntry(contract, 'list_settable_by_member', itemIndex, accounts[0])); -``` - -Or all at once: -```typescript -await dc.getListEntries(contract, 'list_settable_by_member', accounts[0])); -``` -In the current implementation, this function retrieves the entries one at a time and may take a longer time when querying large lists, so be aware of that, when you retrieve lists with many entries. - - -## Encryption -### Usage -Data, that is going to be encrypted, is put into `Envelopes`, which are objects, that implement the `Envelope` interface and are containers for encrypted or soon to encrypted data. The interface looks like this: -```typescript -/** - * container for encrypting data - */ -export interface Envelope { - /** - * unencrypted part of the data; will stay as is during encryption - */ - public?: any; - /** - * encrypted part of the data - * if encrypting, this part will be encrypted, depending on the encryption - * if already encrypted, this will be the encrypted value - */ - private?: any; - /** - * describes used encryption - */ - cryptoInfo?: CryptoInfo; -} -``` - -Data in an envelop can be split in two sections `public` and `private`. -`public` is the data, that is visible before decrypting anything and is intended be seen by users, that have no address to secured data in the envelope. This may a public contract description, a short introduction for a ÐAPP, etc. -`private` is data, that can only be accessed, when the `CryptoInfo` has been used to decrypt its contents. - -`CryptoInfo` is an annotation for the data that specifies, with which algorithm the data will be encrypted and where to look for the key. The `CryptoInfo` interface looks like this: -```typescript -/** - * describes used encryption - */ -export interface CryptoInfo { - /** - * algorith used for encryption - */ - algorithm: string; - /** - * block number for which related item is encrypted - */ - block?: number; - /** - * version of the cryptor used; - * describes the implementation applied during decryption and not the algorithm version - */ - cryptorVersion?: number; - /** - * context for encryption, this can be - * - a context known to all parties (e.g. key exchange) - * - a key exchanged between two accounts (e.g. bmails) - * - a key from a sharings info from a contract (e.g. DataContract) - * defaults to 0 - */ - originator?: string; - /** - * length of the key used in encryption - */ - keyLength?: number; -} -``` - -For info about the `algorithm`s used see [Crypto Algorithms](https://evannetwork.github.io/dev/security#crypto-algorithms)[+]. Each `algorithm` has a Class, that implements the `Cryptor` interface, which is used for en- and decrypting the `private` data. Theses cryptors are usually bundled in a `CryptoProvider`, which maps algorithms to instances of cryptors. The mapping is as following: - -| algorithm | cryptor | usage | -| --------- | ------- | ----- | -| aes-256-cbc | Aes | default encryption | -| aes-blob | AesBlob | encryption for files | -| unencrypted | Unencrypted | used for public parts [IPLD Graphs](https://github.com/ipld/ipld)[+], for example public keys in profiles | - -### Examples -Encrypting data: -```typescript -// sample data -const toEncrypt: Envelope = { - public: 'this will stay as is', - private: 'Id commodo nulla ut eiusmod.', // will be encrypted -}; - -// encrypted data is stored as 'hex' in envelopes -const encodingEncrypted = 'hex'; -// encryption in this sample -const algorithm = 'aes-256-cbc'; -// context for encryption -const context = 'context known to all parties'; - -// encrypt private section -const cryptor = cryptoProvider.getCryptorByCryptoAlgo(algorithm); -// use static key in sample -// random key can be generated with: -// const key = await cryptor.generateKey(); -const key = '346c22768f84f3050f5c94cec98349b3c5cbfa0b7315304e13647a49181fd1ef'; -const encryptedBuffer = await cryptor.encrypt(toEncrypt.private, { key, }); -const encrypted = encryptedBuffer.toString(this.encodingEncrypted); - -// build encrypted envelope -const envelope: Envelope = { - private: encrypted, - cryptoInfo: cryptor.getCryptoInfo(dataContract.options.address), -}; -if (toEncrypt.public) { - envelope.public = toEncrypt; -} -``` - -Decrypting data: -```typescript -// sample data -const envelope: Envelope = { - public: 'this will stay as is', - private: 'fececfb235919647feb26af368e1fcfe3f3335c02e9aec6700b16d7634286d6b', -}; - -// decrypt private section from envelope -const cryptor = cryptoProvider.getCryptorByCryptoInfo(envelope.cryptoInfo); -// key has been has been stored / tranferred beforehand -const key = '346c22768f84f3050f5c94cec98349b3c5cbfa0b7315304e13647a49181fd1ef'; -const decryptedBuffer = await cryptor.decrypt( - Buffer.from(envelope.private, this.encodingEncrypted), { key, }); -envelope.private = decryptedBuffer; -``` - - -## Sharings / Multikeys - -### The Sharing Concept -For getting a better understanding about how Sharings and Multikeys work, have a look at [Security](https://evannetwork.github.io/dev/security#sharings)[+] in the evan.network wiki. - -### How to use -For abbreviation the creation of the sharing helper has been omitted and an existing instance called `sharing` is used. - -Add a sharing to a contract: -```typescript -// two sample users, user1 wants to share a key with user2 -const user1 = '0x0000000000000000000000000000000000000001'; -const user2 = '0x0000000000000000000000000000000000000002'; -// create a sample contract -// usually you would have an existing contract, for which you want to manage the sharings -const contract = await executor.createContract('Shared', [], { from: user1, gas: 500000, }); -// user1 shares the given key with user2 -// this key is shared for all contexts ('*') and valid starting with block 0 -await sharing.addSharing(contract.options.address, user1, user2, '*', 0, 'i am the secred that will be shared'); -``` - -Get keys from sharing with: -```typescript -// a sample user -const user2 = '0x0000000000000000000000000000000000000002'; -// user2 wants to read a key after receiving a sharing -// the key requested should be valid for all contexts ('*') and valid up to and including block 100 -const key = await sharing.getKey(contract.options.address, user2, '*', 100); -``` - -### Example -This is an example for a sharing info of a contract. This example has -- three users - * 0x01 - owner of a contract - * 0x02 - member of a contract - * 0x03 - another member with differing permissions -- two timestamps - * block 82745 - first sharing - * block 90000 - splitting data, update sharings -- three sections - * "\*" generic "catch all"used in first sharing - * "secret area" - available for all members - * "super secret area" - available 0x03 -```json -{ - "0x01": { - "82745": { - "*": { - "private": "secret for 0x01, starting from block 82745 for all data", - "cryptoInfo": { - "originator": "0x01,0x01", - "keyLength": 256, - "algorithm": "aes-256-cbc" - } - } - }, - "90000": { - "secret area": { - "private": "secret for 0x01, starting from block 90000 for 'secret area'", - "cryptoInfo": { - "originator": "0x01,0x01", - "keyLength": 256, - "algorithm": "aes-256-cbc" - } - }, - "super secret area": { - "private": "secret for 0x01, starting from block 90000 for 'super secret area'", - "cryptoInfo": { - "originator": "0x01,0x01", - "keyLength": 256, - "algorithm": "aes-256-cbc" - } - } - } - }, - "0x02": { - "82745": { - "*": { - "private": "secret for 0x02, starting from block 82745 for all data", - "cryptoInfo": { - "originator": "0x01,0x02", - "keyLength": 256, - "algorithm": "aes-256-cbc" - } - } - }, - "90000": { - "secret area": { - "private": "secret for 0x02, starting from block 90000 for 'secret area'", - "cryptoInfo": { - "originator": "0x01,0x02", - "keyLength": 256, - "algorithm": "aes-256-cbc" - } - }, - "super secret area": { - "private": "secret for 0x02, starting from block 90000 for 'super secret area'", - "cryptoInfo": { - "originator": "0x01,0x02", - "keyLength": 256, - "algorithm": "aes-256-cbc" - } - } - }, - }, - "0x03": { - "90000": { - "secret area": { - "private": "secret for 0x03, starting from block 90000 for 'secret area'", - "cryptoInfo": { - "originator": "0x01,0x03", - "keyLength": 256, - "algorithm": "aes-256-cbc" - } - } - } - } -} -``` - -## Rights and Roles -The [`RightsAndRoles`](./src/contracts/rights-and-roles.ts) module follows the approach described in the evan.network wik at: -- [Function Permissions](https://evannetwork.github.io/dev/security#function-permissions) -- [Operation Permissions](https://evannetwork.github.io/dev/security#operations-permissions) - -It allows to manage permissions for contracts, that use the authority [`DSRolesPerContract.sol`](https://github.com/evannetwork/smart-contracts/blob/master/contracts/DSRolesPerContract.sol) for as its permission approach. - -Contracts, that use [`DSRolesPerContract.sol`](https://github.com/evannetwork/smart-contracts/blob/master/contracts/DSRolesPerContract.sol) and therefore allow to configure with the `RightsAndRoles` are: -- [`BaseContract`](https://github.com/evannetwork/smart-contracts/blob/master/contracts/BaseContract.sol) -- [`DataContract`](https://github.com/evannetwork/smart-contracts/blob/master/contracts/DataContract.sol) -- [`ServiceContract`](https://github.com/evannetwork/smart-contracts/blob/master/contracts/ServiceContract.sol) -- [`Shared.sol`](https://github.com/evannetwork/smart-contracts/blob/master/contracts/Shared.sol) -- [`Described.sol`](https://github.com/evannetwork/smart-contracts/blob/master/contracts/Described.sol) -- [`BusinessCenter.sol`](https://github.com/evannetwork/smart-contracts/blob/master/contracts/BusinessCenter.sol) - - -### Add Accounts to Role -The main principle is that accounts can be assigned to roles and those roles can be granted capabilities. "Function Permissions" are basically the capability to call specific functions if the calling account belongs to a certain role. To add an account to the role 'member', for example use: -```typescript -const contractOwner = '0x0000000000000000000000000000000000000001'; -const newMember = '0x0000000000000000000000000000000000000002'; -const memberRole = 1; -await rightsAndRoles.addAccountToRole( - contract, // contract to be updated - contractOwner, // account, that can change permissions - newMember, // add this account to role - memberRole, // role id, uint8 value -); -``` - - -### Get Members of Roles a Contract -The [`DSRolesPerContract.sol`](https://github.com/evannetwork/smart-contracts/blob/master/contracts/DSRolesPerContract.sol) authority tracks used roles and their members and allows to retrieve an overview with all roles and their members. To get this information use: -```typescript -const members = await rightsAndRoles.getMembers(contract); -console.log(members); -// Output: -// { -// "0": [ -// "0x0000000000000000000000000000000000000001" -// ], -// "1": [ -// "0x0000000000000000000000000000000000000001", -// "0x0000000000000000000000000000000000000002" -// ] -// } -``` -The contract from this example has an owner (`0x0000000000000000000000000000000000000001`) and a member (`0x0000000000000000000000000000000000000002`). As the owner account has the member role as well, it is listed among the members. - - -### Setting Function Permissions -"Function permissions" are granted or denying by allowing a certain role to execute a specific function. E.g. to grant the role "member" the permission to use the function `addListEntries`, that has two arguments (a `bytes32` array and a `bytes32` value) use: -```typescript -const contractOwner = '0x0000000000000000000000000000000000000001'; -const memberRole = 1; -await rightsAndRoles.setFunctionPermission( - contract, // contract to be updated - contractOwner, // account, that can change permissions - memberRole, // role id, uint8 value - 'addListEntries(bytes32[],bytes32[])', // (unhashed) function selector - true, // grant this capability -); -``` -The function is specified as the unhashed [function selector](http://solidity.readthedocs.io/en/latest/abi-spec.html#function-selector)[+] and must follow its guidelines (no spaces, property typenames, etc.) for the function to be able to generate valid hashes for later validations. - - -### Setting Operation Permissions -"Operation Permissions" are capabilities granted per contract logic. They have a `bytes32` key, that represents the capability, e.g. in a [`DataContract`](https://github.com/evannetwork/smart-contracts/blob/master/contracts/DataContract.sol) a capability to add values to a certain list can be granted. - -The way, those capability hashes are build depends on the contract logic and differs from contract to contract. For example a capability check for validation if a member is allowed to add an item to the list "example" in a [`DataContract`](https://github.com/evannetwork/smart-contracts/blob/master/contracts/DataContract.sol) has four arguments, in this case: -- which role is allowed to do? (e.g. a member) -- what type of element is modified? (--> a list) -- which element is modified? (name of the list --> "example") -- type of the modification (--> "set an item" (== "add an item")) -These four values are combined into one `bytes32` value, that is used when granting or checking permissions, the `setOperationPermission` function takes care of that: -```typescript -// make sure, you have required the enums from rights-and-roles.ts -import { ModificationType, PropertyType } from 'blockchain-core'; -const contractOwner = '0x0000000000000000000000000000000000000001'; -const memberRole = 1; -await rightsAndRoles.setFunctionPermission( - contract, // contract to be updated - contractOwner, // account, that can change permissions - memberRole, // role id, uint8 value - 'example', // name of the object - PropertyType.ListEntry, // what type of element is modified - ModificationType.Set, // type of the modification - true, // grant this capability -); -``` - - -## IPLD -[IPLD](https://github.com/ipld/ipld)[+] is a way to store data as trees. The used implementation relies on [js-ipld-graph-builder](https://github.com/ipld/js-ipld-graph-builder)[+] for iterating over tree nodes and setting new subtrees, but uses a few modifications to the standard: -- nodes are not stored as [IPFS DAGs](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/DAG.md)[+], but stored as play JSON IPFS files -- nodes, that are encrypted, contain the property `cryptoInfo` for decryption (see [Encryption](#encryption)) - -### Adding Trees to IPLD -To add data to IPLD use the store function. The result is the hash for the root as a `bytes32` hash, that can be stored at smart contracts and used to retrieve the value later on: -```typescript -const sampleObject = { - personalInfo: { - firstName: 'eris', - }, -}; -const stored = await ipld.store(Object.assign({}, sampleObject)); -console.log(stored); -// Output: -// 0x12f6526dbe223eddd6c6a0fb7df118c87c56d34bf0c845b54bdca2fec0f3017d -``` - -### Retrieving Trees from IPLD -To retrieve data from IPLD trees, use the `bytes32` hash from storing the data: -```typescript -const stored = '0x12f6526dbe223eddd6c6a0fb7df118c87c56d34bf0c845b54bdca2fec0f3017d'; -const loaded = await ipld.getLinkedGraph(stored, ''); -console.dir(Ipld.purgeCryptoInfo(loaded)); -// Output: -// { personalInfo: { firstName: 'eris' } } -``` -For info about the `Ipld.purgeCryptoInfo` part see [Encryption in IPLD Trees](#encryption-in-ipld-trees). - -The second argument is the path inside the tree. Passing '' means "retrieve data from root level". To get more specifc data, provide a path: -```typescript -const stored = '0x12f6526dbe223eddd6c6a0fb7df118c87c56d34bf0c845b54bdca2fec0f3017d'; -const loaded = await ipld.getLinkedGraph(stored, 'personalInfo'); -console.dir(Ipld.purgeCryptoInfo(loaded)); -// Output: -// { firstName: 'eris' } -``` - -```typescript -const stored = '0x12f6526dbe223eddd6c6a0fb7df118c87c56d34bf0c845b54bdca2fec0f3017d'; -const loaded = await ipld.getLinkedGraph(stored, 'personalInfo/firstName'); -console.dir(Ipld.purgeCryptoInfo(loaded)); -// Output: -// 'eris' -``` - -### Subtrees -What's pretty useful about IPLD graphs is, that not only plain JSON trees can be stored, but that those trees can be linked to other graphs, which makes it possible to build very powerful tree structures, that consist of multiple separate trees, that can be used on their own or in a tree, that combines all of those. The resulting hash is again `bytes32` hash and this can be stored in smart contracts like any other IPFS hash. - -#### Extending trees -To combine separate IPLD trees, one tree has to be extended with the other one: -```typescript -const sampleObject = { - personalInfo: { - firstName: 'eris', - }, -}; -const sub = { - contracts: ['0x01', '0x02', '0x03'] -}; -const extended = await ipld.set( - sampleObject, // extend this graph - 'dapps', // attach the subgraph under the path "dapps" - sub, // attach this graph as a subgraph -); -console.log(JSON.stringify(extended, null, 2)); -// Output: -// { -// "personalInfo": { -// "firstName": "eris" -// }, -// "dapps": { -// "/": { -// "contracts": [ -// "0x01", -// "0x02", -// "0x03" -// ] -// } -// } -// } -``` - -Not too fancy and still not stored in IPFS, but note the `"/"` key. This is the junction point, that connects the two trees. Subtrees under such a junction point will be stored as a separate IPLD graph and only the reference to this graph is stored as the value of `"/"`. -```typescript -console.log(JSON.stringify(extended, null, 2)); -const extendedstored = await ipld.store(Object.assign({}, extended)); -// Output: -// "0xc74f6946aacbbd1418ddd7dec83a5bcd3710b384de767d529e624f9f08cbf9b4" -const loaded = await ipld.getLinkedGraph(extendedstored, ''); -console.log(JSON.stringify(Ipld.purgeCryptoInfo(loaded), null, 2)); -// Output: -// -// "personalInfo": { -// "firstName": "eris" -// }, -// "dapps": { -// "/": { -// "type": "Buffer", -// "data": [ 18, 32, 246, 21, 166, 135, 236, 212, 70, 130, 94, 47, 81, 135, 153, 154, 201, 69, 109, 249, 97, 84, 252, 56, 214, 195, 149, 133, 116, 253, 19, 87, 217, 66 ] -// } -// } -// -``` - -As you can see, the subgraph is added as a serialized Buffer. This Buffer represents the hash for the root hash of the subtree. - - -#### Getting Values from Subtrees -The path argument from the getLinkedGraph is able to resolve values in subtrees as well: -```typescript -const loaded = await ipld.getLinkedGraph(extendedstored, 'dapps/contracts'); -console.log(JSON.stringify(loaded, null, 2)); -// Output: -// [ -// "0x01", -// "0x02", -// "0x03" -// ] -``` - -The `getLinkedGraph` function resolves subgraphs only when required, which means, that if the path argument does not query into a subgraph, this tree is returned as a Buffer, like in the previous example. - -A second function to retrieve values from IPLD graphs called `getResolvedGraph`, which resolves all subgraphs, but this function is intended for debugging and analysis purposes and should not be used in production environment. - - -### About Encryption in IPLD Trees -The last examples used `Ipld.purgeCryptoInfo` to cleanup the objects before logging them. This was done, because IPLD graphs are encrypted by default, which has a few impact on the data stored: -- The root node of a tree is "encrypted" with the encryption algorithm "unencrypted", resulting in the root node having its data stored as a Buffer. This is done to keep the root node in the same format as the other nodes, as: -- Nodes in the Tree are encrypted. This encryption is specified in the constructor as `defaultCryptoAlgo`. -- All nodes are en- or decrypted with the same account or "originator". The originator, that is used, is specified in the constructor as "originator". This means, that the IPLD instance is account bound and a new instance has to be created if another account should be used. - -Going back to the first example and logging the result without purging the properties, we get: -```typescript -const stored = '0x12f6526dbe223eddd6c6a0fb7df118c87c56d34bf0c845b54bdca2fec0f3017d'; -const loaded = await ipld.getLinkedGraph(stored, ''); -console.dir(loaded); -// Output: -// { personalInfo: { firstName: 'eris' }, -// cryptoInfo: -// { originator: '0xd7c759941fa3962e4833707f2f44f8cb11b471916fb6f9f0facb03119628234e', -// keyLength: 256, -// algorithm: 'aes-256-cbc' } } -// -``` - - -## Mailbox -The [`Mailbox`](src/mailbox.ts) module is used for sending and retrieving bmails (blockchain mails) to other even.network members. Sending regular bmails between to parties requires them to have completed a [Key Exchange](#key-exchange) before being able to send encrypted messages. When exchanging the keys, bmails are encrypted with a commonly known key, that is only valid is this case and the underlying messages, that contain the actual keys are encrypted with Diffie Hellman keys, to ensure, that keys are exchanged in a safe manner (see [Key Exchange](#key-exchange) for details). - -The mailbox is a [smart contract](https://github.com/evannetwork/smart-contracts/blob/master/contracts/MailBox.sol), that holds -- `bytes32` hashes, that are the encrypted contents of the mails -- basic metadata about the mails, like - + recipient of a mail - + sender of a mail - + amount of EVEs, that belongs to the bmail -- if the mail is an answer to another mail, the reference to the original mail - -### Send a Mail -Mails can be sent with: -```typescript -// account, that sends the mail -const account1 = '0x0000000000000000000000000000000000000001'; -// account, that receives the mail -const account2 = '0x0000000000000000000000000000000000000002'; -// mailbox of the sender -const mailbox1 = {}; -// mailbox of the receiver -const mailbox2 = {}; - -const bmail = { - content: { - from: account1, - to, - title: 'Example bmail', - body: 'This is a little example to demonstrate sending a bmail.', - attachments: [ ] - } -}; -await mailbox1.sendMail(bmail, account1, account2); -``` - -### Retrieving bmails -To get received mails use: -```typescript -const received = await mailbox2.getMails(); -console.dir(JSON.stringify(received[0], null, 2)); -// Output: -// { -// "mails": { -// "0x000000000000000000000000000000000000000e": { -// "content": { -// "from": "0x0000000000000000000000000000000000000001", -// "to": "0x0000000000000000000000000000000000000002", -// "title": "Example bmail", -// "body": "This is a little example to demonstrate sending a bmail.", -// "attachments": [ ], -// "sent": 1527083983148 -// }, -// "cryptoInfo": { -// "originator": "0x549704d235e1fe5cd7326a1eb0c44c1e0a5434799ba6ff2370c2955730b66e2b", -// "keyLength": 256, -// "algorithm": "aes-256-cbc" -// } -// } -// }, -// "totalResultCount": 9 -// } -``` - -Results can be paged with passing arguments for page size and offsetto the `getMails` function: -```typescript -const received = await mailbox2.getMails(3, 0); -console.dir(JSON.stringify(received[0], null, 2)); -// Output: -// { mails: -// { '0x000000000000000000000000000000000000000e': { content: [Object], cryptoInfo: [Object] }, -// '0x000000000000000000000000000000000000000d': { content: [Object], cryptoInfo: [Object] }, -// '0x000000000000000000000000000000000000000c': { content: [Object], cryptoInfo: [Object] } }, -// totalResultCount: 9 } -``` - -To get bmails *sent* by an account, use (the example account hasn't sent any bmail yet): -```typescript -const received = await mailbox2.getMails(3, 0, 'Sent'); -console.dir(JSON.stringify(received[0], null, 2)); -// Output: -// { mails: {}, totalResultCount: 0 } -``` - -### Answering to a bmail -Answering to a bmail works similar to sending a bmail, the only difference is, that the id of the original bmail has to be appended to the mail as well: -```typescript -const answer = { - content: { - from: account1, - to, - title: 'Example answer', - body: 'This is a little example to demonstrate sending an answer.', - attachments: [ ], - parentId: '0x000000000000000000000000000000000000000e', - } -}; -await mailbox1.sendMail(answer, account2, account1); -``` - -### Bmails and EVEs -Bmails can contain EVEs for the recipient as well. Because retrieving bmails is a reading operation, funds send with a bmail have to be retrieved separately. - -#### Checking a bmails balance -Funds can be checked with: -```typescript -const bmail = { - content: { - from: account1, - to, - title: 'Example bmail', - body: 'This is a little example to demonstrate sending a bmail.', - attachments: [ ] - } -}; -await mailbox1.sendMail(bmail, account1, account2, web3.utils.toWei('0.1', 'Ether')); -const received = await mailbox2.getMails(1, 0); -const mailBalance = await mailbox2.getBalanceFromMail(Object.keys(received)[0]); -console.log(mailBalance); -// Output: -// 100000000000000000 -``` - -#### Withdrawing funds from bmails -Funds from bmails can be claimed with the account, that received the bmail. Funds are transferred to a specified account, which can be the claiming account or another account of choice. -```typescript -const received = await mailbox2.getMails(1, 0); -const mailBalance = await mailbox2.getBalanceFromMail(Object.keys(received)[0]); -console.log(mailBalance); -// Output: -// 100000000000000000 -await mailbox2.withdrawFromMail(received)[0], accounts2); -const mailBalance = await mailbox2.getBalanceFromMail(Object.keys(received)[0]); -console.log(mailBalance); -// Output: -// 0 -``` - - -## Key Exchange -The `KeyExchange` module is used to exchange communication keys between two parties, assuming that both have created a profile and have a public facing partial Diffie Hellman key part (the combination of their own secret and the shared secret). The key exchange consists of three steps: -1. create a new communication key, that will be used by both parties for en- and decryption and store it on the initiators side -2. look up the other parties partial Diffie Hellman key part and combine it with the own private key to create the exchange key -3. use the exchange key to encrypt the communication key and send it via bmail (blockchain mail) to other party - -### Start the Key Exchange Process -This example retrieves public facing partial Diffie Hellman key part from a second party and sends an invitation mail to it: -```typescript -// -// account, that initiates the invitation -const account1 = '0x0000000000000000000000000000000000000001'; -// account, that will receive the invitation -const account2 = '0x0000000000000000000000000000000000000002'; -// profile from user, that initiates key exchange -const profile1 = {}; -// profile from user, that is going to receive the invitation -const profile2 = {}; -// key exchange instance for account1 -const keyExchange1 = {}; -// key exchange instance for account2 -const keyExchange2 = {}; - -const foreignPubkey = await profile2.getPublicKey(); -const commKey = await keyExchange.generateCommKey(); -await keyExchange.sendInvite(account2, foreignPubkey, commKey, { - fromAlias: 'Bob', // initiating user states, that his name is 'Bob' -}); -await profile1.addContactKey(account2, 'commKey', commKey); -await profile1.storeForAccount(profile1.treeLabels.addressBook); -``` - -### Finishing the Key Exchange Process -Let's assume that the communication key from the last example has been successfully sent to the other party and continue at there end from here. To keep the roles from the last example, the variables profile1, profile2 will belong to the same accounts: -```typescript -const encryptedCommKey = '...'; // key sent by account1 -const profile1 = await profile1.getPublicKey(); -const commSecret = keyExchange2.computeSecretKey(profile1); -const commKey = await keyExchange2.decryptCommKey(encryptedCommKey, commSecret.toString('hex')); -``` - - -## Onboarding -The onboarding process is used to enable users to invite other users, where no blockchain account id is known. It allows to send an email to such contacts, that contains a link. This link points to a evan.network ÐApp, that allows accept the invitation by either creating a new account or by accepting it with an existing account. - -It uses the [Key Exchange](#key-exchange) module described in the last section for its underlying key exchange process but moves the process of creating a new communication key to the invited user. - -To get in contact with a user via email, a smart agent is used. This smart agent has to be added as a contact and a regular key exchange with the smart agent is performed. The agent accepts the invitation automatically and the inviting user sends a bmail (blockchain mail) with the contact details of the user, that should be invited, and an amount of welcome EVEs to the smart agent. - -The onboarding smart creates a session on his end and sends an email to the invited user, that includes the session token, with which the invited user can claim the welcome EVEs. - -The invited user now creates or confirms an account and start the key exchange process on his or her end. The rest of the flow is as described in [Key Exchange](#key-exchange). - -To start the process at from the inviting users side, make sure that this user has exchanged keys with the onboarding smart agent. Then you can use: -```typescript -await onboarding.sendInvitation({ - fromAlias: 'example inviter', - to: 'example invitee ', - lang: 'en', - subject: 'evan.network Onboarding Invitation', - body: 'I\'d like to welcome you on board.', -}, web3.utils.toWei('1')); -``` From aca08ff2dcc6c6c167372ed583496393a159e39e Mon Sep 17 00:00:00 2001 From: Sebastian Dechant Date: Thu, 27 Dec 2018 08:24:00 +0100 Subject: [PATCH 14/22] fix claims tests, switch back to localhost tests, add more timeouts to nameresolver tests --- src/claims/claims.spec.ts | 67 ++++++++++++------- src/claims/claims.ts | 16 ++--- .../service-contract/service-contract.spec.ts | 6 +- src/name-resolver.spec.ts | 10 ++- src/test/test-utils.ts | 2 +- 5 files changed, 65 insertions(+), 36 deletions(-) diff --git a/src/claims/claims.spec.ts b/src/claims/claims.spec.ts index 4a15cea9..c4c41082 100644 --- a/src/claims/claims.spec.ts +++ b/src/claims/claims.spec.ts @@ -50,14 +50,11 @@ describe('Claims handler', function() { before(async () => { web3 = TestUtils.getWeb3(); - console.log(web3.version) executor = await TestUtils.getExecutor(web3); contractLoader = await TestUtils.getContractLoader(web3); dfs = await TestUtils.getIpfs(); claims = await TestUtils.getClaims(web3, dfs); nameResolver = await TestUtils.getNameResolver(web3); - await claims.createIdentity(accounts[0]); - await claims.createIdentity(accounts[1]); }); after(async () => { @@ -65,24 +62,48 @@ describe('Claims handler', function() { }); // can be used for creating new libraries, but disabled by default - // it.only('can deploy a new structure', async () => { - // const keyHolderLib = await executor.createContract( - // 'KeyHolderLibrary', [], { from: accounts[0], gas: 3000000, }); - // contractLoader.contracts['ClaimHolderLibrary'].bytecode = linker.linkBytecode( - // contractLoader.contracts['ClaimHolderLibrary'].bytecode, - // { 'claims/KeyHolderLibrary.sol:KeyHolderLibrary': keyHolderLib.options.address } - // ); - // const claimHolderLib = await executor.createContract( - // 'ClaimHolderLibrary', [], { from: accounts[0], gas: 3000000, }); - // contractLoader.contracts['OriginIdentity'].bytecode = linker.linkBytecode( - // contractLoader.contracts['OriginIdentity'].bytecode, - // { - // 'claims/ClaimHolderLibrary.sol:ClaimHolderLibrary': claimHolderLib.options.address, - // 'claims/KeyHolderLibrary.sol:KeyHolderLibrary': keyHolderLib.options.address, - // }, - // ) - // console.dir({keyHolderLib: keyHolderLib.options.address, claimHolderLib: claimHolderLib.options.address}); - // }) + it('can deploy a new structure', async () => { + const keyHolderLib = await executor.createContract( + 'KeyHolderLibrary', [], { from: accounts[0], gas: 3000000, }); + contractLoader.contracts['ClaimHolderLibrary'].bytecode = linker.linkBytecode( + contractLoader.contracts['ClaimHolderLibrary'].bytecode, + { 'claims/KeyHolderLibrary.sol:KeyHolderLibrary': keyHolderLib.options.address } + ); + + + const claimHolderLib = await executor.createContract( + 'ClaimHolderLibrary', [], { from: accounts[0], gas: 3000000, }); + contractLoader.contracts['OriginIdentity'].bytecode = linker.linkBytecode( + contractLoader.contracts['OriginIdentity'].bytecode, + { + 'claims/ClaimHolderLibrary.sol:ClaimHolderLibrary': claimHolderLib.options.address, + 'claims/KeyHolderLibrary.sol:KeyHolderLibrary': keyHolderLib.options.address, + }, + ); + + const claimsRegistryLib = await executor.createContract( + 'ClaimsRegistryLibrary', [], { from: accounts[0], gas: 3000000, }); + contractLoader.contracts['ClaimsRegistry'].bytecode = linker.linkBytecode( + contractLoader.contracts['ClaimsRegistry'].bytecode, + { + 'claims/ClaimsRegistryLibrary.sol:ClaimsRegistryLibrary': claimsRegistryLib.options.address + }, + ); + (claims.options.executor.signer).contractLoader.contracts['ClaimHolderLibrary'].bytecode = (claims.options.executor.signer).contractLoader.contracts['ClaimHolderLibrary'].bytecode.replace(/3Cf1679B2BA2a70693F55289bf6c81a0097497a6/g, keyHolderLib.options.address.slice(2)); + (claims.options.executor.signer).contractLoader.contracts['OriginIdentity'].bytecode = (claims.options.executor.signer).contractLoader.contracts['OriginIdentity'].bytecode.replace(/3Cf1679B2BA2a70693F55289bf6c81a0097497a6/g, keyHolderLib.options.address.slice(2)); + (claims.options.executor.signer).contractLoader.contracts['OriginIdentity'].bytecode = (claims.options.executor.signer).contractLoader.contracts['OriginIdentity'].bytecode.replace(/674a12Acae46c1E29e5EC124AB698081775C5803/g, claimHolderLib.options.address.slice(2)); + (claims.options.executor.signer).contractLoader.contracts['ClaimsRegistry'].bytecode = (claims.options.executor.signer).contractLoader.contracts['ClaimsRegistry'].bytecode.replace(/d7d62072c409A29a187F81dDd8aCd50bFc070546/g, claimsRegistryLib.options.address.slice(2)); + + const storage = await executor.createContract( + 'V00_UserRegistry', [], { from: accounts[0], gas: 3000000, }); + claims.contracts.storage = storage; + console.dir({keyHolderLib: keyHolderLib.options.address, claimHolderLib: claimHolderLib.options.address}); + }) + + it('can create identities', async () => { + await claims.createIdentity(accounts[0]); + await claims.createIdentity(accounts[1]); + }); it('can add a claim', async () => { const oldLength = (await claims.getClaims('/company', accounts[1])).length; @@ -172,9 +193,9 @@ describe('Claims handler', function() { }); it('can track the creation date', async() => { - const before = Date.now() / 1000; + const before = Math.floor(Date.now() / 1000); await claims.setClaim(accounts[0], accounts[1], '/company'); - const after = Date.now() / 1000; + const after = Math.floor(Date.now() / 1000); const claimsForAccount = await claims.getClaims('/company', accounts[1]); const last = claimsForAccount.length - 1; expect(claimsForAccount[last]).to.have.property('status', ClaimsStatus.Issued); diff --git a/src/claims/claims.ts b/src/claims/claims.ts index 13942084..71ef8720 100644 --- a/src/claims/claims.ts +++ b/src/claims/claims.ts @@ -555,14 +555,14 @@ export class Claims extends Logger { * @param {any} description description of the claim; can be an Envelope but * only public properties are used * @return {Promise} resolved when done - */ - public async setClaimDescription(accountId: string, topic: string, domain: string, description: any) { - let toSet = JSON.parse(JSON.stringify(description)); - if (!toSet.hasOwnProperty('public')) { - toSet = { public: toSet }; - } - const domainWithHash = this.getFullDescriptionDomainWithHash(topic, domain); - await this.options.description.setDescription(domainWithHash, toSet, accountId); + */ + public async setClaimDescription(accountId: string, topic: string, domain: string, description: any) { + let toSet = JSON.parse(JSON.stringify(description)); + if (!toSet.hasOwnProperty('public')) { + toSet = { public: toSet }; + } + const domainWithHash = this.getFullDescriptionDomainWithHash(topic, domain); + await this.options.description.setDescription(domainWithHash, toSet, accountId); } /** diff --git a/src/contracts/service-contract/service-contract.spec.ts b/src/contracts/service-contract/service-contract.spec.ts index c9d1479d..4dc6be1d 100644 --- a/src/contracts/service-contract/service-contract.spec.ts +++ b/src/contracts/service-contract/service-contract.spec.ts @@ -542,10 +542,10 @@ describe('ServiceContract', function() { } // if using existing contract - contract = loader.loadContract('ServiceContractInterface', '0x665339F534618a84B917C0Fc54700F690FC54A4A'); + //contract = loader.loadContract('ServiceContractInterface', '0x665339F534618a84B917C0Fc54700F690FC54A4A'); // if creating new contract - /*contract = await sc0.create(accounts[0], businessCenterDomain, sampleService1); + contract = await sc0.create(accounts[0], businessCenterDomain, sampleService1); await sc0.inviteToContract(businessCenterDomain, contract.options.address, accounts[0], accounts[2]); const contentKey = await sharing.getKey(contract.options.address, accounts[0], '*', 0); await sharing.addSharing(contract.options.address, accounts[0], accounts[2], '*', 0, contentKey); @@ -559,7 +559,7 @@ describe('ServiceContract', function() { console.log(`send test answer ${answerIndex++}`); await sc2.sendAnswer(contract, accounts[2], answer, anweredCallId, accounts[0]) } - console.log(contract.options.address);*/ + console.log(contract.options.address); }); describe('when retrieving calls', () => { diff --git a/src/name-resolver.spec.ts b/src/name-resolver.spec.ts index ce219fa5..fa08e73a 100644 --- a/src/name-resolver.spec.ts +++ b/src/name-resolver.spec.ts @@ -349,8 +349,8 @@ describe('NameResolver class', function() { // wait for timeout await TestUtils.sleep(timeValidMs); + await TestUtils.sleep(2000); await TestUtils.nextBlock(executor, domainOwner); - // check again expect(await nameResolverTimed.getAddress(domain)).to.eq(null); }); @@ -380,6 +380,7 @@ describe('NameResolver class', function() { // wait for timeout await TestUtils.sleep(timeValidMs); + await TestUtils.sleep(2000); await TestUtils.nextBlock(executor, domainOwner); // check again @@ -427,6 +428,7 @@ describe('NameResolver class', function() { // wait for resolval to stop await TestUtils.sleep(timeValidMs); + await TestUtils.sleep(2000); await TestUtils.nextBlock(executor, domainOwner); // check again, resolver should have stopped @@ -478,6 +480,7 @@ describe('NameResolver class', function() { // wait for resolval to be available await TestUtils.sleep(timeValidMs + timeValidPreExpireWindowMs); + await TestUtils.sleep(2000); await TestUtils.nextBlock(executor, domainOwner); // address is still up @@ -509,6 +512,7 @@ describe('NameResolver class', function() { // wait for resolval to be available and extra owner lock has passed await TestUtils.sleep(timeValidMs); + await TestUtils.sleep(2000); await TestUtils.nextBlock(executor, domainOwner); // address is not up anymore @@ -571,6 +575,7 @@ describe('NameResolver class', function() { // wait for resolval to be available (plus 1s to be sure, that we surpassed validity) await TestUtils.sleep(timeValidMs); + await TestUtils.sleep(2000); await TestUtils.nextBlock(executor, domainOwner); // address is not up anymore @@ -620,6 +625,7 @@ describe('NameResolver class', function() { // wait for resolval to be available (plus 1s to be sure, that we surpassed validity) await TestUtils.sleep(timeValidMs + timeValidPostExpireWindowMs); + await TestUtils.sleep(2000); await TestUtils.nextBlock(executor, domainOwner); // owner is still up @@ -733,6 +739,7 @@ describe('NameResolver class', function() { // wait for resolval to be available and extra owner lock has passed await TestUtils.sleep(timeValidMs); + await TestUtils.sleep(2000); await TestUtils.nextBlock(executor, domainOwner); // address is not up anymore @@ -761,6 +768,7 @@ describe('NameResolver class', function() { // wait for resolval to be available (plus 1s to be sure, that we surpassed validity) await TestUtils.sleep(timeValidMs + timeValidPostExpireWindowMs); + await TestUtils.sleep(2000); await TestUtils.nextBlock(executor, domainOwner); // address is not up anymore diff --git a/src/test/test-utils.ts b/src/test/test-utils.ts index 8c32bc8c..39fcccbf 100644 --- a/src/test/test-utils.ts +++ b/src/test/test-utils.ts @@ -69,7 +69,7 @@ import { Wallet } from '../contracts/wallet'; export const publicMailBoxExchange = 'mailboxKeyExchange'; export const sampleContext = 'context sample'; -const web3Provider = 'wss://testcore.evan.network/ws'; +const web3Provider = 'ws://localhost:8546'; const helperWeb3 = new Web3(null); const sampleKeys = {}; // dataKeys From 5b9e8ec8cecb0eac78c843f90467d7b5ec8e9df8 Mon Sep 17 00:00:00 2001 From: Sebastian Dechant Date: Wed, 2 Jan 2019 10:20:59 +0100 Subject: [PATCH 15/22] update travis yml --- .travis.yml | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4a5d13cf..6a1c4811 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,51 +6,57 @@ matrix: include: - name: "non-blockchain specific tests" node_js: "8.11.3" - env: - - ACCOUNT_MAP='{"0xC2ee94f6cf046B02D530cf1cd16A2b32b8A4340d":"EF7012DD4D5DD6A78765C511F452F8CA641378F0DF071F9C32D506F45F31B22C","0xac46D762f0aB316105C5Cf4375bb8e380Be88658":"E29C1E4A683CC629E39CE219CFB1F35BBA898605E1B197162F0EECF0F1139630","0x35f8220bC83577458aEa4a1085A8b832DEa79b7a":"340BA316637FD01A1AFD54D4491A899F6D8EA0FB89A1D7BA94682F7D68B21B20"}' + env: + - ACCOUNT_MAP='{"0x001De828935e8c7e4cb56Fe610495cAe63fb2612":"01734663843202e2245e5796cb120510506343c67915eb4f9348ac0d8c2cf22a","0x0030C5e7394585400B1FB193DdbCb45a37Ab916E":"7d09c0873e3f8dc0c7282bb7c2ba76bfd432bff53c38ace06193d1e4faa977e7","0x00D1267B27C3A80080f9E1B6Ba01DE313b53Ab58":"a76a2b068fb715830d042ca40b1a4dab8d088b217d11af91d15b972a7afaf202"}' - TESTSPECS='src/encryption/*.spec.ts src/dfs/*.spec.ts' + - ENS_ADDRESS='0x9f8063ac44D23C99E943eA3DE3E1bb6Ab7678df0' + - ENS_RESOLVER='0xc6b9F181BFa9eFA7679a3B3a786aB582AeE79dad' script: - npm run testunit $TESTSPECS - name: "services contracts tests" node_js: "8.11.3" - env: - - ACCOUNT_MAP='{"0xC2ee94f6cf046B02D530cf1cd16A2b32b8A4340d":"EF7012DD4D5DD6A78765C511F452F8CA641378F0DF071F9C32D506F45F31B22C","0xac46D762f0aB316105C5Cf4375bb8e380Be88658":"E29C1E4A683CC629E39CE219CFB1F35BBA898605E1B197162F0EECF0F1139630","0x35f8220bC83577458aEa4a1085A8b832DEa79b7a":"340BA316637FD01A1AFD54D4491A899F6D8EA0FB89A1D7BA94682F7D68B21B20"}' - - TESTSPECS='src/claims/*.spec.ts src/profile/*.spec.ts src/*.spec.ts !src/name-resolver.spec.ts' + env: + - ACCOUNT_MAP='{"0x001De828935e8c7e4cb56Fe610495cAe63fb2612":"01734663843202e2245e5796cb120510506343c67915eb4f9348ac0d8c2cf22a","0x0030C5e7394585400B1FB193DdbCb45a37Ab916E":"7d09c0873e3f8dc0c7282bb7c2ba76bfd432bff53c38ace06193d1e4faa977e7","0x00D1267B27C3A80080f9E1B6Ba01DE313b53Ab58":"a76a2b068fb715830d042ca40b1a4dab8d088b217d11af91d15b972a7afaf202"}' + - TESTSPECS='src/claims/*.spec.ts src/profile/*.spec.ts src/*.spec.ts' + - ENS_ADDRESS='0x9f8063ac44D23C99E943eA3DE3E1bb6Ab7678df0' + - ENS_RESOLVER='0xc6b9F181BFa9eFA7679a3B3a786aB582AeE79dad' script: - - npm run testunit $TESTSPECS + - npm run testunit $TESTSPECS -- --exclude src/name-resolver.spec.ts - name: "data contract (encryption) tests" node_js: "8.11.3" - env: - - ACCOUNT_MAP='{"0x0e10fa0aa2273F074F51a09F2eC95890816FD6d6":"4943D3A1D1457E627537D5C1DD6846B718807D11431283B659AED9F2988F3694","0xb0646ee7b728B72bc9F73D0f9DDAf00D1a981fa0":"D9734AFE9168C37481A977C91FE25B9C7D814789F515D78DC084A27BD2137E14","0x04B1Ee1b9D5283B2694B739DA5b49DBC88199750":"68475374AC69364D64F94A47D66410936F63971FE5EEAEFDF85913D153799EE5"}' + env: + - ACCOUNT_MAP='{"0x001De828935e8c7e4cb56Fe610495cAe63fb2612":"01734663843202e2245e5796cb120510506343c67915eb4f9348ac0d8c2cf22a","0x0030C5e7394585400B1FB193DdbCb45a37Ab916E":"7d09c0873e3f8dc0c7282bb7c2ba76bfd432bff53c38ace06193d1e4faa977e7","0x00D1267B27C3A80080f9E1B6Ba01DE313b53Ab58":"a76a2b068fb715830d042ca40b1a4dab8d088b217d11af91d15b972a7afaf202"}' - TESTSPECS="src/contracts/data-contract/*.spec.ts" + - ENS_ADDRESS='0x9f8063ac44D23C99E943eA3DE3E1bb6Ab7678df0' + - ENS_RESOLVER='0xc6b9F181BFa9eFA7679a3B3a786aB582AeE79dad' script: - npm run testunit $TESTSPECS -- --grep 'when working encrypted DFS files' - name: "data contract tests" node_js: "8.11.3" - env: - - ACCOUNT_MAP='{"0x13c9c6ECFA485A74a0A8773856c21a215CbE571A":"ece5780d73ce564f641224c68a12c313bf5cfe0bc5b3ab116be1a573280d1a2a","0x5F67b2134B89Cad2FDAFe6C72D8BEDeF4072cb6b":"b7847096f0bf10996ea70feae73211b7236e9a2317943400fecf8807cd542563","0x2B144A2C8055535A48582c1d0bA11A2Ff10769b2":"ce03f7cd8992ba36687de0d942870286128d379a6fc08aab96dbbde7268e6871"}' + env: + - ACCOUNT_MAP='{"0x001De828935e8c7e4cb56Fe610495cAe63fb2612":"01734663843202e2245e5796cb120510506343c67915eb4f9348ac0d8c2cf22a","0x0030C5e7394585400B1FB193DdbCb45a37Ab916E":"7d09c0873e3f8dc0c7282bb7c2ba76bfd432bff53c38ace06193d1e4faa977e7","0x00D1267B27C3A80080f9E1B6Ba01DE313b53Ab58":"a76a2b068fb715830d042ca40b1a4dab8d088b217d11af91d15b972a7afaf202"}' - TESTSPECS="src/contracts/data-contract/*.spec.ts" + - ENS_ADDRESS='0x9f8063ac44D23C99E943eA3DE3E1bb6Ab7678df0' + - ENS_RESOLVER='0xc6b9F181BFa9eFA7679a3B3a786aB582AeE79dad' script: - npm run testunit $TESTSPECS -- --grep 'when working encrypted DFS files' --invert - name: "service/base/businesscenter contract tests" node_js: "8.11.3" - env: + env: - ACCOUNT_MAP='{"0x001De828935e8c7e4cb56Fe610495cAe63fb2612":"01734663843202e2245e5796cb120510506343c67915eb4f9348ac0d8c2cf22a","0x0030C5e7394585400B1FB193DdbCb45a37Ab916E":"7d09c0873e3f8dc0c7282bb7c2ba76bfd432bff53c38ace06193d1e4faa977e7","0x00D1267B27C3A80080f9E1B6Ba01DE313b53Ab58":"a76a2b068fb715830d042ca40b1a4dab8d088b217d11af91d15b972a7afaf202"}' - TESTSPECS='src/contracts/*.spec.ts src/contracts/base-contract/*.spec.ts src/contracts/business-center/*.spec.ts src/contracts/service-contract/*.spec.ts' + - ENS_ADDRESS='0x9f8063ac44D23C99E943eA3DE3E1bb6Ab7678df0' + - ENS_RESOLVER='0xc6b9F181BFa9eFA7679a3B3a786aB582AeE79dad' script: - npm run testunit $TESTSPECS - - name: "nameresolver contract tests" - node_js: "8.11.3" - env: - - ACCOUNT_MAP='{"0x3Be2E8D1A93139A981dc0dFe5E21B53fD6768FA6":"f42d8b97d89636b9c49d765e471f89b465df1bbb59ced554387ba4c38789fe31","0xfe825e67A8F8a0fB31496280173a3de4a6ddEc43":"5e0dbef7deafe54becbcac51f970307fe1679797cbe40f18f5dc55c9740b8d4d","0x4e61A980F2081fCAc3E1777d667B66DF0516d264":"44367a662acc6267065ce64b83a88949f5adc0249ba1cbf55309877117c2e954"}' - - TESTSPECS='src/name-resolver.spec.ts' - script: - - npm run testunit $TESTSPECS +services: + - docker + addons: apt: sources: @@ -62,9 +68,10 @@ addons: before_install: - export CXX="g++-4.8" - npm install -g npm@latest - + - docker pull evannetwork/parity_testchain + - docker run -d -p 127.0.0.1:8546:8546 -p 127.0.0.1:8545:8545 -u root --entrypoint /home/parity/bin/parity evannetwork/parity_testchain --chain /root/parity/spec.json --jsonrpc-interface all --unsafe-expose install: - - npm install + - npm install - cd node_modules/@evan.network && rm -rf dbcp && git clone https://github.com/evannetwork/dbcp.git && cd dbcp && git checkout develop && npm i && npm run build && cd ../../../ - cd node_modules/@evan.network && rm -rf smart-contracts-core && git clone https://github.com/evannetwork/smart-contracts-core.git && cd smart-contracts-core && git checkout develop && npm i && cd ../../../ - rm node_modules/web3/*.d.ts \ No newline at end of file From e07f42ea8c945466d2e352ae4cb8664f41c8f3b0 Mon Sep 17 00:00:00 2001 From: wulfraem Date: Mon, 7 Jan 2019 15:25:09 +0100 Subject: [PATCH 16/22] add log output for `claimsRegistryLib` --- src/claims/claims.spec.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/claims/claims.spec.ts b/src/claims/claims.spec.ts index c4c41082..2b74d372 100644 --- a/src/claims/claims.spec.ts +++ b/src/claims/claims.spec.ts @@ -97,7 +97,11 @@ describe('Claims handler', function() { const storage = await executor.createContract( 'V00_UserRegistry', [], { from: accounts[0], gas: 3000000, }); claims.contracts.storage = storage; - console.dir({keyHolderLib: keyHolderLib.options.address, claimHolderLib: claimHolderLib.options.address}); + console.dir({ + keyHolderLib: keyHolderLib.options.address, + claimHolderLib: claimHolderLib.options.address, + claimsRegistryLib: claimsRegistryLib.options.address, + }); }) it('can create identities', async () => { From 0a097f3786f74e64796230ba4c60ccdb17d2ec6c Mon Sep 17 00:00:00 2001 From: Tobias Winkler Date: Wed, 9 Jan 2019 10:39:40 +0100 Subject: [PATCH 17/22] remove describe.only --- src/bundles/bcc/dbcp.json | 4 ++-- src/claims/claims.spec.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bundles/bcc/dbcp.json b/src/bundles/bcc/dbcp.json index 795667da..a4a0a934 100644 --- a/src/bundles/bcc/dbcp.json +++ b/src/bundles/bcc/dbcp.json @@ -9,7 +9,7 @@ "files": [ "bcc.js" ], - "origin": "QmSyEyRBsNPfgUBueJozayF3xoYX4UL11Ez9LfAKJ6DSU7", + "origin": "QmVGiU7qp4jUtT3jXAnMUMZL6xBU1o5LQALsmhEGNk6ifC", "type": "library" }, "description": "Contractus for loading ens entries and it's data...", @@ -33,7 +33,7 @@ "1.3.1": "QmbQ9HskNocFPNU8wf8QrweJzidMVMbJp4gqxoWEbTLyas", "1.4.0": "QmVv35DzcryDQnbmTVHJChD1enG459cUGKmqZj6xE74nHX", "1.5.0": "QmQnmbZJcUf6j6u6nsJh5jiqxwAfsBybZWPk65tVN8HZ3P", - "1.6.0": "Qmf1amzH6zaBkbbgz9MaVhq1sooZwjnPebjWijTQ9kQysb" + "1.6.0": "QmTHvUrZEKUQ3KkoHVs6SmnPFw437bPpXuSqji5Pb67gJg" }, "dbcpVersion": 1 } diff --git a/src/claims/claims.spec.ts b/src/claims/claims.spec.ts index 1b40eeb0..bb92db85 100644 --- a/src/claims/claims.spec.ts +++ b/src/claims/claims.spec.ts @@ -320,7 +320,7 @@ describe('Claims handler', function() { }); }); - describe.only('when using identities for contracts', () => { + describe('when using identities for contracts', () => { let claimsRegistry; let contractId; From 093708ac07a7e6ce20973068177394026ccce2cf Mon Sep 17 00:00:00 2001 From: Tobias Winkler Date: Wed, 9 Jan 2019 14:36:02 +0100 Subject: [PATCH 18/22] add missing dbcpVersion to dbcp files; add licenses to dbcp files --- docs/dbcp.json | 6 +++--- src/bundles/bcc/dbcp.json | 10 +++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/dbcp.json b/docs/dbcp.json index 4fd3fa9f..907fb915 100644 --- a/docs/dbcp.json +++ b/docs/dbcp.json @@ -12,6 +12,7 @@ "secondaryColor": "#eaeaea", "type": "library" }, + "dbcpVersion": 2, "description": "blockchain-core documentation", "i18n": { "description": { @@ -26,14 +27,13 @@ "imgSquare": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAABmJLR0QA/wAAACLmRz0XAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH4ggKDS42BPC0agAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAABgfSURBVHja7Z19kFTVmcZ/fbsHZgZsxgEJwoiFAUMka1wTXfBrjVgJgkmMAmoq2VLLj8SoCabWrSWpxKRittaqgFFj/NjSVMXyCzWaBDQp0axfsCRxjSuBIJElIIsI4zAzzAwz0937R5+R0fnq7rnn9j3nPr+q+YfquUy/532fe89zzzlvavryTQinyQJHA03AVGAKMBmYBDQCDeYz44F6oBYYA2SAwFwjD/QC3UAX0AG0A61AC9AM7AX2ALuBXcBOYLv5jHCUjELgBAHwMeA4YDZwLDATOAaYGNL1x5if8WX+7j7gTWArsAXYDPwZeN0Ii5AAiDJIAycDnwROBE4Aju93t44bE83PSR/49zzwGvAq8ArwB2ADkNMQx4eUpgBVpwE4AzgNOAWYa0TAR3LAeuBl4EXgeTPFEBKARPEp4GzgLFPwSWY98CzwDPCcUkMC4CONwLnAQmABMEEhGZT9wNPAGuDXFM1HIQ/ASY4AzgfOM0UvRmYCcKH5wYjBE8DjwDsKj54AXBDUi4ClwGcVjlD5FfAI8BDFV5YiBAKFIBROB+4C3gV+ruK3wmdNbN81sT5dIZEAVJN64BqKr7eeB66k/HfoonzGm1g/b2J/jRkLIQGIhDnAj82c9DbgEwpJ1fiEGYN3zJjMUUgkALaYDzxGcYXbdbrrxO5p7DozNo+ZsRISgFA4j0Pvqc9XOGLP+WasnjVjJyQAFXEB8BLwC4oLd4RbfMqM3UtmLIUEoCTOpWgwPUpxaa5wm1PMWD5vxlZIAAblVGA1xffNesXkH6ebsV1txlpIAACYAdxHcXPKQoXDexaasb7PjL0EIMF8B/grcInqInFcYsb+OxKA5HEBsAn4HpBSLSSWlMmBTSTUKEyaABwNPEDRFJqt/BeG2SYnHjA5IgHwkGuM0l+sfBdDcLHJkWskAP7wEYrO721AnXJcjECdyZXVJnckAA7zNeB/kLsvymehyZ2vSQDcYzLFveO3AzXKZVEhNSaHHjE5JQFwgM8D/w0sUf6KkFhicurzEoB4cxPFI6SmKmdFyEw1uXWTBCCeg7MGWK48FZZZbnJtqgQgHnwa+C/gHOWmiIhzTM59WgJQXa4FfkOxL54QUdJkcu9aCUB1uAW4VXkoqsytJhclABFRT9GM+bpyT8SEr5ucrJcA2OXDwH/i4esY4TyfN7n5YQmAHeYBv6PYNVeIOPJJk6PzJADhshBYi8w+EX+aTK4ulACEw0UUN2ZoI49whTqTsxdJAEbHpcCDyifhKA+aHJYAVMBVwL3KIeE495pclgCUwVeBO5U7whPuNDktASiBK4E7lDPCM+4wuS0BGIZLKLZ+FsJH7iJmJ1DHSQCWUDyrXQifuY8YnVURFwH4DMVTV4RIAo+YnJcAACcBq5QTImGsMrmfaAE4GngYOEz5IBLGYSb3j06qAGQoLpSYoVwQCWWGqYFMEgXgARzaNCGEJeaZWkiUAPw7OrVXiD6WmJpIhABcAdygMRfifdxgasNrATgduFtjLcSg3G1qxEsBOBxt7hFiJO41teKdANwDzNT4CjEsM02teCUAy4ELNLZClMQFRNTkJgoBOBvP2ikJEQE3mdqxiu0FCPVoay8Axx1ZS7Z2oN7++f8O0tqVC+16o7120+E1NDXUhH5dgGxtmuOOHFvy53e29LDz3Z4kp80dwAlAh6sCcDswS+UP3100mbkzBh4bv+TWV9nQVRva9fpz4d1vsn57eYW65MQJfOOsScNf957/Zf22HkiV9wB53JFjefjy6SV//pZn97Jy7d4kp80sU0OXuTgF+Cdifh5aHCjkuskfsJPk+Y5m8l2t4V+3q5XcAfuFme/ugEI+6SlyqaklpwRgKrBS5V1ioh9sp3CwPXxxKeTJdzRTyHWHe93eLgrdHRS6O+wGJtcdidA4wEosdSO2JQA/Aho1bmXkuoVCfU9g2vZYuZPmDuy1focudHeQ72xJeno0mppyQgC+jAPnocdvLpAn326noAr5Xjt30kKeXPse+09InS32nzbiz0WmtmItAA3AzarmUfgBHc3W7qRWphk9XVZ8hsGeNmw9ITnEzabGYisA/wZMUSnHzw+wOc3Id7ZAvtfZJySHmGJqLJYCMB/4iko4xnc7W0VUyEdi1hVkCmJqbH4cBeAHKt0Q76qWjLtCrtuKqRbVVKDQ3WFtmuQQP4ibAFwLzFXZhnlT7bV2t8t3tVox1fIW32QM+PstTZMcYa6puVgIwATgRpWspbudpbtq7sBeK/P2fHs0j+i5iMQmxtxoaq/qAvAd9M7f3t3OVqIX8uTawn+FZ2uKMaifYWma5AiNpvaqKgAfBa5XmVq+27XutucHWJhP5ztbIrk7F/K9kaxDiDHXmxqsmgAsV3lGYghYS/R8VyuF3q7wrxvR3bnQ05V0U3B5tQRgHvAlVWdEGtDTZe3ROmehWAv53siW8CbcFPwSozhefzQCoJN9o/YDOlus3K1tPWHYeroYVMSSbQreELUAnAmcp5Ksgh9ga32ApSeMyFbvFfLWvBIHOM/UZGQCsEylWEU/oHW3xSeMkLcOW1zPEGVsHGBZVAJwGvA5VWIVNSDXTaHHzqN1oSf8BUKRnB3QLzb5ZC4X/pypzbKo5Eiw65JaeKWcwzcU2dr0oP8+pylb2fXqa0b8TCXXbmqss3LdVCrPcUfWlv23zDu2siUmu7pyvNWeTlqKXge8WNa4TF++qZzPHw/8KakC8PDl00c8h0/EgxWrt3LLCx2k0mOS9tU/DrxmawpwtVJLuEJCTcGyarQcAfgQcJXSSjhDMk3Bq0ythi4AVyijhHMakExT8AobAnC50km4SP5geyRnFcSIy8MWgAuBo5VKwlkR6GiObFViDDja1GxoAnCJUki4Tq5tj/2zC+NDSTVbyjqA2cACpc/IrFi9VUGIiKbGOpbOm1amIVA8AyGdnVJ2WzMHWWBqd/NoBUA7/krkR7+WAETFvGMbyxcADp2BEIyblIQwfQn49minAF9Uugmv/IDkmIIj1u5IAvBpYIZSRngnAskwBWeYGq5YAC5UqghfybXtScIZAheORgAWK02EtySj29DiSgXgC0BWWSK81gD/uw1lTS0PSmYEARAhMacpS7Y+Y/3/2bijjdbOnmE/U+kW26jZua+THfs6K/rdcrcSB7WQqhl+p+f6bc52KP4C8ItyBcDZQz+Wzbfziqepoabi3/3ektmRFN7ilRtYt2X4U3IfXXayE+O4YvXWil+tLp03raLXhMMx/Z9fITXGye3gnyv3CeAcQug6Ui2+cVYi3vGKiMkd2EsmMxWCjGt/+gRT00+V6gEs1HAL8UHDIG/tUNYIGLSmhxIALf0VYjANsNRNKQIWlCoAHwNmaqiFGJz8wXYXG5HMNLU9ogdwtoZYuM6OfZ3srPANQkl+QEcz6cwY184cPBt4fSQBmO/64K9Y86aVedqSudM4amKdqssBVq1/y+7mLNOdOD1hqks7C+cDt4wkAGe6Pvgr1+61Mk+bN6tRAiD6aUCx6Ul6/GRX/uQzR/IATgHGuz4wQW2WVE2tMlTYF4HuDpd2Fo43NT6kAJzmy8Ckx01KwqEPIgY4trPwtOEE4FRvRiXIENQ1KDtFJDi0PuDU4QRgrk+DoqmAiNAQsNJi3QJzhxKAY4HJvo2LpgIiMg2w1GI9ZCabWh8gACd5OSqaCogo/YDOlsg6IY+CkwYTgBN9HZSgNpvEJpGiWn7Agb1xP378xMEE4ASfByUYrx2CIkI/oC3WfsAJgwnAx30ek1R6jKYCIjoNiHdPwo9/UACOAib6PihBXYOmAiI6PyC+m4Ymmpp/TwDmJGVQNBUQkfoBHc1xPXl4DhzaCzA7KQPSNxVw4HWNNUY6Miwu7BjFbr5yzwS0Fjdz8nAM25HNBp7uE4CP+JTgI58JOKkiAWjyZCPQ4pUbvBc5G2cCTvvq0xX7ATHcNPSR/k8As3wa/NLOBNRUQERH36ahoDY2J+3P6u8BHKMhEsIu+Xj5Acf0CUCA+v8JEQm51t1x2TQ0AwgCYLqGRYio5gKx2jQ0PcC8DxRCRKQB8dk0dFQGmKYhSRaudAZ6ZP1bPLLuLT/9gM4WUjW1pDJV3a4+LQNMUUkkC1d6A657o9nrcci17SEzoaqdhqZkgA+pJIRv2D4WPDQ/oO9k4erwoQxwhG+Dv2K1neOgdSy4O1g/FjwsDTCdhoL6qjyVHZHBw01AK9futWKy6FhwYcUP6GollR5DamzkB3JPDIDDfQtoUJsl5V4HV5FgqrRp6PAAyHoXzVSgXX/CLcymoYgXCWUD4DAf45nK1JIaU6/EEu5oQPSdhw8LgHG+BjRd36gTgYVbfsDB9ig7DY0LAH9drSATp91XQpQmAtH5AXUBMNbnYAZ1DTIEhXsiEE2nobEBUON7MGUICuf8gHxvFJuGagIg7XswU5lagrHjlVXCLRGwv2koHQCpJAQzkCEoXJwKdLbY7DycCoBCIiKZCtQXQDiJxc7DhQDIJSWQahEmHDUEiicJWdCWDNDDocNBvWDujGEWAOWmk6twsUW2vkbJ6AjXL5rJ9YtmhnrNSk8FDkUD7Gwa6skAB/FsLcDDl+uUM+GhH9DVGvYK14MB0KnQCuGIH3Bgb5iLhDoD4IDCKoQ7fkCIm4YOBECboiqEQxoQ3qahtgBoVUiFcMwPCKfzcGsAvKtwCpFIP+DdANinUArh6JPA6BYJ7QuAdxRGIRz1A/K95A7srfTX38kAb/sWlDieCvzdVZvJ1ttfb7Vxhzzdvhxw4VTgUESgu4N8Z0slS93fzgC7fQvILc+1jEYVh2Q0pwJv3CmvVVicClTWaWh3AHjXeyk1dry2/4rEUcGmobcCYIePwQjGTdLGH5E0Q6DcTUM7AuBvvsYjnZ2iMwBEsjSgvEVCfwuAPLDNy2ikgqIICJEkP6CrlUJ3x0gf2wbk+26Pb/oajFR6TLX6rglRPT/gwF7I9w73kTcB+gTgDZ+DEdRmZQqK5PkBw5uCb/QXgL/4Ho+gvlGmoJAfcIi/9BeAzd5HIxWQPmyyTEGRLD9g6E1Dm/sLwMZERCPIFEVAiCT5AYN3GtrYXwB2kJBNQalMrUxBkTg/4AObhvaZmqf/8/CfkhKPoDarzsEiYRrwvk1D79V6fwF4NUkBSWuloEiaCHR39HUefq/W+29PeyVR0UgFBOMnFZdO2m/CKCJmydxpzJsV7lRv8coNzscl39FMKjPmlb5NQ/0F4Pe+DP72m2aX8enjVS0ectTEuop3bvpOrm3P7zMNTcWbYL9/3wLsUXiE8Jo9FPJb+joPf/Cl+HrFRwivWQ+m83BH8wABeEnxEcJr3qvxfFfrAAF4UfERwmveV+MfFICXgXbFSAgvaTc1PqQAAPxOcRLCSwbU9mACsFZxEsJL1pYiAM8oTkJ4yYDaHuyg+teBrcBMxctPbPVNCJuXtzRrsMJjq6ntEQUA4GngGsXMT5LSMEMMqGlKFYA1zgpAvpd1lu4cc47Kkq3LKJUcecqR0A2o6ZIF4ClgPzDBua8ZZFh65xbynS2hX/rRZScz71idJSCcY7+p6YHlMswv/dLVbxvUNWi/vxAl1PJwAvALl79xetwkUoEe14UYrpZHEgB3O1qmAgKd/ydEa6UCAPCoy99cTUGEGL6GRxKAh13/9jr/TyScYWt4pEnybyn2EJvhuh+Q691FYfhWSaOX2mUnK90iIltfoyCMzDZTwxULAMADwLecDoPxA3L7d1n9b/SKUMSMB0Z8Qi7hIvf7EAn5ASKB3B+GAGxmiGWELvoBahIqEsLTlNDyr9RGeT/zJSpqEioSQkk1W6oAPAxs9yIsph+AmoQKj9lOiW/wyqmC//AlOqn0GNLyA4S/lFyr5QjAPT5FKDV2vPwA4Ssl12o5i+XfBu4CrvLJDyj0dg/WOnlQKmkN9dZPFwz679O+WpmvOtT1RnvtUnY6Ll65oaKt1t88dybXLyr9fJlK/x8BpkbftvEEAHCHV6GSHyD8o6waLTfzXwNWeaUB8gOEP6wyNWpNAABu9S1q8gOEJ5Rdm5UIwIs4fFjIkIEYN0nrA4TL/JIKOntVOvld6WME04dNlh8gXKWimqw0238HPOFdCIMM6XGTlErCNZ6gwo5eo7nd3exjJFNj6glqs0op4RIV1+JoBGAdnuwUHBAU7RcQ7nC/qcXIBQDgh75GVX6AcIRR1eBoM3wTsMLLsMoPEPFnhanBqgkAwPcBL9dtyg8QMabZ1B7VFoD9wI2+RjmobyRVU6t0E3HjRlN7VRcAgNuA9d76AePlB4hYsd7UHHERAIBvexvuVFA0BYWIB6HVWpgCsBa401sNyNQS1DUo9US1udPUWuwEAOBfgd3e+gF1DfIDRDXZbWqMuApAC3CDzyMgP0BUkRtMjcVWAAB+DjwkP0CIUHnI1BZxFwCAb+Lp2gD5AaIKNJuawhUB2AUs83lEgroGNR0VUbHM1FT4N7PpyzfZ/MPvBS71dlgKeXL7h286OtRBm5UeellK/8FKrj2nKUu2fvgzYjfuaKO1s6fsax81sY6miXUlf77S/8dT7gMus/Y0a1kA6oFXgVneakCu23rTUZFY3gBOADqsPcla/gIdwNU+j5CajgqLXG2z+KMQAIBncL29+EhBrM3KDxBh8y1TO7guAFDcs/yYz6OVHjeJVJBR2ooweIyIztqIckXLFcBWf+cCAYHWB4jRs9XUCr4JwLtYdDPlBwhPuMzUincCAPACcKXvfoCajIgKudLUCL4KABQ7l97stQjoUFFRPjdThQ7c1drV8i941mNwgB+gpqOidFaZmiApAgDwRUZxnLELfoCajooSWGdqgaQJQC9wMbDNWxFQ01ExPNtMDfQmUQAAtgMXAm3yA0TCaDO5v72q+RmDQPweWCI/QCSMJSb3SboAAPwGWCo/QCSEpSbnkQAcYhUebx2WHyAMlxKjN2Bxey79GXCVt37AuEnyA5LNVSbHkQAMzd14vIVYTUcTy9Umt5EAjMxPga/4+RigpqMJ5Csmp5EAlM5deLp5SE1HE8VlJpeRAJTPfRQXSvj3IKD1AUngYpPDSAAq5yFgEdApP0A4QqfJ2dj3x3Al+9YA84Gd8gNEzNlpcnWNEynoUGDXAWcCf5AfIGLKH0yOOrPJzbXnz78C/wg86Z0foKajrvOkyc2/OpV7Dga6AzgP+LFXfoCajrrMj01Odrj2h7uccd8ArvNnLqCmo45ynclFN58+HQ/+bcBn8MQcVNNRp9hpcu82p6efHgzEb4F/AJ7ywg+oa5AfEH+eMjn3W+fzzZMB2QUsJKJmCvIDEs0PTa550RDStyz7FkUzxu3BkR8Q15vMeXjW5s7H28yTwN/j+KnD8gNixSqTU0/69sV8fc7cQ/HUlWsAZxvNB3UNajpaXXpMDi01OYUEwC1+AvwdjizLHNQPUNPRarHG5M5PfP6SSXCa/kJxY8a1uLihSE1Ho6bT5MoikztIAPzgduCjwIPOaYCajkbFgyZHbk/KF07au6btFLuwLAY2OzVQtVn5AfbYbHLii1T5nH4JQDQ8ZpT+u0BBfkBiKZgc+KjJicSR9NUm3wc+TMxOapUfEAk/M2P//SQHQcvNiv3ZLgVOw4G3BfIDRs0aM9aX4nFfSglA+bxE0fn9LPBC3P0ANRkpmxfM2C4yYy0kAIPya+AMiqbQy7EdOB0qWiovm7E8w4ytkACUxGPAqcAXgOdi6Qeo6ehwPGfG7lQSavBJAMLhCeAs4Gzg8bj5AWo6OoDHzVidZcZOSABCYS1wAfAx4FZicvyTmo6CGYtbzdhcYMZKSACssBH4OnAExSWjf5QfUDX+aMbgCDMmG5WeEoAo7zq3A5+kaDDdDbTLD7BOu4n1GSb2t+PgYZwSAL94gWLr58OBLwO/kh8QOr8ysT3cxPoFpd3o0brScOkF7jc/RwDnUzxFZkFkfkBvF/mD7b7E82mKRt7jwDtKLws5M335JkXBPo3AuRTPklsATLD5n+X276KQ63YxTvtN0a+h+M6+WakjAfCRT3HoVdXc0K+e76V3/y4o5F2IxXrgWeAZ4rjeQlMAYYHn+iV7A0VD6zTgFCMI6VFd3TQdzbXH7hSrnCn4l4EXgeeBFqWDBCDJtAC/ND+Y4j+ZosN9InACcDxlGrZ9TUfzXa3V+l554DXgVeAVio0zNxgREBIAMcxdch3v7zAbUFzkchwwGzgWmAkcA0wc8kGgvpFCT5dtP2Af8CawFdhC8XCNPwOvGxEQMeb/AYDDAD0ixn7gAAAAAElFTkSuQmCC", "name": "bccdocs", "tags": [ - "dapp", "contractus", + "dapp", "library" ], "version": "1.0.0", "versions": { "1.0.0": "QmanLD3cNKuLFuB3rQJWyk93tAv63ixg6ELtVkF5zdohuc" - }, - "dbcpVersion": 1 + } } } \ No newline at end of file diff --git a/src/bundles/bcc/dbcp.json b/src/bundles/bcc/dbcp.json index a4a0a934..5485a479 100644 --- a/src/bundles/bcc/dbcp.json +++ b/src/bundles/bcc/dbcp.json @@ -12,11 +12,16 @@ "origin": "QmVGiU7qp4jUtT3jXAnMUMZL6xBU1o5LQALsmhEGNk6ifC", "type": "library" }, + "dbcpVersion": 2, "description": "Contractus for loading ens entries and it's data...", + "license": { + "file": "https://ipfs.evan.network/ipns/QmT1FwnYyURjLj7nKMwEuTPUBc5uJ6z1zAVsYnKfUL1X1q/AGPL-3.0-only.txt", + "type": "AGPL-3.0-only" + }, "name": "bcc", "tags": [ - "dapp", "contractus", + "dapp", "library" ], "version": "1.6.0", @@ -34,7 +39,6 @@ "1.4.0": "QmVv35DzcryDQnbmTVHJChD1enG459cUGKmqZj6xE74nHX", "1.5.0": "QmQnmbZJcUf6j6u6nsJh5jiqxwAfsBybZWPk65tVN8HZ3P", "1.6.0": "QmTHvUrZEKUQ3KkoHVs6SmnPFw437bPpXuSqji5Pb67gJg" - }, - "dbcpVersion": 1 + } } } \ No newline at end of file From 10bd4f8d026b97fa8a1231438a25012c709406b0 Mon Sep 17 00:00:00 2001 From: wulfraem Date: Wed, 9 Jan 2019 15:31:35 +0100 Subject: [PATCH 19/22] use dbcpVersion 1 as fallback, if omitted --- docs/blockchain/description.rst | 2 +- src/shared-description.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/blockchain/description.rst b/docs/blockchain/description.rst index 3fda0772..a3fb4d69 100644 --- a/docs/blockchain/description.rst +++ b/docs/blockchain/description.rst @@ -179,7 +179,7 @@ Example validateDescription =================== -Descriptions are validated when setting them. A list of known DBCP definition schemas is maintained in `description.schema.ts `_ . If a description is set, its property `dbcpVersion` will be used for validating the description, if `dbcpVersion` is not provided, the latest version known to the API is used. +Descriptions are validated when setting them. A list of known DBCP definition schemas is maintained in `description.schema.ts `_ . If a description is set, its property `dbcpVersion` will be used for validating the description, if `dbcpVersion` is not provided, version 1 is used and a warning is logged. Descriptions can be checked against the validator before setting them. diff --git a/src/shared-description.ts b/src/shared-description.ts index fc2500b0..e56c5d18 100644 --- a/src/shared-description.ts +++ b/src/shared-description.ts @@ -94,7 +94,10 @@ export class Description extends Dbcp.Description { } else { const content: Envelope = Object.assign({}, envelope); // add dbcp version - content.public.dbcpVersion = content.public.dbcpVersion || this.dbcpVersion; + if (!content.public.dbcpVersion) { + this.log('dbcpVersion not set, using fallback of version 1', 'warning'); + content.public.dbcpVersion = content.public.dbcpVersion || 1; + } const validation = this.validateDescription(content); if (validation !== true) { throw new Error(`description invalid: ${JSON.stringify(validation)}`); From 655aa182df93f987e5dc695918086c30dfd1ea66 Mon Sep 17 00:00:00 2001 From: wulfraem Date: Thu, 10 Jan 2019 09:04:27 +0100 Subject: [PATCH 20/22] remove `OriginIdentity`, as `ClaimHolder` is used for identities --- VERSIONS.md | 2 ++ src/claims/claims.spec.ts | 8 ++++---- src/claims/claims.ts | 8 ++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/VERSIONS.md b/VERSIONS.md index 221be2e1..bc8f9c9b 100644 --- a/VERSIONS.md +++ b/VERSIONS.md @@ -6,6 +6,8 @@ - add linking and checks for contract identities ### Fixes +- remove `OriginIdentity`, as `ClaimHolder` is used for identities + ### Deprecations diff --git a/src/claims/claims.spec.ts b/src/claims/claims.spec.ts index bb92db85..e9c5ce02 100644 --- a/src/claims/claims.spec.ts +++ b/src/claims/claims.spec.ts @@ -82,8 +82,8 @@ describe('Claims handler', function() { const claimHolderLib = await executor.createContract( 'ClaimHolderLibrary', [], { from: accounts[0], gas: 3000000, }); - contractLoader.contracts['OriginIdentity'].bytecode = linker.linkBytecode( - contractLoader.contracts['OriginIdentity'].bytecode, + contractLoader.contracts['ClaimHolder'].bytecode = linker.linkBytecode( + contractLoader.contracts['ClaimHolder'].bytecode, { 'claims/ClaimHolderLibrary.sol:ClaimHolderLibrary': claimHolderLib.options.address, 'claims/KeyHolderLibrary.sol:KeyHolderLibrary': keyHolderLib.options.address, @@ -99,8 +99,8 @@ describe('Claims handler', function() { }, ); (claims.options.executor.signer).contractLoader.contracts['ClaimHolderLibrary'].bytecode = (claims.options.executor.signer).contractLoader.contracts['ClaimHolderLibrary'].bytecode.replace(/3Cf1679B2BA2a70693F55289bf6c81a0097497a6/g, keyHolderLib.options.address.slice(2)); - (claims.options.executor.signer).contractLoader.contracts['OriginIdentity'].bytecode = (claims.options.executor.signer).contractLoader.contracts['OriginIdentity'].bytecode.replace(/3Cf1679B2BA2a70693F55289bf6c81a0097497a6/g, keyHolderLib.options.address.slice(2)); - (claims.options.executor.signer).contractLoader.contracts['OriginIdentity'].bytecode = (claims.options.executor.signer).contractLoader.contracts['OriginIdentity'].bytecode.replace(/674a12Acae46c1E29e5EC124AB698081775C5803/g, claimHolderLib.options.address.slice(2)); + (claims.options.executor.signer).contractLoader.contracts['ClaimHolder'].bytecode = (claims.options.executor.signer).contractLoader.contracts['ClaimHolder'].bytecode.replace(/3Cf1679B2BA2a70693F55289bf6c81a0097497a6/g, keyHolderLib.options.address.slice(2)); + (claims.options.executor.signer).contractLoader.contracts['ClaimHolder'].bytecode = (claims.options.executor.signer).contractLoader.contracts['ClaimHolder'].bytecode.replace(/674a12Acae46c1E29e5EC124AB698081775C5803/g, claimHolderLib.options.address.slice(2)); (claims.options.executor.signer).contractLoader.contracts['ClaimsRegistry'].bytecode = (claims.options.executor.signer).contractLoader.contracts['ClaimsRegistry'].bytecode.replace(/d7d62072c409A29a187F81dDd8aCd50bFc070546/g, claimsRegistryLib.options.address.slice(2)); const storage = await executor.createContract( diff --git a/src/claims/claims.ts b/src/claims/claims.ts index 18d06488..ba700696 100644 --- a/src/claims/claims.ts +++ b/src/claims/claims.ts @@ -129,7 +129,7 @@ export class Claims extends Logger { // create Identity contract await this.ensureStorage(); const identityContract = await this.options.executor.createContract( - 'OriginIdentity', [], { from: accountId, gas: 3000000, }); + 'ClaimHolder', [], { from: accountId, gas: 3000000, }); const identityStorage = this.contracts.storage.options.address !== nullAddress ? this.options.contractLoader.loadContract('V00_UserRegistry', this.contracts.storage.options.address) : null; @@ -305,7 +305,7 @@ export class Claims extends Logger { // check if target identity exists if (targetIdentity !== nullAddress) { this.subjectTypes[subject] = 'account'; - this.cachedIdentities[subject] = this.options.contractLoader.loadContract('OriginIdentity', targetIdentity); + this.cachedIdentities[subject] = this.options.contractLoader.loadContract('ClaimHolder', targetIdentity); } else { const description = await this.options.description.getDescription(subject, null); if (description && description.public && description.public.identity) { @@ -543,7 +543,7 @@ export class Claims extends Logger { const dataHash = this.options.nameResolver.soliditySha3(subjectIdentity, claim.topic, claim.data).replace('0x', ''); const recoveredAddress = this.options.executor.web3.eth.accounts.recover(dataHash, claim.signature); - const issuerContract = this.options.contractLoader.loadContract('OriginIdentity', claim.issuer); + const issuerContract = this.options.contractLoader.loadContract('ClaimHolder', claim.issuer); const keyHasPurpose = await this.options.executor.executeContractCall( issuerContract, 'keyHasPurpose', @@ -604,7 +604,7 @@ export class Claims extends Logger { // account identity return this.options.executor.executeContractCall( isIdentity ? - this.options.contractLoader.loadContract('OriginIdentity', subject) : + this.options.contractLoader.loadContract('ClaimHolder', subject) : await this.getIdentityForAccount(subject), fun, ...args, From 3f1aa45baeaf4f8ba83a9b99286eefbafec76871 Mon Sep 17 00:00:00 2001 From: Tobias Winkler Date: Fri, 11 Jan 2019 13:46:31 +0100 Subject: [PATCH 21/22] update missing versions.md contents --- VERSIONS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/VERSIONS.md b/VERSIONS.md index bc8f9c9b..4a021776 100644 --- a/VERSIONS.md +++ b/VERSIONS.md @@ -4,6 +4,8 @@ ### Features - update `setClaims` to use issuers identity for setting claims on subject - add linking and checks for contract identities +- add missing dbcpVersion to dbcp files +- add licenses to dbcp files ### Fixes - remove `OriginIdentity`, as `ClaimHolder` is used for identities From 1c49c8c4d6fb2d89f52bd8c28363e811502eaeec Mon Sep 17 00:00:00 2001 From: Tobias Winkler Date: Fri, 11 Jan 2019 15:03:58 +0100 Subject: [PATCH 22/22] release preparations --- VERSIONS.md | 6 +++++- package.json | 8 ++++---- src/bundles/bcc/dbcp.json | 9 +++++---- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/VERSIONS.md b/VERSIONS.md index 4a021776..49643842 100644 --- a/VERSIONS.md +++ b/VERSIONS.md @@ -2,6 +2,11 @@ ## Next Version ### Features +### Fixes +### Deprecations + +## Version 1.7.0 +### Features - update `setClaims` to use issuers identity for setting claims on subject - add linking and checks for contract identities - add missing dbcpVersion to dbcp files @@ -12,7 +17,6 @@ ### Deprecations - ## Version 1.6.1 ### Fixes - remove web3 initialization within the `ServiceContract` diff --git a/package.json b/package.json index 4ab0d533..9017c06a 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "author": "evan GmbH", "dependencies": { - "@evan.network/dbcp": "^1.4.4", - "@evan.network/smart-contracts-core": "^1.4.0", + "@evan.network/dbcp": "^1.5.0", + "@evan.network/smart-contracts-core": "^1.5.0", "@types/node": "8.0.53", "ajv": "^5.5.1", "babel-plugin-transform-es3-property-literals": "^6.22.0", @@ -79,5 +79,5 @@ "testunitbrk": "env-cmd ./.env.local npm run build && env-cmd ./.env.local mocha --exit --inspect-brk -r ts-node/register $*" }, "types": "./dist/index.d.ts", - "version": "1.6.1" -} + "version": "1.7.0" +} \ No newline at end of file diff --git a/src/bundles/bcc/dbcp.json b/src/bundles/bcc/dbcp.json index 5485a479..22404b6d 100644 --- a/src/bundles/bcc/dbcp.json +++ b/src/bundles/bcc/dbcp.json @@ -3,13 +3,13 @@ "author": "evan GmbH", "dapp": { "dependencies": { - "smartcontracts": "^1.4.0" + "smartcontracts": "^1.5.0" }, "entrypoint": "bcc.js", "files": [ "bcc.js" ], - "origin": "QmVGiU7qp4jUtT3jXAnMUMZL6xBU1o5LQALsmhEGNk6ifC", + "origin": "QmZtiWW4EWYHd8ZF4dcCFUJi3UNpZuFSKBodpwN8VY9NhA", "type": "library" }, "dbcpVersion": 2, @@ -24,7 +24,7 @@ "dapp", "library" ], - "version": "1.6.0", + "version": "1.7.0", "versions": { "0.1.0": "QmTsY7ASbvxATLnEemHZQ8oQha64ujYe9VXbDCouDk7Xtp", "0.9.0": "Qmbw3yX82TVN9WhsRyeaRpd89M9XXL1pds9GgqJL29ohar", @@ -38,7 +38,8 @@ "1.3.1": "QmbQ9HskNocFPNU8wf8QrweJzidMVMbJp4gqxoWEbTLyas", "1.4.0": "QmVv35DzcryDQnbmTVHJChD1enG459cUGKmqZj6xE74nHX", "1.5.0": "QmQnmbZJcUf6j6u6nsJh5jiqxwAfsBybZWPk65tVN8HZ3P", - "1.6.0": "QmTHvUrZEKUQ3KkoHVs6SmnPFw437bPpXuSqji5Pb67gJg" + "1.6.0": "QmTHvUrZEKUQ3KkoHVs6SmnPFw437bPpXuSqji5Pb67gJg", + "1.7.0": "QmfCYbQHhafqtvTNb8PisTaBBB52pQ4UEuzMHptv1SWdQm" } } } \ No newline at end of file