From bfb5e752548d5ab9d2c59ca4e75a745ae117b93b Mon Sep 17 00:00:00 2001 From: Ezerous Date: Wed, 11 Nov 2020 21:33:44 +0200 Subject: [PATCH] Include contractAddress in OrbitDB Identity --- .../src/options/breezeOptions.js | 5 --- .../concordia-app/src/options/web3Options.js | 3 -- .../concordia-app/src/orbit/levelUtils.js | 2 +- .../concordia-app/src/orbit/orbitUtils.js | 10 ++++- .../src/orbit/ΕthereumIdentityProvider.js | 42 +++++++++++++++---- .../src/redux/sagas/orbitSaga.js | 16 ++++++- .../src/redux/sagas/peerDbReplicationSaga.js | 6 +-- .../src/views/Topic/TopicCreate/index.jsx | 4 +- packages/concordia-contracts/index.js | 1 + 9 files changed, 64 insertions(+), 25 deletions(-) diff --git a/packages/concordia-app/src/options/breezeOptions.js b/packages/concordia-app/src/options/breezeOptions.js index c06ac0b..7390580 100644 --- a/packages/concordia-app/src/options/breezeOptions.js +++ b/packages/concordia-app/src/options/breezeOptions.js @@ -1,10 +1,5 @@ -import { orbitConstants } from '@ezerous/breeze'; -import web3Options from './web3Options'; import EthereumIdentityProvider from '../orbit/ΕthereumIdentityProvider'; -const { web3 } = web3Options; -EthereumIdentityProvider.setWeb3(web3); - const breezeOptions = { ipfs: { config: { diff --git a/packages/concordia-app/src/options/web3Options.js b/packages/concordia-app/src/options/web3Options.js index 13dc9b9..d6cbf3c 100644 --- a/packages/concordia-app/src/options/web3Options.js +++ b/packages/concordia-app/src/options/web3Options.js @@ -1,12 +1,9 @@ import Web3 from 'web3'; -import EthereumIdentityProvider from '../orbit/ΕthereumIdentityProvider'; const { WEB3_URL, WEB3_PORT } = process.env; const web3 = new Web3(Web3.givenProvider || `ws://${WEB3_URL}:${WEB3_PORT}`); -EthereumIdentityProvider.setWeb3(web3); - const web3Options = { web3, }; diff --git a/packages/concordia-app/src/orbit/levelUtils.js b/packages/concordia-app/src/orbit/levelUtils.js index 1a3fd09..344fde3 100644 --- a/packages/concordia-app/src/orbit/levelUtils.js +++ b/packages/concordia-app/src/orbit/levelUtils.js @@ -10,7 +10,7 @@ async function storeIdentitySignaturePubKey(key, signaturePubKey) { } // If it exists, it returns the identity.signatures.publicKey for the given key (key is the -// concatenation of identity.publicKey + identity.signatures.id +// concatenation of identity.publicKey + identity.signatures.id) async function getIdentitySignaturePubKey(key) { try { return await concordiaDB.get(key); diff --git a/packages/concordia-app/src/orbit/orbitUtils.js b/packages/concordia-app/src/orbit/orbitUtils.js index 6835fd5..1460113 100644 --- a/packages/concordia-app/src/orbit/orbitUtils.js +++ b/packages/concordia-app/src/orbit/orbitUtils.js @@ -1,4 +1,6 @@ // https://github.com/orbitdb/orbit-db/blob/master/GUIDE.md#address +import EthereumIdentityProvider from './ΕthereumIdentityProvider'; + async function determineDBAddress({ orbit, dbName, type, identityId, }) { @@ -8,4 +10,10 @@ async function determineDBAddress({ return `/orbitdb/${ipfsMultihash}/${dbName}`; } -export default determineDBAddress; +async function determineKVAddress({ orbit, dbName, userAddress }) { + return determineDBAddress({ + orbit, dbName, type: 'keyvalue', identityId: userAddress + EthereumIdentityProvider.contractAddress, + }); +} + +export default determineKVAddress; diff --git a/packages/concordia-app/src/orbit/ΕthereumIdentityProvider.js b/packages/concordia-app/src/orbit/ΕthereumIdentityProvider.js index 9c7deab..96fffac 100644 --- a/packages/concordia-app/src/orbit/ΕthereumIdentityProvider.js +++ b/packages/concordia-app/src/orbit/ΕthereumIdentityProvider.js @@ -12,13 +12,22 @@ class EthereumIdentityProvider extends IdentityProvider { + 'Please use setWeb3(web3) first!'); } + if (!EthereumIdentityProvider.contractAddress) { + throw new Error(`${LOGGING_PREFIX}Couldn't create identity, because contractAddress wasn't set. ` + + 'Please use setContractAddress(contractAddress) first!'); + } + super(options); // Orbit's Identity Id (user's Ethereum address) - Optional (will be grabbed later if omitted) const { id } = options; if (id) { - if (EthereumIdentityProvider.web3.utils.isAddress(id)) this.id = options.id; - else throw new Error(`${LOGGING_PREFIX}Couldn't create identity, because an invalid id was supplied.`); + const { userAddress, contractAddress } = EthereumIdentityProvider.splitId(id); + if (EthereumIdentityProvider.web3.utils.isAddress(userAddress) + && EthereumIdentityProvider.contractAddress === contractAddress) { + this.id = id; + this.userAddress = userAddress; + } else throw new Error(`${LOGGING_PREFIX}Couldn't create identity, because an invalid id was supplied.`); } } @@ -32,8 +41,8 @@ class EthereumIdentityProvider extends IdentityProvider { throw new Error(`${LOGGING_PREFIX}Couldn't create identity, because no web3 accounts were found ( locked Metamask?).`); } - - [this.id] = accounts; + [this.userAddress] = accounts; + this.id = this.userAddress + EthereumIdentityProvider.contractAddress; } return this.id; } @@ -44,7 +53,7 @@ class EthereumIdentityProvider extends IdentityProvider { const signaturePubKey = await getIdentitySignaturePubKey(data); if (signaturePubKey) { const identityInfo = { - id: this.id, + userAddress: this.userAddress, pubKeySignId: data, signaturePubKey, }; @@ -61,7 +70,7 @@ class EthereumIdentityProvider extends IdentityProvider { // eslint-disable-next-line consistent-return async doSignIdentity(data) { try { - const signaturePubKey = await EthereumIdentityProvider.web3.eth.personal.sign(data, this.id, ''); + const signaturePubKey = await EthereumIdentityProvider.web3.eth.personal.sign(data, this.userAddress, ''); if (process.env.NODE_ENV === 'development') { storeIdentitySignaturePubKey(data, signaturePubKey) .then(() => { @@ -84,10 +93,12 @@ class EthereumIdentityProvider extends IdentityProvider { } static async verifyIdentity(identity) { + const { userAddress } = EthereumIdentityProvider.splitId(identity.id); + // Verify that identity was signed by the ID return new Promise((resolve) => { resolve(EthereumIdentityProvider.web3.eth.accounts.recover(identity.publicKey + identity.signatures.id, - identity.signatures.publicKey) === identity.id); + identity.signatures.publicKey) === userAddress); }); } @@ -95,7 +106,7 @@ class EthereumIdentityProvider extends IdentityProvider { // Verify that identity was signed by the ID return new Promise((resolve) => { resolve(EthereumIdentityProvider.web3.eth.accounts.recover(identityInfo.pubKeySignId, - identityInfo.signaturePubKey) === identityInfo.id); + identityInfo.signaturePubKey) === identityInfo.userAddress); }); } @@ -103,8 +114,23 @@ class EthereumIdentityProvider extends IdentityProvider { static setWeb3(web3) { EthereumIdentityProvider.web3 = web3; } + + // Initialize by supplying a contract's address (to be used as a point of reference) + static setContractAddress(contractAddress) { + EthereumIdentityProvider.contractAddress = contractAddress; + } + + static splitId(id) { + const regex = /(0x.*)(0x.*)/g; + const match = regex.exec(id); + if (match && match.length === 3) { + return { userAddress: match[1], contractAddress: match[2] }; + } + throw new Error(`${LOGGING_PREFIX}Invalid id ${id}! Couldn't split it to userAddress, contractAddress.`); + } } EthereumIdentityProvider.web3 = {}; +EthereumIdentityProvider.contractAddress = {}; export default EthereumIdentityProvider; diff --git a/packages/concordia-app/src/redux/sagas/orbitSaga.js b/packages/concordia-app/src/redux/sagas/orbitSaga.js index 12a169b..7b58949 100644 --- a/packages/concordia-app/src/redux/sagas/orbitSaga.js +++ b/packages/concordia-app/src/redux/sagas/orbitSaga.js @@ -1,11 +1,16 @@ -import { put, all, take } from 'redux-saga/effects'; +import { + call, put, all, take, +} from 'redux-saga/effects'; import { breezeActions } from '@ezerous/breeze'; import { drizzleActions } from '@ezerous/drizzle'; +import { forumContract } from 'concordia-contracts'; +import EthereumIdentityProvider from '../../orbit/ΕthereumIdentityProvider'; + function* initOrbitDatabases(action) { const { account, breeze } = action; - yield put(breezeActions.orbit.orbitInit(breeze, account)); // same as breeze.initOrbit(account); + yield put(breezeActions.orbit.orbitInit(breeze, account + EthereumIdentityProvider.contractAddress)); // same as breeze.initOrbit(account); } function* orbitSaga() { @@ -15,6 +20,13 @@ function* orbitSaga() { take(drizzleActions.account.ACCOUNTS_FETCHED), ]); + const { drizzle: { web3 } } = res[0]; + const networkId = yield call([web3.eth.net, web3.eth.net.getId]); + const contractAddress = forumContract.networks[networkId].address; + + EthereumIdentityProvider.setContractAddress(contractAddress); + EthereumIdentityProvider.setWeb3(web3); + yield initOrbitDatabases({ breeze: res[1].breeze, account: res[2].accounts[0] }); } diff --git a/packages/concordia-app/src/redux/sagas/peerDbReplicationSaga.js b/packages/concordia-app/src/redux/sagas/peerDbReplicationSaga.js index db099d6..e3d3d5f 100644 --- a/packages/concordia-app/src/redux/sagas/peerDbReplicationSaga.js +++ b/packages/concordia-app/src/redux/sagas/peerDbReplicationSaga.js @@ -7,12 +7,12 @@ import { ORBIT_DATABASE_REPLICATED, ORBIT_DATABASE_WRITE, } from '@ezerous/breeze/src/orbit/orbitActions'; -import determineDBAddress from '../../orbit/orbitUtils'; +import determineKVAddress from '../../orbit/orbitUtils'; import { FETCH_USER_DATABASE, UPDATE_ORBIT_DATA } from '../actions/peerDbReplicationActions'; function* fetchUserDb({ orbit, userAddress }) { - const peerDbAddress = yield call(determineDBAddress, { - orbit, dbName: 'topics', type: 'keyvalue', identityId: userAddress, + const peerDbAddress = yield call(determineKVAddress, { + orbit, dbName: 'topics', userAddress, }); yield put(createOrbitDatabase(orbit, { name: peerDbAddress, type: 'keyvalue' })); diff --git a/packages/concordia-app/src/views/Topic/TopicCreate/index.jsx b/packages/concordia-app/src/views/Topic/TopicCreate/index.jsx index 4640651..2870d1d 100644 --- a/packages/concordia-app/src/views/Topic/TopicCreate/index.jsx +++ b/packages/concordia-app/src/views/Topic/TopicCreate/index.jsx @@ -81,12 +81,12 @@ const TopicCreate = (props) => { const postsDb = Object.values(stores).find((store) => store.dbname === 'posts'); topicsDb - .put(topicId, { subject: subjectInput }) + .put(topicId, { subject: subjectInput }, { pin: true }) .then(() => postsDb .put(postId, { subject: subjectInput, content: messageInput, - })) + }, { pin: true })) .then(() => { history.push(`/topics/${topicId}`); }) diff --git a/packages/concordia-contracts/index.js b/packages/concordia-contracts/index.js index ff79437..0ab0aa9 100644 --- a/packages/concordia-contracts/index.js +++ b/packages/concordia-contracts/index.js @@ -10,4 +10,5 @@ try { module.exports = { contracts: [Forum], + forumContract: Forum, };