From 37bec5ae45aa17331ed86bebb866851bd36f47dd Mon Sep 17 00:00:00 2001 From: Mike Xu Date: Mon, 13 Aug 2018 22:04:33 -0400 Subject: [PATCH 01/10] configure vscode to debug jest --- .vscode/launch.json | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..d0be2566 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,33 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Jest All", + "program": "${workspaceFolder}/node_modules/.bin/jest", + "args": ["--runInBand"], + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "windows": { + "program": "${workspaceFolder}/node_modules/jest/bin/jest" + } + }, + { + "type": "node", + "request": "launch", + "name": "Jest Current File", + "program": "${workspaceFolder}/node_modules/.bin/jest", + "args": ["${relativeFile}"], + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "windows": { + "program": "${workspaceFolder}/node_modules/jest/bin/jest" + } + } + ] + } + \ No newline at end of file From c6def53bafaad9628549a2689acb9ce1ce986f87 Mon Sep 17 00:00:00 2001 From: Mike Xu Date: Mon, 13 Aug 2018 23:50:14 -0400 Subject: [PATCH 02/10] added tests for revoking attributes --- src/__tests__/register-test.js | 130 ++++++++++++++++++++++++++++++++- 1 file changed, 128 insertions(+), 2 deletions(-) diff --git a/src/__tests__/register-test.js b/src/__tests__/register-test.js index fb6bc2d0..a0aff9da 100644 --- a/src/__tests__/register-test.js +++ b/src/__tests__/register-test.js @@ -234,7 +234,7 @@ describe('ethrResolver', () => { }) describe('attributes', () => { - describe('publicKey', () => { + describe('add publicKey', () => { describe('Secp256k1VerificationKey2018', () => { beforeAll(async () => { await registry.setAttribute(identity, stringToBytes32('did/pub/Secp256k1/veriKey'), '0x02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71', 10, {from: owner}) @@ -312,7 +312,7 @@ describe('ethrResolver', () => { }) }) - describe('service endpoints', () => { + describe('add service endpoints', () => { describe('HubService', () => { beforeAll(async () => { await registry.setAttribute(identity, stringToBytes32('did/svc/HubService'), 'https://hubs.uport.me', 10, {from: owner}) @@ -358,6 +358,132 @@ describe('ethrResolver', () => { }) }) + + describe('revoke publicKey', () => { + describe('Secp256k1VerificationKey2018', () => { + beforeAll(async () => { + await registry.revokeAttribute( + identity, + stringToBytes32('did/pub/Secp256k1/veriKey'), + '0x02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71', + { from: owner } + ) + sleep(1) + }) + it('resolves document', () => { + return expect(resolve(did)).resolves.toEqual({ + '@context': 'https://w3id.org/did/v1', + id: did, + publicKey: [{ + id: `${did}#owner`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: owner + }, { + id: `${did}#delegate-1`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: delegate2 + }, { + id: `${did}#delegate-3`, + type: 'Ed25519VerificationKey2018', + owner: did, + publicKeyBase64: Buffer.from('02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71', 'hex').toString('base64') + }], + authentication: [{ + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#owner` + }, { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#delegate-1` + }], + service: [{ + type: 'HubService', + serviceEndpoint: 'https://hubs.uport.me' + }] + }) + }) + }) + + describe('Ed25519VerificationKey2018', () => { + beforeAll(async () => { + await registry.revokeAttribute( + identity, + stringToBytes32('did/pub/Ed25519/veriKey/base64'), + '0x02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71', + { from: owner } + ) + sleep(1) + }) + it('resolves document', () => { + return expect(resolve(did)).resolves.toEqual({ + '@context': 'https://w3id.org/did/v1', + id: did, + publicKey: [{ + id: `${did}#owner`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: owner + }, { + id: `${did}#delegate-1`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: delegate2 + }], + authentication: [{ + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#owner` + }, { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#delegate-1` + }], + service: [{ + type: 'HubService', + serviceEndpoint: 'https://hubs.uport.me' + }] + }) + }) + }) + }) + + describe('revoke service endpoints', () => { + describe('HubService', () => { + beforeAll(async () => { + await registry.revokeAttribute( + identity, + stringToBytes32('did/svc/HubService'), + 'https://hubs.uport.me', + { from: owner } + ) + sleep(1) + }) + + it('resolves document', () => { + return expect(resolve(did)).resolves.toEqual({ + '@context': 'https://w3id.org/did/v1', + id: did, + publicKey: [{ + id: `${did}#owner`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: owner + }, { + id: `${did}#delegate-1`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: delegate2 + }], + authentication: [{ + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#owner` + }, { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#delegate-1` + }] + }) + }) + }) + }) }) describe('error handling', () => { From 06d8a99c84f599bac0aedb76c0d549d0b201e0c9 Mon Sep 17 00:00:00 2001 From: Mike Xu Date: Mon, 13 Aug 2018 23:54:36 -0400 Subject: [PATCH 03/10] fix revoke delegate attribute name matching --- src/register.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/register.js b/src/register.js index 6a049ea2..27346630 100644 --- a/src/register.js +++ b/src/register.js @@ -108,7 +108,11 @@ export function wrapDidDocument (did, owner, history) { } } } else { - if (delegateCount > 0 && (event._eventName === 'DIDDelegateChanged' || (event._eventName === 'DIDAttributeChanged' && delegateType.match(/^did\/publicKey\//))) && validTo.lt(now)) delegateCount-- + if (delegateCount > 0 && + (event._eventName === 'DIDDelegateChanged' || + (event._eventName === 'DIDAttributeChanged' && + bytes32toString(event.name).match(/^did\/pub\//))) && + validTo.lt(now)) delegateCount-- delete auth[key] delete pks[key] delete services[key] From 9500a0c380cc0deac9624293f896cb03b08aba9d Mon Sep 17 00:00:00 2001 From: mi-xu Date: Wed, 19 Sep 2018 01:49:23 -0400 Subject: [PATCH 04/10] update category and type of front matter in md doc (#16) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 53c9a563..1bc5454a 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ --- title: "Ethr DID Resolver" index: 7 -category: "reference" -type: "content" +category: "ethr-did-resolver" +type: "reference" source: "https://github.com/uport-project/ethr-did-resolver/blob/develop/README.md" --- From c10a096f2b59f27d8a430f2e3585d3022559968e Mon Sep 17 00:00:00 2001 From: Mike Xu Date: Fri, 28 Sep 2018 10:35:24 -0400 Subject: [PATCH 05/10] create temporary test to reproduce reported issue --- src/__tests__/rinkeby-test.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/__tests__/rinkeby-test.js diff --git a/src/__tests__/rinkeby-test.js b/src/__tests__/rinkeby-test.js new file mode 100644 index 00000000..3c67fef0 --- /dev/null +++ b/src/__tests__/rinkeby-test.js @@ -0,0 +1,18 @@ +// TODO: remove this file +import Contract from 'truffle-contract' +import Web3 from 'web3' +import DidRegistryContract from 'ethr-did-registry' +import resolve from 'did-resolver' +import register from '../register' + +it.only('does not work', async () => { + const provider = new Web3.providers.HttpProvider('https://rinkeby.infura.io/ethr-did') + const DidReg = Contract(DidRegistryContract) + const web3 = new Web3() + web3.setProvider(provider) + DidReg.setProvider(provider) + register({ provider, registry: '0xdca7ef03e98e0dc2b855be647c39abe984fcf21b'}) + const did = 'did:ethr:0x9faefc1c2ed1e2e6e24ba269b5b882bd973821b4' + const doc = await resolve(did) + console.log(doc) +}) \ No newline at end of file From e7bf7702a703b898f4fccb23e439c1c0cc265e04 Mon Sep 17 00:00:00 2001 From: Mike Xu Date: Fri, 28 Sep 2018 10:36:55 -0400 Subject: [PATCH 06/10] add test for multiple events in one block --- src/__tests__/register-test.js | 783 +++++++++++++++++++++------------ 1 file changed, 513 insertions(+), 270 deletions(-) diff --git a/src/__tests__/register-test.js b/src/__tests__/register-test.js index a0aff9da..672b4272 100644 --- a/src/__tests__/register-test.js +++ b/src/__tests__/register-test.js @@ -5,9 +5,12 @@ import DidRegistryContract from 'ethr-did-registry' import Web3 from 'web3' import ganache from 'ganache-cli' -const { Secp256k1SignatureAuthentication2018, Secp256k1VerificationKey2018 } = delegateTypes +const { + Secp256k1SignatureAuthentication2018, + Secp256k1VerificationKey2018, +} = delegateTypes -function sleep (seconds) { +function sleep(seconds) { return new Promise((resolve, reject) => setTimeout(resolve, seconds * 1000)) } @@ -17,9 +20,46 @@ describe('ethrResolver', () => { const DidReg = Contract(DidRegistryContract) const web3 = new Web3() web3.setProvider(provider) - const getAccounts = () => new Promise((resolve, reject) => web3.eth.getAccounts((error, accounts) => error ? reject(error) : resolve(accounts))) + const getAccounts = () => + new Promise((resolve, reject) => + web3.eth.getAccounts( + (error, accounts) => (error ? reject(error) : resolve(accounts)) + ) + ) DidReg.setProvider(provider) + const stopMining = () => + new Promise((resolve, reject) => + web3.currentProvider.send( + { + jsonrpc: '2.0', + method: 'miner_stop', + id: new Date().getTime(), + }, + (e, val) => { + if (e) reject(e) + return resolve(val) + } + ) + ) + + const startMining = () => { + new Promise(async (resolve, reject) => { + web3.currentProvider.send( + { + jsonrpc: '2.0', + method: 'miner_start', + params: [1], + id: new Date().getTime(), + }, + (e, val) => { + if (e) reject(e) + return resolve(val) + } + ) + }) + } + let registry, accounts, did, identity, owner, delegate1, delegate2 beforeAll(async () => { @@ -33,9 +73,9 @@ describe('ethrResolver', () => { registry = await DidReg.new({ from: accounts[0], gasPrice: 100000000000, - gas: 4712388 //1779962 + gas: 4712388, //1779962 }) - register({provider, registry: registry.address}) + register({ provider, registry: registry.address }) }) describe('unregistered', () => { @@ -43,39 +83,47 @@ describe('ethrResolver', () => { return expect(resolve(did)).resolves.toEqual({ '@context': 'https://w3id.org/did/v1', id: did, - publicKey: [{ - id: `${did}#owner`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: identity - }], - authentication: [{ - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#owner` - }] + publicKey: [ + { + id: `${did}#owner`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: identity, + }, + ], + authentication: [ + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#owner`, + }, + ], }) }) }) describe('owner changed', () => { beforeAll(async () => { - await registry.changeOwner(identity, owner, {from: identity}) + await registry.changeOwner(identity, owner, { from: identity }) }) it('resolves document', () => { return expect(resolve(did)).resolves.toEqual({ '@context': 'https://w3id.org/did/v1', id: did, - publicKey: [{ - id: `${did}#owner`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: owner - }], - authentication: [{ - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#owner` - }] + publicKey: [ + { + id: `${did}#owner`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: owner, + }, + ], + authentication: [ + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#owner`, + }, + ], }) }) }) @@ -83,64 +131,88 @@ describe('ethrResolver', () => { describe('delegates', () => { describe('add signing delegate', () => { beforeAll(async () => { - await registry.addDelegate(identity, Secp256k1VerificationKey2018, delegate1, 2, {from: owner}) + await registry.addDelegate( + identity, + Secp256k1VerificationKey2018, + delegate1, + 2, + { from: owner } + ) }) it('resolves document', () => { return expect(resolve(did)).resolves.toEqual({ '@context': 'https://w3id.org/did/v1', id: did, - publicKey: [{ - id: `${did}#owner`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: owner - }, { - id: `${did}#delegate-1`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: delegate1 - }], - authentication: [{ - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#owner` - }] + publicKey: [ + { + id: `${did}#owner`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: owner, + }, + { + id: `${did}#delegate-1`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: delegate1, + }, + ], + authentication: [ + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#owner`, + }, + ], }) }) }) describe('add auth delegate', () => { beforeAll(async () => { - await registry.addDelegate(identity, Secp256k1SignatureAuthentication2018, delegate2, 10, {from: owner}) + await registry.addDelegate( + identity, + Secp256k1SignatureAuthentication2018, + delegate2, + 10, + { from: owner } + ) }) it('resolves document', () => { return expect(resolve(did)).resolves.toEqual({ '@context': 'https://w3id.org/did/v1', id: did, - publicKey: [{ - id: `${did}#owner`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: owner - }, { - id: `${did}#delegate-1`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: delegate1 - }, { - id: `${did}#delegate-2`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: delegate2 - }], - authentication: [{ - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#owner` - }, { - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#delegate-2` - }] + publicKey: [ + { + id: `${did}#owner`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: owner, + }, + { + id: `${did}#delegate-1`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: delegate1, + }, + { + id: `${did}#delegate-2`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: delegate2, + }, + ], + authentication: [ + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#owner`, + }, + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#delegate-2`, + }, + ], }) }) }) @@ -154,31 +226,42 @@ describe('ethrResolver', () => { return expect(resolve(did)).resolves.toEqual({ '@context': 'https://w3id.org/did/v1', id: did, - publicKey: [{ - id: `${did}#owner`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: owner - }, { - id: `${did}#delegate-1`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: delegate2 - }], - authentication: [{ - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#owner` - }, { - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#delegate-1` - }] + publicKey: [ + { + id: `${did}#owner`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: owner, + }, + { + id: `${did}#delegate-1`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: delegate2, + }, + ], + authentication: [ + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#owner`, + }, + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#delegate-1`, + }, + ], }) }) }) describe('revokes delegate', () => { beforeAll(async () => { - await registry.revokeDelegate(identity, Secp256k1SignatureAuthentication2018, delegate2, {from: owner}) + await registry.revokeDelegate( + identity, + Secp256k1SignatureAuthentication2018, + delegate2, + { from: owner } + ) await sleep(1) }) @@ -186,16 +269,20 @@ describe('ethrResolver', () => { return expect(resolve(did)).resolves.toEqual({ '@context': 'https://w3id.org/did/v1', id: did, - publicKey: [{ - id: `${did}#owner`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: owner - }], - authentication: [{ - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#owner` - }] + publicKey: [ + { + id: `${did}#owner`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: owner, + }, + ], + authentication: [ + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#owner`, + }, + ], }) }) }) @@ -203,31 +290,43 @@ describe('ethrResolver', () => { describe('re-add auth delegate', () => { beforeAll(async () => { await sleep(3) - await registry.addDelegate(identity, Secp256k1SignatureAuthentication2018, delegate2, 86400, {from: owner}) + await registry.addDelegate( + identity, + Secp256k1SignatureAuthentication2018, + delegate2, + 86400, + { from: owner } + ) }) it('resolves document', () => { return expect(resolve(did)).resolves.toEqual({ '@context': 'https://w3id.org/did/v1', id: did, - publicKey: [{ - id: `${did}#owner`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: owner - }, { - id: `${did}#delegate-1`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: delegate2 - }], - authentication: [{ - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#owner` - }, { - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#delegate-1` - }] + publicKey: [ + { + id: `${did}#owner`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: owner, + }, + { + id: `${did}#delegate-1`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: delegate2, + }, + ], + authentication: [ + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#owner`, + }, + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#delegate-1`, + }, + ], }) }) }) @@ -237,76 +336,108 @@ describe('ethrResolver', () => { describe('add publicKey', () => { describe('Secp256k1VerificationKey2018', () => { beforeAll(async () => { - await registry.setAttribute(identity, stringToBytes32('did/pub/Secp256k1/veriKey'), '0x02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71', 10, {from: owner}) + await registry.setAttribute( + identity, + stringToBytes32('did/pub/Secp256k1/veriKey'), + '0x02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71', + 10, + { from: owner } + ) }) it('resolves document', () => { return expect(resolve(did)).resolves.toEqual({ '@context': 'https://w3id.org/did/v1', id: did, - publicKey: [{ - id: `${did}#owner`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: owner - }, { - id: `${did}#delegate-1`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: delegate2 - }, { - id: `${did}#delegate-2`, - type: 'Secp256k1VerificationKey2018', - owner: did, - publicKeyHex: '02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71' - }], - authentication: [{ - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#owner` - }, { - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#delegate-1` - }] + publicKey: [ + { + id: `${did}#owner`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: owner, + }, + { + id: `${did}#delegate-1`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: delegate2, + }, + { + id: `${did}#delegate-2`, + type: 'Secp256k1VerificationKey2018', + owner: did, + publicKeyHex: + '02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71', + }, + ], + authentication: [ + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#owner`, + }, + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#delegate-1`, + }, + ], }) }) }) describe('Ed25519VerificationKey2018', () => { beforeAll(async () => { - await registry.setAttribute(identity, stringToBytes32('did/pub/Ed25519/veriKey/base64'), '0x02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71', 10, {from: owner}) + await registry.setAttribute( + identity, + stringToBytes32('did/pub/Ed25519/veriKey/base64'), + '0x02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71', + 10, + { from: owner } + ) }) - + it('resolves document', () => { return expect(resolve(did)).resolves.toEqual({ '@context': 'https://w3id.org/did/v1', id: did, - publicKey: [{ - id: `${did}#owner`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: owner - }, { - id: `${did}#delegate-1`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: delegate2 - }, { - id: `${did}#delegate-2`, - type: 'Secp256k1VerificationKey2018', - owner: did, - publicKeyHex: '02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71' - }, { - id: `${did}#delegate-3`, - type: 'Ed25519VerificationKey2018', - owner: did, - publicKeyBase64: Buffer.from('02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71', 'hex').toString('base64') - }], - authentication: [{ - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#owner` - }, { - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#delegate-1` - }] + publicKey: [ + { + id: `${did}#owner`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: owner, + }, + { + id: `${did}#delegate-1`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: delegate2, + }, + { + id: `${did}#delegate-2`, + type: 'Secp256k1VerificationKey2018', + owner: did, + publicKeyHex: + '02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71', + }, + { + id: `${did}#delegate-3`, + type: 'Ed25519VerificationKey2018', + owner: did, + publicKeyBase64: Buffer.from( + '02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71', + 'hex' + ).toString('base64'), + }, + ], + authentication: [ + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#owner`, + }, + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#delegate-1`, + }, + ], }) }) }) @@ -315,48 +446,67 @@ describe('ethrResolver', () => { describe('add service endpoints', () => { describe('HubService', () => { beforeAll(async () => { - await registry.setAttribute(identity, stringToBytes32('did/svc/HubService'), 'https://hubs.uport.me', 10, {from: owner}) + await registry.setAttribute( + identity, + stringToBytes32('did/svc/HubService'), + 'https://hubs.uport.me', + 10, + { from: owner } + ) }) it('resolves document', () => { return expect(resolve(did)).resolves.toEqual({ '@context': 'https://w3id.org/did/v1', id: did, - publicKey: [{ - id: `${did}#owner`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: owner - }, { - id: `${did}#delegate-1`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: delegate2 - }, { - id: `${did}#delegate-2`, - type: 'Secp256k1VerificationKey2018', - owner: did, - publicKeyHex: '02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71' - }, { - id: `${did}#delegate-3`, - type: 'Ed25519VerificationKey2018', - owner: did, - publicKeyBase64: Buffer.from('02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71', 'hex').toString('base64') - }], - authentication: [{ - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#owner` - }, { - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#delegate-1` - }], - service: [{ - type: 'HubService', - serviceEndpoint: 'https://hubs.uport.me' - }] + publicKey: [ + { + id: `${did}#owner`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: owner, + }, + { + id: `${did}#delegate-1`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: delegate2, + }, + { + id: `${did}#delegate-2`, + type: 'Secp256k1VerificationKey2018', + owner: did, + publicKeyHex: + '02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71', + }, + { + id: `${did}#delegate-3`, + type: 'Ed25519VerificationKey2018', + owner: did, + publicKeyBase64: Buffer.from( + '02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71', + 'hex' + ).toString('base64'), + }, + ], + authentication: [ + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#owner`, + }, + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#delegate-1`, + }, + ], + service: [ + { + type: 'HubService', + serviceEndpoint: 'https://hubs.uport.me', + }, + ], }) }) }) - }) describe('revoke publicKey', () => { @@ -374,33 +524,45 @@ describe('ethrResolver', () => { return expect(resolve(did)).resolves.toEqual({ '@context': 'https://w3id.org/did/v1', id: did, - publicKey: [{ - id: `${did}#owner`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: owner - }, { - id: `${did}#delegate-1`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: delegate2 - }, { - id: `${did}#delegate-3`, - type: 'Ed25519VerificationKey2018', - owner: did, - publicKeyBase64: Buffer.from('02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71', 'hex').toString('base64') - }], - authentication: [{ - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#owner` - }, { - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#delegate-1` - }], - service: [{ - type: 'HubService', - serviceEndpoint: 'https://hubs.uport.me' - }] + publicKey: [ + { + id: `${did}#owner`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: owner, + }, + { + id: `${did}#delegate-1`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: delegate2, + }, + { + id: `${did}#delegate-3`, + type: 'Ed25519VerificationKey2018', + owner: did, + publicKeyBase64: Buffer.from( + '02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71', + 'hex' + ).toString('base64'), + }, + ], + authentication: [ + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#owner`, + }, + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#delegate-1`, + }, + ], + service: [ + { + type: 'HubService', + serviceEndpoint: 'https://hubs.uport.me', + }, + ], }) }) }) @@ -419,28 +581,36 @@ describe('ethrResolver', () => { return expect(resolve(did)).resolves.toEqual({ '@context': 'https://w3id.org/did/v1', id: did, - publicKey: [{ - id: `${did}#owner`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: owner - }, { - id: `${did}#delegate-1`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: delegate2 - }], - authentication: [{ - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#owner` - }, { - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#delegate-1` - }], - service: [{ - type: 'HubService', - serviceEndpoint: 'https://hubs.uport.me' - }] + publicKey: [ + { + id: `${did}#owner`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: owner, + }, + { + id: `${did}#delegate-1`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: delegate2, + }, + ], + authentication: [ + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#owner`, + }, + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#delegate-1`, + }, + ], + service: [ + { + type: 'HubService', + serviceEndpoint: 'https://hubs.uport.me', + }, + ], }) }) }) @@ -462,33 +632,106 @@ describe('ethrResolver', () => { return expect(resolve(did)).resolves.toEqual({ '@context': 'https://w3id.org/did/v1', id: did, - publicKey: [{ - id: `${did}#owner`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: owner - }, { - id: `${did}#delegate-1`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: delegate2 - }], - authentication: [{ - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#owner` - }, { - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#delegate-1` - }] + publicKey: [ + { + id: `${did}#owner`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: owner, + }, + { + id: `${did}#delegate-1`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: delegate2, + }, + ], + authentication: [ + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#owner`, + }, + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#delegate-1`, + }, + ], }) }) }) }) }) + describe('multiple events in one block', () => { + beforeAll(async () => { + await stopMining() + await Promise.all([ + registry.setAttribute( + identity, + stringToBytes32('did/svc/TestService'), + 'https://test.uport.me', + 10, + { from: owner } + ), + registry.setAttribute( + identity, + stringToBytes32('did/svc/TestService'), + 'https://test.uport.me', + 10, + { from: owner } + ), + sleep(1).then(() => startMining()), + ]) + }) + + it('resolves document', async () => { + // expect(resolve(did)).resolves.toEqual({ + expect(await resolve(did)).toEqual({ + '@context': 'https://w3id.org/did/v1', + id: did, + publicKey: [ + { + id: `${did}#owner`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: owner, + }, + { + id: `${did}#delegate-1`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: delegate2, + }, + ], + authentication: [ + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#owner`, + }, + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#delegate-1`, + }, + ], + service: [ + { + type: 'TestService', + serviceEndpoint: 'https://test.uport.me', + }, + ], + }) + }) + }) + describe('error handling', () => { it('rejects promise', () => { - return expect(resolve('did:ethr:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX')).rejects.toEqual(new Error('Not a valid ethr DID: did:ethr:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX')) + return expect( + resolve('did:ethr:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX') + ).rejects.toEqual( + new Error( + 'Not a valid ethr DID: did:ethr:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX' + ) + ) }) }) }) From 602eb585887f31a3e1226545af35c3b354b96b66 Mon Sep 17 00:00:00 2001 From: Mike Xu Date: Fri, 28 Sep 2018 10:40:59 -0400 Subject: [PATCH 07/10] only set previous change block if less than current block num --- src/register.js | 141 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 103 insertions(+), 38 deletions(-) diff --git a/src/register.js b/src/register.js index 27346630..4840a93c 100644 --- a/src/register.js +++ b/src/register.js @@ -8,39 +8,49 @@ import DidRegistryContract from '../contracts/ethr-did-registry.json' import { Buffer } from 'buffer' export const REGISTRY = '0xdca7ef03e98e0dc2b855be647c39abe984fcf21b' -export function bytes32toString (bytes32) { - return Buffer.from(bytes32.slice(2), 'hex').toString('utf8').replace(/\0+$/, '') +export function bytes32toString(bytes32) { + return Buffer.from(bytes32.slice(2), 'hex') + .toString('utf8') + .replace(/\0+$/, '') } -export function stringToBytes32 (str) { - const buffstr = '0x' + Buffer.from(str).slice(0, 32).toString('hex') +export function stringToBytes32(str) { + const buffstr = + '0x' + + Buffer.from(str) + .slice(0, 32) + .toString('hex') return buffstr + '0'.repeat(66 - buffstr.length) } export const delegateTypes = { Secp256k1SignatureAuthentication2018: stringToBytes32('sigAuth'), - Secp256k1VerificationKey2018: stringToBytes32('veriKey') + Secp256k1VerificationKey2018: stringToBytes32('veriKey'), } export const attrTypes = { sigAuth: 'SignatureAuthentication2018', - veriKey: 'VerificationKey2018' + veriKey: 'VerificationKey2018', } -export function wrapDidDocument (did, owner, history) { +export function wrapDidDocument(did, owner, history) { const now = new BN(Math.floor(new Date().getTime() / 1000)) // const expired = {} - const publicKey = [{ - id: `${did}#owner`, - type: 'Secp256k1VerificationKey2018', - owner: did, - ethereumAddress: owner - }] + const publicKey = [ + { + id: `${did}#owner`, + type: 'Secp256k1VerificationKey2018', + owner: did, + ethereumAddress: owner, + }, + ] - const authentication = [{ - type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#owner` - }] + const authentication = [ + { + type: 'Secp256k1SignatureAuthentication2018', + publicKey: `${did}#owner`, + }, + ] let delegateCount = 0 const auth = {} @@ -48,7 +58,8 @@ export function wrapDidDocument (did, owner, history) { const services = {} for (let event of history) { let validTo = event.validTo - const key = `${event._eventName}-${event.delegateType || event.name}-${event.delegate || event.value}` + const key = `${event._eventName}-${event.delegateType || + event.name}-${event.delegate || event.value}` if (validTo && validTo.gte(now)) { if (event._eventName === 'DIDDelegateChanged') { delegateCount++ @@ -57,20 +68,22 @@ export function wrapDidDocument (did, owner, history) { case 'sigAuth': auth[key] = { type: 'Secp256k1SignatureAuthentication2018', - publicKey: `${did}#delegate-${delegateCount}` + publicKey: `${did}#delegate-${delegateCount}`, } case 'veriKey': pks[key] = { id: `${did}#delegate-${delegateCount}`, type: 'Secp256k1VerificationKey2018', owner: did, - ethereumAddress: event.delegate + ethereumAddress: event.delegate, } break } } else if (event._eventName === 'DIDAttributeChanged') { const name = bytes32toString(event.name) - const match = name.match(/^did\/(pub|auth|svc)\/(\w+)(\/(\w+))?(\/(\w+))?$/) + const match = name.match( + /^did\/(pub|auth|svc)\/(\w+)(\/(\w+))?(\/(\w+))?$/ + ) if (match) { const section = match[1] const algo = match[2] @@ -82,7 +95,7 @@ export function wrapDidDocument (did, owner, history) { const pk = { id: `${did}#delegate-${delegateCount}`, type: `${algo}${type}`, - owner: did + owner: did, } switch (encoding) { case null: @@ -91,10 +104,16 @@ export function wrapDidDocument (did, owner, history) { pk.publicKeyHex = event.value.slice(2) break case 'base64': - pk.publicKeyBase64 = Buffer.from(event.value.slice(2), 'hex').toString('base64') + pk.publicKeyBase64 = Buffer.from( + event.value.slice(2), + 'hex' + ).toString('base64') break case 'base58': - pk.publicKeyBase58 = Buffer.from(event.value.slice(2), 'hex').toString('base58') + pk.publicKeyBase58 = Buffer.from( + event.value.slice(2), + 'hex' + ).toString('base58') break default: pk.value = event.value @@ -102,17 +121,26 @@ export function wrapDidDocument (did, owner, history) { pks[key] = pk break case 'svc': - services[key] = {type: algo, serviceEndpoint: Buffer.from(event.value.slice(2), 'hex').toString()} + services[key] = { + type: algo, + serviceEndpoint: Buffer.from( + event.value.slice(2), + 'hex' + ).toString(), + } break } } } } else { - if (delegateCount > 0 && + if ( + delegateCount > 0 && (event._eventName === 'DIDDelegateChanged' || - (event._eventName === 'DIDAttributeChanged' && - bytes32toString(event.name).match(/^did\/pub\//))) && - validTo.lt(now)) delegateCount-- + (event._eventName === 'DIDAttributeChanged' && + bytes32toString(event.name).match(/^did\/pub\//))) && + validTo.lt(now) + ) + delegateCount-- delete auth[key] delete pks[key] delete services[key] @@ -123,7 +151,7 @@ export function wrapDidDocument (did, owner, history) { '@context': 'https://w3id.org/did/v1', id: did, publicKey: publicKey.concat(Object.values(pks)), - authentication: authentication.concat(Object.values(auth)) + authentication: authentication.concat(Object.values(auth)), } if (Object.values(services).length > 0) { doc.service = Object.values(services) @@ -132,7 +160,7 @@ export function wrapDidDocument (did, owner, history) { return doc } -function configureProvider (conf = {}) { +function configureProvider(conf = {}) { if (conf.provider) { return conf.provider } else if (conf.web3) { @@ -142,7 +170,31 @@ function configureProvider (conf = {}) { } } -export default function register (conf = {}) { +// TODO: remove this function +const printEvent = e => { + let str = null + switch (e._eventName) { + case 'DIDDelegateChanged': + str = `${bytes32toString(e.delegateType)}: ${e.delegate}` + break + case 'DIDAttributeChanged': + const name = bytes32toString(e.name) + const value = name.startsWith('did/svc/') + ? Buffer.from(e.value.slice(2), 'hex') + : e.value + str = `${bytes32toString(e.name)}: ${value}` + break + case 'DIDOwnerChanged': + str = `${e.owner}` + break + default: + console.log(e) + str = `???` + } + console.log(`[${e._eventName}] ${str} -> ${e.previousChange.toString(10)}`) +} + +export default function register(conf = {}) { const provider = configureProvider(conf) const eth = new Eth(provider) const registryAddress = conf.registry || REGISTRY @@ -150,28 +202,41 @@ export default function register (conf = {}) { const didReg = DidReg.at(registryAddress) const logDecoder = abi.logDecoder(DidRegistryContract, false) - const lastChanged = async (identity) => { + const lastChanged = async identity => { const result = await didReg.changed(identity) if (result) { return result['0'] } } - async function changeLog (identity) { + async function changeLog(identity) { const history = [] let previousChange = await lastChanged(identity) while (previousChange) { - const logs = await eth.getLogs({address: registryAddress, topics: [null, `0x000000000000000000000000${identity.slice(2)}`], fromBlock: previousChange, toBlock: previousChange}) + const blockNumber = previousChange + const logs = await eth.getLogs({ + address: registryAddress, + topics: [null, `0x000000000000000000000000${identity.slice(2)}`], + fromBlock: previousChange, + toBlock: previousChange, + }) const events = logDecoder(logs) + // TODO: remove line below + console.log(`${events.length} events for block ${blockNumber}`) previousChange = undefined for (let event of events) { + // TODO: remove line below + printEvent(event) history.unshift(event) - previousChange = event.previousChange + if (event.previousChange.lt(blockNumber)) { + previousChange = event.previousChange + } } } return history } - async function resolve (did, parsed) { - if (!parsed.id.match(/^0x[0-9a-fA-F]{40}$/)) throw new Error(`Not a valid ethr DID: ${did}`) + async function resolve(did, parsed) { + if (!parsed.id.match(/^0x[0-9a-fA-F]{40}$/)) + throw new Error(`Not a valid ethr DID: ${did}`) const owner = await didReg.identityOwner(parsed.id) const history = await changeLog(parsed.id) return wrapDidDocument(did, owner['0'], history) From f4f8dc7bec192a56aa3523eb91255aeee6af68d1 Mon Sep 17 00:00:00 2001 From: Mike Xu Date: Fri, 28 Sep 2018 10:43:51 -0400 Subject: [PATCH 08/10] remove temporary files and debug helpers --- src/__tests__/register-test.js | 1 - src/__tests__/rinkeby-test.js | 18 ------------------ src/register.js | 28 ---------------------------- 3 files changed, 47 deletions(-) delete mode 100644 src/__tests__/rinkeby-test.js diff --git a/src/__tests__/register-test.js b/src/__tests__/register-test.js index 672b4272..c0f00b82 100644 --- a/src/__tests__/register-test.js +++ b/src/__tests__/register-test.js @@ -685,7 +685,6 @@ describe('ethrResolver', () => { }) it('resolves document', async () => { - // expect(resolve(did)).resolves.toEqual({ expect(await resolve(did)).toEqual({ '@context': 'https://w3id.org/did/v1', id: did, diff --git a/src/__tests__/rinkeby-test.js b/src/__tests__/rinkeby-test.js deleted file mode 100644 index 3c67fef0..00000000 --- a/src/__tests__/rinkeby-test.js +++ /dev/null @@ -1,18 +0,0 @@ -// TODO: remove this file -import Contract from 'truffle-contract' -import Web3 from 'web3' -import DidRegistryContract from 'ethr-did-registry' -import resolve from 'did-resolver' -import register from '../register' - -it.only('does not work', async () => { - const provider = new Web3.providers.HttpProvider('https://rinkeby.infura.io/ethr-did') - const DidReg = Contract(DidRegistryContract) - const web3 = new Web3() - web3.setProvider(provider) - DidReg.setProvider(provider) - register({ provider, registry: '0xdca7ef03e98e0dc2b855be647c39abe984fcf21b'}) - const did = 'did:ethr:0x9faefc1c2ed1e2e6e24ba269b5b882bd973821b4' - const doc = await resolve(did) - console.log(doc) -}) \ No newline at end of file diff --git a/src/register.js b/src/register.js index 4840a93c..daa4232c 100644 --- a/src/register.js +++ b/src/register.js @@ -170,30 +170,6 @@ function configureProvider(conf = {}) { } } -// TODO: remove this function -const printEvent = e => { - let str = null - switch (e._eventName) { - case 'DIDDelegateChanged': - str = `${bytes32toString(e.delegateType)}: ${e.delegate}` - break - case 'DIDAttributeChanged': - const name = bytes32toString(e.name) - const value = name.startsWith('did/svc/') - ? Buffer.from(e.value.slice(2), 'hex') - : e.value - str = `${bytes32toString(e.name)}: ${value}` - break - case 'DIDOwnerChanged': - str = `${e.owner}` - break - default: - console.log(e) - str = `???` - } - console.log(`[${e._eventName}] ${str} -> ${e.previousChange.toString(10)}`) -} - export default function register(conf = {}) { const provider = configureProvider(conf) const eth = new Eth(provider) @@ -220,12 +196,8 @@ export default function register(conf = {}) { toBlock: previousChange, }) const events = logDecoder(logs) - // TODO: remove line below - console.log(`${events.length} events for block ${blockNumber}`) previousChange = undefined for (let event of events) { - // TODO: remove line below - printEvent(event) history.unshift(event) if (event.previousChange.lt(blockNumber)) { previousChange = event.previousChange From 9358cf42aa409f5b04825645565e23248307436b Mon Sep 17 00:00:00 2001 From: Mike Xu Date: Fri, 28 Sep 2018 13:35:40 -0400 Subject: [PATCH 09/10] increment version to 0.1.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 12e129fe..71e915a0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ethr-did-resolver", - "version": "0.1.1", + "version": "0.1.2", "description": "Resolve DID documents around ethereum addresses", "main": "lib/register.js", "repository": { From 4a7a319eae244aeeb15307e23a9ae9c6fad13682 Mon Sep 17 00:00:00 2001 From: Mike Xu Date: Fri, 28 Sep 2018 13:43:47 -0400 Subject: [PATCH 10/10] increment version to 0.1.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 71e915a0..ad5a2b1f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ethr-did-resolver", - "version": "0.1.2", + "version": "0.1.3", "description": "Resolve DID documents around ethereum addresses", "main": "lib/register.js", "repository": {