1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 18:00:18 +01:00

Merge branch 'master' into i1144-moarrpc

This commit is contained in:
Kevin Serrano 2017-03-07 10:37:31 -08:00
commit 08ca7dac5a
No known key found for this signature in database
GPG Key ID: 7CC862A58D2889B4
11 changed files with 161 additions and 57 deletions

View File

@ -2,6 +2,7 @@ const EventEmitter = require('events')
const ObservableStore = require('obs-store') const ObservableStore = require('obs-store')
const ethUtil = require('ethereumjs-util') const ethUtil = require('ethereumjs-util')
const createId = require('./random-id') const createId = require('./random-id')
const hexRe = /^[0-9A-Fa-f]+$/g
module.exports = class PersonalMessageManager extends EventEmitter{ module.exports = class PersonalMessageManager extends EventEmitter{
@ -24,7 +25,8 @@ module.exports = class PersonalMessageManager extends EventEmitter{
} }
addUnapprovedMessage (msgParams) { addUnapprovedMessage (msgParams) {
msgParams.data = normalizeMsgData(msgParams.data) log.debug(`PersonalMessageManager addUnapprovedMessage: ${JSON.stringify(msgParams)}`)
msgParams.data = this.normalizeMsgData(msgParams.data)
// create txData obj with parameters and meta data // create txData obj with parameters and meta data
var time = (new Date()).getTime() var time = (new Date()).getTime()
var msgId = createId() var msgId = createId()
@ -106,14 +108,18 @@ module.exports = class PersonalMessageManager extends EventEmitter{
this.emit('updateBadge') this.emit('updateBadge')
} }
} normalizeMsgData(data) {
try {
const stripped = ethUtil.stripHexPrefix(data)
if (stripped.match(hexRe)) {
return ethUtil.addHexPrefix(stripped)
}
} catch (e) {
log.debug(`Message was not hex encoded, interpreting as utf8.`)
}
function normalizeMsgData(data) {
if (data.slice(0, 2) === '0x') {
// data is already hex
return data
} else {
// data is unicode, convert to hex
return ethUtil.bufferToHex(new Buffer(data, 'utf8')) return ethUtil.bufferToHex(new Buffer(data, 'utf8'))
} }
} }

View File

@ -415,14 +415,14 @@ module.exports = class MetamaskController extends EventEmitter {
self.sendUpdate() self.sendUpdate()
self.opts.showUnapprovedTx(txMeta) self.opts.showUnapprovedTx(txMeta)
// listen for tx completion (success, fail) // listen for tx completion (success, fail)
self.txManager.once(`${txMeta.id}:finished`, (status) => { self.txManager.once(`${txMeta.id}:finished`, (completedTx) => {
switch (status) { switch (completedTx.status) {
case 'submitted': case 'submitted':
return cb(null, txMeta.hash) return cb(null, completedTx.hash)
case 'rejected': case 'rejected':
return cb(new Error('MetaMask Tx Signature: User denied transaction signature.')) return cb(new Error('MetaMask Tx Signature: User denied transaction signature.'))
default: default:
return cb(new Error(`MetaMask Tx Signature: Unknown problem: ${JSON.stringify(txMeta.txParams)}`)) return cb(new Error(`MetaMask Tx Signature: Unknown problem: ${JSON.stringify(completedTx.txParams)}`))
} }
}) })
}) })

View File

@ -353,7 +353,7 @@ module.exports = class TransactionManager extends EventEmitter {
txMeta.status = status txMeta.status = status
this.emit(`${txMeta.id}:${status}`, txId) this.emit(`${txMeta.id}:${status}`, txId)
if (status === 'submitted' || status === 'rejected') { if (status === 'submitted' || status === 'rejected') {
this.emit(`${txMeta.id}:finished`, status) this.emit(`${txMeta.id}:finished`, txMeta)
} }
this.updateTx(txMeta) this.updateTx(txMeta)
this.emit('updateBadge') this.emit('updateBadge')

View File

@ -56,7 +56,7 @@
"eth-lightwallet": "^2.3.3", "eth-lightwallet": "^2.3.3",
"eth-query": "^1.0.3", "eth-query": "^1.0.3",
"eth-sig-util": "^1.1.1", "eth-sig-util": "^1.1.1",
"eth-simple-keyring": "^1.1.0", "eth-simple-keyring": "^1.1.1",
"ethereumjs-tx": "^1.0.0", "ethereumjs-tx": "^1.0.0",
"ethereumjs-util": "ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", "ethereumjs-util": "ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9",
"ethereumjs-wallet": "^0.6.0", "ethereumjs-wallet": "^0.6.0",

View File

@ -0,0 +1,25 @@
var assert = require('assert')
var BinaryRenderer = require('../../../ui/app/components/binary-renderer')
describe('BinaryRenderer', function() {
let binaryRenderer
const message = 'Hello, world!'
const buffer = new Buffer(message, 'utf8')
const hex = buffer.toString('hex')
beforeEach(function() {
binaryRenderer = new BinaryRenderer()
})
it('recovers message', function() {
const result = binaryRenderer.hexToText(hex)
assert.equal(result, message)
})
it('recovers message with hex prefix', function() {
const result = binaryRenderer.hexToText('0x' + hex)
assert.equal(result, message)
})
})

View File

@ -4,7 +4,7 @@ const EventEmitter = require('events')
const PersonalMessageManager = require('../../app/scripts/lib/personal-message-manager') const PersonalMessageManager = require('../../app/scripts/lib/personal-message-manager')
describe('Transaction Manager', function() { describe('Personal Message Manager', function() {
let messageManager let messageManager
beforeEach(function() { beforeEach(function() {
@ -86,4 +86,25 @@ describe('Transaction Manager', function() {
assert.equal(messageManager.getMsg('2').status, 'approved') assert.equal(messageManager.getMsg('2').status, 'approved')
}) })
}) })
describe('#normalizeMsgData', function() {
it('converts text to a utf8 buffer', function() {
var input = 'hello'
var output = messageManager.normalizeMsgData(input)
assert.equal(output, '0x68656c6c6f', 'predictably hex encoded')
})
it('tolerates a hex prefix', function() {
var input = '0x12'
var output = messageManager.normalizeMsgData(input)
assert.equal(output, '0x12', 'un modified')
})
it('tolerates normal hex', function() {
var input = '12'
var output = messageManager.normalizeMsgData(input)
assert.equal(output, '0x12', 'adds prefix')
})
})
}) })

View File

@ -0,0 +1,43 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const ethUtil = require('ethereumjs-util')
module.exports = BinaryRenderer
inherits(BinaryRenderer, Component)
function BinaryRenderer () {
Component.call(this)
}
BinaryRenderer.prototype.render = function () {
const props = this.props
const { value } = props
const text = this.hexToText(value)
return (
h('textarea.font-small', {
readOnly: true,
style: {
width: '315px',
maxHeight: '210px',
resize: 'none',
border: 'none',
background: 'white',
padding: '3px',
},
defaultValue: text,
})
)
}
BinaryRenderer.prototype.hexToText = function (hex) {
try {
const stripped = ethUtil.stripHexPrefix(hex)
const buff = Buffer.from(stripped, 'hex')
return buff.toString('utf8')
} catch (e) {
return hex
}
}

View File

@ -39,15 +39,17 @@ HexAsDecimalInput.prototype.render = function () {
}, },
}, [ }, [
h('input.ether-balance.ether-balance-amount', { h('input.ether-balance.ether-balance-amount', {
type: 'number',
style: extend({ style: extend({
display: 'block', display: 'block',
textAlign: 'right', textAlign: 'right',
backgroundColor: 'transparent', backgroundColor: 'transparent',
border: '1px solid #bdbdbd', border: '1px solid #bdbdbd',
}, style), }, style),
value: decimalValue, value: decimalValue,
onChange: (event) => { onChange: (event) => {
const hexString = hexify(event.target.value) const hexString = (event.target.value === '') ? '' : hexify(event.target.value)
onChange(hexString) onChange(hexString)
}, },
}), }),
@ -70,7 +72,11 @@ function hexify (decimalString) {
} }
function decimalize (input, toEth) { function decimalize (input, toEth) {
const strippedInput = ethUtil.stripHexPrefix(input) if (input === '') {
const inputBN = new BN(strippedInput, 'hex') return ''
return inputBN.toString(10) } else {
const strippedInput = ethUtil.stripHexPrefix(input)
const inputBN = new BN(strippedInput, 'hex')
return inputBN.toString(10)
}
} }

View File

@ -3,6 +3,7 @@ const h = require('react-hyperscript')
const inherits = require('util').inherits const inherits = require('util').inherits
const AccountPanel = require('./account-panel') const AccountPanel = require('./account-panel')
const BinaryRenderer = require('./binary-renderer')
module.exports = PendingMsgDetails module.exports = PendingMsgDetails
@ -41,18 +42,7 @@ PendingMsgDetails.prototype.render = function () {
// message data // message data
h('div', [ h('div', [
h('label.font-small', { style: { display: 'block' } }, 'MESSAGE'), h('label.font-small', { style: { display: 'block' } }, 'MESSAGE'),
h('textarea.font-small', { h(BinaryRenderer, { value: data }),
readOnly: true,
style: {
width: '315px',
maxHeight: '210px',
resize: 'none',
border: 'none',
background: 'white',
padding: '3px',
},
defaultValue: data,
}),
]), ]),
]) ])

View File

@ -32,10 +32,8 @@ PTXP.render = function () {
var account = props.accounts[address] var account = props.accounts[address]
var balance = account ? account.balance : '0x0' var balance = account ? account.balance : '0x0'
const gas = state.gas || txParams.gas const gas = (state.gas === undefined) ? txParams.gas : state.gas
const gasPrice = state.gasPrice || txData.gasPrice const gasPrice = (state.gasPrice === undefined) ? txData.gasPrice : state.gasPrice
const gasDefault = txParams.gas
const gasPriceDefault = txData.gasPrice
var txFee = state.txFee || txData.txFee || '' var txFee = state.txFee || txData.txFee || ''
var maxCost = state.maxCost || txData.maxCost || '' var maxCost = state.maxCost || txData.maxCost || ''
@ -131,11 +129,7 @@ PTXP.render = function () {
}, },
onChange: (newHex) => { onChange: (newHex) => {
log.info(`Gas limit changed to ${newHex}`) log.info(`Gas limit changed to ${newHex}`)
if (newHex === '0x0') { this.setState({ gas: newHex })
this.setState({gas: gasDefault})
} else {
this.setState({ gas: newHex })
}
}, },
}), }),
]), ]),
@ -155,11 +149,7 @@ PTXP.render = function () {
}, },
onChange: (newHex) => { onChange: (newHex) => {
log.info(`Gas price changed to: ${newHex}`) log.info(`Gas price changed to: ${newHex}`)
if (newHex === '0x0') { this.setState({ gasPrice: newHex })
this.setState({gasPrice: gasPriceDefault})
} else {
this.setState({ gasPrice: newHex })
}
}, },
}), }),
]), ]),
@ -316,7 +306,6 @@ PTXP.gatherParams = function () {
const state = this.state || {} const state = this.state || {}
const txData = state.txData || props.txData const txData = state.txData || props.txData
const txParams = txData.txParams const txParams = txData.txParams
const gas = state.gas || txParams.gas const gas = state.gas || txParams.gas
const gasPrice = state.gasPrice || txParams.gasPrice const gasPrice = state.gasPrice || txParams.gasPrice
const resultTx = extend(txParams, { const resultTx = extend(txParams, {
@ -330,6 +319,16 @@ PTXP.gatherParams = function () {
return resultTxMeta return resultTxMeta
} }
PTXP.verifyGasParams = function () {
// We call this in case the gas has not been modified at all
if (!this.state) { return true }
return this._notZeroOrEmptyString(this.state.gas) && this._notZeroOrEmptyString(this.state.gasPrice)
}
PTXP._notZeroOrEmptyString = function (obj) {
return obj !== '' && obj !== '0x0'
}
function forwardCarrat () { function forwardCarrat () {
return ( return (

View File

@ -1,10 +1,18 @@
const Component = require('react').Component const Component = require('react').Component
const connect = require('react-redux').connect
const h = require('react-hyperscript') const h = require('react-hyperscript')
const inherits = require('util').inherits const inherits = require('util').inherits
const PendingTxDetails = require('./pending-tx-details') const PendingTxDetails = require('./pending-tx-details')
const extend = require('xtend') const extend = require('xtend')
const actions = require('../actions')
module.exports = PendingTx module.exports = connect(mapStateToProps)(PendingTx)
function mapStateToProps (state) {
return {
}
}
inherits(PendingTx, Component) inherits(PendingTx, Component)
function PendingTx () { function PendingTx () {
@ -60,25 +68,31 @@ PendingTx.prototype.render = function () {
}, [ }, [
props.insufficientBalance ? props.insufficientBalance ?
h('button.btn-green', { h('button', {
onClick: props.buyEth, onClick: props.buyEth,
}, 'Buy Ether') }, 'Buy Ether')
: null, : null,
h('button.confirm', {
disabled: props.insufficientBalance,
onClick: props.sendTransaction,
}, 'Accept'),
h('button.cancel.btn-red', {
onClick: props.cancelTransaction,
}, 'Reject'),
h('button', { h('button', {
onClick: () => { onClick: () => {
this.refs.details.resetGasFields() this.refs.details.resetGasFields()
}, },
}, 'Reset'), }, 'Reset'),
h('button.confirm.btn-green', {
disabled: props.insufficientBalance,
onClick: (txData, event) => {
if (this.refs.details.verifyGasParams()) {
props.sendTransaction(txData, event)
} else {
this.props.dispatch(actions.displayWarning('Invalid Gas Parameters'))
}
},
}, 'Accept'),
h('button.cancel.btn-red', {
onClick: props.cancelTransaction,
}, 'Reject'),
]), ]),
]) ])
) )