Browse Source

Put back QR code address scanning and enforce scan security

This commit prevent scanning non-EIP addresses, or more generally
prevent scanning address that generate warning for recipient (currently
the only possible warning is for non-EIP address for ETH/ETC).

If the warning-address is entered with keyboard instead of scanning, it
will still display the warning (as now), the behaviour doesnt change.

Closes #1412
Closes #1406
master
meriadec 6 years ago
parent
commit
fdb3905706
No known key found for this signature in database GPG Key ID: 1D2FC2305E2CB399
  1. 2
      src/components/QRCodeCameraPickerCanvas.js
  2. 4
      src/components/RecipientAddress/index.js
  3. 2
      src/components/modals/AddAccounts/steps/04-step-finish.js
  4. 33
      src/components/modals/Send/fields/RecipientField.js
  5. 1
      src/config/errors.js
  6. 3
      static/i18n/en/errors.json

2
src/components/QRCodeCameraPickerCanvas.js

@ -156,7 +156,7 @@ export default class QRCodeCameraPickerCanvas extends Component<
.catch(e => {
if (this.unmounted) return
this.setState({
message: String(e.message || e),
message: String(e.message || e.name || e),
})
})
}

4
src/components/RecipientAddress/index.js

@ -47,7 +47,7 @@ const BackgroundLayer = styled(Box)`
type Props = {
value: string,
// return false if it can't be changed (invalid info)
onChange: (string, ?{ amount?: BigNumber, currency?: CryptoCurrency }) => ?boolean,
onChange: (string, ?{ amount?: BigNumber, currency?: CryptoCurrency }) => Promise<?boolean>,
withQrCode: boolean,
}
@ -76,6 +76,8 @@ class RecipientAddress extends PureComponent<Props, State> {
handleOnPick = (code: string) => {
const { address, ...rest } = decodeURIScheme(code)
// $FlowFixMe
Object.assign(rest, { fromQRCode: true })
if (this.props.onChange(address, rest) !== false) {
this.setState({ qrReaderOpened: false })
}

2
src/components/modals/AddAccounts/steps/04-step-finish.js

@ -52,7 +52,7 @@ export default StepFinish
export const StepFinishFooter = ({ onGoStep1, t }: StepProps) => (
<Fragment>
<Button mr={2} primary onClick={onGoStep1}>
<Button primary onClick={onGoStep1}>
{t('app:addAccounts.cta.addMore')}
</Button>
</Fragment>

33
src/components/modals/Send/fields/RecipientField.js

@ -10,6 +10,7 @@ import LabelWithExternalIcon from 'components/base/LabelWithExternalIcon'
import RecipientAddress from 'components/RecipientAddress'
import { track } from 'analytics/segment'
import { createCustomErrorClass } from 'helpers/errors'
import { CantScanQRCode } from 'config/errors'
type Props<Transaction> = {
t: T,
@ -24,11 +25,12 @@ const InvalidAddress = createCustomErrorClass('InvalidAddress')
class RecipientField<Transaction> extends Component<
Props<Transaction>,
{ isValid: boolean, warning: ?Error },
{ isValid: boolean, warning: ?Error, QRCodeRefusedReason: ?Error },
> {
state = {
isValid: true,
warning: null,
QRCodeRefusedReason: null,
}
componentDidMount() {
this.resync()
@ -43,7 +45,9 @@ class RecipientField<Transaction> extends Component<
}
componentWillUnmount() {
this.syncId++
this.isUnmounted = true
}
isUnmounted = false
syncId = 0
async resync() {
const { account, bridge, transaction } = this.props
@ -52,18 +56,31 @@ class RecipientField<Transaction> extends Component<
const isValid = await bridge.isRecipientValid(account.currency, recipient)
const warning = await bridge.getRecipientWarning(account.currency, recipient)
if (syncId !== this.syncId) return
if (this.isUnmounted) return
this.setState({ isValid, warning })
}
onChange = (recipient: string, maybeExtra: ?Object) => {
onChange = async (recipient: string, maybeExtra: ?Object) => {
const { bridge, account, transaction, onChangeTransaction } = this.props
const { amount, currency } = maybeExtra || {}
const { QRCodeRefusedReason } = this.state
const { amount, currency, fromQRCode } = maybeExtra || {}
if (currency && currency.scheme !== account.currency.scheme) return false
let t = transaction
if (amount) {
t = bridge.editTransactionAmount(account, t, amount)
}
t = bridge.editTransactionRecipient(account, t, recipient)
const warning = fromQRCode
? await bridge.getRecipientWarning(account.currency, recipient)
: null
if (this.isUnmounted) return false
if (warning) {
// clear the input if field has warning AND has a warning
t = bridge.editTransactionRecipient(account, t, '')
this.setState({ QRCodeRefusedReason: new CantScanQRCode() })
} else {
t = bridge.editTransactionRecipient(account, t, recipient)
if (QRCodeRefusedReason) this.setState({ QRCodeRefusedReason: null })
}
onChangeTransaction(t)
return true
}
@ -74,11 +91,13 @@ class RecipientField<Transaction> extends Component<
}
render() {
const { bridge, account, transaction, t, autoFocus } = this.props
const { isValid, warning } = this.state
const { isValid, warning, QRCodeRefusedReason } = this.state
const value = bridge.getTransactionRecipient(account, transaction)
const error =
!value || isValid ? null : new InvalidAddress(null, { currencyName: account.currency.name })
!value || isValid
? QRCodeRefusedReason
: new InvalidAddress(null, { currencyName: account.currency.name })
return (
<Box flow={1}>
@ -88,7 +107,7 @@ class RecipientField<Transaction> extends Component<
/>
<RecipientAddress
autoFocus={autoFocus}
withQrCode={false}
withQrCode
error={error}
warning={warning}
value={value}

1
src/config/errors.js

@ -14,6 +14,7 @@ export const DeviceNotGenuineError = createCustomErrorClass('DeviceNotGenuine')
export const DeviceGenuineSocketEarlyClose = createCustomErrorClass('DeviceGenuineSocketEarlyClose')
export const TimeoutTagged = createCustomErrorClass('TimeoutTagged')
export const ETHAddressNonEIP = createCustomErrorClass('ETHAddressNonEIP')
export const CantScanQRCode = createCustomErrorClass('CantScanQRCode')
// db stuff, no need to translate
export const NoDBPathGiven = createCustomErrorClass('NoDBPathGiven')

3
static/i18n/en/errors.json

@ -165,5 +165,8 @@
"ETHAddressNonEIP": {
"title": "Auto-verification not available: carefully verify the address",
"description": null
},
"CantScanQRCode": {
"title": "Couldn't scan this QR-code: auto-verification not supported by this address"
}
}

Loading…
Cancel
Save