diff --git a/package-lock.json b/package-lock.json index 7c7bb7a4..4bc250b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,6 +32,16 @@ } } }, + "3id-blockchain-utils": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/3id-blockchain-utils/-/3id-blockchain-utils-0.3.2.tgz", + "integrity": "sha512-5l8aZspimqrJPwJabcbz0fFsCwG0EO3f0A/peB7LPlwCZR0A6gbrwgKVY3NDXi45aaqJFTZ+1PmgLycB+iA/tQ==", + "requires": { + "@ethersproject/contracts": "^5.0.0-beta.140", + "@ethersproject/providers": "^5.0.0-beta.144", + "@ethersproject/wallet": "^5.0.0-beta.133" + } + }, "3id-resolver": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/3id-resolver/-/3id-resolver-0.0.5.tgz", @@ -8351,20 +8361,37 @@ } }, "identity-wallet": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/identity-wallet/-/identity-wallet-0.2.0.tgz", - "integrity": "sha512-/sliWwpx6WGk9VkhfokrLYU95yL0VW47Arj26KtOwjzPw7dm3J2PIDz8lEGqOyLmQQa/MNW8S3yuYgXcjO+mSg==", + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/identity-wallet/-/identity-wallet-1.0.0-beta.2.tgz", + "integrity": "sha512-kThy7ittEQ+JmgLPDfcPskUi7tvG0WzCXZILsAYt8oseL+QDhvKYm+RPYhb47UFwKuUgOj2NqE19ChI+SEjl7Q==", "dev": true, "requires": { + "3id-blockchain-utils": "^0.2.1", "@babel/runtime": "^7.4.5", + "@ethersproject/hdnode": "5.0.0-beta.133", + "@ethersproject/wallet": "5.0.0-beta.133", "did-jwt": "^0.1.3", - "ethers": "^4.0.28", "events": "^3.0.0", + "ipfs-did-document": "^1.2.3", + "ipld-dag-cbor": "^0.15.0", + "js-sha256": "^0.9.0", "multihashes": "^0.4.15", + "store": "^2.0.12", "tweetnacl": "^1.0.1", "tweetnacl-util": "^0.15.0" }, "dependencies": { + "3id-blockchain-utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/3id-blockchain-utils/-/3id-blockchain-utils-0.2.1.tgz", + "integrity": "sha512-acpRvBIH4KstIem1robPctlrQ9Kp09hFN5RWdXqxvIovncOBtV24BNYe6OcJErbhWxiHh3ykmJ9S5x2LThe9jg==", + "dev": true, + "requires": { + "@ethersproject/contracts": "^5.0.0-beta.140", + "@ethersproject/providers": "^5.0.0-beta.144", + "@ethersproject/wallet": "^5.0.0-beta.133" + } + }, "did-jwt": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/did-jwt/-/did-jwt-0.1.3.tgz", @@ -8381,54 +8408,6 @@ "tweetnacl": "^1.0.1", "tweetnacl-util": "^0.15.0" } - }, - "ethers": { - "version": "4.0.39", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.39.tgz", - "integrity": "sha512-QVtC8TTUgTrnlQjQvdFJ7fkSWKwp8HVTbKRmrdbVryrPzJHMTf3WSeRNvLF2enGyAFtyHJyFNnjN0fSshcEr9w==", - "dev": true, - "requires": { - "@types/node": "^10.3.2", - "aes-js": "3.0.0", - "bn.js": "^4.4.0", - "elliptic": "6.3.3", - "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.3.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.3.tgz", - "integrity": "sha1-VILZZG1UvLif19mU/J4ulWiHbj8=", - "dev": true, - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "inherits": "^2.0.1" - } - }, - "js-sha3": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", - "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=", - "dev": true - } - } - }, - "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==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" - } } } }, diff --git a/package.json b/package.json index 78d0dcf8..e56ec427 100644 --- a/package.json +++ b/package.json @@ -44,11 +44,10 @@ "homepage": "https://github.com/3box/3box-js#readme", "dependencies": { "3box-orbitdb-plugins": "^1.0.5", + "3id-blockchain-utils": "^0.3.2", "3id-resolver": "^0.0.5", "@babel/runtime": "^7.4.5", - "@ethersproject/contracts": "^5.0.0-beta.140", "@ethersproject/hdnode": "^5.0.0-beta.133", - "@ethersproject/providers": "^5.0.0-beta.144", "@ethersproject/wallet": "^5.0.0-beta.133", "did-jwt": "^0.2.0", "events": "^3.0.0", @@ -78,7 +77,7 @@ "babel-core": "7.0.0-bridge.0", "babel-loader": "^8.0.6", "express": "^4.17.0", - "identity-wallet": "^0.2.0", + "identity-wallet": "^1.0.0-beta.2", "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 091f0e0f..b607dd17 100644 --- a/src/3box.js +++ b/src/3box.js @@ -1,6 +1,7 @@ const localstorage = require('store') const IPFS = require('ipfs') const registerResolver = require('3id-resolver') +const { createLink, validateLink } = require('3id-blockchain-utils') const ThreeId = require('./3id') const Replicator = require('./replicator') @@ -15,12 +16,6 @@ const API = require('./api') const IPFSRepo = require('ipfs-repo') const LevelStore = require('datastore-level') -const ACCOUNT_TYPES = { - ethereum: 'ethereum', - ethereumEOA: 'ethereum-eoa', - erc1271: 'erc1271' -} - const PINNING_NODE = config.pinning_node const ADDRESS_SERVER_URL = config.address_server_url const IPFS_OPTIONS = config.ipfs_options @@ -92,7 +87,7 @@ class Box { await this._3id.authenticate() const rootstoreName = this._3id.muportFingerprint + '.root' const key = (await this._3id.getPublicKeys(null, true)).signingKey - await this.replicator.new(rootstoreName, key, this.DID) + await this.replicator.new(rootstoreName, key, this._3id.DID, this._3id.muportDID) this._publishRootStore(this.replicator.rootstore.address.toString()) } this.replicator.rootstore.setIdentity(await this._3id.getOdbId()) @@ -101,6 +96,10 @@ class Box { this._3id.events.on('new-auth-method', authData => { this._writeRootstoreEntry(Replicator.entryTypes.AUTH_DATA, authData) }) + this._3id.events.on('new-link-proof', proof => { + this._writeAddressLink(proof) + }) + this._3id.startUpdatePolling() this.public = new PublicStore(this._3id.muportFingerprint + '.public', this._linkProfile.bind(this), this.replicator, this._3id) this.private = new PrivateStore(this._3id.muportFingerprint + '.private', this.replicator, this._3id) @@ -314,19 +313,28 @@ class Box { async _publishRootStore (rootStoreAddress) { // Sign rootstoreAddress - const addressToken = await this._3id.signJWT({ rootStoreAddress }) + const addressToken = await this._3id.signJWT({ rootStoreAddress }, { use3ID: true }) // Store odbAddress on 3box-address-server - try { - await utils.fetchJson(this._serverUrl + '/odbAddress', { - address_token: addressToken - }) - } catch (err) { - // we capture http errors (500, etc) - // see: https://github.com/3box/3box-js/pull/351 - if (!err.statusCode) { - throw new Error(err) + const publish = async token => { + try { + await utils.fetchJson(this._serverUrl + '/odbAddress', { + address_token: token + }) + } catch (err) { + if (err.message === 'Invalid JWT') { + // we tried to publish before address-server has access to 3ID + // so it can't verify the JWT. Retry until it is available + await new Promise(resolve => setTimeout(resolve, 300)) + await publish(token) + } + // we capture http errors (500, etc) + // see: https://github.com/3box/3box-js/pull/351 + if (!err.statusCode) { + throw new Error(err) + } } } + await publish(addressToken) return true } @@ -346,6 +354,7 @@ class Box { * @property {String} DID the DID of the user */ get DID () { + // TODO - update once verification service supports 3ID return this._3id.muportDID } @@ -353,35 +362,16 @@ class Box { * Creates a proof that links an ethereum address to the 3Box account of the user. If given proof, it will simply be added to the root store. * * @param {Object} [link] Optional link object with type or proof - * @param {String} [link.type='ethereum-eoa'] The type of link (default 'ethereum') * @param {Object} [link.proof] Proof object, should follow [spec](https://github.com/3box/3box/blob/master/3IPs/3ip-5.md) */ async linkAddress (link = {}) { if (link.proof) { - let valid - if (link.proof.type === ACCOUNT_TYPES.ethereumEOA) { - valid = await utils.recoverPersonalSign(link.proof.message, link.proof.signature) - } else if (link.proof.type === ACCOUNT_TYPES.erc1271) { - valid = await utils.isValidSignature(link.proof, true, this._web3provider) - } else { - throw new Error('Missing or invalid property "type" in proof') - } - if (!valid) { - throw new Error('There was an issue verifying the supplied proof: ', valid) - } - await this._writeRootstoreEntry(Replicator.entryTypes.ADDRESS_LINK, link.proof) - return - } - if (!link.type || link.type === ACCOUNT_TYPES.ethereumEOA) { + await this._writeAddressLink(link.proof) + } else { await this._linkProfile() } } - async linkAccount (type = ACCOUNT_TYPES.ethereumEOA) { - console.warn('linkAccount: deprecated, please use linkAddress going forward') - await this.linkAddress(type) - } - /** * Remove given address link, returns true if successful * @@ -396,7 +386,7 @@ class Box { type: 'delete-address-link' } const oneHour = 60 * 60 - const deleteToken = await this._3id.signJWT(payload, { expiresIn: oneHour }) + const deleteToken = await this._3id.signJWT(payload, { expiresIn: oneHour, use3ID: true }) try { await utils.fetchJson(this._serverUrl + '/linkdelete', { @@ -432,11 +422,6 @@ class Box { return Boolean(linksQuery) } - async isAccountLinked (type = ACCOUNT_TYPES.ethereumEOA) { - console.warn('isAccountLinked: deprecated, please use isAddressLinked going forward') - return this.isAddressLinked(type) - } - /** * Lists address links associated with this 3Box * @@ -453,66 +438,49 @@ class Box { }, []) } + async _writeAddressLink (proof) { + const validProof = validateLink(proof) + if (!validProof) { + throw new Error('tried to write invalid link proof', proof) + } + if (await this.isAddressLinked({ address: validProof.address })) return true // address already linked + await this._writeRootstoreEntry(Replicator.entryTypes.ADDRESS_LINK, proof) + await utils.fetchJson(this._serverUrl + '/link', proof) + } + async _linkProfile () { const address = await this._3id.getAddress() - let linkData = await this._readAddressLink(address) - - if (!linkData) { - const did = this.DID - - let consent - try { - // TODO - this should be handled in the 3ID class - if (this._web3provider.is3idProvider) { - consent = await utils.callRpc(this._web3provider, '3id_linkManagementKey', { did }) - } else { - consent = await utils.getLinkConsent(address, did, this._web3provider) - } - } catch (e) { - throw new Error('Link consent message must be signed before adding data, to link address to store') - } + let proof = await this._readAddressLink(address) - const addressType = await this._detectAddressType(address) - if (addressType === ACCOUNT_TYPES.erc1271) { - const chainId = await utils.getChainId(this._web3provider) - linkData = { - version: 1, - type: ACCOUNT_TYPES.erc1271, - chainId, - address, - message: consent.msg, - timestamp: consent.timestamp, - signature: consent.sig + if (!proof) { + if (!this._web3provider.is3idProvider) { + try { + proof = await createLink(this._3id.DID, address, this._web3provider) + } catch (e) { + throw new Error('Link consent message must be signed before adding data, to link address to store', e) } - } else { - linkData = { - version: 1, - type: ACCOUNT_TYPES.ethereumEOA, - message: consent.msg, - signature: consent.sig, - timestamp: consent.timestamp + try { + await this._writeAddressLink(proof) + } catch (err) { + throw new Error('An error occured while publishing link:', err) } } - try { - await this._writeRootstoreEntry(Replicator.entryTypes.ADDRESS_LINK, linkData) - } catch (err) { - throw new Error('An error occured while publishing link:', err) - } } else { // Send consentSignature to 3box-address-server to link profile with ethereum address // _writeAddressLink already does this if the other conditional is called - if (!this.hasPublishedLink[linkData.signature]) { + if (!this.hasPublishedLink[proof.signature]) { // Don't want to publish on every call to _linkProfile - this.hasPublishedLink[linkData.signature] = true + this.hasPublishedLink[proof.signature] = true try { // Send consentSignature to 3box-address-server to link profile with ethereum address - await utils.fetchJson(this._serverUrl + '/link', linkData) + await utils.fetchJson(this._serverUrl + '/link', proof) } catch (err) { throw new Error('An error occured while publishing link:', err) } } } // Ensure we self-published our did + // TODO - is this still needed? if (!(await this.public.get('proof_did'))) { // 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 }) @@ -522,16 +490,19 @@ class Box { async _writeRootstoreEntry (type, payload) { const cid = (await this._ipfs.dag.put(payload)).toBaseEncodedString() await this._ipfs.pin.add(cid) - const linkExist = await this._typeCIDExists(type, cid) - if (linkExist) return - const link = { + const entryExist = await this._typeCIDExists(type, cid) + if (entryExist) return + const entry = { type, data: cid } - await this.replicator.rootstore.add(link) - if (type === Replicator.entryTypes.ADDRESS_LINK) { - await utils.fetchJson(this._serverUrl + '/link', payload) - } + // the below code prevents multiple simultaneous writes, + // which orbitdb doesn't support + const prev = this._rootstoreQueue + this._rootstoreQueue = (async () => { + if (prev) await prev + await this.replicator.rootstore.add(entry) + })() } async _typeCIDExists (type, cid) { @@ -549,16 +520,7 @@ class Box { async _readAddressLinks () { const links = await this.replicator.getAddressLinks() - const allLinks = await Promise.all(links.map(async linkObj => { - if (!linkObj.address) { - linkObj.address = utils.recoverPersonalSign(linkObj.message, linkObj.signature) - } - const isErc1271 = linkObj.type === ACCOUNT_TYPES.erc1271 - if (!(await utils.isValidSignature(linkObj, isErc1271, this._web3provider))) { - return null - } - return linkObj - })) + const allLinks = await Promise.all(links.map(validateLink)) return allLinks.filter(Boolean) } @@ -568,19 +530,6 @@ class Box { return links.find(link => link.address.toLowerCase() === address) } - async _detectAddressType (address) { - try { - const bytecode = await utils.getCode(this._web3provider, address).catch(() => null) - if (!bytecode || bytecode === '0x' || bytecode === '0x0' || bytecode === '0x00') { - return ACCOUNT_TYPES.ethereumEOA - } - return ACCOUNT_TYPES.erc1271 - } catch (e) { - // Throws an error assume the provider is a 3id provider only - return ACCOUNT_TYPES.ethereumEOA - } - } - async close () { await this.replicator.stop() } @@ -643,7 +592,7 @@ function initIPFSRepo () { async function initIPFS (ipfs, iframeStore, ipfsOptions) { // if (!ipfs && !ipfsProxy) throw new Error('No IPFS object configured and no default available for environment') - if (!!ipfs && iframeStore) console.log('Warning: iframeStore true, orbit db cache in iframe, but the given ipfs object is being used, and may not be running in same iframe.') + if (!!ipfs && iframeStore) console.warn('Warning: iframeStore true, orbit db cache in iframe, but the given ipfs object is being used, and may not be running in same iframe.') if (ipfs) { return ipfs } else { diff --git a/src/3id/__tests__/3id.test.js b/src/3id/__tests__/3id.test.js index 45b04340..b0a35281 100644 --- a/src/3id/__tests__/3id.test.js +++ b/src/3id/__tests__/3id.test.js @@ -23,7 +23,7 @@ const clearLocalStorage3id = (address) => { localstorage.remove(STORAGE_KEY + address) } -const ID_WALLET_SEED = '0x8726348762348723487238476238746827364872634876234876234' +const ID_WALLET_SEED = '0x95838ece1ac686bde68823b21ce9f564bc536eebb9c3500fa6da81f17086a6be' const ADDR_1 = '0x12345' const ADDR_2 = '0xabcde' const ADDR_3 = '0xlmnop' @@ -214,10 +214,8 @@ describe('3id', () => { describe('get 3ID using IdentityWallet', () => { it('instantiate threeId with IdentityWallet', async () => { - const idWallet = new IdentityWallet({ seed: ID_WALLET_SEED }) + const idWallet = new IdentityWallet(() => true, { seed: ID_WALLET_SEED }) const provider = idWallet.get3idProvider() - // monkey patch because we're not using latest version of idwallet - provider.is3idProvider = true idw3id = await ThreeId.getIdFromEthAddress(null, provider, ipfs) expect(idw3id.DID).toBeUndefined() await idw3id.authenticate() @@ -258,7 +256,7 @@ describe('3id', () => { expect(await idw3id.decrypt(enc1)).toEqual(message) const enc2 = await idw3id.encrypt(message, SPACE_1) expect(await idw3id.decrypt(enc2, SPACE_1)).toEqual(message) - //await expect(idw3id.decrypt(enc1, SPACE_1)).rejects.toMatchSnapshot() + await expect(idw3id.decrypt(enc1, SPACE_1)).rejects.toMatchSnapshot() }) }) diff --git a/src/3id/__tests__/__snapshots__/3id.test.js.snap b/src/3id/__tests__/__snapshots__/3id.test.js.snap index 6358073d..b95b6b6a 100644 --- a/src/3id/__tests__/__snapshots__/3id.test.js.snap +++ b/src/3id/__tests__/__snapshots__/3id.test.js.snap @@ -6,38 +6,39 @@ Object { "@context": "https://w3id.org/did/v1", "authentication": Array [ Object { - "publicKey": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra#signingKey", + "publicKey": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly#signingKey", "type": "Secp256k1SignatureAuthentication2018", }, ], - "id": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra", + "id": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly", "publicKey": Array [ Object { - "id": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra#signingKey", - "publicKeyHex": "040c7062c8a227af1239fff421099f0d77b2b1ff50d21c50406db270ffee55ededb8cbdb9c5de8efe1fe91869e0138dfc90c5d0d80b253fb11066bc22d78a72300", + "id": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly#signingKey", + "publicKeyHex": "042dec3aabcbe632644e7251fb0124493233e70caf427c2ba229e977b4c317de6fc55e6061bc0091213c18cd0afb67a9f67fc9d87f1e24d2bf180606442a43038b", "type": "Secp256k1VerificationKey2018", }, Object { - "id": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra#encryptionKey", + "id": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly#encryptionKey", + "publicKeyBase64": "U6UYbPZs+t9WOjCHIAaFCzEM8+U4JZ+LssEO/YNBXxE=", "type": "Curve25519EncryptionPublicKey", }, Object { - "ethereumAddress": "0x2918486bb140899533Cc661e879aA512316aB8a2", - "id": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra#managementKey", + "ethereumAddress": "0x2D10ce5C50000496715891073804577E0Af964C0", + "id": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly#managementKey", "type": "Secp256k1VerificationKey2018", }, ], }, - "issuer": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra", - "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpYXQiOm51bGwsImRhdGEiOiJzb21lIGRhdGEiLCJpc3MiOiJkaWQ6MzpiYWZ5cmVpYXVtZ3d3azRzZHoya3lmc3BxZG92M3M2N240YXpzNm5lYzRhY2p5bnZsZ3Vna3R5eTVyYSJ9.N2Dx4jw_QeWIXJvGDamtUm0Bae7__WjBlUsO8dmHFQWgv74AqsaiDJybEOnFfM67u7vuJRgGZuADXntJtiVJzw", + "issuer": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly", + "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpYXQiOm51bGwsImRhdGEiOiJzb21lIGRhdGEiLCJpc3MiOiJkaWQ6MzpiYWZ5cmVpZmd3ZWdrems2cnhlbWZjazJ2Zm0yenB3MjIzaGtsMzdlcXZ0bXM2Z2R3dTJlam5ia3JseSJ9.09GTxgPRtf9vXW3woqrdWGZAQCvpW0ocBRXr6762cI5N_ZurKLGsKhEaUGDjSmHfTBeQDZN81S_JZswF3FF8fQ", "payload": Object { "data": "some data", "iat": null, - "iss": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra", + "iss": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly", }, "signer": Object { - "id": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra#signingKey", - "publicKeyHex": "040c7062c8a227af1239fff421099f0d77b2b1ff50d21c50406db270ffee55ededb8cbdb9c5de8efe1fe91869e0138dfc90c5d0d80b253fb11066bc22d78a72300", + "id": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly#signingKey", + "publicKeyHex": "042dec3aabcbe632644e7251fb0124493233e70caf427c2ba229e977b4c317de6fc55e6061bc0091213c18cd0afb67a9f67fc9d87f1e24d2bf180606442a43038b", "type": "Secp256k1VerificationKey2018", }, } @@ -49,73 +50,75 @@ Object { "@context": "https://w3id.org/did/v1", "authentication": Array [ Object { - "publicKey": "did:3:bafyreihvap3ufpns7mbfsbg5m73lwqnngvscgtwggctckelwqohyi2ylbi#subSigningKey", + "publicKey": "did:3:bafyreid2pa73cf67gxii4qb3xdyw6mef7enq262mzg7nebwheqyum5nfoi#subSigningKey", "type": "Secp256k1SignatureAuthentication2018", }, ], - "id": "did:3:bafyreihvap3ufpns7mbfsbg5m73lwqnngvscgtwggctckelwqohyi2ylbi", + "id": "did:3:bafyreid2pa73cf67gxii4qb3xdyw6mef7enq262mzg7nebwheqyum5nfoi", "proof": Object { "alg": "ES256K", - "signature": "E4SqeAewYh6-1iczgYHTOKqHK8BPbRR5--ddWrOJR0Jg4QLVgA48dqZRwKyKkSXydKMhEdmN8wkKVGlHd-B8MA", + "signature": "W5OpzAu5gy5FgKrkq_KS2Y7dlHGrLDn-dg73nHmN7rMVA6nP_4zzXPivUMCKgG3b9bylrREtZM4XpAlXJvXQXA", }, "publicKey": Array [ Object { - "id": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra#signingKey", - "publicKeyHex": "040c7062c8a227af1239fff421099f0d77b2b1ff50d21c50406db270ffee55ededb8cbdb9c5de8efe1fe91869e0138dfc90c5d0d80b253fb11066bc22d78a72300", + "id": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly#signingKey", + "publicKeyHex": "042dec3aabcbe632644e7251fb0124493233e70caf427c2ba229e977b4c317de6fc55e6061bc0091213c18cd0afb67a9f67fc9d87f1e24d2bf180606442a43038b", "type": "Secp256k1VerificationKey2018", }, Object { - "id": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra#encryptionKey", + "id": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly#encryptionKey", + "publicKeyBase64": "U6UYbPZs+t9WOjCHIAaFCzEM8+U4JZ+LssEO/YNBXxE=", "type": "Curve25519EncryptionPublicKey", }, Object { - "ethereumAddress": "0x2918486bb140899533Cc661e879aA512316aB8a2", - "id": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra#managementKey", + "ethereumAddress": "0x2D10ce5C50000496715891073804577E0Af964C0", + "id": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly#managementKey", "type": "Secp256k1VerificationKey2018", }, Object { - "id": "did:3:bafyreihvap3ufpns7mbfsbg5m73lwqnngvscgtwggctckelwqohyi2ylbi#subSigningKey", - "publicKeyHex": "043348d76fea638731116fc350c1922393a997db43362efdaeb950a3d5d9c84ccb05f856cd0fba76120d645e7e76e87577481fedf9aee33647ed44197e13d34ef1", + "id": "did:3:bafyreid2pa73cf67gxii4qb3xdyw6mef7enq262mzg7nebwheqyum5nfoi#subSigningKey", + "publicKeyHex": "04db9c88d0202a2d2539ef88978609fb5c198cbf620a06a68ab3b4cdb6efbee62dcb970716398cded19d31f4d3f29d92354c882f5ac89f00f3ec8be2b4ff71f0a3", "type": "Secp256k1VerificationKey2018", }, Object { - "id": "did:3:bafyreihvap3ufpns7mbfsbg5m73lwqnngvscgtwggctckelwqohyi2ylbi#subEncryptionKey", + "id": "did:3:bafyreid2pa73cf67gxii4qb3xdyw6mef7enq262mzg7nebwheqyum5nfoi#subEncryptionKey", + "publicKeyBase64": "43OpI6iE3LSNhaN1r6YWEQWhjF1LpAD7rMUUZHl3/V0=", "type": "Curve25519EncryptionPublicKey", }, ], - "root": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra", + "root": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly", "space": "space1", }, - "issuer": "did:3:bafyreihvap3ufpns7mbfsbg5m73lwqnngvscgtwggctckelwqohyi2ylbi", - "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpYXQiOm51bGwsImRhdGEiOiJzb21lIGRhdGEiLCJpc3MiOiJkaWQ6MzpiYWZ5cmVpaHZhcDN1ZnBuczdtYmZzYmc1bTczbHdxbm5ndnNjZ3R3Z2djdGNrZWx3cW9oeWkyeWxiaSJ9.6c639QMKB6fBevDAJx3WFqCjtwZmoeaYlkix11K8nT9MEdmKlMKxr13FMUGKWzvYtMeYPxlVr_o5l3CfRYhIiA", + "issuer": "did:3:bafyreid2pa73cf67gxii4qb3xdyw6mef7enq262mzg7nebwheqyum5nfoi", + "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpYXQiOm51bGwsImRhdGEiOiJzb21lIGRhdGEiLCJpc3MiOiJkaWQ6MzpiYWZ5cmVpZDJwYTczY2Y2N2d4aWk0cWIzeGR5dzZtZWY3ZW5xMjYybXpnN25lYndoZXF5dW01bmZvaSJ9.W1ktZ3JePY1fqURAz5cbbc0u6Sq0dnXncieti4FfhA-nCSL-UwnbWAlagozWcYHcNtjc3jMAYkk1NPvjQLtKVA", "payload": Object { "data": "some data", "iat": null, - "iss": "did:3:bafyreihvap3ufpns7mbfsbg5m73lwqnngvscgtwggctckelwqohyi2ylbi", + "iss": "did:3:bafyreid2pa73cf67gxii4qb3xdyw6mef7enq262mzg7nebwheqyum5nfoi", }, "signer": Object { - "id": "did:3:bafyreihvap3ufpns7mbfsbg5m73lwqnngvscgtwggctckelwqohyi2ylbi#subSigningKey", - "publicKeyHex": "043348d76fea638731116fc350c1922393a997db43362efdaeb950a3d5d9c84ccb05f856cd0fba76120d645e7e76e87577481fedf9aee33647ed44197e13d34ef1", + "id": "did:3:bafyreid2pa73cf67gxii4qb3xdyw6mef7enq262mzg7nebwheqyum5nfoi#subSigningKey", + "publicKeyHex": "04db9c88d0202a2d2539ef88978609fb5c198cbf620a06a68ab3b4cdb6efbee62dcb970716398cded19d31f4d3f29d92354c882f5ac89f00f3ec8be2b4ff71f0a3", "type": "Secp256k1VerificationKey2018", }, } `; -exports[`3id get 3ID using IdentityWallet instantiate threeId with IdentityWallet 1`] = `"did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra"`; +exports[`3id get 3ID using IdentityWallet instantiate threeId with IdentityWallet 1`] = `"did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly"`; exports[`3id get 3ID using IdentityWallet instantiate threeId with IdentityWallet 2`] = ` Object { - "encryptionKey": "gEtBz4I7u67NlVuB75nmRQfYviv4Yo5WWldkTjiS2mQ=", - "managementKey": "0x2918486bb140899533Cc661e879aA512316aB8a2", - "signingKey": "020c7062c8a227af1239fff421099f0d77b2b1ff50d21c50406db270ffee55eded", + "asymEncryptionKey": "U6UYbPZs+t9WOjCHIAaFCzEM8+U4JZ+LssEO/YNBXxE=", + "managementKey": "0x2D10ce5C50000496715891073804577E0Af964C0", + "signingKey": "032dec3aabcbe632644e7251fb0124493233e70caf427c2ba229e977b4c317de6f", } `; exports[`3id get 3ID using IdentityWallet instantiate threeId with IdentityWallet 3`] = ` Object { - "encryptionKey": "gEtBz4I7u67NlVuB75nmRQfYviv4Yo5WWldkTjiS2mQ=", - "managementKey": "0x2918486bb140899533Cc661e879aA512316aB8a2", - "signingKey": "040c7062c8a227af1239fff421099f0d77b2b1ff50d21c50406db270ffee55ededb8cbdb9c5de8efe1fe91869e0138dfc90c5d0d80b253fb11066bc22d78a72300", + "asymEncryptionKey": "U6UYbPZs+t9WOjCHIAaFCzEM8+U4JZ+LssEO/YNBXxE=", + "managementKey": "0x2D10ce5C50000496715891073804577E0Af964C0", + "signingKey": "042dec3aabcbe632644e7251fb0124493233e70caf427c2ba229e977b4c317de6fc55e6061bc0091213c18cd0afb67a9f67fc9d87f1e24d2bf180606442a43038b", } `; @@ -124,154 +127,161 @@ Object { "@context": "https://w3id.org/did/v1", "authentication": Array [ Object { - "publicKey": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra#signingKey", + "publicKey": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly#signingKey", "type": "Secp256k1SignatureAuthentication2018", }, ], - "id": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra", + "id": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly", "publicKey": Array [ Object { - "id": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra#signingKey", - "publicKeyHex": "040c7062c8a227af1239fff421099f0d77b2b1ff50d21c50406db270ffee55ededb8cbdb9c5de8efe1fe91869e0138dfc90c5d0d80b253fb11066bc22d78a72300", + "id": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly#signingKey", + "publicKeyHex": "042dec3aabcbe632644e7251fb0124493233e70caf427c2ba229e977b4c317de6fc55e6061bc0091213c18cd0afb67a9f67fc9d87f1e24d2bf180606442a43038b", "type": "Secp256k1VerificationKey2018", }, Object { - "id": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra#encryptionKey", + "id": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly#encryptionKey", + "publicKeyBase64": "U6UYbPZs+t9WOjCHIAaFCzEM8+U4JZ+LssEO/YNBXxE=", "type": "Curve25519EncryptionPublicKey", }, Object { - "ethereumAddress": "0x2918486bb140899533Cc661e879aA512316aB8a2", - "id": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra#managementKey", + "ethereumAddress": "0x2D10ce5C50000496715891073804577E0Af964C0", + "id": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly#managementKey", "type": "Secp256k1VerificationKey2018", }, ], } `; +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`] = ` Object { - "encryptionKey": "gEtBz4I7u67NlVuB75nmRQfYviv4Yo5WWldkTjiS2mQ=", - "managementKey": "0x2918486bb140899533Cc661e879aA512316aB8a2", - "signingKey": "020c7062c8a227af1239fff421099f0d77b2b1ff50d21c50406db270ffee55eded", + "asymEncryptionKey": "U6UYbPZs+t9WOjCHIAaFCzEM8+U4JZ+LssEO/YNBXxE=", + "managementKey": "0x2D10ce5C50000496715891073804577E0Af964C0", + "signingKey": "032dec3aabcbe632644e7251fb0124493233e70caf427c2ba229e977b4c317de6f", } `; exports[`3id get 3ID using IdentityWallet keyring logic should get public keys correctly 2`] = ` Object { - "encryptionKey": "2G5n/HprsVf4xXgW7By6ZYW8ZZXiylPzUbJ+z7FGvzw=", + "asymEncryptionKey": "43OpI6iE3LSNhaN1r6YWEQWhjF1LpAD7rMUUZHl3/V0=", "managementKey": null, - "signingKey": "043348d76fea638731116fc350c1922393a997db43362efdaeb950a3d5d9c84ccb05f856cd0fba76120d645e7e76e87577481fedf9aee33647ed44197e13d34ef1", + "signingKey": "04db9c88d0202a2d2539ef88978609fb5c198cbf620a06a68ab3b4cdb6efbee62dcb970716398cded19d31f4d3f29d92354c882f5ac89f00f3ec8be2b4ff71f0a3", } `; exports[`3id get 3ID using IdentityWallet keyring logic should get public keys correctly 3`] = ` Object { - "encryptionKey": "gEtBz4I7u67NlVuB75nmRQfYviv4Yo5WWldkTjiS2mQ=", - "managementKey": "0x2918486bb140899533Cc661e879aA512316aB8a2", - "signingKey": "040c7062c8a227af1239fff421099f0d77b2b1ff50d21c50406db270ffee55ededb8cbdb9c5de8efe1fe91869e0138dfc90c5d0d80b253fb11066bc22d78a72300", + "asymEncryptionKey": "U6UYbPZs+t9WOjCHIAaFCzEM8+U4JZ+LssEO/YNBXxE=", + "managementKey": "0x2D10ce5C50000496715891073804577E0Af964C0", + "signingKey": "042dec3aabcbe632644e7251fb0124493233e70caf427c2ba229e977b4c317de6fc55e6061bc0091213c18cd0afb67a9f67fc9d87f1e24d2bf180606442a43038b", } `; exports[`3id get 3ID using IdentityWallet keyring logic should get public keys correctly 4`] = ` Object { - "encryptionKey": "2G5n/HprsVf4xXgW7By6ZYW8ZZXiylPzUbJ+z7FGvzw=", + "asymEncryptionKey": "43OpI6iE3LSNhaN1r6YWEQWhjF1LpAD7rMUUZHl3/V0=", "managementKey": null, - "signingKey": "043348d76fea638731116fc350c1922393a997db43362efdaeb950a3d5d9c84ccb05f856cd0fba76120d645e7e76e87577481fedf9aee33647ed44197e13d34ef1", + "signingKey": "04db9c88d0202a2d2539ef88978609fb5c198cbf620a06a68ab3b4cdb6efbee62dcb970716398cded19d31f4d3f29d92354c882f5ac89f00f3ec8be2b4ff71f0a3", } `; -exports[`3id get 3ID using IdentityWallet keyring logic should hashDBKey correctly 1`] = `"124036393264373332313662353537376162613765613432343131656139396163366333316666373132323462656564323963393663623366346637356132646661"`; +exports[`3id get 3ID using IdentityWallet keyring logic should hashDBKey correctly 1`] = `"124039353564383561613461336166303636393362653637393131663134636463636634393131363534313662626462366433373839366365636339323532653939"`; -exports[`3id get 3ID using IdentityWallet keyring logic should hashDBKey correctly 2`] = `"124037663937366435316639316361363564656365653362383161666332643933646239626330666339343236366161613166303061316464353933396265393064"`; +exports[`3id get 3ID using IdentityWallet keyring logic should hashDBKey correctly 2`] = `"124032393236383765643933363365616464643434393632396538346632323633653165383964376362663332366437386636356134663761646639653935616264"`; -exports[`3id get 3ID using IdentityWallet keyring logic should init space keyrings correctly 1`] = `"did:3:bafyreihvap3ufpns7mbfsbg5m73lwqnngvscgtwggctckelwqohyi2ylbi"`; +exports[`3id get 3ID using IdentityWallet keyring logic should init space keyrings correctly 1`] = `"did:3:bafyreid2pa73cf67gxii4qb3xdyw6mef7enq262mzg7nebwheqyum5nfoi"`; exports[`3id get 3ID using IdentityWallet keyring logic should init space keyrings correctly 2`] = ` Object { "@context": "https://w3id.org/did/v1", "authentication": Array [ Object { - "publicKey": "did:3:bafyreihvap3ufpns7mbfsbg5m73lwqnngvscgtwggctckelwqohyi2ylbi#subSigningKey", + "publicKey": "did:3:bafyreid2pa73cf67gxii4qb3xdyw6mef7enq262mzg7nebwheqyum5nfoi#subSigningKey", "type": "Secp256k1SignatureAuthentication2018", }, ], - "id": "did:3:bafyreihvap3ufpns7mbfsbg5m73lwqnngvscgtwggctckelwqohyi2ylbi", + "id": "did:3:bafyreid2pa73cf67gxii4qb3xdyw6mef7enq262mzg7nebwheqyum5nfoi", "proof": Object { "alg": "ES256K", - "signature": "E4SqeAewYh6-1iczgYHTOKqHK8BPbRR5--ddWrOJR0Jg4QLVgA48dqZRwKyKkSXydKMhEdmN8wkKVGlHd-B8MA", + "signature": "W5OpzAu5gy5FgKrkq_KS2Y7dlHGrLDn-dg73nHmN7rMVA6nP_4zzXPivUMCKgG3b9bylrREtZM4XpAlXJvXQXA", }, "publicKey": Array [ Object { - "id": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra#signingKey", - "publicKeyHex": "040c7062c8a227af1239fff421099f0d77b2b1ff50d21c50406db270ffee55ededb8cbdb9c5de8efe1fe91869e0138dfc90c5d0d80b253fb11066bc22d78a72300", + "id": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly#signingKey", + "publicKeyHex": "042dec3aabcbe632644e7251fb0124493233e70caf427c2ba229e977b4c317de6fc55e6061bc0091213c18cd0afb67a9f67fc9d87f1e24d2bf180606442a43038b", "type": "Secp256k1VerificationKey2018", }, Object { - "id": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra#encryptionKey", + "id": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly#encryptionKey", + "publicKeyBase64": "U6UYbPZs+t9WOjCHIAaFCzEM8+U4JZ+LssEO/YNBXxE=", "type": "Curve25519EncryptionPublicKey", }, Object { - "ethereumAddress": "0x2918486bb140899533Cc661e879aA512316aB8a2", - "id": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra#managementKey", + "ethereumAddress": "0x2D10ce5C50000496715891073804577E0Af964C0", + "id": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly#managementKey", "type": "Secp256k1VerificationKey2018", }, Object { - "id": "did:3:bafyreihvap3ufpns7mbfsbg5m73lwqnngvscgtwggctckelwqohyi2ylbi#subSigningKey", - "publicKeyHex": "043348d76fea638731116fc350c1922393a997db43362efdaeb950a3d5d9c84ccb05f856cd0fba76120d645e7e76e87577481fedf9aee33647ed44197e13d34ef1", + "id": "did:3:bafyreid2pa73cf67gxii4qb3xdyw6mef7enq262mzg7nebwheqyum5nfoi#subSigningKey", + "publicKeyHex": "04db9c88d0202a2d2539ef88978609fb5c198cbf620a06a68ab3b4cdb6efbee62dcb970716398cded19d31f4d3f29d92354c882f5ac89f00f3ec8be2b4ff71f0a3", "type": "Secp256k1VerificationKey2018", }, Object { - "id": "did:3:bafyreihvap3ufpns7mbfsbg5m73lwqnngvscgtwggctckelwqohyi2ylbi#subEncryptionKey", + "id": "did:3:bafyreid2pa73cf67gxii4qb3xdyw6mef7enq262mzg7nebwheqyum5nfoi#subEncryptionKey", + "publicKeyBase64": "43OpI6iE3LSNhaN1r6YWEQWhjF1LpAD7rMUUZHl3/V0=", "type": "Curve25519EncryptionPublicKey", }, ], - "root": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra", + "root": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly", "space": "space1", } `; -exports[`3id get 3ID using IdentityWallet keyring logic should init space keyrings correctly 3`] = `"did:3:bafyreidlcarpsxnux4qdvmg5vtn6kaqgdek2q4wp33nov3jdhs5suh5vee"`; +exports[`3id get 3ID using IdentityWallet keyring logic should init space keyrings correctly 3`] = `"did:3:bafyreidfhxbxlygsak5amqlktutzu6swvki5fumpbf72ny5hm5ig5fq4re"`; exports[`3id get 3ID using IdentityWallet keyring logic should init space keyrings correctly 4`] = ` Object { "@context": "https://w3id.org/did/v1", "authentication": Array [ Object { - "publicKey": "did:3:bafyreidlcarpsxnux4qdvmg5vtn6kaqgdek2q4wp33nov3jdhs5suh5vee#subSigningKey", + "publicKey": "did:3:bafyreidfhxbxlygsak5amqlktutzu6swvki5fumpbf72ny5hm5ig5fq4re#subSigningKey", "type": "Secp256k1SignatureAuthentication2018", }, ], - "id": "did:3:bafyreidlcarpsxnux4qdvmg5vtn6kaqgdek2q4wp33nov3jdhs5suh5vee", + "id": "did:3:bafyreidfhxbxlygsak5amqlktutzu6swvki5fumpbf72ny5hm5ig5fq4re", "proof": Object { "alg": "ES256K", - "signature": "1yxv71HG1L9cF00_guvUEjDEEVyIMFYe3SREskceJqDi0JINp3Db0rpXgXah6vB4KY_lECi-rlots9S_HQuzlw", + "signature": "jDDIpI8vn-VkzjNMYU27-EWiA9J5vx-yGqmd0i4m5oXwo0qg76SgmDi0thidsgdVslNHrqJapp6hrupaf-4d2w", }, "publicKey": Array [ Object { - "id": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra#signingKey", - "publicKeyHex": "040c7062c8a227af1239fff421099f0d77b2b1ff50d21c50406db270ffee55ededb8cbdb9c5de8efe1fe91869e0138dfc90c5d0d80b253fb11066bc22d78a72300", + "id": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly#signingKey", + "publicKeyHex": "042dec3aabcbe632644e7251fb0124493233e70caf427c2ba229e977b4c317de6fc55e6061bc0091213c18cd0afb67a9f67fc9d87f1e24d2bf180606442a43038b", "type": "Secp256k1VerificationKey2018", }, Object { - "id": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra#encryptionKey", + "id": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly#encryptionKey", + "publicKeyBase64": "U6UYbPZs+t9WOjCHIAaFCzEM8+U4JZ+LssEO/YNBXxE=", "type": "Curve25519EncryptionPublicKey", }, Object { - "ethereumAddress": "0x2918486bb140899533Cc661e879aA512316aB8a2", - "id": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra#managementKey", + "ethereumAddress": "0x2D10ce5C50000496715891073804577E0Af964C0", + "id": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly#managementKey", "type": "Secp256k1VerificationKey2018", }, Object { - "id": "did:3:bafyreidlcarpsxnux4qdvmg5vtn6kaqgdek2q4wp33nov3jdhs5suh5vee#subSigningKey", - "publicKeyHex": "0444c963eae74f260a51f6a5a6a45a17932062c74ab13c5d4b51d86b2ca14fbea765089b441fd6ea75e848dc32b7109b4cbcbdbcd178605b545eaf86754b64cf12", + "id": "did:3:bafyreidfhxbxlygsak5amqlktutzu6swvki5fumpbf72ny5hm5ig5fq4re#subSigningKey", + "publicKeyHex": "047a494fb9681baa97d476d3d11d941c28510db24067896451ab3c78ad28a45ecc9dace481442e183eca38c3ac59003ff82f5c79504578b6030e41015fd84745ce", "type": "Secp256k1VerificationKey2018", }, Object { - "id": "did:3:bafyreidlcarpsxnux4qdvmg5vtn6kaqgdek2q4wp33nov3jdhs5suh5vee#subEncryptionKey", + "id": "did:3:bafyreidfhxbxlygsak5amqlktutzu6swvki5fumpbf72ny5hm5ig5fq4re#subEncryptionKey", + "publicKeyBase64": "6PPQJNXpQB7WTmcpC5OtL/yWxb9IKL9pqgppSgM+XQ4=", "type": "Curve25519EncryptionPublicKey", }, ], - "root": "did:3:bafyreiaumgwwk4sdz2kyfspqdov3s67n4azs6nec4acjynvlgugktyy5ra", + "root": "did:3:bafyreifgwegkzk6rxemfck2vfm2zpw223hkl37eqvtms6gdwu2ejnbkrly", "space": "space2", } `; diff --git a/src/3id/index.js b/src/3id/index.js index f35ae03f..9c62e6da 100644 --- a/src/3id/index.js +++ b/src/3id/index.js @@ -14,6 +14,7 @@ const config = require('../config.js') const DID_METHOD_NAME = '3' const STORAGE_KEY = 'serialized3id_' const MUPORT_IPFS = { host: config.muport_ipfs_host, port: config.muport_ipfs_port, protocol: config.muport_ipfs_protocol} +const POLL_INTERVAL = 500 class ThreeId { constructor (provider, ipfs, opts = {}) { @@ -23,15 +24,20 @@ class ThreeId { this._ipfs = ipfs this._muportIpfs = opts.muportIpfs || MUPORT_IPFS this._pubkeys = { spaces: {} } + } + + startUpdatePolling () { if (this._has3idProv) { - setInterval(async () => { - const result = await utils.callRpc(this._provider, '3id_newAuthMethodPoll') - if (result.length) { - result.map(authData => { - this.events.emit('new-auth-method', authData) - }) - } - }, 500) + const poll = async (method, event) => { + const result = await utils.callRpc(this._provider, method) + result.map(data => { + this.events.emit(event, data) + }) + } + setInterval(() => { + poll('3id_newAuthMethodPoll', 'new-auth-method') + poll('3id_newLinkPoll', 'new-link-proof') + }, POLL_INTERVAL) } } diff --git a/src/__mocks__/3ID.js b/src/__mocks__/3ID.js index 2988524f..8276964e 100644 --- a/src/__mocks__/3ID.js +++ b/src/__mocks__/3ID.js @@ -49,6 +49,7 @@ const threeIDMockFactory = (did) => { signJWT, getPublicKeys, getOdbId, + startUpdatePolling: () => {}, events: { on: () => {} }, getSubDID } diff --git a/src/__tests__/3box.test.js b/src/__tests__/3box.test.js index 2732e964..d34e0659 100644 --- a/src/__tests__/3box.test.js +++ b/src/__tests__/3box.test.js @@ -22,7 +22,7 @@ const DIDMUPORT2 = DID2.replace('3', 'muport') const randomStr = () => `${Math.floor(Math.random() * 1000000)}` - +jest.mock('3id-resolver') jest.mock('../3id', () => { const randomStr = () => `${Math.floor(Math.random() * 1000000)}` const { threeIDMockFactory, didResolverMock } = require('../__mocks__/3ID') @@ -111,6 +111,18 @@ jest.mock('../replicator', () => { } }) +jest.mock('3id-blockchain-utils', () => ({ + createLink: jest.fn(async (did, address, provider) => ({ + message: 'I agree to stuff,' + did, + signature: '0xSuchRealSig,' + address, + timestamp: 111, + type: 'ethereum-eoa', + version: 1 + })), + validateLink: (proof, did) => { + return 'todo' + } +})) jest.mock('../utils/verifier') jest.mock('../utils/index', () => { @@ -122,7 +134,6 @@ jest.mock('../utils/index', () => { let linkNum = 0 return { getMessageConsent: actualUtils.getMessageConsent, - recoverPersonalSign: () => '0x8726348762348723487238476238746827364872634876234876234', openBoxConsent: jest.fn(async () => '0x8726348762348723487238476238746827364872634876234876234'), fetchJson: jest.fn(async (url, body) => { const split = url.split('/') @@ -162,22 +173,6 @@ jest.mock('../utils/index', () => { } } }), - getLinkConsent: jest.fn(async (address, did, web3prov) => { - return { - msg: 'I agree to stuff,' + did, - sig: '0xSuchRealSig,' + address, - timestamp: 111 - } - }), - getChainId: jest.fn(async (web3prov) => { - return 1 - }), - getCode: jest.fn(async (web3prov, address) => { - return '0x' - }), - isValidSignature: jest.fn(async (linkObj, isErc1271, web3Provider) => { - return true - }), sha256Multihash: jest.fn(str => { if (str === 'did:muport:Qmsdsdf87g329') return 'ab8c73d8f' return 'b932fe7ab' @@ -187,6 +182,7 @@ jest.mock('../utils/index', () => { }) const mockedUtils = require('../utils/index') +const { createLink } = require('3id-blockchain-utils') const mocked3id = require('../3id') const MOCK_HASH_SERVER = 'address-server' const MOCK_PROFILE_SERVER = 'profile-server' @@ -198,9 +194,9 @@ describe('3Box', () => { const clearMocks = () => { mockedUtils.openBoxConsent.mockClear() mockedUtils.fetchJson.mockClear() - mockedUtils.getLinkConsent.mockClear() mocked3id.getIdFromEthAddress.mockClear() mocked3id.logoutFn.mockClear() + createLink.mockClear() } beforeAll(async () => { @@ -271,7 +267,7 @@ describe('3Box', () => { it('should handle error and not link profile on first call to _linkProfile', async () => { const box = await Box.openBox('0x12345','web3prov', boxOpts) - const didMuPort = box._3id.muportDID + const did = box._3id.DID clearMocks() // first two calls in our mock will throw an error @@ -282,17 +278,17 @@ describe('3Box', () => { // It will check the self-signed did expect(mockedUtils.fetchJson).toHaveBeenCalledTimes(1) expect(mockedUtils.fetchJson).toHaveBeenNthCalledWith(1, 'address-server/link', { - message: `I agree to stuff,${didMuPort}`, + message: `I agree to stuff,${did}`, signature: "0xSuchRealSig,0x12345", timestamp: 111, type: "ethereum-eoa", version: 1, }) - expect(mockedUtils.getLinkConsent).toHaveBeenCalledTimes(1) + expect(createLink).toHaveBeenCalledTimes(1) await box.close() }) - it('should not call getLinkConsent if ethereum_proof in rootStore on call to _linkProfile', async () => { + it('should not call createLink if ethereum_proof in rootStore on call to _linkProfile', async () => { const boxWithLinks = await Box.openBox('0x12345', 'web3prov', boxOpts) clearMocks() @@ -324,7 +320,7 @@ describe('3Box', () => { type: "ethereum-eoa", version: 1, }) - expect(mockedUtils.getLinkConsent).toHaveBeenCalledTimes(0) + expect(createLink).toHaveBeenCalledTimes(0) expect(boxWithLinks.public.set).toHaveBeenCalledTimes(0) await boxWithLinks.close() @@ -332,7 +328,7 @@ describe('3Box', () => { it('should link profile on call to _linkProfile', async () => { const box = await Box.openBox('0x12345', 'web3prov', boxOpts) - const didMuPort = box._3id.muportDID + const did = box._3id.DID clearMocks() box.public.set.mockClear() @@ -341,13 +337,13 @@ describe('3Box', () => { expect(mockedUtils.fetchJson).toHaveBeenCalledTimes(1) expect(mockedUtils.fetchJson).toHaveBeenNthCalledWith(1, 'address-server/link', { - message: `I agree to stuff,${didMuPort}`, + message: `I agree to stuff,${did}`, signature: "0xSuchRealSig,0x12345", timestamp: 111, type: "ethereum-eoa", version: 1, }) - expect(mockedUtils.getLinkConsent).toHaveBeenCalledTimes(1) + expect(createLink).toHaveBeenCalledTimes(1) expect(box.public.set).toHaveBeenCalledTimes(1) // did proof await box.close() }) diff --git a/src/__tests__/__snapshots__/3box.test.js.snap b/src/__tests__/__snapshots__/3box.test.js.snap index 7fed30f1..3e37bca0 100644 --- a/src/__tests__/__snapshots__/3box.test.js.snap +++ b/src/__tests__/__snapshots__/3box.test.js.snap @@ -2,4 +2,4 @@ exports[`3Box should handle error and not link profile on first call to _linkProfile 1`] = `[Error: An error occured while publishing link:]`; -exports[`3Box should not call getLinkConsent if ethereum_proof in rootStore on call to _linkProfile 1`] = `[Error: An error occured while publishing link:]`; +exports[`3Box should not call createLink if ethereum_proof in rootStore on call to _linkProfile 1`] = `[Error: An error occured while publishing link:]`; diff --git a/src/__tests__/idWallet.integration.js b/src/__tests__/idWallet.integration.js index 13029f65..c428599b 100644 --- a/src/__tests__/idWallet.integration.js +++ b/src/__tests__/idWallet.integration.js @@ -7,7 +7,8 @@ const IdentityWallet = require('identity-wallet') const PINNING_ROOM = '3box-pinning' jest.mock('node-fetch', () => { - const rootStoreAddress = '/orbitdb/QmZggbAyvHMBgQX6vSFXpG31BvqwVAiLF6UUJn4s91ZUP2/122099b9c5866419e91e3d470b364b721e4b43e9f699fb0b032bdc0d402a0ac41a27.root' + // be careful, this address might change + const rootStoreAddress = '/orbitdb/QmX25N5fMa9bw6g3dqstjbDGuMMGf4u5SaPaBJGy37tanz/1220693f7b44d61924943390395980d9f76c01f9d029129e15f4bcff77280104cace.root' let called = false return (url, opts) => { //console.log('fetch', url, opts) @@ -39,17 +40,8 @@ jest.mock('node-fetch', () => { }) const utils = require('../utils/index') -utils.recoverPersonalSign = () => '0x2D10ce5C50000496715891073804577E0Af964C0' - -const mockEthProvider = { - sendAsync: (d, fn) => { - if (d.method.startsWith('3id')) { - fn('error!') - } else { - fn(null, 0x12345) - } - } -} + +const getConsent = () => true describe('Integration Test: IdentityWallet', () => { @@ -61,11 +53,10 @@ describe('Integration Test: IdentityWallet', () => { let rootStoreAddress, pubAddr, privAddr const SEED = '0x95838ece1ac686bde68823b21ce9f564bc536eebb9c3500fa6da81f17086a6be' - const ADDRESS = '0x2D10ce5C50000496715891073804577E0Af964C0' const AUTH_1 = '68b682d67f0fccb0c56236c27ccdd70577722c385c65c00ed1c3d4fbee57db3c' - const AUTH_2 = '05273ade0b139165d9e5864a18d1ad6b291a1a1ebc841fd68d126c593c89ce7f ' + const AUTH_2 = '05273ade0b139165d9e5864a18d1ad6b291a1a1ebc841fd68d126c593c89ce7f' const publishHasEntries = async () => { - await testUtils.delay(900) + await testUtils.delay(2000) pubsub.publish(PINNING_ROOM, { type: 'HAS_ENTRIES', odbAddress: rootStoreAddress, numEntries: 2 }) pubsub.publish(PINNING_ROOM, { type: 'HAS_ENTRIES', odbAddress: privAddr, numEntries: 0 }) pubsub.publish(PINNING_ROOM, { type: 'HAS_ENTRIES', odbAddress: pubAddr, numEntries: 2 }) @@ -85,7 +76,7 @@ describe('Integration Test: IdentityWallet', () => { }) beforeEach(async () => { - idWallet = new IdentityWallet({ seed: SEED }) + idWallet = new IdentityWallet(getConsent, { seed: SEED }) pubsub.subscribe(PINNING_ROOM, (topic, data) => {}, () => {}) }) @@ -96,8 +87,6 @@ describe('Integration Test: IdentityWallet', () => { it('should openBox correctly when idWallet is passed', async () => { const provider = idWallet.get3idProvider() - // monkey patch because we're not using latest version of idwallet - provider.is3idProvider = true const box = await Box.openBox(null, provider, opts) await box.syncDone await box.public.set('a', 1) @@ -111,10 +100,8 @@ describe('Integration Test: IdentityWallet', () => { }) it('should get same state on second openBox', async () => { - publishHasEntries() const provider = idWallet.get3idProvider() - // monkey patch because we're not using latest version of idwallet - provider.is3idProvider = true + publishHasEntries() const box = await Box.openBox(null, provider, opts) await box.syncDone expect(await box.public.all()).toEqual(pubState) @@ -128,11 +115,9 @@ describe('Integration Test: IdentityWallet', () => { }) it('should get same state on openBox with IdentityWallet opened using first authSecret', async () => { - publishHasEntries() - idWallet = new IdentityWallet({ authSecret: AUTH_1, ethereumAddress: ADDRESS }) + idWallet = new IdentityWallet(getConsent, { authSecret: AUTH_1 }) const provider = idWallet.get3idProvider() - // monkey patch because we're not using latest version of idwallet - provider.is3idProvider = true + publishHasEntries() const box = await Box.openBox(null, provider, opts) await box.syncDone expect(await box.public.all()).toEqual(pubState) @@ -146,11 +131,9 @@ describe('Integration Test: IdentityWallet', () => { }) it('should get same state on openBox with IdentityWallet opened using second authSecret', async () => { - publishHasEntries() - idWallet = new IdentityWallet({ authSecret: AUTH_2, ethereumAddress: ADDRESS }) + idWallet = new IdentityWallet(getConsent, { authSecret: AUTH_2 }) const provider = idWallet.get3idProvider() - // monkey patch because we're not using latest version of idwallet - provider.is3idProvider = true + publishHasEntries() const box = await Box.openBox(null, provider, opts) await box.syncDone expect(await box.public.all()).toEqual(pubState) diff --git a/src/replicator.js b/src/replicator.js index 7c09b287..275b32bf 100644 --- a/src/replicator.js +++ b/src/replicator.js @@ -124,7 +124,7 @@ class Replicator { this.syncDone = waitForSync() } - async new (rootstoreName, pubkey, did) { + async new (rootstoreName, pubkey, did, muportDID) { if (this.rootstore) throw new Error('This method can only be called once before the replicator has started') const opts = { ...ODB_STORE_OPTS, @@ -133,7 +133,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 }) + this._publishDB({ odbAddress: this.rootstore.address.toString(), did, muportDID }) await this.rootstore.load() this.rootstoreSyncDone = Promise.resolve() this.syncDone = Promise.resolve() @@ -261,7 +261,7 @@ class Replicator { } } - async _publishDB ({ odbAddress, did, isThread }, unsubscribe) { + async _publishDB ({ odbAddress, did, muportDID, isThread }, unsubscribe) { this._joinPinningRoom() odbAddress = odbAddress || this.rootstore.address.toString() // make sure that the pinning node is in the pubsub room before publishing @@ -279,6 +279,7 @@ class Replicator { type: isThread ? 'SYNC_DB' : 'PIN_DB', odbAddress, did, + muportDID, thread: isThread }) this.events.removeAllListeners('pinning-room-peer') diff --git a/src/utils/index.js b/src/utils/index.js index cc5c64c7..d05c564f 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -1,9 +1,6 @@ const fetch = typeof window !== 'undefined' ? window.fetch : require('node-fetch') const Multihash = require('multihashes') const sha256 = require('js-sha256').sha256 -const { Contract } = require('@ethersproject/contracts') -const { Web3Provider } = require('@ethersproject/providers') -const { verifyMessage } = require('@ethersproject/wallet') const ENC_BLOCK_SIZE = 24 const MAGIC_ERC1271_VALUE = '0x20c13b0b' @@ -51,15 +48,6 @@ module.exports = { getMessageConsent, callRpc, - recoverPersonalSign: (msg, personalSig) => { - if (!msg || !personalSig) throw new Error('recoverPersonalSign: missing arguments, msg and/or personalSig') - const msgParams = { - data: msg, - sig: personalSig - } - return verifyMessage(msg , personalSig) - }, - openBoxConsent: (fromAddress, ethereum) => { const text = 'This app wants to view and update your 3Box profile.' var msg = '0x' + Buffer.from(text, 'utf8').toString('hex') @@ -88,68 +76,6 @@ module.exports = { }) }, - getLinkConsent: async (fromAddress, toDID, ethereum) => { - const timestamp = Math.floor(new Date().getTime() / 1000) - const text = getMessageConsent(toDID, timestamp) - const msg = '0x' + Buffer.from(text, 'utf8').toString('hex') - const params = [msg, fromAddress] - const method = 'personal_sign' - - const sig = await safeSend(ethereum, { - jsonrpc: '2.0', - id: 0, - method, - params, - fromAddress - }) - return { - msg: text, - sig, - timestamp - } - }, - - getChainId: async (ethereumProvider) => { - const method = 'eth_chainId' - const params = [] - - const chainIdHex = await safeSend(ethereumProvider, { - jsonrpc: '2.0', - id: 0, - method, - params - }) - return parseInt(chainIdHex, 16) - }, - - getCode: async (ethereumProvider, address) => { - const method = 'eth_getCode' - const params = [address, 'latest'] - - const code = await safeSend(ethereumProvider, { - jsonrpc: '2.0', - id: 1, - method, - params - }) - return code - }, - - isValidSignature: async (linkObj, isErc1271, web3Provider) => { - if (!linkObj.address) return false - if (!isErc1271) return true - - const abi = [ - 'function isValidSignature(bytes _messageHash, bytes _signature) public view returns (bytes4 magicValue)' - ] - const ethersProvider = new Web3Provider(web3Provider) - const contract = new Contract(linkObj.address, abi, ethersProvider) - const message = '0x' + Buffer.from(linkObj.message, 'utf8').toString('hex') - const returnValue = await contract.isValidSignature(message, linkObj.signature) - - return returnValue === MAGIC_ERC1271_VALUE - }, - fetchJson: async (url, body) => { let opts if (body) { @@ -158,7 +84,8 @@ module.exports = { const r = await fetch(url, opts) if (r.ok) { - return r.json() + let res = await r.json() + return res } else { throw HTTPError(r.status, (await r.json()).message) } diff --git a/src/utils/verifier.js b/src/utils/verifier.js index 39b23ce1..7e514441 100644 --- a/src/utils/verifier.js +++ b/src/utils/verifier.js @@ -102,6 +102,8 @@ module.exports = { * @return {String} The ethereum address used to sign the message */ verifyEthereum: async (ethProof, 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'] const consentSig = ethProof.version ? ethProof.signature : ethProof['consent_signature']