From c2b8dada91c90788dcd81a0318c52a66b4b769d1 Mon Sep 17 00:00:00 2001 From: Sergey Ukustov Date: Fri, 29 Sep 2017 19:24:08 +0300 Subject: Add eth_signTypedData handler --- ui/app/actions.js | 27 ++++++++++++ ui/app/components/pending-typed-msg-details.js | 59 ++++++++++++++++++++++++++ ui/app/components/pending-typed-msg.js | 46 ++++++++++++++++++++ ui/app/components/typed-message-renderer.js | 42 ++++++++++++++++++ ui/app/conf-tx.js | 25 ++++++++++- ui/app/reducers/app.js | 4 +- ui/index.js | 2 +- ui/lib/tx-helper.js | 13 ++++-- 8 files changed, 210 insertions(+), 8 deletions(-) create mode 100644 ui/app/components/pending-typed-msg-details.js create mode 100644 ui/app/components/pending-typed-msg.js create mode 100644 ui/app/components/typed-message-renderer.js (limited to 'ui') diff --git a/ui/app/actions.js b/ui/app/actions.js index e793e6a21..84a1b8dcc 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -97,6 +97,8 @@ var actions = { cancelMsg: cancelMsg, signPersonalMsg, cancelPersonalMsg, + signTypedMsg, + cancelTypedMsg, signTx: signTx, updateAndApproveTx, cancelTx: cancelTx, @@ -395,6 +397,25 @@ function signPersonalMsg (msgData) { } } +function signTypedMsg (msgData) { + log.debug('action - signTypedMsg') + return (dispatch) => { + dispatch(actions.showLoadingIndication()) + + log.debug(`actions calling background.signTypedMessage`) + background.signTypedMessage(msgData, (err, newState) => { + log.debug('signTypedMessage called back') + dispatch(actions.updateMetamaskState(newState)) + dispatch(actions.hideLoadingIndication()) + + if (err) log.error(err) + if (err) return dispatch(actions.displayWarning(err.message)) + + dispatch(actions.completedTx(msgData.metamaskId)) + }) + } +} + function signTx (txData) { return (dispatch) => { dispatch(actions.showLoadingIndication()) @@ -449,6 +470,12 @@ function cancelPersonalMsg (msgData) { return actions.completedTx(id) } +function cancelTypedMsg (msgData) { + const id = msgData.id + background.cancelTypedMessage(id) + return actions.completedTx(id) +} + function cancelTx (txData) { return (dispatch) => { log.debug(`background.cancelTransaction`) diff --git a/ui/app/components/pending-typed-msg-details.js b/ui/app/components/pending-typed-msg-details.js new file mode 100644 index 000000000..b5fd29f71 --- /dev/null +++ b/ui/app/components/pending-typed-msg-details.js @@ -0,0 +1,59 @@ +const Component = require('react').Component +const h = require('react-hyperscript') +const inherits = require('util').inherits + +const AccountPanel = require('./account-panel') +const TypedMessageRenderer = require('./typed-message-renderer') + +module.exports = PendingMsgDetails + +inherits(PendingMsgDetails, Component) +function PendingMsgDetails () { + Component.call(this) +} + +PendingMsgDetails.prototype.render = function () { + var state = this.props + var msgData = state.txData + + var msgParams = msgData.msgParams || {} + var address = msgParams.from || state.selectedAddress + var identity = state.identities[address] || { address: address } + var account = state.accounts[address] || { address: address } + + var { data } = msgParams + + return ( + h('div', { + key: msgData.id, + style: { + margin: '10px 20px', + }, + }, [ + + // account that will sign + h(AccountPanel, { + showFullAddress: true, + identity: identity, + account: account, + imageifyIdenticons: state.imageifyIdenticons, + }), + + // message data + h('div', { + style: { + height: '260px', + }, + }, [ + h('label.font-small', { style: { display: 'block' } }, 'YOU ARE SIGNING'), + h(TypedMessageRenderer, { + value: data, + style: { + height: '215px', + }, + }), + ]), + + ]) + ) +} diff --git a/ui/app/components/pending-typed-msg.js b/ui/app/components/pending-typed-msg.js new file mode 100644 index 000000000..f8926d0a3 --- /dev/null +++ b/ui/app/components/pending-typed-msg.js @@ -0,0 +1,46 @@ +const Component = require('react').Component +const h = require('react-hyperscript') +const inherits = require('util').inherits +const PendingTxDetails = require('./pending-typed-msg-details') + +module.exports = PendingMsg + +inherits(PendingMsg, Component) +function PendingMsg () { + Component.call(this) +} + +PendingMsg.prototype.render = function () { + var state = this.props + var msgData = state.txData + + return ( + + h('div', { + key: msgData.id, + }, [ + + // header + h('h3', { + style: { + fontWeight: 'bold', + textAlign: 'center', + }, + }, 'Sign Message'), + + // message details + h(PendingTxDetails, state), + + // sign + cancel + h('.flex-row.flex-space-around', [ + h('button', { + onClick: state.cancelTypedMessage, + }, 'Cancel'), + h('button', { + onClick: state.signTypedMessage, + }, 'Sign'), + ]), + ]) + + ) +} diff --git a/ui/app/components/typed-message-renderer.js b/ui/app/components/typed-message-renderer.js new file mode 100644 index 000000000..50e8da02c --- /dev/null +++ b/ui/app/components/typed-message-renderer.js @@ -0,0 +1,42 @@ +const Component = require('react').Component +const h = require('react-hyperscript') +const inherits = require('util').inherits +const ethUtil = require('ethereumjs-util') +const extend = require('xtend') + +module.exports = TypedMessageRenderer + +inherits(TypedMessageRenderer, Component) +function TypedMessageRenderer () { + Component.call(this) +} + +TypedMessageRenderer.prototype.render = function () { + const props = this.props + const { value, style } = props + const text = renderTypedData(value) + + const defaultStyle = extend({ + width: '315px', + maxHeight: '210px', + resize: 'none', + border: 'none', + background: 'white', + padding: '3px', + }, style) + + return ( + h('div.font-small', { + style: defaultStyle, + }, text) + ) +} + +function renderTypedData(values) { + return values.map(function (value) { + return h('div', {}, [ + h('strong', {style: {display: 'block', fontWeight: 'bold', textTransform: 'capitalize'}}, String(value.name) + ':'), + h('div', {}, value.value) + ]) + }) +} \ No newline at end of file diff --git a/ui/app/conf-tx.js b/ui/app/conf-tx.js index 15fb9a59f..f93fc2373 100644 --- a/ui/app/conf-tx.js +++ b/ui/app/conf-tx.js @@ -10,6 +10,7 @@ const isPopupOrNotification = require('../../app/scripts/lib/is-popup-or-notific const PendingTx = require('./components/pending-tx') const PendingMsg = require('./components/pending-msg') const PendingPersonalMsg = require('./components/pending-personal-msg') +const PendingTypedMsg = require('./components/pending-typed-msg') const Loading = require('./components/loading') module.exports = connect(mapStateToProps)(ConfirmTxScreen) @@ -22,6 +23,7 @@ function mapStateToProps (state) { unapprovedTxs: state.metamask.unapprovedTxs, unapprovedMsgs: state.metamask.unapprovedMsgs, unapprovedPersonalMsgs: state.metamask.unapprovedPersonalMsgs, + unapprovedTypedMessages: state.metamask.unapprovedTypedMessages, index: state.appState.currentView.context, warning: state.appState.warning, network: state.metamask.network, @@ -41,9 +43,9 @@ function ConfirmTxScreen () { ConfirmTxScreen.prototype.render = function () { const props = this.props const { network, provider, unapprovedTxs, currentCurrency, computedBalances, - unapprovedMsgs, unapprovedPersonalMsgs, conversionRate, blockGasLimit } = props + unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, conversionRate, blockGasLimit } = props - var unconfTxList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, network) + var unconfTxList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, network) var txData = unconfTxList[props.index] || {} var txParams = txData.params || {} @@ -112,8 +114,10 @@ ConfirmTxScreen.prototype.render = function () { cancelAllTransactions: this.cancelAllTransactions.bind(this, unconfTxList), signMessage: this.signMessage.bind(this, txData), signPersonalMessage: this.signPersonalMessage.bind(this, txData), + signTypedMessage: this.signTypedMessage.bind(this, txData), cancelMessage: this.cancelMessage.bind(this, txData), cancelPersonalMessage: this.cancelPersonalMessage.bind(this, txData), + cancelTypedMessage: this.cancelTypedMessage.bind(this, txData) }), ]) ) @@ -136,6 +140,9 @@ function currentTxView (opts) { } else if (type === 'personal_sign') { log.debug('rendering personal_sign message') return h(PendingPersonalMsg, opts) + } else if (type === 'eth_signTypedData') { + log.debug('rendering eth_signTypedData message') + return h(PendingTypedMsg, opts) } } } @@ -184,6 +191,14 @@ ConfirmTxScreen.prototype.signPersonalMessage = function (msgData, event) { this.props.dispatch(actions.signPersonalMsg(params)) } +ConfirmTxScreen.prototype.signTypedMessage = function (msgData, event) { + log.info('conf-tx.js: signing typed message') + var params = msgData.msgParams + params.metamaskId = msgData.id + this.stopPropagation(event) + this.props.dispatch(actions.signTypedMsg(params)) +} + ConfirmTxScreen.prototype.cancelMessage = function (msgData, event) { log.info('canceling message') this.stopPropagation(event) @@ -196,6 +211,12 @@ ConfirmTxScreen.prototype.cancelPersonalMessage = function (msgData, event) { this.props.dispatch(actions.cancelPersonalMsg(msgData)) } +ConfirmTxScreen.prototype.cancelTypedMessage = function (msgData, event) { + log.info('canceling typed message') + this.stopPropagation(event) + this.props.dispatch(actions.cancelTypedMsg(msgData)) +} + ConfirmTxScreen.prototype.goHome = function (event) { this.stopPropagation(event) this.props.dispatch(actions.goHome()) diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js index 3a98d53a9..349c25b96 100644 --- a/ui/app/reducers/app.js +++ b/ui/app/reducers/app.js @@ -574,9 +574,9 @@ function checkUnconfActions (state) { function getUnconfActionList (state) { const { unapprovedTxs, unapprovedMsgs, - unapprovedPersonalMsgs, network } = state.metamask + unapprovedPersonalMsgs, unapprovedTypedMessages, network } = state.metamask - const unconfActionList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, network) + const unconfActionList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, network) return unconfActionList } diff --git a/ui/index.js b/ui/index.js index a729138d3..ae05cbe67 100644 --- a/ui/index.js +++ b/ui/index.js @@ -37,7 +37,7 @@ function startApp (metamaskState, accountManager, opts) { }) // if unconfirmed txs, start on txConf page - const unapprovedTxsAll = txHelper(metamaskState.unapprovedTxs, metamaskState.unapprovedMsgs, metamaskState.unapprovedPersonalMsgs, metamaskState.network) + const unapprovedTxsAll = txHelper(metamaskState.unapprovedTxs, metamaskState.unapprovedMsgs, metamaskState.unapprovedPersonalMsgs, metamaskState.unapprovedTypedMessages, metamaskState.network) if (unapprovedTxsAll.length > 0) { store.dispatch(actions.showConfTxPage()) } diff --git a/ui/lib/tx-helper.js b/ui/lib/tx-helper.js index 5def23e51..341567e2f 100644 --- a/ui/lib/tx-helper.js +++ b/ui/lib/tx-helper.js @@ -1,20 +1,27 @@ const valuesFor = require('../app/util').valuesFor -module.exports = function (unapprovedTxs, unapprovedMsgs, personalMsgs, network) { +module.exports = function (unapprovedTxs, unapprovedMsgs, personalMsgs, typedMessages, network) { log.debug('tx-helper called with params:') - log.debug({ unapprovedTxs, unapprovedMsgs, personalMsgs, network }) + log.debug({ unapprovedTxs, unapprovedMsgs, personalMsgs, typedMessages, network }) const txValues = network ? valuesFor(unapprovedTxs).filter(txMeta => txMeta.metamaskNetworkId === network) : valuesFor(unapprovedTxs) log.debug(`tx helper found ${txValues.length} unapproved txs`) + const msgValues = valuesFor(unapprovedMsgs) log.debug(`tx helper found ${msgValues.length} unsigned messages`) let allValues = txValues.concat(msgValues) + const personalValues = valuesFor(personalMsgs) log.debug(`tx helper found ${personalValues.length} unsigned personal messages`) allValues = allValues.concat(personalValues) + + const typedValues = valuesFor(typedMessages) + log.debug(`tx helper found ${typedValues.length} unsigned typed messages`) + allValues = allValues.concat(typedValues) + allValues = allValues.sort((a, b) => { return a.time > b.time }) return allValues -} +} \ No newline at end of file -- cgit From 82d1f391986ac6f7cb7d9029f50d44b5a8c9442b Mon Sep 17 00:00:00 2001 From: Sergey Ukustov Date: Fri, 29 Sep 2017 19:47:40 +0300 Subject: Respect code style --- ui/app/components/typed-message-renderer.js | 3 +-- ui/app/conf-tx.js | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'ui') diff --git a/ui/app/components/typed-message-renderer.js b/ui/app/components/typed-message-renderer.js index 50e8da02c..b7d1572c2 100644 --- a/ui/app/components/typed-message-renderer.js +++ b/ui/app/components/typed-message-renderer.js @@ -1,7 +1,6 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const ethUtil = require('ethereumjs-util') const extend = require('xtend') module.exports = TypedMessageRenderer @@ -36,7 +35,7 @@ function renderTypedData(values) { return values.map(function (value) { return h('div', {}, [ h('strong', {style: {display: 'block', fontWeight: 'bold', textTransform: 'capitalize'}}, String(value.name) + ':'), - h('div', {}, value.value) + h('div', {}, value.value), ]) }) } \ No newline at end of file diff --git a/ui/app/conf-tx.js b/ui/app/conf-tx.js index f93fc2373..cb1afedfe 100644 --- a/ui/app/conf-tx.js +++ b/ui/app/conf-tx.js @@ -117,7 +117,7 @@ ConfirmTxScreen.prototype.render = function () { signTypedMessage: this.signTypedMessage.bind(this, txData), cancelMessage: this.cancelMessage.bind(this, txData), cancelPersonalMessage: this.cancelPersonalMessage.bind(this, txData), - cancelTypedMessage: this.cancelTypedMessage.bind(this, txData) + cancelTypedMessage: this.cancelTypedMessage.bind(this, txData), }), ]) ) -- cgit From 53bb4bebb11b355f2655b2be0116005df573e907 Mon Sep 17 00:00:00 2001 From: Sergey Ukustov Date: Sat, 7 Oct 2017 23:25:33 +0300 Subject: More appropriate styling --- ui/app/components/typed-message-renderer.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'ui') diff --git a/ui/app/components/typed-message-renderer.js b/ui/app/components/typed-message-renderer.js index b7d1572c2..a042b57be 100644 --- a/ui/app/components/typed-message-renderer.js +++ b/ui/app/components/typed-message-renderer.js @@ -22,6 +22,7 @@ TypedMessageRenderer.prototype.render = function () { border: 'none', background: 'white', padding: '3px', + overflow: 'scroll', }, style) return ( @@ -34,7 +35,7 @@ TypedMessageRenderer.prototype.render = function () { function renderTypedData(values) { return values.map(function (value) { return h('div', {}, [ - h('strong', {style: {display: 'block', fontWeight: 'bold', textTransform: 'capitalize'}}, String(value.name) + ':'), + h('strong', {style: {display: 'block', fontWeight: 'bold'}}, String(value.name) + ':'), h('div', {}, value.value), ]) }) -- cgit