Browse Source

internals refactoring & rename DeviceMonitNew to EnsureDeviceApp

master
Gaëtan Renaudeau 7 years ago
parent
commit
481c057b28
  1. 125
      src/components/DeviceMonit/index.js
  2. 10
      src/components/EnsureDeviceApp/index.js
  3. 4
      src/components/modals/StepConnectDevice.js
  4. 13
      src/internals/accounts/helpers.js
  5. 54
      src/internals/devices/checkIfAppOpened.js
  6. 36
      src/internals/devices/ensureDeviceApp.js
  7. 23
      src/internals/devices/getAddressForCurrency/btc.js
  8. 17
      src/internals/devices/getAddressForCurrency/ethereum.js
  9. 28
      src/internals/devices/getAddressForCurrency/index.js
  10. 2
      src/internals/devices/index.js

125
src/components/DeviceMonit/index.js

@ -1,125 +0,0 @@
// @flow
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { ipcRenderer } from 'electron'
import type { Account } from '@ledgerhq/live-common/lib/types'
import { sendEvent } from 'renderer/events'
import { getCurrentDevice } from 'reducers/devices'
import type { Device } from 'types/common'
import type { State as StoreState } from 'reducers'
type DeviceStatus = 'unconnected' | 'connected' | 'appOpened'
type OwnProps = {
account?: Account,
onStatusChange?: DeviceStatus => void,
// FIXME prefer use of children function
render?: DeviceStatus => React$Element<*>,
}
type Props = OwnProps & {
currentDevice: ?Device,
}
type State = {
status: DeviceStatus,
}
const mapStateToProps = (state: StoreState, _props: OwnProps) => ({
currentDevice: getCurrentDevice(state),
})
class DeviceMonit extends PureComponent<Props, State> {
state = {
status: this.props.currentDevice ? 'connected' : 'unconnected',
}
componentDidMount() {
ipcRenderer.on('msg', this.handleMsgEvent)
if (this.props.currentDevice !== null) {
this.checkAppOpened()
}
}
componentWillReceiveProps(nextProps) {
const { status } = this.state
const { currentDevice } = this.props
const { currentDevice: nextCurrentDevice } = nextProps
if (status === 'unconnected' && !currentDevice && nextCurrentDevice) {
this.handleStatusChange('connected')
}
if (status !== 'unconnected' && !nextCurrentDevice) {
this.handleStatusChange('unconnected')
}
}
componentDidUpdate() {
const { currentDevice } = this.props
if (currentDevice !== null) {
this.checkAppOpened()
} else {
clearTimeout(this._timeout)
}
}
componentWillUnmount() {
ipcRenderer.removeListener('msg', this.handleMsgEvent)
clearTimeout(this._timeout)
}
checkAppOpened = () => {
const { currentDevice, account } = this.props
if (!currentDevice || !account) {
return
}
sendEvent('devices', 'checkIfAppOpened', {
devicePath: currentDevice.path,
accountPath: account.path,
accountAddress: account.address,
segwit: account.path.startsWith("49'"), // TODO: store segwit info in account
})
}
_timeout: any = null
handleStatusChange = (status: DeviceStatus) => {
const { onStatusChange } = this.props
this.setState({ status })
onStatusChange && onStatusChange(status)
}
handleMsgEvent = (e, { type }) => {
if (type === 'devices.checkIfAppOpened.success') {
this.handleStatusChange('appOpened')
clearTimeout(this._timeout)
}
if (type === 'devices.checkIfAppOpened.fail') {
this._timeout = setTimeout(this.checkAppOpened, 1e3)
}
}
render() {
const { status } = this.state
const { render } = this.props
if (render) {
return render(status)
}
return (
<div>
<div>device connected {status !== 'unconnected' ? 'TRUE' : 'FALSE'}</div>
<div>app opened {status === 'appOpened' ? 'TRUE' : 'FALSE'}</div>
</div>
)
}
}
export default connect(mapStateToProps)(DeviceMonit)

10
src/components/DeviceMonitNew/index.js → src/components/EnsureDeviceApp/index.js

@ -43,7 +43,7 @@ const mapStateToProps = (state: StoreState) => ({
devices: getDevices(state),
})
class DeviceMonit extends PureComponent<Props, State> {
class EnsureDeviceApp extends PureComponent<Props, State> {
state = {
appStatus: 'progress',
deviceStatus: this.props.deviceSelected ? 'connected' : 'unconnected',
@ -110,7 +110,7 @@ class DeviceMonit extends PureComponent<Props, State> {
}
}
sendEvent('devices', 'checkIfAppOpened', {
sendEvent('devices', 'ensureDeviceApp', {
devicePath: deviceSelected.path,
...options,
})
@ -133,12 +133,12 @@ class DeviceMonit extends PureComponent<Props, State> {
return
}
if (type === 'devices.checkIfAppOpened.success' && deviceSelected.path === data.devicePath) {
if (type === 'devices.ensureDeviceApp.success' && deviceSelected.path === data.devicePath) {
this.handleStatusChange(deviceStatus, 'success')
this._timeout = setTimeout(this.checkAppOpened, 1e3)
}
if (type === 'devices.checkIfAppOpened.fail' && deviceSelected.path === data.devicePath) {
if (type === 'devices.ensureDeviceApp.fail' && deviceSelected.path === data.devicePath) {
this.handleStatusChange(deviceStatus, 'fail')
this._timeout = setTimeout(this.checkAppOpened, 1e3)
}
@ -164,4 +164,4 @@ class DeviceMonit extends PureComponent<Props, State> {
}
}
export default connect(mapStateToProps)(DeviceMonit)
export default connect(mapStateToProps)(EnsureDeviceApp)

4
src/components/modals/StepConnectDevice.js

@ -6,7 +6,7 @@ import type { Account, CryptoCurrency } from '@ledgerhq/live-common/lib/types'
import type { Device } from 'types/common'
import DeviceConnect from 'components/DeviceConnect'
import DeviceMonit from 'components/DeviceMonitNew'
import EnsureDeviceApp from 'components/EnsureDeviceApp'
type Props = {
accountName?: string,
@ -25,7 +25,7 @@ const StepConnectDevice = ({
onChangeDevice,
onStatusChange,
}: Props) => (
<DeviceMonit
<EnsureDeviceApp
account={account}
currency={currency}
deviceSelected={deviceSelected}

13
src/internals/accounts/helpers.js

@ -4,10 +4,15 @@
import Btc from '@ledgerhq/hw-app-btc'
const coinTypeCurrencyMap = {
bitcoin: 0,
ethereum: 60,
bitcoin_testnet: 1,
ethereum_testnet: 1,
}
export function coinTypeForId(id: string) {
if (id === 'bitcoin_testnet') return 1
if (id === 'bitcoin') return 0
throw new Error('coinTypeForId is a hack and will disappear with libcore')
return coinTypeCurrencyMap[id]
}
export function getPath({
@ -17,7 +22,7 @@ export function getPath({
}: {
currencyId: string,
account?: any,
segwit: boolean,
segwit?: boolean,
}) {
return `${segwit ? 49 : 44}'/${coinTypeForId(currencyId)}'${
account !== undefined ? `/${account}'` : ''

54
src/internals/devices/checkIfAppOpened.js

@ -1,54 +0,0 @@
// @flow
import CommNodeHid from '@ledgerhq/hw-transport-node-hid'
import Btc from '@ledgerhq/hw-app-btc'
import type Transport from '@ledgerhq/hw-transport'
import type { IPCSend } from 'types/electron'
import { getPath } from 'internals/accounts/helpers'
export default async (
send: IPCSend,
{
currencyId,
devicePath,
accountPath,
accountAddress,
segwit = true,
}: {
currencyId?: string,
devicePath: string,
accountPath: string,
accountAddress: string,
segwit: boolean,
},
) => {
try {
const transport: Transport<*> = await CommNodeHid.open(devicePath)
const btc = new Btc(transport)
// FIXME code should be moved into a map, otherwise it's going to be too much spaghetti
if (currencyId === 'ethereum') {
// MOCK
send('devices.checkIfAppOpened.success', { devicePath })
return
}
if (accountPath) {
const { bitcoinAddress } = await btc.getWalletPublicKey(accountPath, false, segwit)
if (bitcoinAddress === accountAddress) {
send('devices.checkIfAppOpened.success', { devicePath })
} else {
throw new Error('Address is different')
}
}
if (currencyId) {
await btc.getWalletPublicKey(getPath({ currencyId, segwit }), false, segwit)
send('devices.checkIfAppOpened.success', { devicePath })
}
} catch (err) {
send('devices.checkIfAppOpened.fail', { devicePath })
}
}

36
src/internals/devices/ensureDeviceApp.js

@ -0,0 +1,36 @@
// @flow
import invariant from 'invariant'
import CommNodeHid from '@ledgerhq/hw-transport-node-hid'
import type Transport from '@ledgerhq/hw-transport'
import type { IPCSend } from 'types/electron'
import getAdressFromCurrency from './getAddressForCurrency'
export default async (
send: IPCSend,
{
currencyId,
devicePath,
accountPath,
accountAddress,
...options
}: {
currencyId: string,
devicePath: string,
accountPath: ?string,
accountAddress: ?string,
},
) => {
try {
invariant(currencyId, 'currencyId is defined')
const transport: Transport<*> = await CommNodeHid.open(devicePath)
const resolver = getAdressFromCurrency(currencyId)
const address = await resolver(transport, currencyId, accountPath, options)
if (accountPath && accountAddress && address !== accountAddress) {
throw new Error('Account address is different than device address')
}
send('devices.ensureDeviceApp.success', { devicePath })
} catch (err) {
send('devices.ensureDeviceApp.fail', { devicePath })
}
}

23
src/internals/devices/getAddressForCurrency/btc.js

@ -0,0 +1,23 @@
// @flow
import Btc from '@ledgerhq/hw-app-btc'
import type Transport from '@ledgerhq/hw-transport'
import { getPath } from 'internals/accounts/helpers'
export default async (
transport: Transport<*>,
currencyId: string,
bip32path: ?string,
{
segwit = true,
verify = false,
}: {
segwit: boolean,
verify: boolean,
},
) => {
const btc = new Btc(transport)
const path = bip32path || getPath({ currencyId, segwit })
const { bitcoinAddress } = await btc.getWalletPublicKey(path, verify, segwit)
return bitcoinAddress
}

17
src/internals/devices/getAddressForCurrency/ethereum.js

@ -0,0 +1,17 @@
// @flow
import Eth from '@ledgerhq/hw-app-eth'
import type Transport from '@ledgerhq/hw-transport'
import { getPath } from 'internals/accounts/helpers'
export default async (
transport: Transport<*>,
currencyId: string,
bip32path: ?string,
{ verify = false }: { verify: boolean },
) => {
const eth = new Eth(transport)
const path = bip32path || getPath({ currencyId })
const { address } = await eth.getAddress(path, verify)
return address
}

28
src/internals/devices/getAddressForCurrency/index.js

@ -0,0 +1,28 @@
// @flow
import type Transport from '@ledgerhq/hw-transport'
import btc from './btc'
type Resolver = (
transport: Transport<*>,
currencyId: string,
bip32path: ?string, // if provided use this path, otherwise resolve it
options: *,
) => Promise<string>
type Module = (currencyId: string) => Resolver
const fallback: string => Resolver = currencyId => () =>
Promise.reject(new Error(`${currencyId} device support not implemented`))
const all = {
bitcoin: btc,
bitcoin_testnet: btc,
ethereum: btc,
ethereum_testnet: btc,
}
const module: Module = (currencyId: string) => all[currencyId] || fallback(currencyId)
export default module

2
src/internals/devices/index.js

@ -1,2 +1,2 @@
export listen from './listen'
export checkIfAppOpened from './checkIfAppOpened'
export ensureDeviceApp from './ensureDeviceApp'

Loading…
Cancel
Save