From 905c5998e664c156e6d33fe064bb868cf4fd0813 Mon Sep 17 00:00:00 2001 From: meriadec Date: Mon, 25 Jun 2018 16:50:41 +0200 Subject: [PATCH] Create EnsureDeviceAppInteraction --- src/components/EnsureDeviceAppInteraction.js | 118 +++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 src/components/EnsureDeviceAppInteraction.js diff --git a/src/components/EnsureDeviceAppInteraction.js b/src/components/EnsureDeviceAppInteraction.js new file mode 100644 index 00000000..fcc79996 --- /dev/null +++ b/src/components/EnsureDeviceAppInteraction.js @@ -0,0 +1,118 @@ +// @flow + +import React, { Component } from 'react' +import invariant from 'invariant' +import { connect } from 'react-redux' +import type { Account, CryptoCurrency } from '@ledgerhq/live-common/lib/types' +import { getCryptoCurrencyIcon } from '@ledgerhq/live-common/lib/react' + +import logger from 'logger' +import { createCancelablePolling } from 'helpers/promise' +import { standardDerivation } from 'helpers/derivations' +import { isSegwitAccount } from 'helpers/bip32' +import DeviceInteraction from 'components/DeviceInteraction' +import getAddress from 'commands/getAddress' +import IconUsb from 'icons/Usb' + +import type { Device } from 'types/common' + +import { createCustomErrorClass } from 'helpers/errors' +import { getCurrentDevice } from 'reducers/devices' + +export const WrongAppOpened = createCustomErrorClass('WrongAppOpened') +export const WrongDeviceForAccount = createCustomErrorClass('WrongDeviceForAccount') + +const usbIcon = + +const mapStateToProps = state => ({ + device: getCurrentDevice(state), +}) + +class EnsureDeviceAppInteraction extends Component<{ + device: ?Device, + account?: ?Account, + currency?: ?CryptoCurrency, +}> { + connectInteractionHandler = () => + createCancelablePolling(() => { + if (!this.props.device) return Promise.reject() + return Promise.resolve(this.props.device) + }) + + openAppInteractionHandler = ({ device }) => + createCancelablePolling(async () => { + const { account, currency } = this.props + const cur = account ? account.currency : currency + invariant(cur, 'No currency given') + const { address } = await getAddress + .send({ + devicePath: device.path, + 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') + ) { + throw new WrongAppOpened(`WrongAppOpened ${cur.id}`, { currencyName: cur.name }) + } + throw e + }) + + if (account) { + const { freshAddress } = account + if (account && freshAddress !== address) { + logger.warn({ freshAddress, address }) + throw new WrongDeviceForAccount(`WrongDeviceForAccount ${account.name}`, { + accountName: account.name, + }) + } + } + return address + }) + + renderOpenAppTitle = ({ device }) => { + const { account, currency } = this.props + const cur = account ? account.currency : currency + invariant(cur, 'No currency given') + return `Open the ${cur.name} app on your ${device ? `${device.product} ` : 'device'}` + } + + render() { + const { account, currency, ...props } = this.props + const cur = account ? account.currency : currency + const Icon = cur ? getCryptoCurrencyIcon(cur) : null + return ( + : null, + run: this.openAppInteractionHandler, + }, + ]} + {...props} + /> + ) + } +} + +export default connect(mapStateToProps)(EnsureDeviceAppInteraction)