From b1c20d7b57e1fe74ef724315edbf760c3ff86543 Mon Sep 17 00:00:00 2001 From: Zach Ferland Date: Wed, 11 Dec 2019 19:31:56 -0500 Subject: [PATCH 01/15] feat: 3id migration --- src/3box.js | 5 ++--- src/3id/index.js | 7 ------- src/replicator.js | 7 +++---- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/3box.js b/src/3box.js index ddeea8a4..f2b3dbcd 100644 --- a/src/3box.js +++ b/src/3box.js @@ -93,7 +93,7 @@ class Box extends BoxApi { await this._3id.authenticate(opts.spaces) const rootstoreName = this._3id.muportFingerprint + '.root' const key = (await this._3id.getPublicKeys(null, true)).signingKey - await this.replicator.new(rootstoreName, key, this._3id.DID, this._3id.muportDID) + await this.replicator.new(rootstoreName, key, this._3id.DID) this._publishRootStore(this.replicator.rootstore.address.toString()) } this.replicator.rootstore.setIdentity(await this._3id.getOdbId()) @@ -286,8 +286,7 @@ class Box extends BoxApi { */ get DID () { if (!this._3id) throw new Error('DID: auth required') - // TODO - update once verification service supports 3ID - return this._3id.muportDID + return this._3id.did } /** diff --git a/src/3id/index.js b/src/3id/index.js index 9c62e6da..a2da3d3f 100644 --- a/src/3id/index.js +++ b/src/3id/index.js @@ -163,13 +163,6 @@ class ThreeId { let docHash = (await this._ipfs.add(Buffer.from(JSON.stringify(doc))))[0].hash this._muportDID = 'did:muport:' + docHash this.muportFingerprint = utils.sha256Multihash(this.muportDID) - const publishToInfura = async () => { - const ipfsMini = new IpfsMini(this._muportIpfs) - ipfsMini.addJSON(doc, (err, res) => { - if (err) console.error(err) - }) - } - publishToInfura() } async getAddress () { diff --git a/src/replicator.js b/src/replicator.js index 290ff1df..97e57c1e 100644 --- a/src/replicator.js +++ b/src/replicator.js @@ -124,7 +124,7 @@ class Replicator { this.syncDone = waitForSync() } - async new (rootstoreName, pubkey, did, muportDID) { + async new (rootstoreName, pubkey, did) { if (this.rootstore) throw new Error('This method can only be called once before the replicator has started') await this._joinPinningRoom(true) const opts = { @@ -134,7 +134,7 @@ class Replicator { opts.accessController.write = [pubkey] this.rootstore = await this._orbitdb.feed(rootstoreName, opts) this._pinningRoomFilter = [] - this._publishDB({ odbAddress: this.rootstore.address.toString(), did, muportDID }) + this._publishDB({ odbAddress: this.rootstore.address.toString(), did }) await this.rootstore.load() this.rootstoreSyncDone = Promise.resolve() this.syncDone = Promise.resolve() @@ -262,7 +262,7 @@ class Replicator { } } - async _publishDB ({ odbAddress, did, muportDID, isThread }, unsubscribe) { + async _publishDB ({ odbAddress, did, isThread }, unsubscribe) { this._joinPinningRoom() odbAddress = odbAddress || this.rootstore.address.toString() // make sure that the pinning node is in the pubsub room before publishing @@ -280,7 +280,6 @@ class Replicator { type: isThread ? 'SYNC_DB' : 'PIN_DB', odbAddress, did, - muportDID, thread: isThread }) this.events.removeAllListeners('pinning-room-peer') From 1947ec694aba1034020f7c8330b056988884488a Mon Sep 17 00:00:00 2001 From: Zach Ferland Date: Tue, 17 Dec 2019 21:09:24 -0500 Subject: [PATCH 02/15] feat: update verifications to support 3id and backwards muport --- src/3box.js | 16 +++++++++++++--- src/3id/__tests__/3id.test.js | 4 ++-- src/3id/index.js | 8 +++----- src/__mocks__/3ID.js | 4 ++-- src/__tests__/3box.test.js | 2 +- src/api.js | 17 ++++++++++++----- src/ghost.js | 4 ++-- src/utils/verifier.js | 32 +++++++++++++++++++++++--------- 8 files changed, 58 insertions(+), 29 deletions(-) diff --git a/src/3box.js b/src/3box.js index f2b3dbcd..9a581bd0 100644 --- a/src/3box.js +++ b/src/3box.js @@ -15,6 +15,7 @@ const config = require('./config.js') const BoxApi = require('./api') const IPFSRepo = require('ipfs-repo') const LevelStore = require('datastore-level') +const didJWT = require('did-jwt') const PINNING_NODE = config.pinning_node const ADDRESS_SERVER_URL = config.address_server_url @@ -244,7 +245,7 @@ class Box extends BoxApi { async _publishRootStore (rootStoreAddress) { // Sign rootstoreAddress - const addressToken = await this._3id.signJWT({ rootStoreAddress }, { use3ID: true }) + const addressToken = await this._3id.signJWT({ rootStoreAddress }) // Store odbAddress on 3box-address-server const publish = async token => { try { @@ -319,7 +320,7 @@ class Box extends BoxApi { type: 'delete-address-link' } const oneHour = 60 * 60 - const deleteToken = await this._3id.signJWT(payload, { expiresIn: oneHour, use3ID: true }) + const deleteToken = await this._3id.signJWT(payload, { expiresIn: oneHour }) try { await utils.fetchJson(this._serverUrl + '/linkdelete', { @@ -416,7 +417,16 @@ class Box extends BoxApi { } // Ensure we self-published our did // TODO - is this still needed? - if (!(await this.public.get('proof_did'))) { + const proofdid = await this.public.get('proof_did') + + if (proofdid) { + // if prior muport, re publish with 3id including muport + const issuer = didJWT.decodeJWT(proofdid).payload.iss + if (issuer.includes('muport')) { + const jwt = { muport: proofdid } + await this.public.set('proof_did', await this._3id.signJWT(jwt), { noLink: true }) + } + } else { // we can just sign an empty JWT as a proof that we own this DID await this.public.set('proof_did', await this._3id.signJWT(), { noLink: true }) } diff --git a/src/3id/__tests__/3id.test.js b/src/3id/__tests__/3id.test.js index b0a35281..b1cbf7cb 100644 --- a/src/3id/__tests__/3id.test.js +++ b/src/3id/__tests__/3id.test.js @@ -187,7 +187,7 @@ describe('3id', () => { const jwt = await threeId.signJWT({ iat: null, data: 'some data' - }, { use3ID: true }) + }) await expect(verifyJWT(jwt)).resolves.toMatchSnapshot() }) @@ -265,7 +265,7 @@ describe('3id', () => { const jwt = await idw3id.signJWT({ iat: null, data: 'some data' - }, { use3ID: true }) + }) await expect(verifyJWT(jwt)).resolves.toMatchSnapshot() }) diff --git a/src/3id/index.js b/src/3id/index.js index a2da3d3f..40cad116 100644 --- a/src/3id/index.js +++ b/src/3id/index.js @@ -41,11 +41,9 @@ class ThreeId { } } - async signJWT (payload, { use3ID, space, expiresIn } = {}) { - let issuer = this.muportDID - if (use3ID) { - issuer = this.DID - } else if (space) { + async signJWT (payload, { space, expiresIn } = {}) { + let issuer = this.DID + if (space) { issuer = this._subDIDs[space] } if (this._has3idProv) { diff --git a/src/__mocks__/3ID.js b/src/__mocks__/3ID.js index 8276964e..e1f74e04 100644 --- a/src/__mocks__/3ID.js +++ b/src/__mocks__/3ID.js @@ -23,10 +23,10 @@ const didResolverMock = async (did) => { } const threeIDMockFactory = (did) => { - const signJWT = (payload, { use3ID } = {}) => { + const signJWT = (payload) => { return didJWT.createJWT(payload, { signer: didJWT.SimpleSigner(privKey), - issuer: use3ID ? did : did.replace('3', 'muport') + issuer: did }) } diff --git a/src/__tests__/3box.test.js b/src/__tests__/3box.test.js index 6f3373e8..a4e82471 100644 --- a/src/__tests__/3box.test.js +++ b/src/__tests__/3box.test.js @@ -503,7 +503,7 @@ describe('3Box', () => { verifier.verifyDID.mockImplementationOnce(() => { throw new Error() }) expect(await Box.getVerifiedAccounts(profile)).toEqual({}) - verifier.verifyDID.mockImplementationOnce(() => userDID) + verifier.verifyDID.mockImplementationOnce(() => ({ did: userDID, muport: userDID})) verifier.verifyGithub.mockImplementationOnce(() => { return { username: 'test', proof: 'some url' } }) diff --git a/src/api.js b/src/api.js index 8fda704b..d6e2089b 100644 --- a/src/api.js +++ b/src/api.js @@ -229,27 +229,34 @@ class BoxApi { static async getVerifiedAccounts (profile) { const verifs = {} try { - const did = await verifier.verifyDID(profile.proof_did) + const didVerified = await verifier.verifyDID(profile.proof_did) - verifs.did = did + const dids = [didVerified.did] + verifs.did = didVerified.did + + if (didVerified.muport) { + verifs.muport = didVerified.muport + dids.push(muport) + } if (profile.proof_github) { try { - verifs.github = await verifier.verifyGithub(did, profile.proof_github) + verifs.github = await verifier.verifyGithub(dids, profile.proof_github) } catch (err) { // Invalid github verification } } if (profile.proof_twitter) { try { - verifs.twitter = await verifier.verifyTwitter(did, profile.proof_twitter) + verifs.twitter = await verifier.verifyTwitter(dids, profile.proof_twitter) } catch (err) { // Invalid twitter verification } } if (profile.ethereum_proof) { try { - verifs.ethereum = await verifier.verifyEthereum(profile.ethereum_proof, did) + // won't be any proofs here with 3id + verifs.ethereum = await verifier.verifyEthereum(profile.ethereum_proof, verifs.did) } catch (err) { // Invalid eth verification } diff --git a/src/ghost.js b/src/ghost.js index 53e1d7ba..f292658f 100644 --- a/src/ghost.js +++ b/src/ghost.js @@ -156,7 +156,7 @@ class GhostThread extends EventEmitter { */ async _broadcast (message) { if (!this._3id) throw new Error('Can not send message if not authenticated') - const jwt = await this._3id.signJWT(message, { use3ID: true }) + const jwt = await this._3id.signJWT(message) this._room.broadcast(jwt) } @@ -168,7 +168,7 @@ class GhostThread extends EventEmitter { */ async _sendDirect (message, to) { if (!this._3id) throw new Error('Can not send message if not authenticated') - const jwt = await this._3id.signJWT(message, { use3ID: true }) + const jwt = await this._3id.signJWT(message) to.startsWith('Qm') ? this._room.sendTo(to, jwt) : this._room.sendTo(this._threeIdToPeerId(to), jwt) } diff --git a/src/utils/verifier.js b/src/utils/verifier.js index 7e514441..ed549aaa 100644 --- a/src/utils/verifier.js +++ b/src/utils/verifier.js @@ -6,21 +6,25 @@ require('muport-did-resolver')() module.exports = { /** - * Verifies that the gist contains the given muportDID and returns the users github username. + * Verifies that the gist contains the given 3ID and returns the users github username. * Throws an error otherwise. * - * @param {String} did The muport DID of the user + * @param {String} did The 3ID of the user (or array of equivalent dids) * @param {Object} gistUrl URL of the proof * @return {Object} Object containing username, and proof */ verifyGithub: async (did, gistUrl) => { + const dids = typeof did === 'string' ? [did] : did + if (!gistUrl || gistUrl.trim() === '') { return null } let gistFileContent = await fetchText(gistUrl) - if (gistFileContent.indexOf(did) === -1) { + const includeDid = dids.reduce((acc, val) => (acc || gistFileContent.indexOf(val) !== -1), false) + + if (!includeDid) { throw new Error('Gist File provided does not contain the correct DID of the user') } @@ -32,17 +36,18 @@ module.exports = { }, /** - * Verifies that the tweet contains the given muportDID and returns the users twitter username. + * Verifies that the tweet contains the given 3ID and returns the users twitter username. * Throws an error otherwise. * - * @param {String} did The muport DID of the user + * @param {String} did The 3ID of the user (or array of equivalent dids) * @param {String} claim A did-JWT with claim * @return {Object} Object containing username, proof, and the verifier */ verifyTwitter: async (did, claim) => { + const dids = typeof did === 'string' ? [did] : did if (!claim) return null const verified = await didJWT.verifyJWT(claim) - if (verified.payload.sub !== did) { + if (!dids.includes(verified.payload.sub)) { throw new Error('Verification not valid for given user') } const claimData = verified.payload.claim @@ -60,14 +65,15 @@ module.exports = { * Verifies that the code entered by the user is the same one that was sent via email. * Throws an error otherwise. * - * @param {String} did The muport DID of the user + * @param {String} did The 3ID of the user (or array of equivalent dids) * @param {String} claim A did-JWT with claim * @return {Object} Object containing username, proof, and the verifier */ verifyEmail: async (did, claim) => { + const dids = typeof did === 'string' ? [did] : did if (!claim) return null const verified = await didJWT.verifyJWT(claim) - if (verified.payload.sub !== did) { + if (!dids.includes(verified.payload.sub)) { throw new Error('Verification not valid for given user') } const claimData = verified.payload.claim @@ -88,7 +94,14 @@ module.exports = { */ verifyDID: async (claim) => { const verified = await didJWT.verifyJWT(claim) - return verified.payload.iss + const muport = verified.payload.muport + const res = {} + if (muport) { + const muportDID = await didJWT.verifyJWT(muport).payload.iss + res.muport = muportDID + } + res.did = verified.payload.iss + return res }, /** @@ -102,6 +115,7 @@ module.exports = { * @return {String} The ethereum address used to sign the message */ verifyEthereum: async (ethProof, did) => { + const dids = typeof did === 'string' ? [did] : did // TODO - is this function needed? Can it be removed in // favour of proofs that are in the rootstore? const consentMsg = ethProof.version ? ethProof.message : ethProof['consent_msg'] From e6a39195f591cba41971db1e5e09d73786dfdaaa Mon Sep 17 00:00:00 2001 From: Zach Ferland Date: Sun, 8 Dec 2019 15:52:22 -0500 Subject: [PATCH 03/15] feat: up orbitdb v0.22 --- package-lock.json | 483 +++++++++++++++++++++++------------ package.json | 2 +- src/__tests__/thread.test.js | 10 +- src/replicator.js | 7 +- 4 files changed, 326 insertions(+), 176 deletions(-) diff --git a/package-lock.json b/package-lock.json index d537005c..4f2bc3de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "3box", - "version": "1.14.1-beta.1", + "version": "1.15.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2092,12 +2092,12 @@ "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" }, "aggregate-error": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.0.tgz", - "integrity": "sha512-yKD9kEoJIR+2IFqhMwayIBgheLYbB3PS2OBhWae1L/ODTd/JF/30cW0bc9TqzRL3k4U41Dieu3BF4I29p8xesA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", + "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", "requires": { "clean-stack": "^2.0.0", - "indent-string": "^3.2.0" + "indent-string": "^4.0.0" } }, "ajv": { @@ -4304,7 +4304,7 @@ "datastore-core": "~0.6.0", "encoding-down": "^6.0.2", "interface-datastore": "~0.6.0", - "level-js": "github:timkuijsten/level.js#idbunwrapper", + "level-js": "github:timkuijsten/level.js#18e03adab34c49523be7d3d58fafb0c632f61303", "leveldown": "^5.0.0", "levelup": "^4.0.1", "pull-stream": "^3.6.9" @@ -4326,16 +4326,6 @@ "idb-readable-stream": "0.0.4", "ltgt": "^2.1.2", "xtend": "^4.0.1" - }, - "dependencies": { - "idb-readable-stream": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/idb-readable-stream/-/idb-readable-stream-0.0.4.tgz", - "integrity": "sha1-MoPaZkW/ayINxhumHfYr7l2uSs8=", - "requires": { - "xtend": "^4.0.1" - } - } } } } @@ -5734,6 +5724,52 @@ "secp256k1": "^3.0.1" } }, + "ethers": { + "version": "4.0.40", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.40.tgz", + "integrity": "sha512-MC9BtV7Hpq4dgFONEfanx9aU9GhhoWU270F+/wegHZXA7FR+2KXFdt36YIQYLmVY5ykUWswDxd+f9EVkIa7JOA==", + "requires": { + "aes-js": "3.0.0", + "bn.js": "^4.4.0", + "elliptic": "6.5.2", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.4", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + }, + "dependencies": { + "elliptic": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", + "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=" + } + } + }, "ethjs-util": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", @@ -6126,11 +6162,6 @@ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", "dev": true }, - "fast-future": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/fast-future/-/fast-future-1.0.2.tgz", - "integrity": "sha1-hDWpqqAteSSNF9cE52JZMB2ZKAo=" - }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", @@ -6626,8 +6657,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -6651,15 +6681,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6676,22 +6704,19 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -6822,8 +6847,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -6837,7 +6861,6 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -6854,7 +6877,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -6863,15 +6885,13 @@ "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -6892,7 +6912,6 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -6981,8 +7000,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -6996,7 +7014,6 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -7092,8 +7109,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -7135,7 +7151,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -7157,7 +7172,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -7206,15 +7220,13 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", - "dev": true, - "optional": true + "dev": true } } }, @@ -7269,8 +7281,7 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "optional": true + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "aproba": { "version": "1.2.0", @@ -7291,14 +7302,12 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "optional": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -7313,20 +7322,17 @@ "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "optional": true + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "optional": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "optional": true + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "core-util-is": { "version": "1.0.2", @@ -7443,8 +7449,7 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "optional": true + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ini": { "version": "1.3.5", @@ -7456,7 +7461,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -7471,7 +7475,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -7479,14 +7482,12 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "optional": true + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "minipass": { "version": "2.3.5", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -7505,7 +7506,6 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "optional": true, "requires": { "minimist": "0.0.8" } @@ -7586,8 +7586,7 @@ "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "optional": true + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "object-assign": { "version": "4.1.1", @@ -7599,7 +7598,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "optional": true, "requires": { "wrappy": "1" } @@ -7685,8 +7683,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "optional": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safer-buffer": { "version": "2.1.2", @@ -7722,7 +7719,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -7742,7 +7738,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -7786,14 +7781,12 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "optional": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "yallist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", - "optional": true + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" } } }, @@ -8362,6 +8355,14 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "idb-readable-stream": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/idb-readable-stream/-/idb-readable-stream-0.0.4.tgz", + "integrity": "sha1-MoPaZkW/ayINxhumHfYr7l2uSs8=", + "requires": { + "xtend": "^4.0.1" + } + }, "identity-wallet": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/identity-wallet/-/identity-wallet-1.0.0.tgz", @@ -8517,9 +8518,9 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" }, "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" }, "indexof": { "version": "0.0.1", @@ -8886,7 +8887,7 @@ "bs58": "^4.0.1", "buffer": "^5.2.1", "cids": "~0.7.1", - "concat-stream": "github:hugomrdias/concat-stream#feat/smaller", + "concat-stream": "github:hugomrdias/concat-stream#057bc7b5d6d8df26c8cf00a3f151b6721a0a8034", "debug": "^4.1.0", "detect-node": "^2.0.4", "end-of-stream": "^1.4.1", @@ -8910,7 +8911,7 @@ "multibase": "~0.6.0", "multicodec": "~0.5.1", "multihashes": "~0.4.14", - "ndjson": "github:hugomrdias/ndjson#feat/readable-stream3", + "ndjson": "github:hugomrdias/ndjson#4db16da6b42e5b39bf300c3a7cde62abb3fa3a11", "once": "^1.4.0", "peer-id": "~0.12.2", "peer-info": "~0.15.1", @@ -9129,7 +9130,7 @@ "protons": "^1.0.1", "rsa-pem-to-jwk": "^1.1.3", "tweetnacl": "^1.0.0", - "webcrypto-shim": "github:dignifiedquire/webcrypto-shim#master" + "webcrypto-shim": "github:dignifiedquire/webcrypto-shim#190bc9ec341375df6025b17ae12ddb2428ea49c8" }, "dependencies": { "js-sha3": { @@ -9149,10 +9150,6 @@ "murmurhash3js": "^3.0.1", "nodeify": "^1.0.1" } - }, - "webcrypto-shim": { - "version": "github:dignifiedquire/webcrypto-shim#190bc9ec341375df6025b17ae12ddb2428ea49c8", - "from": "github:dignifiedquire/webcrypto-shim#master" } } }, @@ -9244,13 +9241,7 @@ "protons": "^1.0.1", "rsa-pem-to-jwk": "^1.1.3", "tweetnacl": "^1.0.0", - "webcrypto-shim": "github:dignifiedquire/webcrypto-shim#master" - }, - "dependencies": { - "webcrypto-shim": { - "version": "github:dignifiedquire/webcrypto-shim#190bc9ec341375df6025b17ae12ddb2428ea49c8", - "from": "github:dignifiedquire/webcrypto-shim#master" - } + "webcrypto-shim": "github:dignifiedquire/webcrypto-shim#190bc9ec341375df6025b17ae12ddb2428ea49c8" } }, "multiaddr": { @@ -9771,6 +9762,11 @@ "multihashes": "~0.4.13" } }, + "is-node": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-node/-/is-node-1.0.2.tgz", + "integrity": "sha1-19ACdF733ru3R36YiVarCk/MtlM=" + }, "is-npm": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-3.0.0.tgz", @@ -11919,6 +11915,70 @@ "varint": "^5.0.0" } }, + "level": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/level/-/level-5.0.1.tgz", + "integrity": "sha512-wcak5OQeA4rURGacqS62R/xNHjCYnJSQDBOlm4KNUGJVE9bWv2B04TclqReYejN+oD65PzD4FsqeWoI5wNC5Lg==", + "requires": { + "level-js": "^4.0.0", + "level-packager": "^5.0.0", + "leveldown": "^5.0.0", + "opencollective-postinstall": "^2.0.0" + }, + "dependencies": { + "abstract-leveldown": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.2.tgz", + "integrity": "sha512-/a+Iwj0rn//CX0EJOasNyZJd2o8xur8Ce9C57Sznti/Ilt/cb6Qd8/k98A4ZOklXgTG+iAYYUs1OTG0s1eH+zQ==", + "requires": { + "level-concat-iterator": "~2.0.0", + "level-supports": "~1.0.0", + "xtend": "~4.0.0" + } + }, + "deferred-leveldown": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz", + "integrity": "sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw==", + "requires": { + "abstract-leveldown": "~6.2.1", + "inherits": "^2.0.3" + } + }, + "encoding-down": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-6.3.0.tgz", + "integrity": "sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw==", + "requires": { + "abstract-leveldown": "^6.2.1", + "inherits": "^2.0.3", + "level-codec": "^9.0.0", + "level-errors": "^2.0.0" + } + }, + "level-packager": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/level-packager/-/level-packager-5.1.1.tgz", + "integrity": "sha512-HMwMaQPlTC1IlcwT3+swhqf/NUO+ZhXVz6TY1zZIIZlIR0YSn8GtAAWmIvKjNY16ZkEg/JcpAuQskxsXqC0yOQ==", + "requires": { + "encoding-down": "^6.3.0", + "levelup": "^4.3.2" + } + }, + "levelup": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/levelup/-/levelup-4.3.2.tgz", + "integrity": "sha512-cRTjU4ktWo59wf13PHEiOayHC3n0dOh4i5+FHr4tv4MX9+l7mqETicNq3Aj07HKlLdk0z5muVoDL2RD+ovgiyA==", + "requires": { + "deferred-leveldown": "~5.3.0", + "level-errors": "~2.0.0", + "level-iterator-stream": "~4.0.0", + "level-supports": "~1.0.0", + "xtend": "~4.0.0" + } + } + } + }, "level-codec": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-9.0.1.tgz", @@ -12587,7 +12647,7 @@ "socket.io": "^2.1.1", "socket.io-client": "^2.1.1", "stream-to-pull-stream": "^1.7.3", - "webrtcsupport": "github:ipfs/webrtcsupport" + "webrtcsupport": "github:ipfs/webrtcsupport#0669f576582c53a3a42aa5ac014fcc5966809615" }, "dependencies": { "minimist": { @@ -12641,7 +12701,7 @@ "interface-connection": "~0.3.3", "mafmt": "^6.0.7", "multiaddr-to-uri": "^5.0.0", - "pull-ws": "github:hugomrdias/pull-ws#fix/bundle-size" + "pull-ws": "github:hugomrdias/pull-ws#8e2ce0bb3b1cd6804828316e937fff8e0bef6225" }, "dependencies": { "multiaddr-to-uri": { @@ -14139,27 +14199,56 @@ "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=" }, "orbit-db": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/orbit-db/-/orbit-db-0.21.5.tgz", - "integrity": "sha512-DrEQfpisxS4v4bZnJw4bVelKftxYqyET8fVXTtD9iGWKuMUQjKQeYbtQSrwMaAqGPLXQsLdX1vAvo0/1LtaiLg==", + "version": "0.22.1", + "resolved": "https://registry.npmjs.org/orbit-db/-/orbit-db-0.22.1.tgz", + "integrity": "sha512-auQVRBFyf/FeamZ4aAk0C9gZFamgftcV4tYLH1hsCpX9mCIV6P1LlUZoWh6nPF3E6xShaIa8a1FeabWCP2WBOQ==", "requires": { "cids": "^0.7.1", "ipfs-pubsub-1on1": "~0.0.4", + "is-node": "^1.0.2", "localstorage-down": "^0.6.7", "logplease": "^1.2.14", "multihashes": "^0.4.12", - "orbit-db-access-controllers": "~0.2.0", - "orbit-db-cache": "~0.2.4", - "orbit-db-counterstore": "~1.5.0", - "orbit-db-docstore": "~1.5.0", - "orbit-db-eventstore": "~1.5.0", - "orbit-db-feedstore": "~1.5.0", - "orbit-db-identity-provider": "~0.1.0", - "orbit-db-io": "~0.1.0", - "orbit-db-keystore": "^0.2.1", - "orbit-db-kvstore": "~1.5.0", + "orbit-db-access-controllers": "~0.2.2", + "orbit-db-cache": "~0.3.0", + "orbit-db-counterstore": "~1.6.0", + "orbit-db-docstore": "~1.6.0", + "orbit-db-eventstore": "~1.6.0", + "orbit-db-feedstore": "~1.6.0", + "orbit-db-identity-provider": "~0.2.0", + "orbit-db-io": "^0.1.1", + "orbit-db-keystore": "~0.3.0", + "orbit-db-kvstore": "~1.6.0", "orbit-db-pubsub": "~0.5.5", - "orbit-db-store": "~2.6.0" + "orbit-db-storage-adapter": "^0.5.3", + "orbit-db-store": "~2.7.0" + }, + "dependencies": { + "orbit-db-identity-provider": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/orbit-db-identity-provider/-/orbit-db-identity-provider-0.2.1.tgz", + "integrity": "sha512-IG8oNetdFBp1B2SYw8rLtZXkGEErfMGIZxps2i9AahM7qFvZDoaJ8r1ME6GQMEStFCQ14N4n6Tf+owTGBIPK2A==", + "requires": { + "ethers": "^4.0.20", + "orbit-db-keystore": "~0.3.0" + } + }, + "orbit-db-keystore": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/orbit-db-keystore/-/orbit-db-keystore-0.3.4.tgz", + "integrity": "sha512-TcTGxHrBBOe1lv5K/I21UDGJghzMMhO7gbFURzFtEnV+ar0P09kP1q4WzML8B96SJnROMP2aTO8VY3jeLLK8Lg==", + "requires": { + "elliptic": "^6.4.1", + "level": "~5.0.1", + "leveldown": "~5.1.1", + "levelup": "~4.1.0", + "libp2p-crypto": "^0.16.0", + "libp2p-crypto-secp256k1": "^0.3.0", + "lru": "^3.1.0", + "mkdirp": "^0.5.1", + "safe-buffer": "^5.1.2" + } + } } }, "orbit-db-access-controllers": { @@ -14172,49 +14261,28 @@ } }, "orbit-db-cache": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/orbit-db-cache/-/orbit-db-cache-0.2.5.tgz", - "integrity": "sha512-e6/jsBk02AMwi4+c02mt5W7oI/GUMdpZhRORcOrnq4QWs5gbP1PkiXcji9IhWakXpMUfuqodldj1nqrBQjPF3Q==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/orbit-db-cache/-/orbit-db-cache-0.3.0.tgz", + "integrity": "sha512-jUsS+D3jXCwvFy92rqvsEroBMRD1SVyBwRJO248F/0/xIJ7zg+DGmhgukivUDvCrx3cpAXqYqh3Ob+kS+K9QBA==", "requires": { - "level-js": "~4.0.1", - "leveldown": "~5.0.3", - "logplease": "~1.2.15", - "mkdirp": "^0.5.1" - }, - "dependencies": { - "leveldown": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-5.0.3.tgz", - "integrity": "sha512-isfWtOQIXbGbQRI8nmU9FqCZM0klmqTAOFi0vF6G/D0O1ZgxLrSh6Xd4Zj9iVQfGt6+8jpYwkRbN07VLrxRM8w==", - "requires": { - "abstract-leveldown": "~6.0.3", - "fast-future": "~1.0.2", - "napi-macros": "~1.8.1", - "node-gyp-build": "~3.8.0" - } - }, - "node-gyp-build": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.8.0.tgz", - "integrity": "sha512-bYbpIHyRqZ7sVWXxGpz8QIRug5JZc/hzZH4GbdT9HTZi6WmKCZ8GLvP8OZ9TTiIBvwPFKgtGrlWQSXDAvYdsPw==" - } + "logplease": "~1.2.15" } }, "orbit-db-counterstore": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/orbit-db-counterstore/-/orbit-db-counterstore-1.5.2.tgz", - "integrity": "sha512-TlzifqqsBk6sA5SsDpXVhsq4TC8YUQ/Pr9+osUxxKcfR17X1oEWGUgpRUNhT9LnZklPe9orvuEb0gk+Y3EsNdw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/orbit-db-counterstore/-/orbit-db-counterstore-1.6.0.tgz", + "integrity": "sha512-cIvTg7/9GdKamw5kaQHsvE2K4T64sZGDqeM/YN5w7zWwGi/TGH0V1DDrDfx6CxpB4O4ke9VVSbP9jgMij17E9g==", "requires": { "crdts": "~0.1.2", - "orbit-db-store": "~2.6.0" + "orbit-db-store": "~2.7.0" } }, "orbit-db-docstore": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/orbit-db-docstore/-/orbit-db-docstore-1.5.1.tgz", - "integrity": "sha512-HzV93dJ6r5K0+elEXam31ZWxz2z6Gvil8jwCM27wceZbqrnjibzkCavIflknsosgA49o0y7ZbL6F1Z9JwI7PCQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/orbit-db-docstore/-/orbit-db-docstore-1.6.0.tgz", + "integrity": "sha512-U3uJF0dO0vzHMqttv4oTPa7eUh0jXnewbKwvCEx5/thtFfmara21MjafF7oXqmMIi+p/VO3AW9P6UGMtIatqmQ==", "requires": { - "orbit-db-store": "~2.6.0", + "orbit-db-store": "~2.7.0", "p-map": "~1.1.1" }, "dependencies": { @@ -14226,19 +14294,19 @@ } }, "orbit-db-eventstore": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/orbit-db-eventstore/-/orbit-db-eventstore-1.5.1.tgz", - "integrity": "sha512-ZPRe9jXaf7P5QcJWEJKOZi5WRDt4K62pbTk1wdoQPvZ9xJiB/dUaA7M0Twq4qosv2SfbKVCClUbTzqzreLqIeA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/orbit-db-eventstore/-/orbit-db-eventstore-1.6.0.tgz", + "integrity": "sha512-yXLIv0U4B87far9oWCa9O25752xtytE81EfLb21731k+L92s3JRGOiuE8ZX3PNeJlMhHRzjBLOcl1WivR/iNnw==", "requires": { - "orbit-db-store": "~2.6.0" + "orbit-db-store": "~2.7.0" } }, "orbit-db-feedstore": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/orbit-db-feedstore/-/orbit-db-feedstore-1.5.1.tgz", - "integrity": "sha512-o9XYcrhb0+Cx+QgF4W9gynYUTDFLvJA/r94VJM9O1g53Aw9pA/106TGlX/1bo7oUpFFlIjDIWfawRPSWgw9yqw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/orbit-db-feedstore/-/orbit-db-feedstore-1.6.0.tgz", + "integrity": "sha512-nv4X1vW/kXRGBIsgRTETEP6SDSTRYAVJ+n3FF5r0BA06+8PbKoN+K1c3Ljs4q97aFCwkpU2G6Bw9Gt9AAjb/YQ==", "requires": { - "orbit-db-eventstore": "~1.5.0" + "orbit-db-eventstore": "~1.6.0" } }, "orbit-db-identity-provider": { @@ -14320,11 +14388,11 @@ } }, "orbit-db-kvstore": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/orbit-db-kvstore/-/orbit-db-kvstore-1.5.1.tgz", - "integrity": "sha512-fCov8iLmUA0GIsZi6oRspsAy3Rh5yaTBTnuJ/gN6MPU0LWuhZwH3sq/WVsrEQI8uGU4or4SKypSFSp8PC/G3qA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/orbit-db-kvstore/-/orbit-db-kvstore-1.6.0.tgz", + "integrity": "sha512-yr2wNvL6n3smXK6tQ122IAmtX7NOQVTzDx0bxcNACn1ODSNhjDFxwxwwhNpdalYV15Aoq6YyeubH8XSkOrcs5w==", "requires": { - "orbit-db-store": "~2.6.0" + "orbit-db-store": "~2.7.0" } }, "orbit-db-pubsub": { @@ -14337,19 +14405,81 @@ "p-series": "^1.1.0" } }, + "orbit-db-storage-adapter": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/orbit-db-storage-adapter/-/orbit-db-storage-adapter-0.5.3.tgz", + "integrity": "sha512-K/YDVcKkhzEnqK1WFtjcADTtNZdskBJyaTCUY+m0dCuf39VHsXO4kRq5htpT1wJ6yI9dlG6TysVh+duA3o+Xig==", + "requires": { + "level": "^5.0.1", + "mkdirp": "^0.5.1" + } + }, "orbit-db-store": { - "version": "2.6.6", - "resolved": "https://registry.npmjs.org/orbit-db-store/-/orbit-db-store-2.6.6.tgz", - "integrity": "sha512-t5i0lHCPuUDN3wXWVjRnB1OK3BeRr4MsjlOwsa5i7PRzkFlWpoWsoYCrbPpavW0oaynqOsJ8F6dpIJYFbfDVZA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/orbit-db-store/-/orbit-db-store-2.7.1.tgz", + "integrity": "sha512-dO4YxH69qnKuuV5zZTz0gTb3pNHyUVpLMWHzFTLMksdlyKUxtRbGZbv4w6ynPolOOlyeOU/INCpRKSMX5scngQ==", "requires": { - "ipfs-log": "~4.3.2", + "ipfs-log": "~4.4.0", "logplease": "^1.2.14", - "orbit-db-io": "~0.1.0", + "orbit-db-io": "~0.1.1", "p-each-series": "^1.0.0", "p-map": "^3.0.0", "readable-stream": "~2.3.5" }, "dependencies": { + "ipfs-log": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ipfs-log/-/ipfs-log-4.4.0.tgz", + "integrity": "sha512-XlZGgZWnIPkdKwhJ1ETESx8yrJbR3Yd527vPhBwQWevb2KziTJQi0XXHpPHOLMRSSRE5dgCzcKnDbatTpJvtWw==", + "requires": { + "cids": "~0.7.1", + "ipld-dag-pb": "^0.17.4", + "json-stringify-deterministic": "^1.0.1", + "multihashing-async": "^0.7.0", + "orbit-db-identity-provider": "~0.2.0", + "orbit-db-io": "~0.1.1", + "p-each-series": "^2.1.0", + "p-map": "^1.1.1", + "p-whilst": "^1.0.0" + }, + "dependencies": { + "p-each-series": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.1.0.tgz", + "integrity": "sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ==" + }, + "p-map": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", + "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==" + } + } + }, + "orbit-db-identity-provider": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/orbit-db-identity-provider/-/orbit-db-identity-provider-0.2.1.tgz", + "integrity": "sha512-IG8oNetdFBp1B2SYw8rLtZXkGEErfMGIZxps2i9AahM7qFvZDoaJ8r1ME6GQMEStFCQ14N4n6Tf+owTGBIPK2A==", + "requires": { + "ethers": "^4.0.20", + "orbit-db-keystore": "~0.3.0" + } + }, + "orbit-db-keystore": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/orbit-db-keystore/-/orbit-db-keystore-0.3.4.tgz", + "integrity": "sha512-TcTGxHrBBOe1lv5K/I21UDGJghzMMhO7gbFURzFtEnV+ar0P09kP1q4WzML8B96SJnROMP2aTO8VY3jeLLK8Lg==", + "requires": { + "elliptic": "^6.4.1", + "level": "~5.0.1", + "leveldown": "~5.1.1", + "levelup": "~4.1.0", + "libp2p-crypto": "^0.16.0", + "libp2p-crypto-secp256k1": "^0.3.0", + "lru": "^3.1.0", + "mkdirp": "^0.5.1", + "safe-buffer": "^5.1.2" + } + }, "p-each-series": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", @@ -14378,19 +14508,28 @@ "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } } }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } } } } @@ -15493,7 +15632,7 @@ "resolved": "https://registry.npmjs.org/rabin-wasm/-/rabin-wasm-0.0.8.tgz", "integrity": "sha512-TpIki3NG/X7nPnYHtYdF4Vp5NLrHvztiM5oL8+9NoeX/ClUfUyy7Y7DMrESZl1ropCpZJAjFMv/ZHYrkLu3bCQ==", "requires": { - "assemblyscript": "github:assemblyscript/assemblyscript#v0.6", + "assemblyscript": "github:assemblyscript/assemblyscript#3ed76a97f05335504166fce1653da75f4face28f", "bl": "^1.0.0", "debug": "^4.1.1", "minimist": "^1.2.0", @@ -18313,6 +18452,10 @@ "neo-async": "^2.5.0" } }, + "webcrypto-shim": { + "version": "github:dignifiedquire/webcrypto-shim#190bc9ec341375df6025b17ae12ddb2428ea49c8", + "from": "github:dignifiedquire/webcrypto-shim#master" + }, "webidl-conversions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", diff --git a/package.json b/package.json index f6e05e7b..2a4a2736 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "js-sha256": "^0.9.0", "muport-did-resolver": "^0.3.0", "node-fetch": "^2.6.0", - "orbit-db": "~0.21.4", + "orbit-db": "^0.22.1", "store": "^2.0.12", "tweetnacl": "^1.0.1", "tweetnacl-util": "^0.15.0" diff --git a/src/__tests__/thread.test.js b/src/__tests__/thread.test.js index d212bc98..ed134bff 100644 --- a/src/__tests__/thread.test.js +++ b/src/__tests__/thread.test.js @@ -2,13 +2,13 @@ const utils = require('./testUtils') const Thread = require('../thread') const OrbitDB = require('orbit-db') const { - // OdbIdentityProvider, + OdbIdentityProvider, LegacyIPFS3BoxAccessController, ThreadAccessController, ModeratorAccessController } = require('3box-orbitdb-plugins') -// const Identities = require('orbit-db-identity-provider') -// Identities.addIdentityProvider(OdbIdentityProvider) +const Identities = require('orbit-db-identity-provider') +Identities.addIdentityProvider(OdbIdentityProvider) const AccessControllers = require('orbit-db-access-controllers') AccessControllers.addAccessController({ AccessController: LegacyIPFS3BoxAccessController }) AccessControllers.addAccessController({ AccessController: ThreadAccessController }) @@ -49,8 +49,10 @@ describe('Thread', () => { beforeAll(async () => { ipfs = await utils.initIPFS(4) + const identity = await Identities.createIdentity({ id: 'nullid' }) orbitdb = await OrbitDB.createInstance(ipfs, { - directory:'./tmp/orbitdb4' + directory:'./tmp/orbitdb4', + identity }) replicatorMock = { _orbitdb: orbitdb, diff --git a/src/replicator.js b/src/replicator.js index 290ff1df..0308ee21 100644 --- a/src/replicator.js +++ b/src/replicator.js @@ -4,6 +4,7 @@ const Pubsub = require('orbit-db-pubsub') const AccessControllers = require('orbit-db-access-controllers') const resolveDID = require('did-resolver').default const { + OdbIdentityProvider, LegacyIPFS3BoxAccessController, ThreadAccessController, ModeratorAccessController @@ -12,6 +13,8 @@ AccessControllers.addAccessController({ AccessController: LegacyIPFS3BoxAccessCo AccessControllers.addAccessController({ AccessController: ThreadAccessController }) AccessControllers.addAccessController({ AccessController: ModeratorAccessController }) const config = require('./config') +const Identities = require('orbit-db-identity-provider') +Identities.addIdentityProvider(OdbIdentityProvider) const PINNING_NODE = config.pinning_node const PINNING_ROOM = config.pinning_room @@ -84,7 +87,9 @@ class Replicator { async _init (opts) { this._pubsub = new Pubsub(this.ipfs, (await this.ipfs.id()).id) - this._orbitdb = await OrbitDB.createInstance(this.ipfs, { directory: opts.orbitPath }) + // Identity not used, passes ref to 3ID orbit identity provider + const identity = await Identities.createIdentity({ id: 'nullid' }) + this._orbitdb = await OrbitDB.createInstance(this.ipfs, { directory: opts.orbitPath, identity }) } async _joinPinningRoom (firstJoin) { From b4967f2cddf993aea3c09fb0ca55e172f7486dec Mon Sep 17 00:00:00 2001 From: Zach Ferland Date: Thu, 19 Dec 2019 20:34:47 -0500 Subject: [PATCH 04/15] feat: ipfs mcok, api resolve did doc until ipfs instance available --- src/3box.js | 2 +- src/__mocks__/3box.js | 8 ++++---- src/__tests__/3box.test.js | 15 +++++++-------- src/__tests__/verified.test.js | 14 +++++++------- src/api.js | 3 +-- src/utils/verifier.js | 19 +++++++++++++++++++ 6 files changed, 39 insertions(+), 22 deletions(-) diff --git a/src/3box.js b/src/3box.js index 9a581bd0..4cc8c8b1 100644 --- a/src/3box.js +++ b/src/3box.js @@ -287,7 +287,7 @@ class Box extends BoxApi { */ get DID () { if (!this._3id) throw new Error('DID: auth required') - return this._3id.did + return this._3id.DID } /** diff --git a/src/__mocks__/3box.js b/src/__mocks__/3box.js index 9b861f3e..f03b5c59 100644 --- a/src/__mocks__/3box.js +++ b/src/__mocks__/3box.js @@ -1,9 +1,9 @@ class Box { - constructor (muportDID, ethereumProvider, opts = {}) { + constructor (DID, ethereumProvider, opts = {}) { this._publicStore = {} this._privateStore = {} this._3id = { - muportDID: muportDID + muportDID: DID.replace('3', 'muport') } this.public = { set: (k, v) => this._publicStore[k] = v, @@ -13,11 +13,11 @@ class Box { set: (k, v) => this._privateStore[k] = v, get: (k) => this._privateStore[k] } - this.DID = muportDID + this.DID = DID } static async openBox (address, ethereumProvider, opts = {}) { - let did = 'did:muport:' + address + let did = 'did:3:' + address return new Box(did, ethereumProvider, opts) } } diff --git a/src/__tests__/3box.test.js b/src/__tests__/3box.test.js index a4e82471..ace28ee7 100644 --- a/src/__tests__/3box.test.js +++ b/src/__tests__/3box.test.js @@ -15,9 +15,6 @@ registerMethod('muport', didResolverMock) const DID1 = 'did:3:zdpuAsaK9YsqpphSBeQvfrKAjs8kF7vUX4Y3kMkMRgEQigzCt' const DID2 = 'did:3:zdpuB2DcKQKNBDz3difEYxjTupsho5VuPCLgRbRunXqhmrJaX' -const DIDMUPORT1 = DID1.replace('3', 'muport') -const DIDMUPORT2 = DID2.replace('3', 'muport') - const randomStr = () => `${Math.floor(Math.random() * 1000000)}` @@ -352,7 +349,7 @@ describe('3Box', () => { boxWithLinks._readAddressLink = jest.fn(() => { return { - message: `I agree to stuff,${DIDMUPORT1}`, + message: `I agree to stuff,${DID1}`, signature: "0xSuchRealSig,0x12345", timestamp: 111, type: "ethereum-eoa", @@ -367,7 +364,7 @@ describe('3Box', () => { expect(mockedUtils.fetchJson).toHaveBeenCalledTimes(1) // TODO now hwy this second clal as expected?? expect(mockedUtils.fetchJson).toHaveBeenNthCalledWith(1, 'address-server/link', { - message: `I agree to stuff,${DIDMUPORT1}`, + message: `I agree to stuff,${DID1}`, signature: "0xSuchRealSig,0x12345", timestamp: 111, type: "ethereum-eoa", @@ -496,14 +493,15 @@ describe('3Box', () => { proof_github: 'github proof url', proof_twitter: 'twitter proof claim jwt' } - const userDID = 'did:muport:Qmsdpuhs' + const userMuPort = 'did:muport:Qmsdpuhs' + const userDID = 'did:3:zdpuAsaK9Ysqpph' let verifier = require('../utils/verifier') verifier.verifyDID.mockImplementationOnce(() => { throw new Error() }) expect(await Box.getVerifiedAccounts(profile)).toEqual({}) - verifier.verifyDID.mockImplementationOnce(() => ({ did: userDID, muport: userDID})) + verifier.verifyDID.mockImplementationOnce(() => ({ did: userDID, muport: userMuPort})) verifier.verifyGithub.mockImplementationOnce(() => { return { username: 'test', proof: 'some url' } }) @@ -515,7 +513,8 @@ describe('3Box', () => { expect(verifiedAccounts).toEqual({ 'github': { 'proof': 'some url', 'username': 'test' }, 'twitter': { 'proof': 'some url', 'username': 'test' }, - 'did': userDID + 'did': userDID, + 'muport': userMuPort }) }) diff --git a/src/__tests__/verified.test.js b/src/__tests__/verified.test.js index 3b92a96f..d627335e 100644 --- a/src/__tests__/verified.test.js +++ b/src/__tests__/verified.test.js @@ -10,7 +10,7 @@ const GITHUB_LINK2_URL = 'https://gist.githubusercontent.com/user1/wrongLink' jest.mock('../3box') jest.mock('../utils', () => { const GITHUB_LINK1_URL = 'https://gist.githubusercontent.com/user1/12345' - const GITHUB_LINK1_CONTENT = 'some random text did:muport:0x12345 more random text' + const GITHUB_LINK1_CONTENT = 'some random text did:3:0x12345 more random text' const GITHUB_LINK2_URL = 'https://gist.githubusercontent.com/user1/wrongLink' const GITHUB_LINK2_CONTENT = 'wrong did' return { @@ -78,7 +78,7 @@ describe('Verified', () => { beforeAll(async () => { incorrectClaim = await didJWT.createJWT({ - sub: 'did:muport:QMasdivuhs', + sub: 'did:3:QMasdivuhs', iat: 123456789, claim: { werid_claim: 'some data' @@ -88,7 +88,7 @@ describe('Verified', () => { signer: httpsDidSigner }) correctClaim = await didJWT.createJWT({ - sub: 'did:muport:0x12345', + sub: 'did:3:0x12345', iat: 123456789, claim: { twitter_handle: 'twitterUser', @@ -113,7 +113,7 @@ describe('Verified', () => { it('should throw if twitter claim does not contain username and proof', async () => { incorrectClaim = await didJWT.createJWT({ - sub: 'did:muport:0x12345', + sub: 'did:3:0x12345', iat: 123456789, claim: { werid_claim: 'some data' @@ -132,7 +132,7 @@ describe('Verified', () => { beforeAll(async () => { incorrectClaim = await didJWT.createJWT({ - sub: 'did:muport:QMasdivuhs', + sub: 'did:3:QMasdivuhs', iat: 123456789, claim: { werid_claim: 'some data' @@ -142,7 +142,7 @@ describe('Verified', () => { signer: httpsDidSigner }) correctClaim = await didJWT.createJWT({ - sub: 'did:muport:0x12345', + sub: 'did:3:0x12345', iat: 123456789, claim: { email_address: 'user@3box.io', @@ -166,7 +166,7 @@ describe('Verified', () => { it('should throw if twitter claim does not contain email_address and proof', async () => { incorrectClaim = await didJWT.createJWT({ - sub: 'did:muport:0x12345', + sub: 'did:3:0x12345', iat: 123456789, claim: { werid_claim: 'some data' diff --git a/src/api.js b/src/api.js index d6e2089b..5c931d0e 100644 --- a/src/api.js +++ b/src/api.js @@ -230,13 +230,12 @@ class BoxApi { const verifs = {} try { const didVerified = await verifier.verifyDID(profile.proof_did) - const dids = [didVerified.did] verifs.did = didVerified.did if (didVerified.muport) { verifs.muport = didVerified.muport - dids.push(muport) + dids.push(didVerified.muport) } if (profile.proof_github) { diff --git a/src/utils/verifier.js b/src/utils/verifier.js index ed549aaa..50d3dfd7 100644 --- a/src/utils/verifier.js +++ b/src/utils/verifier.js @@ -1,9 +1,28 @@ const { fetchText, getMessageConsent } = require('./index') const didJWT = require('did-jwt') const { verifyMessage } = require('@ethersproject/wallet') +const config = require('../config.js') +const utils = require('./index') +const registerResolver = require('3id-resolver') require('https-did-resolver').default() require('muport-did-resolver')() +const PROFILE_SERVER_URL = config.profile_server_url + +// Mocks ipfs obj for 3id resolve, to resolve through api, until ipfs instance is available +const ipfs = (didServerUrl) => { + return { + dag: { + get: async (cid) => { + const req = `${didServerUrl}/did-doc?cid=${encodeURIComponent(cid)}` + return utils.fetchJson(req) + } + } + } +} + +registerResolver(ipfs(PROFILE_SERVER_URL), { pin: false }) + module.exports = { /** * Verifies that the gist contains the given 3ID and returns the users github username. From d97087f1fed9fbb15f1c060807dea6999ba82d56 Mon Sep 17 00:00:00 2001 From: Joel Torstensson Date: Fri, 27 Dec 2019 10:55:20 +0100 Subject: [PATCH 05/15] fix(3box): await promise to validate link --- src/3box.js | 2 +- src/__tests__/idWallet.integration.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/3box.js b/src/3box.js index ddeea8a4..b5299d88 100644 --- a/src/3box.js +++ b/src/3box.js @@ -375,7 +375,7 @@ class Box extends BoxApi { } async _writeAddressLink (proof) { - const validProof = validateLink(proof) + const validProof = await validateLink(proof) if (!validProof) { throw new Error('tried to write invalid link proof', proof) } diff --git a/src/__tests__/idWallet.integration.js b/src/__tests__/idWallet.integration.js index 9b204a89..1d802883 100644 --- a/src/__tests__/idWallet.integration.js +++ b/src/__tests__/idWallet.integration.js @@ -73,11 +73,11 @@ describe('Integration Test: IdentityWallet', () => { identityKeysPath: `./tmp/did1`, pinningNode: ipfsMultiAddr2 } + pubsub.subscribe(PINNING_ROOM, (topic, data) => {}, () => {}) }) beforeEach(async () => { idWallet = new IdentityWallet(getConsent, { seed: SEED }) - pubsub.subscribe(PINNING_ROOM, (topic, data) => {}, () => {}) }) afterAll(async () => { @@ -111,8 +111,8 @@ describe('Integration Test: IdentityWallet', () => { expect(box.replicator.rootstore._oplog.values.length).toEqual(3) idWallet.addAuthMethod(AUTH_1) - await testUtils.delay(800) - expect(box.replicator.rootstore._oplog.values.length).toEqual(4) + await testUtils.delay(1200) + expect(box.replicator.rootstore._oplog.values.length).toEqual(5) await box.close() }) @@ -126,10 +126,10 @@ describe('Integration Test: IdentityWallet', () => { await box.syncDone expect(await box.public.all()).toEqual(pubState) - expect(box.replicator.rootstore._oplog.values.length).toEqual(4) - idWallet.addAuthMethod(AUTH_2) - await testUtils.delay(800) expect(box.replicator.rootstore._oplog.values.length).toEqual(5) + idWallet.addAuthMethod(AUTH_2) + await testUtils.delay(1200) + expect(box.replicator.rootstore._oplog.values.length).toEqual(7) await box.close() }) From beccd63acbb186bb2823ec62a634069ffb1e602d Mon Sep 17 00:00:00 2001 From: Joel Torstensson Date: Thu, 2 Jan 2020 11:44:29 +0100 Subject: [PATCH 06/15] fix(3id): Open space correctly when using IDW in browser --- src/3id/index.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/3id/index.js b/src/3id/index.js index 9c62e6da..39372eb4 100644 --- a/src/3id/index.js +++ b/src/3id/index.js @@ -190,7 +190,9 @@ class ThreeId { await this._initDID() } else { for (const space of spaces) { - this._subDIDs[space] = await this._init3ID(space) + if (!this._subDIDs[space]) { + this._subDIDs[space] = await this._init3ID(space) + } } } } else { @@ -201,13 +203,7 @@ class ThreeId { } async isAuthenticated (spaces = []) { - if (this._has3idProv) { - return utils.callRpc(this._provider, '3id_isAuthenticated', { spaces }) - } else { - return spaces - .map(space => Boolean(this._keyrings[space])) - .reduce((acc, val) => acc && val, true) - } + return spaces.reduce((acc, space) => acc && Object.keys(this._subDIDs).includes(space), true) } async _initKeyringByName (name) { From 57fcdd497a732774883bc187a214196d22c302d9 Mon Sep 17 00:00:00 2001 From: Joel Torstensson Date: Thu, 19 Dec 2019 14:18:47 +0100 Subject: [PATCH 07/15] feat: implement asymmetric encryption interface --- src/3id/__tests__/3id.test.js | 22 +++++++++++++++++-- .../__tests__/__snapshots__/3id.test.js.snap | 16 +++++++------- src/3id/__tests__/keyring.test.js | 2 +- src/3id/index.js | 19 +++++++++++++--- src/3id/keyring.js | 4 +++- 5 files changed, 48 insertions(+), 15 deletions(-) diff --git a/src/3id/__tests__/3id.test.js b/src/3id/__tests__/3id.test.js index b1cbf7cb..abfe80ea 100644 --- a/src/3id/__tests__/3id.test.js +++ b/src/3id/__tests__/3id.test.js @@ -8,7 +8,9 @@ const IdentityWallet = require('identity-wallet') const utils = require('../../utils/index') utils.openBoxConsent = jest.fn(async () => '0x8726348762348723487238476238746827364872634876234876234') -utils.openSpaceConsent = jest.fn(async () => '0x8ab87482987498387634985734987b9834598734597887070702535') +utils.openSpaceConsent = jest.fn(async (a, b, space) => { + return space === 'space1' ? '0x8ab87482987498387634985734987b9834598734597887070702535' : '0x8234be82987498387634985734987b9834598734597887070702535' +}) utils.sha256Multihash = jest.fn(str => { if (str === 'did:muport:Qmsdsdf87g329') return 'ab8c73d8f' return 'b932fe7ab' @@ -28,7 +30,7 @@ const ADDR_1 = '0x12345' const ADDR_2 = '0xabcde' const ADDR_3 = '0xlmnop' const ADDR_1_STATE_1 = '{"managementAddress":"0x12345","seed":"0xbc95bb0aeb7e5c7a9519ef066d4b60a944373ba1163b0c962a043bebec1579ef33e0ef4f63c0888d7a8ec95df34ada58fb739b2a4d3b44362747e6b193db9af2","spaceSeeds":{}}' -const ADDR_1_STATE_2 = '{"managementAddress":"0x12345","seed":"0xbc95bb0aeb7e5c7a9519ef066d4b60a944373ba1163b0c962a043bebec1579ef33e0ef4f63c0888d7a8ec95df34ada58fb739b2a4d3b44362747e6b193db9af2","spaceSeeds":{"space1":"0xedfac8a7bcc52f33b88cfb9f310bc533f77800183beecfa49dcdf8d3b4b906502ec46533d9d7fb12eced9b04e0bdebd1c26872cf5fa759331e4c2f97ab95f450","space2":"0xedfac8a7bcc52f33b88cfb9f310bc533f77800183beecfa49dcdf8d3b4b906502ec46533d9d7fb12eced9b04e0bdebd1c26872cf5fa759331e4c2f97ab95f450"}}' +const ADDR_1_STATE_2 = '{"managementAddress":"0x12345","seed":"0xbc95bb0aeb7e5c7a9519ef066d4b60a944373ba1163b0c962a043bebec1579ef33e0ef4f63c0888d7a8ec95df34ada58fb739b2a4d3b44362747e6b193db9af2","spaceSeeds":{"space1":"0xedfac8a7bcc52f33b88cfb9f310bc533f77800183beecfa49dcdf8d3b4b906502ec46533d9d7fb12eced9b04e0bdebd1c26872cf5fa759331e4c2f97ab95f450","space2":"0x9dcc08a8813362b2188cf40216fbdff577f77c291e7b96cd8f31b60493a6b6a9572eee62b01fcb9a7759c12247cb57cc38e0b4e46e186c23d1d4b26db46108c7"}}' const ADDR_2_STATE = '{"managementAddress":"0xabcde","seed":"0xbc95bb0aeb7e5c7a9519ef066d4b60a944373ba1163b0c962a043bebec1579ef33e0ef4f63c0888d7a8ec95df34ada58fb739b2a4d3b44362747e6b193db9af2","spaceSeeds":{}}' const ADDR_3_STATE_1 = '{"managementAddress":"0xlmnop","seed":"0xaedd3b597a14ad1c941ca535208fabd0b44a668dd0c8156f68a823ef8d713212d356731839a354ac5b781f4b986ff54aa2cadfa3551846c9e43bfa0122f3d55b","spaceSeeds":{}}' const SPACE_1 = 'space1' @@ -175,6 +177,14 @@ describe('3id', () => { expect(await threeId.decrypt(enc1, SPACE_1)).toEqual(null) }) + it('should encrypt and decrypt asymmetrically correctly', async () => { + const message = 'test message' + const { asymEncryptionKey } = await threeId.getPublicKeys(SPACE_1) + const enc1 = await threeId.encrypt(message, null, asymEncryptionKey) + expect(await threeId.decrypt(enc1, SPACE_1)).toEqual(message) + expect(await threeId.decrypt(enc1, SPACE_2)).toEqual(null) + }) + it('should get identity with spaces automatically initialized', async () => { threeId = await ThreeId.getIdFromEthAddress(ADDR_1, ETHEREUM, ipfs) expect(threeId.serializeState()).toEqual(ADDR_1_STATE_2) @@ -258,6 +268,14 @@ describe('3id', () => { expect(await idw3id.decrypt(enc2, SPACE_1)).toEqual(message) await expect(idw3id.decrypt(enc1, SPACE_1)).rejects.toMatchSnapshot() }) + + it('should encrypt and decrypt asymmetrically correctly', async () => { + const message = 'test message' + const { asymEncryptionKey } = await threeId.getPublicKeys(SPACE_1) + const enc1 = await threeId.encrypt(message, null, asymEncryptionKey) + expect(await threeId.decrypt(enc1, SPACE_1)).toEqual(message) + expect(await threeId.decrypt(enc1, SPACE_2)).toEqual(null) + }) }) describe('claim signing', () => { diff --git a/src/3id/__tests__/__snapshots__/3id.test.js.snap b/src/3id/__tests__/__snapshots__/3id.test.js.snap index b95b6b6a..7fc3883e 100644 --- a/src/3id/__tests__/__snapshots__/3id.test.js.snap +++ b/src/3id/__tests__/__snapshots__/3id.test.js.snap @@ -478,21 +478,21 @@ Object { } `; -exports[`3id getIdFromEthAddress keyring logic should init space keyrings correctly 3`] = `"did:3:bafyreihflugvhgu5gxh5yxeajxsrw5mxv46ejsp3ga24jvtli25az4r3cm"`; +exports[`3id getIdFromEthAddress keyring logic should init space keyrings correctly 3`] = `"did:3:bafyreiah6tbfx36lacnw2ofx6pt2ibysggwbsc23dk23koiedm7dzvxzvu"`; exports[`3id getIdFromEthAddress keyring logic should init space keyrings correctly 4`] = ` Object { "@context": "https://w3id.org/did/v1", "authentication": Array [ Object { - "publicKey": "did:3:bafyreihflugvhgu5gxh5yxeajxsrw5mxv46ejsp3ga24jvtli25az4r3cm#subSigningKey", + "publicKey": "did:3:bafyreiah6tbfx36lacnw2ofx6pt2ibysggwbsc23dk23koiedm7dzvxzvu#subSigningKey", "type": "Secp256k1SignatureAuthentication2018", }, ], - "id": "did:3:bafyreihflugvhgu5gxh5yxeajxsrw5mxv46ejsp3ga24jvtli25az4r3cm", + "id": "did:3:bafyreiah6tbfx36lacnw2ofx6pt2ibysggwbsc23dk23koiedm7dzvxzvu", "proof": Object { "alg": "ES256K", - "signature": "r5tZSizljdgVmjb1SOIQjavqxw8s8LS1CNPrIyGq-9kYnlNbqH5yT2UcZPyexeyji08x3Og9ymPMYfSVJxwnNA", + "signature": "a6k7ZxOgfgHSeApVYWpbHzKt7T2mQry5zTY1XSLWxetNatbhUFjln_uhstzLKm3mh0njUbT6HfpB5Y3eH_mlHw", }, "publicKey": Array [ Object { @@ -511,13 +511,13 @@ Object { "type": "Secp256k1VerificationKey2018", }, Object { - "id": "did:3:bafyreihflugvhgu5gxh5yxeajxsrw5mxv46ejsp3ga24jvtli25az4r3cm#subSigningKey", - "publicKeyHex": "04a514c9de733883c7e264353988188dd815677af6d219068b540077a8eeaf5aad8ca93b512006fd50257347f849475dfe719acfc60256e40b5f4399dcc7350bbf", + "id": "did:3:bafyreiah6tbfx36lacnw2ofx6pt2ibysggwbsc23dk23koiedm7dzvxzvu#subSigningKey", + "publicKeyHex": "043903523a65f689ff52b216108a587b14282f654a48c6ba34f05378d077c48b2e9e541041ab80dc161cbb253e22bb4e86e1f891b92e909949aa5cca408c4e4885", "type": "Secp256k1VerificationKey2018", }, Object { - "id": "did:3:bafyreihflugvhgu5gxh5yxeajxsrw5mxv46ejsp3ga24jvtli25az4r3cm#subEncryptionKey", - "publicKeyBase64": "zaPBNwm0qXFe9lUAqldGuhNdle6jbRtyUISoO+S3CBY=", + "id": "did:3:bafyreiah6tbfx36lacnw2ofx6pt2ibysggwbsc23dk23koiedm7dzvxzvu#subEncryptionKey", + "publicKeyBase64": "lL7nwPFH1ISLplkZb4uywfRTvHvbYdVx5WrIvHF7IDE=", "type": "Curve25519EncryptionPublicKey", }, ], diff --git a/src/3id/__tests__/keyring.test.js b/src/3id/__tests__/keyring.test.js index 9d81290e..ba634de1 100644 --- a/src/3id/__tests__/keyring.test.js +++ b/src/3id/__tests__/keyring.test.js @@ -37,7 +37,7 @@ describe('Keyring', () => { const testMsg = "Very secret test message" let box = keyring1.asymEncrypt(testMsg, keyring2.getPublicKeys().asymEncryptionKey) - let cleartext = keyring2.asymDecrypt(box.ciphertext, keyring1.getPublicKeys().asymEncryptionKey, box.nonce) + let cleartext = keyring2.asymDecrypt(box.ciphertext, box.ephemeralFrom, box.nonce) expect(cleartext).toEqual(testMsg) }) diff --git a/src/3id/index.js b/src/3id/index.js index 63eec65d..8c19925e 100644 --- a/src/3id/index.js +++ b/src/3id/index.js @@ -226,11 +226,17 @@ class ThreeId { return pubkeys } - async encrypt (message, space) { + async encrypt (message, space, to) { if (this._has3idProv) { return utils.callRpc(this._provider, '3id_encrypt', { message, space }) } else { - return this._keyringBySpace(space).symEncrypt(utils.pad(message)) + const keyring = this._keyringBySpace(space) + let paddedMsg = utils.pad(message) + if (to) { + return keyring.asymEncrypt(paddedMsg, to) + } else { + return keyring.symEncrypt(paddedMsg) + } } } @@ -238,7 +244,14 @@ class ThreeId { if (this._has3idProv) { return utils.callRpc(this._provider, '3id_decrypt', { ...encObj, space }) } else { - return utils.unpad(this._keyringBySpace(space).symDecrypt(encObj.ciphertext, encObj.nonce)) + const keyring = this._keyringBySpace(space) + let paddedMsg + if (encObj.ephemeralFrom) { + paddedMsg = keyring.asymDecrypt(encObj.ciphertext, encObj.ephemeralFrom, encObj.nonce) + } else { + paddedMsg = keyring.symDecrypt(encObj.ciphertext, encObj.nonce) + } + return utils.unpad(paddedMsg) } } diff --git a/src/3id/keyring.js b/src/3id/keyring.js index a5d79980..a918be9d 100644 --- a/src/3id/keyring.js +++ b/src/3id/keyring.js @@ -29,9 +29,11 @@ class Keyring { if (typeof msg === 'string') { msg = nacl.util.decodeUTF8(msg) } - const ciphertext = nacl.box(msg, nonce, toPublic, this.asymEncryptionKey.secretKey) + const ephemneralKeypair = nacl.box.keyPair() + const ciphertext = nacl.box(msg, nonce, toPublic, ephemneralKeypair.secretKey) return { nonce: nacl.util.encodeBase64(nonce), + ephemeralFrom: nacl.util.encodeBase64(ephemneralKeypair.publicKey), ciphertext: nacl.util.encodeBase64(ciphertext) } } From a914ee905df1b0256ad278e0187a3f6eda03ca26 Mon Sep 17 00:00:00 2001 From: Joel Torstensson Date: Fri, 27 Dec 2019 15:43:05 +0100 Subject: [PATCH 08/15] feat: implement the user object --- README.md | 72 +++++++++++++++- package-lock.json | 6 +- package.json | 2 +- src/3id/__tests__/3id.test.js | 8 +- .../__tests__/__snapshots__/3id.test.js.snap | 2 + src/3id/index.js | 2 +- src/api.js | 3 +- src/space.js | 86 ++++++++++++++++++- 8 files changed, 164 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 3ea607d7..89246472 100644 --- a/README.md +++ b/README.md @@ -876,6 +876,70 @@ const log = store.log console.log(entry) // { op: 'PUT', key: 'Name', value: 'Botbot', timeStamp: '1538575416068' } ``` + + +### User +Class representing a user. + +**Kind**: global class + +* [User](#User) + * [.DID](#User+DID) + * [.signClaim(payload, opts)](#User+signClaim) ⇒ String + * [.encrypt(message, opts, to)](#User+encrypt) ⇒ Object + * [.decrypt(encryptedObject)](#User+decrypt) ⇒ String + + + +#### user.DID +**Kind**: instance property of [User](#User) +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| DID | String | the DID of the user | + + + +#### user.signClaim(payload, opts) ⇒ String +Sign a JWT claim + +**Kind**: instance method of [User](#User) +**Returns**: String - The signed JWT + +| Param | Type | Description | +| --- | --- | --- | +| payload | Object | The payload to sign | +| opts | Object | Optional parameters | + + + +#### user.encrypt(message, opts, to) ⇒ Object +Encrypt a message. By default encrypts messages symmetrically +with the users private key. If the `to` parameter is used, +the message will be asymmetrically encrypted to the recipient. + +**Kind**: instance method of [User](#User) +**Returns**: Object - An object containing the encrypted payload + +| Param | Type | Description | +| --- | --- | --- | +| message | String | The message to encrypt | +| opts | Object | Optional parameters | +| to | String | The receiver of the message, a DID or an ethereum address | + + + +#### user.decrypt(encryptedObject) ⇒ String +Decrypts a message if the user owns the correct key to decrypt it. + +**Kind**: instance method of [User](#User) +**Returns**: String - The clear text message + +| Param | Type | Description | +| --- | --- | --- | +| encryptedObject | Object | The encrypted message to decrypt (as encoded by the `encrypt` method | + ### Space @@ -886,7 +950,7 @@ const log = store.log * [.public](#Space+public) * [.private](#Space+private) * [.syncDone](#Space+syncDone) - * [.DID](#Space+DID) + * [.user](#Space+user) * [.joinThread(name, opts)](#Space+joinThread) ⇒ [Thread](#Thread) * [.joinThreadByAddress(address, opts)](#Space+joinThreadByAddress) ⇒ [Thread](#Thread) * [.subscribeThread(address, config)](#Space+subscribeThread) @@ -928,15 +992,15 @@ Please use **box.openSpace** to get the instance of this class | --- | --- | --- | | syncDone | Promise | A promise that is resolved when the space data is synced | - + -#### space.DID +#### space.user **Kind**: instance property of [Space](#Space) **Properties** | Name | Type | Description | | --- | --- | --- | -| DID | String | the did of the user in this space | +| user | [User](#User) | access the user object to encrypt data and sign claims | diff --git a/package-lock.json b/package-lock.json index 4f2bc3de..ec4fcbee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8364,9 +8364,9 @@ } }, "identity-wallet": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/identity-wallet/-/identity-wallet-1.0.0.tgz", - "integrity": "sha512-Vmf9oGFhVynhPaVJhlbPYIpJjtREoEMn6iln9Totq5+Ee5PtckSEyhDles0XlCQMShwCdoU4Xwq/rypUvVQh3Q==", + "version": "1.1.0-beta.1", + "resolved": "https://registry.npmjs.org/identity-wallet/-/identity-wallet-1.1.0-beta.1.tgz", + "integrity": "sha512-icn2Yc7v87bzs+S2XZzur8XHihICLxre+26bB+gHn1aWy/dQERXG2bPtmuDKb2U4K1DRqSNirtQzxHQoTnBPaw==", "dev": true, "requires": { "3id-blockchain-utils": "^0.3.2", diff --git a/package.json b/package.json index 2a4a2736..fc714d02 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "babel-core": "7.0.0-bridge.0", "babel-loader": "^8.0.6", "express": "^4.17.0", - "identity-wallet": "^1.0.0", + "identity-wallet": "^1.1.0-beta.1", "jest": "^23.6.0", "jsdoc-to-markdown": "^5.0.0", "standard": "^14.3.1", diff --git a/src/3id/__tests__/3id.test.js b/src/3id/__tests__/3id.test.js index abfe80ea..5a13e893 100644 --- a/src/3id/__tests__/3id.test.js +++ b/src/3id/__tests__/3id.test.js @@ -271,10 +271,10 @@ describe('3id', () => { it('should encrypt and decrypt asymmetrically correctly', async () => { const message = 'test message' - const { asymEncryptionKey } = await threeId.getPublicKeys(SPACE_1) - const enc1 = await threeId.encrypt(message, null, asymEncryptionKey) - expect(await threeId.decrypt(enc1, SPACE_1)).toEqual(message) - expect(await threeId.decrypt(enc1, SPACE_2)).toEqual(null) + const { asymEncryptionKey } = await idw3id.getPublicKeys(SPACE_1) + const enc1 = await idw3id.encrypt(message, null, asymEncryptionKey) + expect(await idw3id.decrypt(enc1, SPACE_1)).toEqual(message) + await expect(idw3id.decrypt(enc1, SPACE_2)).rejects.toMatchSnapshot() }) }) diff --git a/src/3id/__tests__/__snapshots__/3id.test.js.snap b/src/3id/__tests__/__snapshots__/3id.test.js.snap index 7fc3883e..e8bbf9c5 100644 --- a/src/3id/__tests__/__snapshots__/3id.test.js.snap +++ b/src/3id/__tests__/__snapshots__/3id.test.js.snap @@ -152,6 +152,8 @@ Object { } `; +exports[`3id get 3ID using IdentityWallet keyring logic should encrypt and decrypt asymmetrically correctly 1`] = `[Error: IdentityWallet: Could not decrypt message]`; + exports[`3id get 3ID using IdentityWallet keyring logic should encrypt and decrypt correctly 1`] = `[Error: IdentityWallet: Could not decrypt message]`; exports[`3id get 3ID using IdentityWallet keyring logic should get public keys correctly 1`] = ` diff --git a/src/3id/index.js b/src/3id/index.js index 8c19925e..d035a9a9 100644 --- a/src/3id/index.js +++ b/src/3id/index.js @@ -228,7 +228,7 @@ class ThreeId { async encrypt (message, space, to) { if (this._has3idProv) { - return utils.callRpc(this._provider, '3id_encrypt', { message, space }) + return utils.callRpc(this._provider, '3id_encrypt', { message, space, to }) } else { const keyring = this._keyringBySpace(space) let paddedMsg = utils.pad(message) diff --git a/src/api.js b/src/api.js index 5c931d0e..1c4bdda5 100644 --- a/src/api.js +++ b/src/api.js @@ -139,8 +139,9 @@ class BoxApi { */ static async getConfig (address, opts = {}) { const serverUrl = opts.profileServer || PROFILE_SERVER_URL + const isAddr = address.startsWith('0x') // assume 3ID if not address try { - return await utils.fetchJson(`${serverUrl}/config?address=${encodeURIComponent(address)}`) + return await utils.fetchJson(`${serverUrl}/config?${isAddr ? 'address' : 'did'}=${encodeURIComponent(address)}`) } catch (err) { throw new Error(err) } diff --git a/src/space.js b/src/space.js index 21bae17f..705eabb7 100644 --- a/src/space.js +++ b/src/space.js @@ -1,12 +1,86 @@ const KeyValueStore = require('./keyValueStore') const Thread = require('./thread') const GhostThread = require('./ghost') +const API = require('./api') const { throwIfUndefined, throwIfNotEqualLenArrays } = require('./utils') const OrbitDBAddress = require('orbit-db/src/orbit-db-address') +const resolveDID = require('did-resolver').default const nameToSpaceName = name => `3box.space.${name}.keyvalue` const namesTothreadName = (spaceName, threadName) => `3box.thread.${spaceName}.${threadName}` const namesToChatName = (spaceName, chatName) => `3box.ghost.${spaceName}.${chatName}` +const findSpacePubKey = async (did, spaceName) => { + if (did.startsWith('0x')) { + // we got an ethereum address + did = await API.getSpaceDID(did, spaceName) + } + let doc = await resolveDID(did) + let pubkey = doc.publicKey.find(key => key.id.includes('#subEncryptionKey')) + if (!pubkey) { + // A root 3ID was passed, get the space 3ID + did = await API.getSpaceDID(did, spaceName) + doc = await resolveDID(did) + pubkey = doc.publicKey.find(key => key.id.includes('#subEncryptionKey')) + } + return pubkey.publicKeyBase64 +} + +/** Class representing a user. */ +class User { + constructor (spaceName, threeId) { + this._name = spaceName + this._3id = threeId + } + + /** + * @property {String} DID the DID of the user + */ + get DID () { + return this._3id.getSubDID(this._name) + } + + /** + * Sign a JWT claim + * + * @param {Object} payload The payload to sign + * @param {Object} opts Optional parameters + * + * @return {String} The signed JWT + */ + async signClaim (payload, opts = {}) { + return this._3id.signJWT(payload, Object.assign(opts, { space: this._name })) + } + + /** + * Encrypt a message. By default encrypts messages symmetrically + * with the users private key. If the `to` parameter is used, + * the message will be asymmetrically encrypted to the recipient. + * + * @param {String} message The message to encrypt + * @param {Object} opts Optional parameters + * @param {String} to The receiver of the message, a DID or an ethereum address + * + * @return {Object} An object containing the encrypted payload + */ + async encrypt (message, { to }) { + let toPubkey + if (to) { + toPubkey = await findSpacePubKey(to, this._name) + } + return this._3id.encrypt(message, this._name, toPubkey) + } + + /** + * Decrypts a message if the user owns the correct key to decrypt it. + * + * @param {Object} encryptedObject The encrypted message to decrypt (as encoded by the `encrypt` method + * + * @return {String} The clear text message + */ + async decrypt (encryptedObject) { + return this._3id.decrypt(encryptedObject, this._name) + } +} class Space { /** @@ -31,11 +105,17 @@ class Space { this.syncDone = null } + get DID () { + return this.user.DID + } + /** - * @property {String} DID the did of the user in this space + * @property {User} user access the user object to encrypt data and sign claims */ - get DID () { - return this._3id.getSubDID(this._name) + get user () { + if (!this._3id) throw new Error('user is not authenticated') + this._user = this._user || new User(this._name, this._3id) + return this._user } get isOpen () { From 5576e0b4668740cff22691630acf0ddb0084aabc Mon Sep 17 00:00:00 2001 From: Michael Sterle-Contala <2691351+msterle@users.noreply.github.com> Date: Mon, 23 Dec 2019 17:29:14 -0500 Subject: [PATCH 09/15] add dockerfile with example server --- .dockerignore | 3 ++- Dockerfile.example | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 Dockerfile.example diff --git a/.dockerignore b/.dockerignore index b512c09d..85dcc16d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1 +1,2 @@ -node_modules \ No newline at end of file +.git +node_modules diff --git a/Dockerfile.example b/Dockerfile.example new file mode 100644 index 00000000..41cda4da --- /dev/null +++ b/Dockerfile.example @@ -0,0 +1,14 @@ +FROM node:10 + +WORKDIR /3box-js + +COPY package.json package-lock.json ./ +RUN npm install + +COPY src ./src +COPY webpack*.config.js .babelrc ./ +COPY example ./example + +EXPOSE 30000 + +CMD npm run example-server:start | npm run build:dist:dev From e3098bd60ed2b072d94ed00e690cb10966874771 Mon Sep 17 00:00:00 2001 From: Michael Sterle-Contala <2691351+msterle@users.noreply.github.com> Date: Mon, 30 Dec 2019 15:08:04 -0500 Subject: [PATCH 10/15] add option to disable connecting to rendezvous server, or to specify a server address --- example/index.js | 2 +- src/config.js | 9 +++++++-- webpack.dev.config.js | 2 ++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/example/index.js b/example/index.js index 64e7fc7a..3840c8ec 100644 --- a/example/index.js +++ b/example/index.js @@ -277,6 +277,6 @@ function updateLinksData (box, address) { box.isAddressLinked({ address }).then(result => { addressLinked.innerHTML = result ? 'Yes' : 'No' - linkAddress.style.display = result ? 'none' : 'block' + linkAddress.style.display = 'block' }) } diff --git a/src/config.js b/src/config.js index b7cd864b..f0c18cf0 100644 --- a/src/config.js +++ b/src/config.js @@ -1,6 +1,11 @@ const Log = require('ipfs-log') const IFRAME_STORE_VERSION = '0.0.3' +const RENDEZVOUS_DISABLE = !( + !process.env.RENDEZVOUS_DISABLE + || ['0','f', 'false', 'no', 'off'].includes(process.env.RENDEZVOUS_DISABLE.toLowerCase()) +) + module.exports = { address_server_url: process.env.ADDRESS_SERVER_URL || 'https://beta.3box.io/address-server', pinning_node: process.env.PINNING_NODE || '/dnsaddr/ipfs.3box.io/tcp/443/wss/ipfs/QmZvxEpiVNjmNbEKyQGvFzAY1BwmGuuvdUTmcTstQPhyVC', @@ -15,8 +20,8 @@ module.exports = { config: { Bootstrap: [], Addresses: { - Swarm: [ - '/dns4/p2p.3box.io/tcp/9090/wss/p2p-websocket-star/' + Swarm: RENDEZVOUS_DISABLE ? [] : [ + process.env.RENDEZVOUS_ADDRESS || '/dns4/p2p.3box.io/tcp/9090/wss/p2p-websocket-star/' ] } } diff --git a/webpack.dev.config.js b/webpack.dev.config.js index e6629ede..c7a076a8 100644 --- a/webpack.dev.config.js +++ b/webpack.dev.config.js @@ -14,6 +14,8 @@ module.exports = Object.assign(require('./webpack.config.js'), { 'ADDRESS_SERVER_URL', 'PINNING_NODE', 'PINNING_ROOM', + 'RENDEZVOUS_DISABLE', + 'RENDEZVOUS_ADDRESS', 'IFRAME_STORE_VERSION', 'IFRAME_STORE_URL', 'GRAPHQL_SERVER_URL', From ca48f3d923cd7fc257fe0ca876eaa4dae0316c6b Mon Sep 17 00:00:00 2001 From: Michael Sterle-Contala <2691351+msterle@users.noreply.github.com> Date: Mon, 30 Dec 2019 15:20:05 -0500 Subject: [PATCH 11/15] fix lint errors --- src/config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config.js b/src/config.js index f0c18cf0..e4cc9ac5 100644 --- a/src/config.js +++ b/src/config.js @@ -2,8 +2,8 @@ const Log = require('ipfs-log') const IFRAME_STORE_VERSION = '0.0.3' const RENDEZVOUS_DISABLE = !( - !process.env.RENDEZVOUS_DISABLE - || ['0','f', 'false', 'no', 'off'].includes(process.env.RENDEZVOUS_DISABLE.toLowerCase()) + !process.env.RENDEZVOUS_DISABLE || + ['0', 'f', 'false', 'no', 'off'].includes(process.env.RENDEZVOUS_DISABLE.toLowerCase()) ) module.exports = { From 6ea13b4135940326b55c781c188572269144d9cd Mon Sep 17 00:00:00 2001 From: Michael Sterle-Contala <2691351+msterle@users.noreply.github.com> Date: Tue, 7 Jan 2020 13:38:23 +0100 Subject: [PATCH 12/15] update lockfile --- package-lock.json | 98 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 30 deletions(-) diff --git a/package-lock.json b/package-lock.json index ec4fcbee..40234942 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4304,7 +4304,7 @@ "datastore-core": "~0.6.0", "encoding-down": "^6.0.2", "interface-datastore": "~0.6.0", - "level-js": "github:timkuijsten/level.js#18e03adab34c49523be7d3d58fafb0c632f61303", + "level-js": "github:timkuijsten/level.js#idbunwrapper", "leveldown": "^5.0.0", "levelup": "^4.0.1", "pull-stream": "^3.6.9" @@ -6657,7 +6657,8 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -6681,13 +6682,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6704,19 +6707,22 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -6847,7 +6853,8 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -6861,6 +6868,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -6877,6 +6885,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -6885,13 +6894,15 @@ "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -6912,6 +6923,7 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -7000,7 +7012,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -7014,6 +7027,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -7109,7 +7123,8 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -7151,6 +7166,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -7172,6 +7188,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -7220,13 +7237,15 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", - "dev": true + "dev": true, + "optional": true } } }, @@ -7281,7 +7300,8 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "optional": true }, "aproba": { "version": "1.2.0", @@ -7302,12 +7322,14 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "optional": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -7322,17 +7344,20 @@ "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "optional": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "optional": true }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -7449,7 +7474,8 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "optional": true }, "ini": { "version": "1.3.5", @@ -7461,6 +7487,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -7475,6 +7502,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -7482,12 +7510,14 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "optional": true }, "minipass": { "version": "2.3.5", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -7506,6 +7536,7 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "optional": true, "requires": { "minimist": "0.0.8" } @@ -7586,7 +7617,8 @@ "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "optional": true }, "object-assign": { "version": "4.1.1", @@ -7598,6 +7630,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "optional": true, "requires": { "wrappy": "1" } @@ -7683,7 +7716,8 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -7719,6 +7753,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -7738,6 +7773,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -7781,12 +7817,14 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "optional": true }, "yallist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "optional": true } } }, @@ -8887,7 +8925,7 @@ "bs58": "^4.0.1", "buffer": "^5.2.1", "cids": "~0.7.1", - "concat-stream": "github:hugomrdias/concat-stream#057bc7b5d6d8df26c8cf00a3f151b6721a0a8034", + "concat-stream": "github:hugomrdias/concat-stream#feat/smaller", "debug": "^4.1.0", "detect-node": "^2.0.4", "end-of-stream": "^1.4.1", @@ -8911,7 +8949,7 @@ "multibase": "~0.6.0", "multicodec": "~0.5.1", "multihashes": "~0.4.14", - "ndjson": "github:hugomrdias/ndjson#4db16da6b42e5b39bf300c3a7cde62abb3fa3a11", + "ndjson": "github:hugomrdias/ndjson#feat/readable-stream3", "once": "^1.4.0", "peer-id": "~0.12.2", "peer-info": "~0.15.1", @@ -9130,7 +9168,7 @@ "protons": "^1.0.1", "rsa-pem-to-jwk": "^1.1.3", "tweetnacl": "^1.0.0", - "webcrypto-shim": "github:dignifiedquire/webcrypto-shim#190bc9ec341375df6025b17ae12ddb2428ea49c8" + "webcrypto-shim": "github:dignifiedquire/webcrypto-shim#master" }, "dependencies": { "js-sha3": { @@ -9241,7 +9279,7 @@ "protons": "^1.0.1", "rsa-pem-to-jwk": "^1.1.3", "tweetnacl": "^1.0.0", - "webcrypto-shim": "github:dignifiedquire/webcrypto-shim#190bc9ec341375df6025b17ae12ddb2428ea49c8" + "webcrypto-shim": "github:dignifiedquire/webcrypto-shim#master" } }, "multiaddr": { @@ -12647,7 +12685,7 @@ "socket.io": "^2.1.1", "socket.io-client": "^2.1.1", "stream-to-pull-stream": "^1.7.3", - "webrtcsupport": "github:ipfs/webrtcsupport#0669f576582c53a3a42aa5ac014fcc5966809615" + "webrtcsupport": "github:ipfs/webrtcsupport" }, "dependencies": { "minimist": { @@ -12701,7 +12739,7 @@ "interface-connection": "~0.3.3", "mafmt": "^6.0.7", "multiaddr-to-uri": "^5.0.0", - "pull-ws": "github:hugomrdias/pull-ws#8e2ce0bb3b1cd6804828316e937fff8e0bef6225" + "pull-ws": "github:hugomrdias/pull-ws#fix/bundle-size" }, "dependencies": { "multiaddr-to-uri": { @@ -15632,7 +15670,7 @@ "resolved": "https://registry.npmjs.org/rabin-wasm/-/rabin-wasm-0.0.8.tgz", "integrity": "sha512-TpIki3NG/X7nPnYHtYdF4Vp5NLrHvztiM5oL8+9NoeX/ClUfUyy7Y7DMrESZl1ropCpZJAjFMv/ZHYrkLu3bCQ==", "requires": { - "assemblyscript": "github:assemblyscript/assemblyscript#3ed76a97f05335504166fce1653da75f4face28f", + "assemblyscript": "github:assemblyscript/assemblyscript#v0.6", "bl": "^1.0.0", "debug": "^4.1.1", "minimist": "^1.2.0", From 41027bd28dcae053b8007cfa6595cc93d7cd3bd7 Mon Sep 17 00:00:00 2001 From: Rachel Date: Thu, 9 Jan 2020 11:41:40 +0100 Subject: [PATCH 13/15] openThread in docs (#690) * openThread in docs * remove joinThreads --- README.md | 8 +++++--- readme-template.md | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 89246472..3cb198d4 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ console.log(profile) 3Box allows applications to create, read, update, and delete public and private data stored in a user's 3Box. To enable this functionality, applications must first authenticate the user's 3Box by calling the `auth` method. This method prompts the user to authenticate (sign-in) to your dapp and returns a promise with a threeBox instance. You can only update (set, get, remove) data for users that have authenticated to and are currently interacting with your dapp. Below `ethereumProvider` refers to the object that you would get from `web3.currentProvider`, or `window.ethereum`. #### 1. Create a 3Box instance -To create a 3Box session you call the `create` method. This creates an instance of the Box class which can be used to joinThreads and authenticate the user in any order. In order to create a 3Box session a `provider` needs to be passed. This can be an `ethereum provider` (from `web3.currentProvider`, or `window.ethereum`) or a `3ID Provider` (from [IdentityWallet](https://github.com/3box/identity-wallet-js)). +To create a 3Box session you call the `create` method. This creates an instance of the Box class which can be used to openThreads and authenticate the user in any order. In order to create a 3Box session a `provider` needs to be passed. This can be an `ethereum provider` (from `web3.currentProvider`, or `window.ethereum`) or a `3ID Provider` (from [IdentityWallet](https://github.com/3box/identity-wallet-js)). ```js const box = await Box.create(provider) ``` @@ -72,7 +72,7 @@ When you first authenticate the box in your dapp all data might not be synced fr ```js await box.syncDone ``` -This will allow you to know when all the user's data is available to you. We advise against *setting* any data before this sync has happened. However, reading data before the sync is complete is fine and encouraged - just remember to check for updates once the sync is finished! +This will allow you to know when all the user's data is available to you. We advise against *setting* any data before this sync has happened. However, reading data before the sync is complete is fine and encouraged - just remember to check for updates once the sync is finished! Please note, `box.syncDone` can only be called once the user has been authenticated, it is not possible if only the `Box.create` method has been called. If you prefer to not use promises you can add a callback using the `onSyncDone` method. @@ -113,11 +113,12 @@ await box.private.setMultiple(privateFields, privateValues) ``` ##### Open a thread -Once you have created a 3Box session you can open a thread to view data in it. This can be done before you authenticate the user to be able to post in the thread. +Once you have created a 3Box session you can open a thread to view data in it. This can be done before you authenticate the user (required for them to post in the thread). When opening a thread the moderation options need to be given. You can pass `firstModerator`, a 3ID (or ethereum address) of the first moderator, and a `members` boolean which indicates if it is a members thread or not. ```js const thread = await box.openThread('myDapp', 'myThread', { firstModerator: 'did:3:bafy...', members: true }) ``` +Once a thread has been opened you can call the `getPosts()` method to retrive the posts. - + + @@ -145,6 +106,48 @@

Posts:

+
+

Threads:

+
+
+
+ Members Only Thread +
+ Ghost ? +
+

+ + +
+ +

+ +

+ + +
+
diff --git a/example/index.js b/example/index.js index 3840c8ec..06ace27d 100644 --- a/example/index.js +++ b/example/index.js @@ -2,13 +2,19 @@ const syncComplete = (res) => { console.log('Sync Complete') updateProfileData(window.box) } -bopen.addEventListener('click', event => { + +Box.create(window.ethereum).then(box => { + window.box = box + bauth.disabled = false + openThread.disabled = false +}) + +bauth.addEventListener('click', event => { window.ethereum.enable().then(addresses => { - window.Box.openBox(addresses[0], window.ethereum, {}).then(box => { + window.box.auth([], { address: addresses[0] }).then(() => { box.onSyncDone(syncComplete) - window.box = box - console.log(box) + console.log('authed') controlls.style.display = 'block' updateProfileData(box) @@ -95,104 +101,105 @@ bopen.addEventListener('click', event => { }) }) } + }) - joinThread.addEventListener('click', () => { - const name = threadName.value - const firstModerator = threadfirstModerator.value - const membersBool = members.checked - const ghostBool = ghostCheck.checked - console.log('ghost?', ghostBool); - posts.style.display = 'block' - threadModeration.style.display = 'block' - if (members.checked) threadMembers.style.display = 'block' - if (ghostCheck.checked) { - addThreadMod.disabled = true - } - box.spaces[window.currentSpace].joinThread(name, {firstModerator, members: membersBool, ghost: ghostBool}).then(thread => { - window.currentThread = thread - thread.onUpdate(() => { - updateThreadData() - }) - thread.onNewCapabilities(() => { - updateThreadCapabilities() - }) - if (window.currentThread._room == undefined) { - updateThreadData() - updateThreadCapabilities() - } - }).catch(updateThreadError) - }) + bclose.addEventListener('click', () => { + logout(box) + }) + }) +}) - addThreadMod.addEventListener('click', () => { - const id = threadMod.value - window.currentThread.addModerator(id).then(res => { - updateThreadCapabilities() - }).catch(updateThreadError) - }) +openThread.addEventListener('click', () => { + const name = threadName.value + const space = threadSpaceName.value + const firstModerator = threadfirstModerator.value + const membersBool = members.checked + const ghostBool = ghostCheck.checked + console.log('ghost?', ghostBool); + posts.style.display = 'block' + threadModeration.style.display = 'block' + if (members.checked) threadMembers.style.display = 'block' + if (ghostCheck.checked) { + addThreadMod.disabled = true + } + box.openThread(space, name, {firstModerator, members: membersBool, ghost: ghostBool}).then(thread => { + window.currentThread = thread + thread.onUpdate(() => { + updateThreadData() + }) + thread.onNewCapabilities(() => { + updateThreadCapabilities() + }) + if (window.currentThread._room == undefined) { + updateThreadData() + updateThreadCapabilities() + } + }).catch(updateThreadError) +}) - addThreadMember.addEventListener('click', () => { - const id = threadMember.value - window.currentThread.addMember(id).then(res => { - updateThreadCapabilities() - }).catch(updateThreadError) - }) +addThreadMod.addEventListener('click', () => { + const id = threadMod.value + window.currentThread.addModerator(id).then(res => { + updateThreadCapabilities() + }).catch(updateThreadError) +}) - window.deletePost = (el) => { - window.currentThread.deletePost(el.id).then(res => { - updateThreadData() - }).catch(updateThreadError) - } +addThreadMember.addEventListener('click', () => { + const id = threadMember.value + window.currentThread.addMember(id).then(res => { + updateThreadCapabilities() + }).catch(updateThreadError) +}) - const updateThreadError = (e = '') => { - threadACError.innerHTML = e - } +window.deletePost = (el) => { + window.currentThread.deletePost(el.id).then(res => { + updateThreadData() + }).catch(updateThreadError) +} - const updateThreadData = () => { - threadData.innerHTML = '' - updateThreadError() - window.currentThread.getPosts().then(posts => { - posts.map(post => { - threadData.innerHTML += post.author + ':
' + post.message + '

' - threadData.innerHTML += `` + '

' - }) - }) - } +const updateThreadError = (e = '') => { + threadACError.innerHTML = e +} - const updateThreadCapabilities = () => { - threadMemberList.innerHTML = '' - // if else statement cause ghost thread can't list moderators - if (window.currentThread._peerId) { - window.currentThread.listMembers().then(members => { - members.map(member => { - threadMemberList.innerHTML += member + '
' - }) - }) - } else { - if (window.currentThread._members) { - window.currentThread.listMembers().then(members => { - members.map(member => { - threadMemberList.innerHTML += member + '
' - }) - }) - } - threadModeratorList.innerHTML = '' - window.currentThread.listModerators().then(moderators => { - moderators.map(moderator => { - threadModeratorList.innerHTML += moderator + '
' - }) - }) - } - } +const updateThreadData = () => { + threadData.innerHTML = '' + updateThreadError() + window.currentThread.getPosts().then(posts => { + posts.map(post => { + threadData.innerHTML += post.author + ':
' + post.message + '

' + threadData.innerHTML += `` + '

' + }) + }) +} - postThread.addEventListener('click', () => { - window.currentThread.post(postMsg.value).catch(updateThreadError) +const updateThreadCapabilities = () => { + threadMemberList.innerHTML = '' + // if else statement cause ghost thread can't list moderators + if (window.currentThread._peerId) { + window.currentThread.listMembers().then(members => { + members.map(member => { + threadMemberList.innerHTML += member + '
' }) - - bclose.addEventListener('click', () => { - logout(box) + }) + } else { + if (window.currentThread._members) { + window.currentThread.listMembers().then(members => { + members.map(member => { + threadMemberList.innerHTML += member + '
' + }) + }) + } + threadModeratorList.innerHTML = '' + window.currentThread.listModerators().then(moderators => { + moderators.map(moderator => { + threadModeratorList.innerHTML += moderator + '
' }) }) - }) + } +} + +postThread.addEventListener('click', () => { + window.currentThread.post(postMsg.value).catch(updateThreadError) }) getProfile.addEventListener('click', () => { diff --git a/package-lock.json b/package-lock.json index 40234942..16605bb5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "3box", - "version": "1.15.0", + "version": "1.16.0-beta.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -8402,9 +8402,9 @@ } }, "identity-wallet": { - "version": "1.1.0-beta.1", - "resolved": "https://registry.npmjs.org/identity-wallet/-/identity-wallet-1.1.0-beta.1.tgz", - "integrity": "sha512-icn2Yc7v87bzs+S2XZzur8XHihICLxre+26bB+gHn1aWy/dQERXG2bPtmuDKb2U4K1DRqSNirtQzxHQoTnBPaw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/identity-wallet/-/identity-wallet-1.1.0.tgz", + "integrity": "sha512-D6zGznRc3ba+MO916mUDYZcFHBwScHBm0qIopMHZvUvKgRWrHr7A/19xBV6G5BNe3rSIa9TzMeeLCm3qR1i6Ag==", "dev": true, "requires": { "3id-blockchain-utils": "^0.3.2", diff --git a/package.json b/package.json index fc714d02..3ebd8f2a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "3box", - "version": "1.15.0", + "version": "1.16.0-beta.2", "description": "Interact with user data", "main": "lib/3box.js", "directories": { @@ -77,7 +77,7 @@ "babel-core": "7.0.0-bridge.0", "babel-loader": "^8.0.6", "express": "^4.17.0", - "identity-wallet": "^1.1.0-beta.1", + "identity-wallet": "^1.1.0", "jest": "^23.6.0", "jsdoc-to-markdown": "^5.0.0", "standard": "^14.3.1", diff --git a/src/3box.js b/src/3box.js index 20b7ec52..ec6d46b1 100644 --- a/src/3box.js +++ b/src/3box.js @@ -149,11 +149,11 @@ class Box extends BoxApi { await this._3id.authenticate(spaces) } // make sure we are authenticated to threads - spaces.forEach(space => { + await Promise.all(spaces.map(async space => { if (this.spaces[space]) { - this.spaces[space]._authThreads(this._3id) + await this.spaces[space]._authThreads(this._3id) } - }) + })) } /** diff --git a/src/ghost.js b/src/ghost.js index f292658f..71de9fd7 100644 --- a/src/ghost.js +++ b/src/ghost.js @@ -20,7 +20,19 @@ class GhostThread extends EventEmitter { this._filters = opts.ghostFilters || [] this._room.on('message', async ({ from, data }) => { - const { payload, issuer } = await this._verifyData(data) + let payload, issuer + if (data.toString().startsWith('{')) { + // we got a non signed message (can only be backlog request, or response) + payload = JSON.parse(data) + if (payload.type !== 'request_backlog' && payload.type !== 'backlog_response') { + // join and messages need signatures + return + } + } else { + const verified = await this._verifyData(data) + payload = verified.payload + issuer = verified.issuer + } // we pass the payload, issuer and peerID (from) to each filter in our filters array and reduce the value to a single boolean // this boolean indicates whether the message passed the filters @@ -33,7 +45,7 @@ class GhostThread extends EventEmitter { break case 'request_backlog': this.getPosts(this._backlogLimit) - .then(posts => this._sendDirect({ type: 'backlog_response', message: posts }, from)) + .then(posts => this._sendDirect({ type: 'backlog_response', message: posts }, from, true)) break case 'backlog_response': payload.message.map(msg => { @@ -59,6 +71,12 @@ class GhostThread extends EventEmitter { _set3id (threeId) { this._3id = threeId + // announce to other peers that we are online + this.listMembers().then(members => { + members.map(({ id }) => { + this._announce(this._threeIdToPeerId(id)) + }) + }) } /** @@ -100,8 +118,11 @@ class GhostThread extends EventEmitter { * @param {String} to The PeerID of a user (optional) */ async _announce (to) { - !to ? await this._broadcast({ type: 'join' }) - : await this._sendDirect({ type: 'join' }, to) + if (this._3id) { + // we don't announce presence if we're not authed + !to ? await this._broadcast({ type: 'join' }) + : await this._sendDirect({ type: 'join' }, to) + } } /** @@ -138,7 +159,7 @@ class GhostThread extends EventEmitter { */ async _requestBacklog (to) { !to ? await this._broadcast({ type: 'request_backlog' }) - : await this._sendDirect({ type: 'request_backlog' }, to) + : await this._sendDirect({ type: 'request_backlog' }, to, true) } /** @@ -154,10 +175,10 @@ class GhostThread extends EventEmitter { * * @param {Object} message The message */ - async _broadcast (message) { - if (!this._3id) throw new Error('Can not send message if not authenticated') - const jwt = await this._3id.signJWT(message) - this._room.broadcast(jwt) + async _broadcast (message, noSignature) { + if (!this._3id ? !noSignature : false) throw new Error('Can not send message if not authenticated') + const payload = noSignature ? JSON.stringify(message) : await this._3id.signJWT(message) + this._room.broadcast(payload) } /** @@ -166,11 +187,11 @@ class GhostThread extends EventEmitter { * @param {Object} message The message * @param {String} to The PeerID or 3ID of the receiver */ - async _sendDirect (message, to) { - if (!this._3id) throw new Error('Can not send message if not authenticated') - const jwt = await this._3id.signJWT(message) - to.startsWith('Qm') ? this._room.sendTo(to, jwt) - : this._room.sendTo(this._threeIdToPeerId(to), jwt) + async _sendDirect (message, to, noSignature) { + if (!this._3id ? !noSignature : false) throw new Error('Can not send message if not authenticated') + const payload = noSignature ? JSON.stringify(message) : await this._3id.signJWT(message) + to.startsWith('Qm') ? this._room.sendTo(to, payload) + : this._room.sendTo(this._threeIdToPeerId(to), payload) } /** diff --git a/src/space.js b/src/space.js index 705eabb7..9a1e5450 100644 --- a/src/space.js +++ b/src/space.js @@ -149,7 +149,7 @@ class Space { const odbIdentity = await threeId.getOdbId(this._name) Object.values(this._activeThreads).forEach(thread => { if (thread.isGhost) { - thread._set3id(this._3id) + thread._set3id(threeId) } else { thread._setIdentity(odbIdentity) } From 7cf2f6f6f7d50ad88f85d9fd4ccd3cc4a007d7f1 Mon Sep 17 00:00:00 2001 From: Joel Torstensson Date: Fri, 10 Jan 2020 12:03:05 +0100 Subject: [PATCH 15/15] Release v1.16.0 --- RELEASE-NOTES.md | 11 +++++++++++ package.json | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 80f935b6..279c7be2 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,5 +1,16 @@ # Release Notes +## v1.16.0 - 2020-01-10 +This release brings a few performance updates as well as minor features in preparation for the upcoming Confidential Threads feature. + +--- +* feat: support for asymmetric encryption in spaces +* feat: fully migrate to 3ID, no more references to legacy "muport" DID +* chore: update OrbitDB for improved performance +* fix: IdentityWallet now works in a browser context +* fix: issue with using ghost threads while not authenticated resolved +* fix: linkAddress now works as expected with externally provided proof + ## v1.15.0 - 2019-12-13 This release features a new interface for how to create and authenticate to a 3Box, it also adds the ability to open a thread before being authenticated to a space. diff --git a/package.json b/package.json index 3ebd8f2a..423c2ac2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "3box", - "version": "1.16.0-beta.2", + "version": "1.16.0", "description": "Interact with user data", "main": "lib/3box.js", "directories": {