diff --git a/package.json b/package.json
index 9ee3d020..9c98dca4 100644
--- a/package.json
+++ b/package.json
@@ -41,7 +41,7 @@
"@ledgerhq/hw-transport": "^4.32.0",
"@ledgerhq/hw-transport-node-hid": "^4.32.0",
"@ledgerhq/ledger-core": "2.0.0-rc.14",
- "@ledgerhq/live-common": "4.8.0-beta.4",
+ "@ledgerhq/live-common": "4.8.0-beta.12",
"animated": "^0.2.2",
"async": "^2.6.1",
"axios": "^0.18.0",
diff --git a/src/commands/.DS_Store b/src/commands/.DS_Store
new file mode 100644
index 00000000..5008ddfc
Binary files /dev/null and b/src/commands/.DS_Store differ
diff --git a/src/commands/firmwareCheckId.js b/src/commands/firmwareCheckId.js
new file mode 100644
index 00000000..17025469
--- /dev/null
+++ b/src/commands/firmwareCheckId.js
@@ -0,0 +1,19 @@
+// @flow
+
+import checkId from '@ledgerhq/live-common/lib/hw/firmwareUpdate-checkId'
+import type { OsuFirmware } from '@ledgerhq/live-common/lib/types/manager'
+import { createCommand, Command } from 'helpers/ipc'
+
+type Input = {
+ devicePath: string,
+ osuFirmware: OsuFirmware,
+}
+
+type Result = *
+
+const cmd: Command = createCommand(
+ 'firmwareCheckId',
+ ({ devicePath, osuFirmware }) => checkId(devicePath, osuFirmware),
+)
+
+export default cmd
diff --git a/src/commands/firmwareMain.js b/src/commands/firmwareMain.js
new file mode 100644
index 00000000..4397a590
--- /dev/null
+++ b/src/commands/firmwareMain.js
@@ -0,0 +1,19 @@
+// @flow
+
+import main from '@ledgerhq/live-common/lib/hw/firmwareUpdate-main'
+import type { FinalFirmware } from '@ledgerhq/live-common/lib/types/manager'
+import { createCommand, Command } from 'helpers/ipc'
+
+type Input = {
+ finalFirmware: FinalFirmware,
+}
+
+type Result = *
+
+const cmd: Command = createCommand(
+ 'firmwareMain',
+ ({ finalFirmware }) => main('', finalFirmware),
+ // devicePath='' HACK to not depend on a devicePath because it's dynamic
+)
+
+export default cmd
diff --git a/src/commands/firmwareRepair.js b/src/commands/firmwareRepair.js
new file mode 100644
index 00000000..41e34401
--- /dev/null
+++ b/src/commands/firmwareRepair.js
@@ -0,0 +1,14 @@
+// @flow
+
+import repair from '@ledgerhq/live-common/lib/hw/firmwareUpdate-repair'
+import { createCommand, Command } from 'helpers/ipc'
+
+type Input = void
+type Result = *
+
+const cmd: Command = createCommand(
+ 'firmwareRepair',
+ () => repair(''), // devicePath='' HACK to not depend on a devicePath because it's dynamic
+)
+
+export default cmd
diff --git a/src/commands/getLatestFirmwareForDevice.js b/src/commands/getLatestFirmwareForDevice.js
index e88f6a50..5dfe8a72 100644
--- a/src/commands/getLatestFirmwareForDevice.js
+++ b/src/commands/getLatestFirmwareForDevice.js
@@ -1,15 +1,18 @@
// @flow
import { createCommand, Command } from 'helpers/ipc'
-import { fromPromise } from 'rxjs/observable/fromPromise'
-import type { DeviceInfo, OsuFirmware } from 'helpers/types'
+import { from } from 'rxjs'
+import type {
+ DeviceInfo,
+ OsuFirmware,
+ FinalFirmware,
+} from '@ledgerhq/live-common/lib/types/manager'
+import manager from '@ledgerhq/live-common/lib/manager'
-import getLatestFirmwareForDevice from '../helpers/devices/getLatestFirmwareForDevice'
+type Result = ?{ osu: OsuFirmware, final: FinalFirmware }
-type Result = ?(OsuFirmware & { shouldFlashMcu: boolean })
-
-const cmd: Command = createCommand('getLatestFirmwareForDevice', data =>
- fromPromise(getLatestFirmwareForDevice(data)),
+const cmd: Command = createCommand('getLatestFirmwareForDevice', deviceInfo =>
+ from(manager.getLatestFirmwareForDevice(deviceInfo)),
)
export default cmd
diff --git a/src/commands/index.js b/src/commands/index.js
index 1022021c..a55d2bb4 100644
--- a/src/commands/index.js
+++ b/src/commands/index.js
@@ -4,6 +4,9 @@ import invariant from 'invariant'
import type { Command } from 'helpers/ipc'
import debugAppInfosForCurrency from 'commands/debugAppInfosForCurrency'
+import firmwareCheckId from 'commands/firmwareCheckId'
+import firmwareMain from 'commands/firmwareMain'
+import firmwareRepair from 'commands/firmwareRepair'
import getAddress from 'commands/getAddress'
import getDeviceInfo from 'commands/getDeviceInfo'
import getCurrentFirmware from 'commands/getCurrentFirmware'
@@ -11,9 +14,6 @@ import getIsGenuine from 'commands/getIsGenuine'
import getLatestFirmwareForDevice from 'commands/getLatestFirmwareForDevice'
import getMemInfo from 'commands/getMemInfo'
import installApp from 'commands/installApp'
-import installFinalFirmware from 'commands/installFinalFirmware'
-import installMcu from 'commands/installMcu'
-import installOsuFirmware from 'commands/installOsuFirmware'
import isDashboardOpen from 'commands/isDashboardOpen'
import killInternalProcess from 'commands/killInternalProcess'
import libcoreGetFees from 'commands/libcoreGetFees'
@@ -28,7 +28,6 @@ import listAppVersions from 'commands/listAppVersions'
import listCategories from 'commands/listCategories'
import listenDevices from 'commands/listenDevices'
import ping from 'commands/ping'
-import shouldFlashMcu from 'commands/shouldFlashMcu'
import signTransaction from 'commands/signTransaction'
import testApdu from 'commands/testApdu'
import testCrash from 'commands/testCrash'
@@ -37,6 +36,9 @@ import uninstallApp from 'commands/uninstallApp'
const all: Array> = [
debugAppInfosForCurrency,
+ firmwareCheckId,
+ firmwareMain,
+ firmwareRepair,
getAddress,
getDeviceInfo,
getCurrentFirmware,
@@ -44,9 +46,6 @@ const all: Array> = [
getLatestFirmwareForDevice,
getMemInfo,
installApp,
- installFinalFirmware,
- installMcu,
- installOsuFirmware,
isDashboardOpen,
killInternalProcess,
libcoreGetFees,
@@ -61,7 +60,6 @@ const all: Array> = [
listCategories,
listenDevices,
ping,
- shouldFlashMcu,
signTransaction,
testApdu,
testCrash,
diff --git a/src/commands/installApp.js b/src/commands/installApp.js
index 2fd3c1c4..71e04ecb 100644
--- a/src/commands/installApp.js
+++ b/src/commands/installApp.js
@@ -1,25 +1,21 @@
// @flow
import { createCommand, Command } from 'helpers/ipc'
-import { from } from 'rxjs'
+import installApp from '@ledgerhq/live-common/lib/hw/installApp'
import { withDevice } from '@ledgerhq/live-common/lib/hw/deviceAccess'
-import installApp from 'helpers/apps/installApp'
-
-import type { ApplicationVersion } from 'helpers/types'
+import type { ApplicationVersion } from '@ledgerhq/live-common/lib/types/manager'
type Input = {
- app: ApplicationVersion,
devicePath: string,
targetId: string | number,
+ app: ApplicationVersion,
}
-type Result = void
+type Result = *
-const cmd: Command = createCommand(
- 'installApp',
- ({ devicePath, targetId, ...app }) =>
- withDevice(devicePath)(transport => from(installApp(transport, targetId, app))),
+const cmd: Command = createCommand('installApp', ({ devicePath, targetId, app }) =>
+ withDevice(devicePath)(transport => installApp(transport, targetId, app)),
)
export default cmd
diff --git a/src/commands/installFinalFirmware.js b/src/commands/installFinalFirmware.js
deleted file mode 100644
index bf56eeb3..00000000
--- a/src/commands/installFinalFirmware.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// @flow
-
-import { createCommand, Command } from 'helpers/ipc'
-import { from } from 'rxjs'
-import { withDevice } from '@ledgerhq/live-common/lib/hw/deviceAccess'
-
-import installFinalFirmware from 'helpers/firmware/installFinalFirmware'
-
-type Input = {
- devicePath: string,
-}
-
-type Result = {
- success: boolean,
-}
-
-const cmd: Command = createCommand('installFinalFirmware', ({ devicePath }) =>
- withDevice(devicePath)(transport => from(installFinalFirmware(transport))),
-)
-
-export default cmd
diff --git a/src/commands/installMcu.js b/src/commands/installMcu.js
deleted file mode 100644
index 1301a68b..00000000
--- a/src/commands/installMcu.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// @flow
-
-import { createCommand, Command } from 'helpers/ipc'
-import { from } from 'rxjs'
-
-import { withDevice } from '@ledgerhq/live-common/lib/hw/deviceAccess'
-import installMcu from 'helpers/firmware/installMcu'
-
-type Input = {
- devicePath: string,
-}
-
-type Result = void
-
-const cmd: Command = createCommand('installMcu', ({ devicePath }) =>
- withDevice(devicePath)(transport => from(installMcu(transport))),
-)
-
-export default cmd
diff --git a/src/commands/installOsuFirmware.js b/src/commands/installOsuFirmware.js
deleted file mode 100644
index e306eaa4..00000000
--- a/src/commands/installOsuFirmware.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// @flow
-
-import { createCommand, Command } from 'helpers/ipc'
-import { from } from 'rxjs'
-
-import { withDevice } from '@ledgerhq/live-common/lib/hw/deviceAccess'
-import installOsuFirmware from 'helpers/firmware/installOsuFirmware'
-
-import type { Firmware } from 'components/modals/UpdateFirmware'
-
-type Input = {
- devicePath: string,
- targetId: string | number,
- firmware: Firmware,
-}
-
-type Result = { success: boolean }
-
-const cmd: Command = createCommand(
- 'installOsuFirmware',
- ({ devicePath, firmware, targetId }) =>
- withDevice(devicePath)(transport => from(installOsuFirmware(transport, targetId, firmware))),
-)
-
-export default cmd
diff --git a/src/commands/shouldFlashMcu.js b/src/commands/shouldFlashMcu.js
deleted file mode 100644
index f58c629c..00000000
--- a/src/commands/shouldFlashMcu.js
+++ /dev/null
@@ -1,15 +0,0 @@
-// @flow
-
-import { createCommand, Command } from 'helpers/ipc'
-import { fromPromise } from 'rxjs/observable/fromPromise'
-import shouldFlashMcu from 'helpers/devices/shouldFlashMcu'
-
-import type { DeviceInfo } from 'helpers/types'
-
-type Result = boolean
-
-const cmd: Command = createCommand('shouldFlashMcu', data =>
- fromPromise(shouldFlashMcu(data)),
-)
-
-export default cmd
diff --git a/src/commands/uninstallApp.js b/src/commands/uninstallApp.js
index b0b581b8..684712c3 100644
--- a/src/commands/uninstallApp.js
+++ b/src/commands/uninstallApp.js
@@ -1,10 +1,8 @@
// @flow
import { createCommand, Command } from 'helpers/ipc'
-import { from } from 'rxjs'
import { withDevice } from '@ledgerhq/live-common/lib/hw/deviceAccess'
-
-import uninstallApp from 'helpers/apps/uninstallApp'
+import uninstallApp from '@ledgerhq/live-common/lib/hw/uninstallApp'
import type { ApplicationVersion } from 'helpers/types'
@@ -14,12 +12,10 @@ type Input = {
targetId: string | number,
}
-type Result = void
+type Result = *
-const cmd: Command = createCommand(
- 'uninstallApp',
- ({ devicePath, targetId, ...app }) =>
- withDevice(devicePath)(transport => from(uninstallApp(transport, targetId, app))),
+const cmd: Command = createCommand('uninstallApp', ({ devicePath, targetId, app }) =>
+ withDevice(devicePath)(transport => uninstallApp(transport, targetId, app)),
)
export default cmd
diff --git a/src/components/GenuineCheck.js b/src/components/GenuineCheck.js
index ff02986c..76a53ba7 100644
--- a/src/components/GenuineCheck.js
+++ b/src/components/GenuineCheck.js
@@ -18,6 +18,7 @@ import {
CantOpenDevice,
DeviceNotGenuineError,
DeviceGenuineSocketEarlyClose,
+ UnexpectedBootloader,
} from '@ledgerhq/live-common/lib/errors'
import getDeviceInfo from 'commands/getDeviceInfo'
@@ -81,7 +82,12 @@ class GenuineCheck extends PureComponent {
device: Device,
deviceInfo: DeviceInfo,
}) => {
- if (deviceInfo.isOSU || deviceInfo.isBootloader) {
+ if (deviceInfo.isBootloader) {
+ logger.log('device is in bootloader mode')
+ throw new UnexpectedBootloader()
+ }
+
+ if (deviceInfo.isOSU) {
logger.log('device is in update mode. skipping genuine')
return true
}
diff --git a/src/components/ManagerPage/AppsList.js b/src/components/ManagerPage/AppsList.js
index 91443678..a155af7c 100644
--- a/src/components/ManagerPage/AppsList.js
+++ b/src/components/ManagerPage/AppsList.js
@@ -6,6 +6,8 @@ import styled from 'styled-components'
import { translate } from 'react-i18next'
import { connect } from 'react-redux'
import { compose } from 'redux'
+import { throttleTime, filter, map } from 'rxjs/operators'
+
import type { Device, T } from 'types/common'
import type { ApplicationVersion, DeviceInfo } from 'helpers/types'
import { getFullListSortedCryptoCurrencies } from 'helpers/countervalues'
@@ -19,7 +21,7 @@ import Space from 'components/base/Space'
import Modal, { ModalBody, ModalFooter, ModalTitle, ModalContent } from 'components/base/Modal'
import Tooltip from 'components/base/Tooltip'
import Text from 'components/base/Text'
-import Progress from 'components/base/Progress'
+import ProgressBar from 'components/ProgressBar'
import Spinner from 'components/base/Spinner'
import Button from 'components/base/Button'
import TranslatedError from 'components/TranslatedError'
@@ -65,6 +67,7 @@ type State = {
appsLoaded: boolean,
app: string,
mode: Mode,
+ progress: number,
}
const oldAppsInstallDisabled = ['ZenCash', 'Ripple']
@@ -86,6 +89,7 @@ class AppsList extends PureComponent {
appsLoaded: false,
app: '',
mode: 'home',
+ progress: 0,
}
componentDidMount() {
@@ -158,41 +162,44 @@ class AppsList extends PureComponent {
}
}
- handleInstallApp = (app: ApplicationVersion) => async () => {
- this.setState({ status: 'busy', app: app.name, mode: 'installing' })
- try {
- const {
- device: { path: devicePath },
- deviceInfo,
- } = this.props
- const data = { app, devicePath, targetId: deviceInfo.targetId }
- await installApp.send(data).toPromise()
- this.setState({ status: 'success' })
- } catch (err) {
- this.setState({ status: 'error', error: err, mode: 'home' })
- }
+ sub: *
+ runAppScript = (app: ApplicationVersion, mode: *, cmd: *) => {
+ this.setState({ status: 'busy', app: app.name, mode, progress: 0 })
+ const {
+ device: { path: devicePath },
+ deviceInfo: { targetId },
+ } = this.props
+ this.sub = cmd
+ .send({ app, devicePath, targetId })
+ .pipe(
+ filter(e => e.type === 'bulk-progress'), // only bulk progress interests the UI
+ throttleTime(100), // throttle to only emit 10 event/s max, to not spam the UI
+ map(e => e.progress), // extract a stream of progress percentage
+ )
+ .subscribe({
+ next: progress => {
+ this.setState({ progress })
+ },
+ complete: () => {
+ this.setState({ status: 'success' })
+ },
+ error: error => {
+ this.setState({ status: 'error', error, app: '', mode: 'home' })
+ },
+ })
}
- handleUninstallApp = (app: ApplicationVersion) => async () => {
- this.setState({ status: 'busy', app: app.name, mode: 'uninstalling' })
- try {
- const {
- device: { path: devicePath },
- deviceInfo,
- } = this.props
- const data = { app, devicePath, targetId: deviceInfo.targetId }
- await uninstallApp.send(data).toPromise()
- this.setState({ status: 'success' })
- } catch (err) {
- this.setState({ status: 'error', error: err, app: '', mode: 'home' })
- }
- }
+ handleInstallApp = (app: ApplicationVersion) => () =>
+ this.runAppScript(app, 'installing', installApp)
+
+ handleUninstallApp = (app: ApplicationVersion) => () =>
+ this.runAppScript(app, 'uninstalling', uninstallApp)
handleCloseModal = () => this.setState({ status: 'idle', mode: 'home' })
renderModal = () => {
const { t } = this.props
- const { app, status, error, mode } = this.state
+ const { app, status, error, mode, progress } = this.state
return (
{
{t(`manager.apps.${mode}`, { app })}
-
+
diff --git a/src/components/ManagerPage/FirmwareUpdate.js b/src/components/ManagerPage/FirmwareUpdate.js
index 90e997b1..e9c7fe72 100644
--- a/src/components/ManagerPage/FirmwareUpdate.js
+++ b/src/components/ManagerPage/FirmwareUpdate.js
@@ -5,18 +5,17 @@ import React, { PureComponent, Fragment } from 'react'
import { translate } from 'react-i18next'
import isEqual from 'lodash/isEqual'
import isEmpty from 'lodash/isEmpty'
-import invariant from 'invariant'
import type { Device, T } from 'types/common'
-import type { DeviceInfo, OsuFirmware } from 'helpers/types'
+import type {
+ DeviceInfo,
+ OsuFirmware,
+ FinalFirmware,
+} from '@ledgerhq/live-common/lib/types/manager'
import type { StepId } from 'components/modals/UpdateFirmware'
import getLatestFirmwareForDevice from 'commands/getLatestFirmwareForDevice'
-import shouldFlashMcu from 'commands/shouldFlashMcu'
-import installOsuFirmware from 'commands/installOsuFirmware'
-import installFinalFirmware from 'commands/installFinalFirmware'
-import installMcu from 'commands/installMcu'
import DisclaimerModal from 'components/modals/UpdateFirmware/Disclaimer'
import UpdateModal from 'components/modals/UpdateFirmware'
@@ -42,7 +41,7 @@ type Props = {
}
type State = {
- latestFirmware: ?OsuFirmware & ?{ shouldFlashMcu: boolean },
+ firmware: ?{ osu: OsuFirmware, final: FinalFirmware },
modal: ModalStatus,
stepId: ?StepId,
shouldFlash: boolean,
@@ -50,7 +49,7 @@ type State = {
}
const intializeState = ({ deviceInfo }): State => ({
- latestFirmware: null,
+ firmware: null,
modal: 'closed',
stepId: deviceInfo.isBootloader ? 'updateMCU' : 'idCheck',
shouldFlash: false,
@@ -64,9 +63,7 @@ class FirmwareUpdate extends PureComponent {
const { deviceInfo } = this.props
if (!deviceInfo.isOSU && !deviceInfo.isBootloader) {
this.fetchLatestFirmware()
- } else if (deviceInfo.isOSU) {
- this.shouldFlashMcu()
- } else if (deviceInfo.isBootloader) {
+ } else {
this.handleInstallModal('updateMCU', true)
}
}
@@ -79,45 +76,16 @@ class FirmwareUpdate extends PureComponent {
fetchLatestFirmware = async () => {
const { deviceInfo } = this.props
- const latestFirmware = await getLatestFirmwareForDevice.send(deviceInfo).toPromise()
- if (
- !isEmpty(latestFirmware) &&
- !isEqual(this.state.latestFirmware, latestFirmware) &&
- !this._unmounting
- ) {
- this.setState({ latestFirmware, ready: true })
+ const firmware = await getLatestFirmwareForDevice.send(deviceInfo).toPromise()
+ if (!isEmpty(firmware) && !isEqual(this.state.firmware, firmware) && !this._unmounting) {
+ this.setState({ firmware, ready: true })
}
}
- shouldFlashMcu = async () => {
- const { deviceInfo } = this.props
- const shouldFlash = await shouldFlashMcu.send(deviceInfo).toPromise()
- if (!this._unmounting) {
- this.setState({ shouldFlash, modal: 'install', stepId: 'idCheck', ready: true })
- }
- }
-
- installOsuFirmware = async (device: Device) => {
- const { latestFirmware } = this.state
- const { deviceInfo } = this.props
- invariant(latestFirmware, 'did not find a new firmware or firmware is not set')
-
- this.setState({ modal: 'install' })
- const result = await installOsuFirmware
- .send({ devicePath: device.path, firmware: latestFirmware, targetId: deviceInfo.targetId })
- .toPromise()
-
- return result
- }
-
- installFinalFirmware = (device: Device) =>
- installFinalFirmware.send({ devicePath: device.path }).toPromise()
-
- flashMCU = async (device: Device) => installMcu.send({ devicePath: device.path }).toPromise()
-
handleCloseModal = () => this.setState({ modal: 'closed' })
handleDisclaimerModal = () => this.setState({ modal: 'disclaimer' })
+
handleInstallModal = (stepId: StepId = 'idCheck', shouldFlash?: boolean) =>
this.setState({ modal: 'install', stepId, shouldFlash, ready: true })
@@ -125,7 +93,7 @@ class FirmwareUpdate extends PureComponent {
render() {
const { deviceInfo, t, device } = this.props
- const { latestFirmware, modal, stepId, shouldFlash, ready } = this.state
+ const { firmware, modal, stepId, shouldFlash, ready } = this.state
return (
@@ -151,12 +119,12 @@ class FirmwareUpdate extends PureComponent {
})}
-
+
{ready ? (
{
status={modal}
stepId={stepId}
onClose={this.handleCloseModal}
- firmware={latestFirmware}
+ firmware={firmware}
shouldFlashMcu={shouldFlash}
- installOsuFirmware={this.installOsuFirmware}
- installFinalFirmware={this.installFinalFirmware}
- flashMCU={this.flashMCU}
/>
) : null}
diff --git a/src/components/ManagerPage/UpdateFirmwareButton.js b/src/components/ManagerPage/UpdateFirmwareButton.js
index fcfc529e..66d6e314 100644
--- a/src/components/ManagerPage/UpdateFirmwareButton.js
+++ b/src/components/ManagerPage/UpdateFirmwareButton.js
@@ -3,19 +3,14 @@ import React, { Fragment } from 'react'
import { translate } from 'react-i18next'
import type { T } from 'types/common'
-
+import type { OsuFirmware, FinalFirmware } from '@ledgerhq/live-common/lib/types/manager'
import Button from 'components/base/Button'
import Text from 'components/base/Text'
import { getCleanVersion } from 'components/ManagerPage/FirmwareUpdate'
-type FirmwareInfos = {
- name: string,
- notes: string,
-}
-
type Props = {
t: T,
- firmware: ?FirmwareInfos,
+ firmware: ?{ osu: OsuFirmware, finalFirmware: FinalFirmware },
onClick: () => void,
}
@@ -23,14 +18,14 @@ const UpdateFirmwareButton = ({ t, firmware, onClick }: Props) =>
firmware ? (
- {t('manager.firmware.latest', { version: getCleanVersion(firmware.name) })}
+ {t('manager.firmware.latest', { version: getCleanVersion(firmware.osu.name) })}