Browse Source

Include contractAddress in OrbitDB Identity

develop
Ezerous 4 years ago
parent
commit
bfb5e75254
  1. 5
      packages/concordia-app/src/options/breezeOptions.js
  2. 3
      packages/concordia-app/src/options/web3Options.js
  3. 2
      packages/concordia-app/src/orbit/levelUtils.js
  4. 10
      packages/concordia-app/src/orbit/orbitUtils.js
  5. 42
      packages/concordia-app/src/orbit/ΕthereumIdentityProvider.js
  6. 16
      packages/concordia-app/src/redux/sagas/orbitSaga.js
  7. 6
      packages/concordia-app/src/redux/sagas/peerDbReplicationSaga.js
  8. 4
      packages/concordia-app/src/views/Topic/TopicCreate/index.jsx
  9. 1
      packages/concordia-contracts/index.js

5
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'; import EthereumIdentityProvider from '../orbit/ΕthereumIdentityProvider';
const { web3 } = web3Options;
EthereumIdentityProvider.setWeb3(web3);
const breezeOptions = { const breezeOptions = {
ipfs: { ipfs: {
config: { config: {

3
packages/concordia-app/src/options/web3Options.js

@ -1,12 +1,9 @@
import Web3 from 'web3'; import Web3 from 'web3';
import EthereumIdentityProvider from '../orbit/ΕthereumIdentityProvider';
const { WEB3_URL, WEB3_PORT } = process.env; const { WEB3_URL, WEB3_PORT } = process.env;
const web3 = new Web3(Web3.givenProvider || `ws://${WEB3_URL}:${WEB3_PORT}`); const web3 = new Web3(Web3.givenProvider || `ws://${WEB3_URL}:${WEB3_PORT}`);
EthereumIdentityProvider.setWeb3(web3);
const web3Options = { const web3Options = {
web3, web3,
}; };

2
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 // 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) { async function getIdentitySignaturePubKey(key) {
try { try {
return await concordiaDB.get(key); return await concordiaDB.get(key);

10
packages/concordia-app/src/orbit/orbitUtils.js

@ -1,4 +1,6 @@
// https://github.com/orbitdb/orbit-db/blob/master/GUIDE.md#address // https://github.com/orbitdb/orbit-db/blob/master/GUIDE.md#address
import EthereumIdentityProvider from './ΕthereumIdentityProvider';
async function determineDBAddress({ async function determineDBAddress({
orbit, dbName, type, identityId, orbit, dbName, type, identityId,
}) { }) {
@ -8,4 +10,10 @@ async function determineDBAddress({
return `/orbitdb/${ipfsMultihash}/${dbName}`; 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;

42
packages/concordia-app/src/orbit/ΕthereumIdentityProvider.js

@ -12,13 +12,22 @@ class EthereumIdentityProvider extends IdentityProvider {
+ 'Please use setWeb3(web3) first!'); + '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); super(options);
// Orbit's Identity Id (user's Ethereum address) - Optional (will be grabbed later if omitted) // Orbit's Identity Id (user's Ethereum address) - Optional (will be grabbed later if omitted)
const { id } = options; const { id } = options;
if (id) { if (id) {
if (EthereumIdentityProvider.web3.utils.isAddress(id)) this.id = options.id; const { userAddress, contractAddress } = EthereumIdentityProvider.splitId(id);
else throw new Error(`${LOGGING_PREFIX}Couldn't create identity, because an invalid id was supplied.`); 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 ( throw new Error(`${LOGGING_PREFIX}Couldn't create identity, because no web3 accounts were found (
locked Metamask?).`); locked Metamask?).`);
} }
[this.userAddress] = accounts;
[this.id] = accounts; this.id = this.userAddress + EthereumIdentityProvider.contractAddress;
} }
return this.id; return this.id;
} }
@ -44,7 +53,7 @@ class EthereumIdentityProvider extends IdentityProvider {
const signaturePubKey = await getIdentitySignaturePubKey(data); const signaturePubKey = await getIdentitySignaturePubKey(data);
if (signaturePubKey) { if (signaturePubKey) {
const identityInfo = { const identityInfo = {
id: this.id, userAddress: this.userAddress,
pubKeySignId: data, pubKeySignId: data,
signaturePubKey, signaturePubKey,
}; };
@ -61,7 +70,7 @@ class EthereumIdentityProvider extends IdentityProvider {
// eslint-disable-next-line consistent-return // eslint-disable-next-line consistent-return
async doSignIdentity(data) { async doSignIdentity(data) {
try { 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') { if (process.env.NODE_ENV === 'development') {
storeIdentitySignaturePubKey(data, signaturePubKey) storeIdentitySignaturePubKey(data, signaturePubKey)
.then(() => { .then(() => {
@ -84,10 +93,12 @@ class EthereumIdentityProvider extends IdentityProvider {
} }
static async verifyIdentity(identity) { static async verifyIdentity(identity) {
const { userAddress } = EthereumIdentityProvider.splitId(identity.id);
// Verify that identity was signed by the ID // Verify that identity was signed by the ID
return new Promise((resolve) => { return new Promise((resolve) => {
resolve(EthereumIdentityProvider.web3.eth.accounts.recover(identity.publicKey + identity.signatures.id, 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 // Verify that identity was signed by the ID
return new Promise((resolve) => { return new Promise((resolve) => {
resolve(EthereumIdentityProvider.web3.eth.accounts.recover(identityInfo.pubKeySignId, 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) { static setWeb3(web3) {
EthereumIdentityProvider.web3 = 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.web3 = {};
EthereumIdentityProvider.contractAddress = {};
export default EthereumIdentityProvider; export default EthereumIdentityProvider;

16
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 { breezeActions } from '@ezerous/breeze';
import { drizzleActions } from '@ezerous/drizzle'; import { drizzleActions } from '@ezerous/drizzle';
import { forumContract } from 'concordia-contracts';
import EthereumIdentityProvider from '../../orbit/ΕthereumIdentityProvider';
function* initOrbitDatabases(action) { function* initOrbitDatabases(action) {
const { account, breeze } = 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() { function* orbitSaga() {
@ -15,6 +20,13 @@ function* orbitSaga() {
take(drizzleActions.account.ACCOUNTS_FETCHED), 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] }); yield initOrbitDatabases({ breeze: res[1].breeze, account: res[2].accounts[0] });
} }

6
packages/concordia-app/src/redux/sagas/peerDbReplicationSaga.js

@ -7,12 +7,12 @@ import {
ORBIT_DATABASE_REPLICATED, ORBIT_DATABASE_REPLICATED,
ORBIT_DATABASE_WRITE, ORBIT_DATABASE_WRITE,
} from '@ezerous/breeze/src/orbit/orbitActions'; } 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'; import { FETCH_USER_DATABASE, UPDATE_ORBIT_DATA } from '../actions/peerDbReplicationActions';
function* fetchUserDb({ orbit, userAddress }) { function* fetchUserDb({ orbit, userAddress }) {
const peerDbAddress = yield call(determineDBAddress, { const peerDbAddress = yield call(determineKVAddress, {
orbit, dbName: 'topics', type: 'keyvalue', identityId: userAddress, orbit, dbName: 'topics', userAddress,
}); });
yield put(createOrbitDatabase(orbit, { name: peerDbAddress, type: 'keyvalue' })); yield put(createOrbitDatabase(orbit, { name: peerDbAddress, type: 'keyvalue' }));

4
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'); const postsDb = Object.values(stores).find((store) => store.dbname === 'posts');
topicsDb topicsDb
.put(topicId, { subject: subjectInput }) .put(topicId, { subject: subjectInput }, { pin: true })
.then(() => postsDb .then(() => postsDb
.put(postId, { .put(postId, {
subject: subjectInput, subject: subjectInput,
content: messageInput, content: messageInput,
})) }, { pin: true }))
.then(() => { .then(() => {
history.push(`/topics/${topicId}`); history.push(`/topics/${topicId}`);
}) })

1
packages/concordia-contracts/index.js

@ -10,4 +10,5 @@ try {
module.exports = { module.exports = {
contracts: [Forum], contracts: [Forum],
forumContract: Forum,
}; };

Loading…
Cancel
Save