Commit bd7dad21 authored by Marek Kotewicz's avatar Marek Kotewicz Committed by GitHub
Browse files

refactored qr scanner (#57)

* fixing scanner warnings

* fixed #47 (details of "signTransactionHash") && fixed #49 (details blockies)

* applied review suggestions
parent 0418c48e
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
'use strict'
import { Alert } from 'react-native'
import { Actions } from 'react-native-router-flux'
import { ENABLE_SCANNER, DISABLE_SCANNER, DISABLE_SCANNER_WARNINGS, RESET_SCANNER } from '../constants/ScannerActions'
import { selectAccount } from './accounts'
import { scannedTx } from './transactions'
import transaction from '../util/transaction'
import { keccak } from '../util/native'
export function enableScanner () {
return {
type: ENABLE_SCANNER
}
}
export function disableScanner () {
return {
type: DISABLE_SCANNER
}
}
export function disableScannerWarnings () {
return {
type: DISABLE_SCANNER_WARNINGS
}
}
export function resetScanner () {
return {
type: RESET_SCANNER
}
}
export function displayScannerWarning (warning) {
return function (dispatch, getState) {
if (getState().scanner.shouldDisplayWarning) {
dispatch(disableScannerWarnings())
Alert.alert(warning, undefined, [{
text: 'OK',
onPress: () => {
dispatch(enableScanner())
}
}])
} else {
dispatch(enableScanner())
}
}
}
function findAccountWithAddress (getState, address) {
return getState().accounts.all.find(account => {
return account.address.toLowerCase() === address.toLowerCase()
})
}
export function scannerDispatch (data) {
return async function (dispatch, getState) {
if (!getState().scanner.scannerEnabled) {
return
}
dispatch(disableScanner())
try {
let txRequest = JSON.parse(data)
let account = findAccountWithAddress(getState, txRequest.data.account)
if (!account) {
dispatch(displayScannerWarning('Invalid sender address ' + txRequest.data.account))
return
}
if (txRequest.action === 'signTransaction') {
let tx = await transaction(txRequest.data.rlp)
let hash = await keccak(txRequest.data.rlp)
dispatch(selectAccount(account))
dispatch(scannedTx(hash, tx))
} else if (txRequest.action === 'signTransactionHash') {
var details = txRequest.data.details
details.isSafe = false
let hash = txRequest.data.hash
dispatch(selectAccount(account))
dispatch(scannedTx(hash, details))
} else {
dispatch(displayScannerWarning('Invalid request'))
return
}
Actions.txDetails()
dispatch(resetScanner())
} catch (e) {
console.error(e)
dispatch(displayScannerWarning('Invalid transaction' + e))
}
}
}
......@@ -39,7 +39,7 @@ export function signTx (account) {
})
Actions.qrViewTx()
},
error => console.log(error)
error => console.error(error)
)
}
}
......@@ -22,24 +22,12 @@ import AppStyles from '../styles'
export default class AccountAddress extends Component {
static propTypes = {
address: PropTypes.string.isRequired
}
state = {
address: this.props.address
}
componentWillReceiveProps (newProps) {
if (newProps.address !== this.props.address) {
this.setState({
address: newProps.address
})
}
address: PropTypes.string
}
render () {
return (
<Text selectable style={AppStyles.valueText}>0x{this.state.address}</Text>
<Text selectable style={AppStyles.valueText}>{this.props.address ? '0x' + this.props.address : 'Unknown'}</Text>
)
}
}
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
'use strict'
import React, { Component, PropTypes} from 'react'
import { Text, View, StyleSheet } from 'react-native'
import AppStyles from '../styles'
import AccountIcon from './AccountIcon'
import AccountAddress from './AccountAddress'
export default class AccountPrettyAddress extends Component {
static propTypes = {
name: PropTypes.string.isRequired,
address: PropTypes.string
}
render () {
return (
<View>
<View style={styles.row}>
<AccountIcon style={[AppStyles.icon, styles.icon]} seed={this.props.address || ''} />
<Text style={{marginTop: 5, marginLeft: 5}}>{this.props.name}</Text>
</View>
<AccountAddress address={this.props.address} />
</View>
)
}
}
const styles = StyleSheet.create({
row: {
flexDirection: 'row'
},
icon: {
width: 30,
height: 30,
borderRadius: 15
}
})
......@@ -19,41 +19,60 @@
import React, { Component, PropTypes } from 'react'
import { ScrollView, View, Text, Button } from 'react-native'
import AppStyles from '../styles'
import AccountIcon from './AccountIcon'
import AccountAddress from './AccountAddress'
import AccountPrettyAddress from './AccountPrettyAddress'
const orUnknown = (value = 'Unknown') => value
export default class Send extends Component {
static propTypes = {
nextButtonTitle: PropTypes.string.isRequired,
nextButtonDescription: PropTypes.string.isRequired,
nextButtonAction: PropTypes.func.isRequired,
txRlpHash: PropTypes.string.isRequired,
txSenderAddress: PropTypes.string.isRequired,
txRecipientAddress: PropTypes.string.isRequired,
txValue: PropTypes.string.isRequired,
txNonce: PropTypes.string.isRequired,
txGas: PropTypes.string.isRequired,
txGasPrice: PropTypes.string.isRequired,
txData: PropTypes.string.isRequired
txRecipientAddress: PropTypes.string,
txValue: PropTypes.string,
txNonce: PropTypes.string,
txGas: PropTypes.string,
txGasPrice: PropTypes.string,
txData: PropTypes.string,
isSafe: PropTypes.bool.isRequired,
txSenderName: PropTypes.string.isRequired,
txRecipientName: PropTypes.string
}
render () {
return (
<ScrollView style={AppStyles.view}>
<AccountIcon style={AppStyles.icon} seed={'0x' + this.props.txSenderAddress} />
<Text style={AppStyles.hintText}>transaction hash</Text>
<Text style={AppStyles.valueText}>0x{this.props.txRlpHash}</Text>
<Text style={AppStyles.hintText}>sender address</Text>
<AccountAddress address={this.props.txSenderAddress} />
<AccountPrettyAddress
address={this.props.txSenderAddress}
name={this.props.txSenderName}
/>
<Text style={AppStyles.hintText}>recipient address</Text>
<AccountAddress address={this.props.txRecipientAddress} />
<AccountPrettyAddress
address={this.props.txRecipientAddress}
name={orUnknown(this.props.txRecipientName)}
/>
<Text style={AppStyles.hintText}>amount to transfer (in ETH)</Text>
<Text style={AppStyles.valueText}>{this.props.txValue}</Text>
<Text style={AppStyles.valueText}>{orUnknown(this.props.txValue)}</Text>
<Text style={AppStyles.hintText}>nonce</Text>
<Text style={AppStyles.valueText}>{this.props.txNonce}</Text>
<Text style={AppStyles.valueText}>{orUnknown(this.props.txNonce)}</Text>
<Text style={AppStyles.hintText}>gas</Text>
<Text style={AppStyles.valueText}>{this.props.txGas}</Text>
<Text style={AppStyles.valueText}>{orUnknown(this.props.txGas)}</Text>
<Text style={AppStyles.hintText}>gasPrice</Text>
<Text style={AppStyles.valueText}>{this.props.txGasPrice}</Text>
<Text style={AppStyles.valueText}>{orUnknown(this.props.txGasPrice)}</Text>
<Text style={AppStyles.hintText}>data</Text>
<Text style={AppStyles.valueText}>{this.props.txData}</Text>
<Text style={AppStyles.valueText}>{orUnknown(this.props.txData)}</Text>
{
!this.props.isSafe
? <Text style={AppStyles.hintText}>
Signing this transaction is unsafe. Proceed only if this transaction comes from trusted source.
</Text>
: null
}
<View style={AppStyles.buttonContainer}>
<Button
onPress={() => this.props.nextButtonAction()}
......
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
'use strict'
export const ENABLE_SCANNER = 'SCANNER_ACTION_ENABLE_SCANNER'
export const DISABLE_SCANNER = 'SCANNER_ACTION_DISABLE_SCANNER'
export const DISABLE_SCANNER_WARNINGS = 'SCANNER_ACTION_DISABLE_SCANNER_WARNINGS'
export const RESET_SCANNER = 'SCANNER_ACTION_RESET_SCANNER'
......@@ -16,72 +16,13 @@
'use strict'
import { Alert } from 'react-native'
import { connect } from 'react-redux'
import { Actions } from 'react-native-router-flux'
import QrScanner from '../components/QrScanner'
import { selectAccount } from '../actions/accounts'
import { scannedTx } from '../actions/transactions'
import transaction from '../util/transaction'
import { keccak } from '../util/native'
import store from '../util/store'
var scanning = false
function displayAlert (text) {
Alert.alert(text, undefined, [
{ text: 'OK', onPress: () => { scanning = false } }
])
}
function findAccountWithAddress (address) {
return store.getState().accounts.all.find(account => {
return account.address.toLowerCase() === address.toLowerCase()
})
}
async function onScannedTransaction (data, dispatch) {
try {
if (scanning) {
return
}
scanning = true
let txRequest = JSON.parse(data)
if (txRequest.action === 'signTransaction') {
let account = findAccountWithAddress(txRequest.data.account)
if (!account) {
displayAlert('Invalid sender address ' + txRequest.data.account)
return
}
let tx = await transaction(txRequest.data.rlp)
let hash = await keccak(txRequest.data.rlp)
dispatch(selectAccount(account))
dispatch(scannedTx(hash, tx))
} else if (txRequest.action === 'signTransactionHash') {
let account = findAccountWithAddress(txRequest.data.account)
if (!account) {
displayAlert('Invalid sender address ' + txRequest.data.account)
return
}
let details = txRequest.data.details
let hash = txRequest.data.hash
dispatch(selectAccount(account))
dispatch(scannedTx(hash, details))
} else {
displayAlert('Invalid request')
return
}
Actions.txDetails()
scanning = false
} catch (e) {
console.log(e)
displayAlert('Invalid transaction ' + e)
}
}
import { scannerDispatch } from '../actions/scanner'
const mapDispatchToProps = (dispatch, ownProps) => ({
onBarCodeRead: (scanned) => {
onScannedTransaction(scanned.data, dispatch)
dispatch(scannerDispatch(scanned.data))
}
})
......
......@@ -20,16 +20,27 @@ import { connect } from 'react-redux'
import { Actions } from 'react-native-router-flux'
import TxDetails from '../components/TxDetails'
const fetchAccountName = (state, address = '') => {
let account = state.accounts.all.find(account => {
return account.address.toLowerCase() === address.toLowerCase()
})
return account ? account.name : 'Unknown'
}
const mapStateToProps = (state, ownProps) => ({
nextButtonTitle: 'Next',
nextButtonDescription: 'Enter Pin',
txRlpHash: state.transactions.pendingTransaction.rlpHash,
txSenderAddress: state.accounts.selected.address,
txRecipientAddress: state.transactions.pendingTransaction.transaction.action,
txValue: state.transactions.pendingTransaction.transaction.value,
txNonce: state.transactions.pendingTransaction.transaction.nonce,
txGas: state.transactions.pendingTransaction.transaction.gas,
txGasPrice: state.transactions.pendingTransaction.transaction.gasPrice,
txData: state.transactions.pendingTransaction.transaction.data
txData: state.transactions.pendingTransaction.transaction.data,
isSafe: state.transactions.pendingTransaction.transaction.isSafe,
txSenderName: fetchAccountName(state, state.accounts.selected.address),
txRecipientName: fetchAccountName(state, state.transactions.pendingTransaction.transaction.action)
})
const mapDispatchToProps = (dispatch, ownProps) => ({
......
......@@ -19,10 +19,12 @@
import { combineReducers } from 'redux'
import accounts from './accounts'
import routes from './routes'
import scanner from './scanner'
import transactions from './transactions'
export default combineReducers({
accounts,
routes,
scanner,
transactions
})
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
'use strict'
import { ENABLE_SCANNER, DISABLE_SCANNER, DISABLE_SCANNER_WARNINGS, RESET_SCANNER } from '../constants/ScannerActions'
const initialState = {
scannerEnabled: true,
shouldDisplayWarning: true
}
export default function scanner (state = initialState, action) {
switch (action.type) {
case ENABLE_SCANNER:
return {
...state,
scannerEnabled: true
}
case DISABLE_SCANNER:
return {
...state,
scannerEnabled: false
}
case DISABLE_SCANNER_WARNINGS:
return {
...state,
shouldDisplayWarning: false
}
case RESET_SCANNER:
return {
...state,
scannerEnabled: false,
shouldDisplayWarning: false
}
default:
return state
}
}
......@@ -25,6 +25,7 @@ class Transaction {
this.action = action
this.value = fromWei(value)
this.data = data || '-'
this.isSafe = true
}
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment