From d55e3de987632161f82835d5f412f6e5778d21ad Mon Sep 17 00:00:00 2001 From: Ezerous Date: Wed, 22 May 2019 18:49:37 +0300 Subject: [PATCH] Avoid signing transaction repeatedly while in development --- app/package.json | 1 + app/src/utils/EthereumIdentityProvider.js | 30 ----------- app/src/utils/ethereumIdentityProvider.js | 64 +++++++++++++++++++++++ app/src/utils/levelUtils.js | 24 +++++++++ app/src/utils/orbitUtils.js | 3 +- 5 files changed, 90 insertions(+), 32 deletions(-) delete mode 100644 app/src/utils/EthereumIdentityProvider.js create mode 100644 app/src/utils/ethereumIdentityProvider.js create mode 100644 app/src/utils/levelUtils.js diff --git a/app/package.json b/app/package.json index 63bcf72..8a3a0e9 100644 --- a/app/package.json +++ b/app/package.json @@ -14,6 +14,7 @@ "drizzle": "1.4.0", "history": "4.9.0", "ipfs": "0.35.0", + "level": "5.0.1", "lodash.isequal": "4.5.0", "orbit-db": "0.21.0-rc.1", "orbit-db-identity-provider": "0.1.0", diff --git a/app/src/utils/EthereumIdentityProvider.js b/app/src/utils/EthereumIdentityProvider.js deleted file mode 100644 index 7efaff8..0000000 --- a/app/src/utils/EthereumIdentityProvider.js +++ /dev/null @@ -1,30 +0,0 @@ -import { web3 } from '../redux/sagas/drizzleUtilsSaga'; - -class EthereumIdentityProvider { - constructor (options = {}) { // Orbit's Identity Id (equals user's Ethereum address) - this.id = options.id; // web3.eth.getAccounts())[0] - } - - static get type () { return 'ethereum'; } - - async getId () { return this.id; } - - async signIdentity (data) { - while(true){ //Insist (e.g. if user dismisses dialog) - try{ - return await web3.eth.personal.sign(data, this.id,""); //Password not required for MetaMask - } - catch (e) { - console.error("Failed to sign data."); - } - } - } - - static async verifyIdentity (identity) { - // Verify that identity was signed by the ID - return web3.eth.accounts.recover(identity.publicKey + identity.signatures.id, - identity.signatures.publicKey) === identity.id; - } -} - -export default EthereumIdentityProvider; diff --git a/app/src/utils/ethereumIdentityProvider.js b/app/src/utils/ethereumIdentityProvider.js new file mode 100644 index 0000000..de9a258 --- /dev/null +++ b/app/src/utils/ethereumIdentityProvider.js @@ -0,0 +1,64 @@ +import { web3 } from '../redux/sagas/drizzleUtilsSaga'; +import { getIdentitySignaturePubKey, storeIdentitySignaturePubKey } from './levelUtils'; + +class EthereumIdentityProvider { + constructor (options = {}) { // Orbit's Identity Id (equals user's Ethereum address) + this.id = options.id; // web3.eth.getAccounts())[0] + } + + static get type () { return 'ethereum'; } + + async getId () { return this.id; } + + async signIdentity (data) { + if(process.env.NODE_ENV==='development') { + console.debug("Attempting to find stored Orbit identity data..."); + const signaturePubKey = await getIdentitySignaturePubKey(data); + if (signaturePubKey) { + if (EthereumIdentityProvider.verifyIdentityInfo({ + id: this.id, + pubKeySignId: data, + signaturePubKey + })) { + console.debug("Found and verified stored Orbit identity data!"); + return signaturePubKey; + } + console.debug("Stored Orbit identity data couldn't be verified."); + } + else + console.debug("No stored Orbit identity data were found."); + } + + while(true){ //Insist (e.g. if user dismisses dialog) + try{ + const signaturePubKey = await web3.eth.personal.sign(data, this.id,""); + if(process.env.NODE_ENV==='development') + storeIdentitySignaturePubKey(data, signaturePubKey) + .then(()=>{ + console.debug("Successfully stored current Orbit identity data."); + }) + .catch(()=>{ + console.warn("Couldn't store current Orbit identity data..."); + }); + return signaturePubKey; //Password not required for MetaMask + } + catch (e) { + console.error("Failed to sign data."); + } + } + } + + static async verifyIdentity (identity) { + // Verify that identity was signed by the ID + return web3.eth.accounts.recover(identity.publicKey + identity.signatures.id, + identity.signatures.publicKey) === identity.id; + } + + static async verifyIdentityInfo (identityInfo) { + // Verify that identity was signed by the ID + return web3.eth.accounts.recover(identityInfo.pubKeySignId, + identityInfo.signaturePubKey) === identityInfo.id; + } +} + +export default EthereumIdentityProvider; diff --git a/app/src/utils/levelUtils.js b/app/src/utils/levelUtils.js new file mode 100644 index 0000000..eed5926 --- /dev/null +++ b/app/src/utils/levelUtils.js @@ -0,0 +1,24 @@ +import level from 'level' + +/* Used in development only to store the identity.signatures.publicKey so developers don't have to +repeatedly sign theOrbitDB creation transaction in MetaMask when React development server reloads +the app */ +const apellaDB = level('./apella/identities'); + +async function storeIdentitySignaturePubKey(key, signaturePubKey){ + await apellaDB.put(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 +async function getIdentitySignaturePubKey(key){ + try{ + return await apellaDB.get(key); + } catch (err) { + if (err && err.notFound) + return null; // Not found + throw err; + } +} + +export { storeIdentitySignaturePubKey ,getIdentitySignaturePubKey }; diff --git a/app/src/utils/orbitUtils.js b/app/src/utils/orbitUtils.js index 4adfc23..4a3135e 100644 --- a/app/src/utils/orbitUtils.js +++ b/app/src/utils/orbitUtils.js @@ -4,7 +4,7 @@ import IPFS from 'ipfs'; import store from '../redux/store'; import { DATABASES_LOADED, IPFS_INITIALIZED, updateDatabases } from '../redux/actions/orbitActions'; import ipfsOptions from '../config/ipfsOptions'; -import EthereumIdentityProvider from './EthereumIdentityProvider'; +import EthereumIdentityProvider from './ethereumIdentityProvider'; function initIPFS() { Identities.addIdentityProvider(EthereumIdentityProvider); @@ -99,7 +99,6 @@ async function createDBs(identityId){ return { orbitdb, topicsDB, postsDB }; } - export { initIPFS, createDatabases,