Browse Source

Better error message precision

- differenciate between wrong app & wrong account
- unify isCurrencyAppOpened back into getAddress (making it more strong for bitcoin related apps)
master
Gaëtan Renaudeau 7 years ago
parent
commit
16c96c19d0
  1. 2
      src/commands/index.js
  2. 53
      src/commands/isCurrencyAppOpened.js
  3. 11
      src/components/DeviceConnect/index.js
  4. 3
      src/components/DeviceConnect/stories.js
  5. 42
      src/components/EnsureDeviceApp/index.js
  6. 1
      src/components/modals/Send/SendModalBody.js
  7. 3
      src/components/modals/StepConnectDevice.js
  8. 10
      src/helpers/getAddressForCurrency/btc.js

2
src/commands/index.js

@ -12,7 +12,6 @@ import installApp from 'commands/installApp'
import installFinalFirmware from 'commands/installFinalFirmware'
import installMcu from 'commands/installMcu'
import installOsuFirmware from 'commands/installOsuFirmware'
import isCurrencyAppOpened from 'commands/isCurrencyAppOpened'
import isDashboardOpen from 'commands/isDashboardOpen'
import libcoreGetVersion from 'commands/libcoreGetVersion'
import libcoreScanAccounts from 'commands/libcoreScanAccounts'
@ -37,7 +36,6 @@ const all: Array<Command<any, any>> = [
installFinalFirmware,
installMcu,
installOsuFirmware,
isCurrencyAppOpened,
isDashboardOpen,
libcoreGetVersion,
libcoreScanAccounts,

53
src/commands/isCurrencyAppOpened.js

@ -1,53 +0,0 @@
// @flow
import { getCryptoCurrencyById } from '@ledgerhq/live-common/lib/helpers/currencies'
import { createCommand, Command } from 'helpers/ipc'
import { fromPromise } from 'rxjs/observable/fromPromise'
import { withDevice } from 'helpers/deviceAccess'
import getBitcoinLikeInfo from 'helpers/devices/getBitcoinLikeInfo'
import getAddress from 'helpers/getAddressForCurrency'
import { standardDerivation } from 'helpers/derivations'
type Input = {
devicePath: string,
currencyId: string,
}
type Result = boolean
const cmd: Command<Input, Result> = createCommand(
'isCurrencyAppOpened',
({ devicePath, currencyId }) =>
fromPromise(
withDevice(devicePath)(async transport => {
const currency = getCryptoCurrencyById(currencyId)
// First, we check if the app can derivates on the currency
try {
await getAddress(
transport,
currency,
standardDerivation({ currency, segwit: false, x: 0 }),
{ segwit: false },
)
// then, just in case of BTC, we need to make sure we are on the correct BTC fork
const { bitcoinLikeInfo } = currency
if (bitcoinLikeInfo) {
const { P2SH, P2PKH } = await getBitcoinLikeInfo(transport)
return P2SH === bitcoinLikeInfo.P2SH && P2PKH === bitcoinLikeInfo.P2PKH
}
// in case of ETH / XRP, the address derivation is enough
return true
} catch (e) {
// if anything failed, it does not pass
return false
}
}),
),
)
export default cmd

11
src/components/DeviceConnect/index.js

@ -138,7 +138,6 @@ StepCheck.defaultProps = {
}
type Props = {
accountName: null | string,
appOpened: null | 'success' | 'fail',
genuineCheckStatus: null | 'success' | 'fail',
withGenuineCheck: boolean,
@ -188,7 +187,6 @@ class DeviceConnect extends PureComponent<Props> {
withGenuineCheck,
appOpened,
errorMessage,
accountName,
currency,
t,
onChangeDevice,
@ -311,14 +309,7 @@ class DeviceConnect extends PureComponent<Props> {
<Info hasErrors>
<IconInfoCircle size={12} />
<Box shrink selectable>
{accountName ? (
<Trans i18nKey="deviceConnect:info" parent="div">
{'You must use the device associated to the account '}
<strong>{accountName}</strong>
</Trans>
) : (
String(errorMessage || '')
)}
{String(errorMessage || '')}
</Box>
</Info>
) : null}

3
src/components/DeviceConnect/stories.js

@ -2,7 +2,7 @@
import React from 'react'
import { storiesOf } from '@storybook/react'
import { boolean, select, text } from '@storybook/addon-knobs'
import { select } from '@storybook/addon-knobs'
import { action } from '@storybook/addon-actions'
import {
getCryptoCurrencyById,
@ -45,7 +45,6 @@ stories.add('DeviceConnect', () => (
{({ currency }) => (
<DeviceConnect
currency={currency}
accountName={boolean('withAccount', true) ? text('accountName', 'Test Account') : null}
appOpened={select('appOpened', ['', 'success', 'fail'], '')}
devices={devices.slice(0, Number(select('devices', [0, 1, 2, 3], '0')))}
deviceSelected={devices[select('deviceSelected', ['', 0, 1, 2], '')] || null}

42
src/components/EnsureDeviceApp/index.js

@ -2,6 +2,7 @@
import { PureComponent } from 'react'
import { connect } from 'react-redux'
import logger from 'logger'
import invariant from 'invariant'
import { isSegwitAccount } from 'helpers/bip32'
import type { Account, CryptoCurrency } from '@ledgerhq/live-common/lib/types'
@ -10,7 +11,7 @@ import type { Device } from 'types/common'
import { getDevices } from 'reducers/devices'
import type { State as StoreState } from 'reducers/index'
import getAddress from 'commands/getAddress'
import isCurrencyAppOpened from 'commands/isCurrencyAppOpened'
import { standardDerivation } from 'helpers/derivations'
import isDashboardOpen from 'commands/isDashboardOpen'
import { CHECK_APP_INTERVAL_WHEN_VALID, CHECK_APP_INTERVAL_WHEN_INVALID } from 'config/constants'
@ -116,31 +117,42 @@ class EnsureDeviceApp extends PureComponent<Props, State> {
let isSuccess = true
try {
if (account) {
if (account || currency) {
const cur = account ? account.currency : currency
invariant(cur, 'currency is available')
const { address } = await getAddress
.send({
devicePath: deviceSelected.path,
currencyId: account.currency.id,
path: account.freshAddressPath,
segwit: isSegwitAccount(account),
currencyId: cur.id,
path: account
? account.freshAddressPath
: standardDerivation({ currency: cur, segwit: false, x: 0 }),
segwit: account ? isSegwitAccount(account) : false,
})
.toPromise()
.catch(e => {
if (
e &&
(e.name === 'TransportStatusError' ||
// we don't want these error to appear (caused by usb disconnect..)
e.message === 'could not read from HID device' ||
e.message === 'Cannot write to HID device')
) {
logger.log(e)
throw new Error(`You must open application ‘${cur.name}’ on the device`)
}
throw e
})
if (account) {
const { freshAddress } = account
if (account && freshAddress !== address) {
logger.warn({ freshAddress, address })
throw new Error('Account address is different than device address')
throw new Error(`You must use the device associated to the account ‘${account.name}`)
}
} else if (currency) {
const pass = await isCurrencyAppOpened
.send({
devicePath: deviceSelected.path,
currencyId: currency.id,
})
.toPromise()
if (!pass) {
throw new Error(`${currency.name} app is not opened on the device`)
}
} else {
// FIXME REMOVE THIS ! should use EnsureDashboard dedicated component.
const isDashboard = isDashboardOpen.send({ devicePath: deviceSelected.path }).toPromise()
if (!isDashboard) {

1
src/components/modals/Send/SendModalBody.js

@ -300,7 +300,6 @@ class SendModalBody extends PureComponent<Props, State<*>> {
<StepConnectDevice
t={t}
account={account}
accountName={account && account.name}
deviceSelected={deviceSelected}
onChangeDevice={this.onChangeDevice}
onStatusChange={this.onChangeStatus}

3
src/components/modals/StepConnectDevice.js

@ -9,7 +9,6 @@ import DeviceConnect from 'components/DeviceConnect'
import EnsureDeviceApp from 'components/EnsureDeviceApp'
type Props = {
accountName?: string,
account?: ?Account,
currency?: ?CryptoCurrency,
deviceSelected?: ?Device,
@ -20,7 +19,6 @@ type Props = {
const StepConnectDevice = ({
account,
currency,
accountName,
deviceSelected,
onChangeDevice,
onStatusChange,
@ -32,7 +30,6 @@ const StepConnectDevice = ({
onStatusChange={onStatusChange}
render={({ currency, appStatus, devices, deviceSelected, errorMessage }) => (
<DeviceConnect
accountName={accountName}
currency={currency}
appOpened={appStatus === 'success' ? 'success' : appStatus === 'fail' ? 'fail' : null}
devices={devices}

10
src/helpers/getAddressForCurrency/btc.js

@ -3,6 +3,7 @@
import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types'
import Btc from '@ledgerhq/hw-app-btc'
import type Transport from '@ledgerhq/hw-transport'
import getBitcoinLikeInfo from '../devices/getBitcoinLikeInfo'
export default async (
transport: Transport<*>,
@ -18,5 +19,14 @@ export default async (
) => {
const btc = new Btc(transport)
const { bitcoinAddress, publicKey } = await btc.getWalletPublicKey(path, verify, segwit)
const { bitcoinLikeInfo } = currency
if (bitcoinLikeInfo) {
const { P2SH, P2PKH } = await getBitcoinLikeInfo(transport)
if (P2SH !== bitcoinLikeInfo.P2SH || P2PKH !== bitcoinLikeInfo.P2PKH) {
throw new Error(`You must open application ‘${currency.name}’ on the device`)
}
}
return { address: bitcoinAddress, path, publicKey }
}

Loading…
Cancel
Save