Browse Source

Implement Repair & Fix firmware update

gre-patch-1
Gaëtan Renaudeau 6 years ago
parent
commit
75a7dc831d
No known key found for this signature in database GPG Key ID: 7B66B85F042E5451
  1. 2
      package.json
  2. BIN
      src/commands/.DS_Store
  3. 19
      src/commands/firmwareCheckId.js
  4. 19
      src/commands/firmwareMain.js
  5. 14
      src/commands/firmwareRepair.js
  6. 17
      src/commands/getLatestFirmwareForDevice.js
  7. 14
      src/commands/index.js
  8. 16
      src/commands/installApp.js
  9. 21
      src/commands/installFinalFirmware.js
  10. 19
      src/commands/installMcu.js
  11. 25
      src/commands/installOsuFirmware.js
  12. 15
      src/commands/shouldFlashMcu.js
  13. 12
      src/commands/uninstallApp.js
  14. 8
      src/components/GenuineCheck.js
  15. 59
      src/components/ManagerPage/AppsList.js
  16. 67
      src/components/ManagerPage/FirmwareUpdate.js
  17. 13
      src/components/ManagerPage/UpdateFirmwareButton.js
  18. 2
      src/components/ProgressBar/index.js
  19. 4
      src/components/ProgressCircle/index.js
  20. 90
      src/components/SettingsPage/RepairDeviceButton.js
  21. 7
      src/components/SettingsPage/sections/Help.js
  22. 4
      src/components/base/Modal/ConfirmModal.js
  23. 16
      src/components/modals/UpdateFirmware/Disclaimer.js
  24. 7
      src/components/modals/UpdateFirmware/Installing.js
  25. 36
      src/components/modals/UpdateFirmware/index.js
  26. 106
      src/components/modals/UpdateFirmware/steps/01-step-install-full-firmware.js
  27. 123
      src/components/modals/UpdateFirmware/steps/02-step-flash-mcu.js
  28. 41
      src/helpers/devices/getDeviceInfo.js
  29. 76
      src/helpers/devices/getLatestFirmwareForDevice.js
  30. 49
      src/helpers/devices/shouldFlashMcu.js
  31. 51
      src/helpers/firmware/installFinalFirmware.js
  32. 34
      src/helpers/firmware/installMcu.js
  33. 50
      src/helpers/firmware/installOsuFirmware.js
  34. 1
      src/helpers/live-common-setup-internal-hw.js
  35. 4
      src/helpers/live-common-setup.js
  36. 9
      static/i18n/en/app.json
  37. 211
      yarn.lock

2
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",

BIN
src/commands/.DS_Store

Binary file not shown.

19
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<Input, Result> = createCommand(
'firmwareCheckId',
({ devicePath, osuFirmware }) => checkId(devicePath, osuFirmware),
)
export default cmd

19
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<Input, Result> = createCommand(
'firmwareMain',
({ finalFirmware }) => main('', finalFirmware),
// devicePath='' HACK to not depend on a devicePath because it's dynamic
)
export default cmd

14
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<Input, Result> = createCommand(
'firmwareRepair',
() => repair(''), // devicePath='' HACK to not depend on a devicePath because it's dynamic
)
export default cmd

17
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<DeviceInfo, Result> = createCommand('getLatestFirmwareForDevice', data =>
fromPromise(getLatestFirmwareForDevice(data)),
const cmd: Command<DeviceInfo, Result> = createCommand('getLatestFirmwareForDevice', deviceInfo =>
from(manager.getLatestFirmwareForDevice(deviceInfo)),
)
export default cmd

14
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<Command<any, any>> = [
debugAppInfosForCurrency,
firmwareCheckId,
firmwareMain,
firmwareRepair,
getAddress,
getDeviceInfo,
getCurrentFirmware,
@ -44,9 +46,6 @@ const all: Array<Command<any, any>> = [
getLatestFirmwareForDevice,
getMemInfo,
installApp,
installFinalFirmware,
installMcu,
installOsuFirmware,
isDashboardOpen,
killInternalProcess,
libcoreGetFees,
@ -61,7 +60,6 @@ const all: Array<Command<any, any>> = [
listCategories,
listenDevices,
ping,
shouldFlashMcu,
signTransaction,
testApdu,
testCrash,

16
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<Input, Result> = createCommand(
'installApp',
({ devicePath, targetId, ...app }) =>
withDevice(devicePath)(transport => from(installApp(transport, targetId, app))),
const cmd: Command<Input, Result> = createCommand('installApp', ({ devicePath, targetId, app }) =>
withDevice(devicePath)(transport => installApp(transport, targetId, app)),
)
export default cmd

21
src/commands/installFinalFirmware.js

@ -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<Input, Result> = createCommand('installFinalFirmware', ({ devicePath }) =>
withDevice(devicePath)(transport => from(installFinalFirmware(transport))),
)
export default cmd

19
src/commands/installMcu.js

@ -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<Input, Result> = createCommand('installMcu', ({ devicePath }) =>
withDevice(devicePath)(transport => from(installMcu(transport))),
)
export default cmd

25
src/commands/installOsuFirmware.js

@ -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<Input, Result> = createCommand(
'installOsuFirmware',
({ devicePath, firmware, targetId }) =>
withDevice(devicePath)(transport => from(installOsuFirmware(transport, targetId, firmware))),
)
export default cmd

15
src/commands/shouldFlashMcu.js

@ -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<DeviceInfo, Result> = createCommand('shouldFlashMcu', data =>
fromPromise(shouldFlashMcu(data)),
)
export default cmd

12
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<Input, Result> = createCommand(
'uninstallApp',
({ devicePath, targetId, ...app }) =>
withDevice(devicePath)(transport => from(uninstallApp(transport, targetId, app))),
const cmd: Command<Input, Result> = createCommand('uninstallApp', ({ devicePath, targetId, app }) =>
withDevice(devicePath)(transport => uninstallApp(transport, targetId, app)),
)
export default cmd

8
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<Props> {
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
}

59
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<Props, State> {
appsLoaded: false,
app: '',
mode: 'home',
progress: 0,
}
componentDidMount() {
@ -158,41 +162,44 @@ class AppsList extends PureComponent<Props, State> {
}
}
handleInstallApp = (app: ApplicationVersion) => async () => {
this.setState({ status: 'busy', app: app.name, mode: 'installing' })
try {
sub: *
runAppScript = (app: ApplicationVersion, mode: *, cmd: *) => {
this.setState({ status: 'busy', app: app.name, mode, progress: 0 })
const {
device: { path: devicePath },
deviceInfo,
deviceInfo: { targetId },
} = this.props
const data = { app, devicePath, targetId: deviceInfo.targetId }
await installApp.send(data).toPromise()
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' })
} catch (err) {
this.setState({ status: 'error', error: err, mode: 'home' })
}
},
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 (
<Modal
isOpened={status !== 'idle' && status !== 'loading'}
@ -217,7 +224,7 @@ class AppsList extends PureComponent<Props, State> {
{t(`manager.apps.${mode}`, { app })}
</Text>
<Box mt={6}>
<Progress style={{ width: '100%' }} infinite />
<ProgressBar width={150} progress={progress} />
</Box>
</ModalContent>
</Fragment>

67
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<Props, State> {
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<Props, State> {
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<Props, State> {
render() {
const { deviceInfo, t, device } = this.props
const { latestFirmware, modal, stepId, shouldFlash, ready } = this.state
const { firmware, modal, stepId, shouldFlash, ready } = this.state
return (
<Card p={4}>
<Box horizontal align="center" flow={2}>
@ -151,12 +119,12 @@ class FirmwareUpdate extends PureComponent<Props, State> {
})}
</Text>
</Box>
<UpdateFirmwareButton firmware={latestFirmware} onClick={this.handleDisclaimerModal} />
<UpdateFirmwareButton firmware={firmware} onClick={this.handleDisclaimerModal} />
</Box>
{ready ? (
<Fragment>
<DisclaimerModal
firmware={latestFirmware}
firmware={firmware}
status={modal}
goToNextStep={this.handleDisclaimerNext}
onClose={this.handleCloseModal}
@ -165,11 +133,8 @@ class FirmwareUpdate extends PureComponent<Props, State> {
status={modal}
stepId={stepId}
onClose={this.handleCloseModal}
firmware={latestFirmware}
firmware={firmware}
shouldFlashMcu={shouldFlash}
installOsuFirmware={this.installOsuFirmware}
installFinalFirmware={this.installFinalFirmware}
flashMCU={this.flashMCU}
/>
</Fragment>
) : null}

13
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 ? (
<Fragment>
<Text ff="Open Sans|Regular" fontSize={4} style={{ marginLeft: 'auto', marginRight: 15 }}>
{t('manager.firmware.latest', { version: getCleanVersion(firmware.name) })}
{t('manager.firmware.latest', { version: getCleanVersion(firmware.osu.name) })}
</Text>
<Button
primary
onClick={onClick}
event={'Manager Firmware Update Click'}
eventProperties={{
firmwareName: firmware.name,
firmwareName: firmware.osu.name,
}}
>
{t('manager.firmware.update')}

2
src/components/ProgressBar/index.js

@ -21,7 +21,7 @@ const Outer = styled.div`
background-color: ${colors.fog};
border-radius: 3px;
overflow: hidden;
height: 10px;
height: 5px;
width: ${p => p.width}px;
position: relative;
`

4
src/components/ProgressCircle/index.js

@ -7,7 +7,7 @@ import { colors } from 'styles/theme'
import Text from 'components/base/Text'
const STROKE_WIDTH = 10
const STROKE_WIDTH = 5
type Props = {
progress: number,
@ -64,7 +64,7 @@ class ProgressCircle extends PureComponent<Props> {
return (
<Container size={size}>
<TextContainer>
<Text ff="Museo Sans|Bold" color="graphite" fontSize={6}>
<Text ff="Museo Sans|Bold" color="graphite" fontSize={5}>
{`${Math.round(progress * 100)}%`}
</Text>
</TextContainer>

90
src/components/SettingsPage/RepairDeviceButton.js

@ -0,0 +1,90 @@
// @flow
import React, { Fragment, PureComponent } from 'react'
import { filter, tap } from 'rxjs/operators'
import { translate } from 'react-i18next'
import type { T } from 'types/common'
import firmwareRepair from 'commands/firmwareRepair'
import Button from 'components/base/Button'
import { ConfirmModal } from 'components/base/Modal'
type Props = {
t: T,
}
type State = {
opened: boolean,
isLoading: boolean,
error: ?Error,
}
class CleanButton extends PureComponent<Props, State> {
state = {
opened: false,
isLoading: false,
error: null,
}
open = () => this.setState({ opened: true })
sub: *
close = () => {
if (this.sub) this.sub.unsubscribe()
this.setState({ opened: false })
}
action = () => {
if (this.state.isLoading) return
this.setState({ isLoading: true })
this.sub = firmwareRepair
.send()
.pipe(
tap(e => console.log(e)), // eslint-disable-line no-console
// ^ TODO remove at the end
filter(e => e.type === 'bulk-progress'),
)
.subscribe({
next: () => {
// TODO cc @val
},
error: error => {
this.setState({ error, opened: false, isLoading: false })
},
complete: () => {
this.setState({ opened: false, isLoading: false })
},
})
}
render() {
const { t } = this.props
const { opened, isLoading, error } = this.state
// @val basically I think we want to diverge from the traditional ConfirmModal to make our own version
// with the progress and the error cases handled.
console.log({ error }) // eslint-disable-line no-console
// ^ TODO use error to pass in that custom thing
return (
<Fragment>
<Button small primary onClick={this.open} event="RepairDeviceButton">
{t('settings.repairDevice.button')}
</Button>
<ConfirmModal
cancellable
analyticsName="RepairDevice"
isOpened={opened}
onClose={this.close}
onReject={this.close}
onConfirm={this.action}
isLoading={isLoading}
title={t('settings.repairDevice.title')}
subTitle={t('common.areYouSure')}
desc={t('settings.repairDevice.desc')}
/>
</Fragment>
)
}
}
export default translate()(CleanButton)

7
src/components/SettingsPage/sections/Help.js

@ -11,6 +11,7 @@ import ExportLogsBtn from 'components/ExportLogsBtn'
import OpenUserDataDirectoryBtn from 'components/OpenUserDataDirectoryBtn'
import CleanButton from '../CleanButton'
import ResetButton from '../ResetButton'
import RepairDeviceButton from '../RepairDeviceButton'
import AboutRowItem from '../AboutRowItem'
import LaunchOnboardingBtn from '../LaunchOnboardingBtn'
@ -72,6 +73,12 @@ class SectionHelp extends PureComponent<Props> {
>
<ResetButton />
</Row>
<Row
title={t('settings.repairDevice.title')}
desc={t('settings.repairDevice.desc')}
>
<RepairDeviceButton />
</Row>
</Body>
</Section>
)

4
src/components/base/Modal/ConfirmModal.js

@ -25,11 +25,13 @@ type Props = {
t: T,
isLoading?: boolean,
analyticsName: string,
cancellable?: boolean,
}
class ConfirmModal extends PureComponent<Props> {
render() {
const {
cancellable,
isOpened,
title,
subTitle,
@ -54,7 +56,7 @@ class ConfirmModal extends PureComponent<Props> {
preventBackdropClick={isLoading}
{...props}
render={({ onClose }) => (
<ModalBody onClose={isLoading ? undefined : onClose}>
<ModalBody onClose={!cancellable && isLoading ? undefined : onClose}>
<TrackPage category="Modal" name={analyticsName} />
<ModalTitle>{title}</ModalTitle>
<ModalContent>

16
src/components/modals/UpdateFirmware/Disclaimer.js

@ -3,7 +3,7 @@
import React, { PureComponent, Fragment } from 'react'
import { translate, Trans } from 'react-i18next'
import type { OsuFirmware, FinalFirmware } from '@ledgerhq/live-common/lib/types/manager'
import type { T } from 'types/common'
import Modal, { ModalBody, ModalFooter, ModalTitle, ModalContent } from 'components/base/Modal'
@ -18,15 +18,13 @@ import type { ModalStatus } from 'components/ManagerPage/FirmwareUpdate'
import { getCleanVersion } from 'components/ManagerPage/FirmwareUpdate'
type FirmwareInfos = {
name: string,
notes: string,
}
type Props = {
t: T,
status: ModalStatus,
firmware: FirmwareInfos,
firmware: {
osu: OsuFirmware,
final: FinalFirmware,
},
goToNextStep: () => void,
onClose: () => void,
}
@ -50,7 +48,7 @@ class DisclaimerModal extends PureComponent<Props, State> {
<Trans i18nKey="manager.firmware.disclaimerTitle">
You are about to install
<Text ff="Open Sans|SemiBold" color="dark">
{`firmware version ${firmware ? getCleanVersion(firmware.name) : ''}`}
{`firmware version ${firmware ? getCleanVersion(firmware.osu.name) : ''}`}
</Text>
</Trans>
</Text>
@ -62,7 +60,7 @@ class DisclaimerModal extends PureComponent<Props, State> {
<ModalContent relative pb={0} style={{ height: 250, width: '100%' }}>
<GrowScroll pb={5}>
<Notes>
<Markdown>{firmware.notes}</Markdown>
<Markdown>{firmware.osu.notes}</Markdown>
</Notes>
</GrowScroll>
<GradientBox />

7
src/components/modals/UpdateFirmware/Installing.js

@ -4,19 +4,20 @@ import { translate } from 'react-i18next'
import Box from 'components/base/Box'
import Text from 'components/base/Text'
import Spinner from 'components/base/Spinner'
import ProgressCircle from 'components/ProgressCircle'
import type { T } from 'types/common'
type Props = {
t: T,
progress: number,
}
function Installing({ t }: Props) {
function Installing({ t, progress }: Props) {
return (
<Fragment>
<Box mx={7} align="center">
<Spinner color="fog" size={44} />
<ProgressCircle size={64} progress={progress} />
</Box>
<Box mx={7} mt={4} mb={2}>
<Text ff="Museo Sans|Regular" align="center" color="dark" fontSize={6}>

36
src/components/modals/UpdateFirmware/index.js

@ -2,22 +2,22 @@
import React, { PureComponent } from 'react'
import { translate } from 'react-i18next'
import type { T, Device } from 'types/common'
import type { T } from 'types/common'
import Modal from 'components/base/Modal'
import Stepper from 'components/base/Stepper'
import SyncSkipUnderPriority from 'components/SyncSkipUnderPriority'
import type { OsuFirmware, FinalFirmware } from '@ledgerhq/live-common/lib/types/manager'
import type { StepProps as DefaultStepProps, Step } from 'components/base/Stepper'
import type { ModalStatus } from 'components/ManagerPage/FirmwareUpdate'
import type { OsuFirmware } from 'helpers/types'
import { FreezeDeviceChangeEvents } from '../../ManagerPage/HookDeviceChange'
import StepFullFirmwareInstall from './steps/01-step-install-full-firmware'
import StepFlashMcu from './steps/02-step-flash-mcu'
import StepConfirmation, { StepConfirmFooter } from './steps/03-step-confirmation'
const createSteps = ({ t, shouldFlashMcu }: { t: T, shouldFlashMcu: boolean }): Array<*> => {
const createSteps = ({ t }: { t: T }): Array<*> => {
const updateStep = {
id: 'idCheck',
label: t('manager.modal.identifier'),
@ -45,26 +45,13 @@ const createSteps = ({ t, shouldFlashMcu }: { t: T, shouldFlashMcu: boolean }):
hideFooter: true,
}
const steps = [updateStep]
if (shouldFlashMcu) {
steps.push(mcuStep)
}
steps.push(finalStep)
return steps
return [updateStep, mcuStep, finalStep]
}
export type Firmware = OsuFirmware & { shouldFlashMcu: boolean }
export type StepProps = DefaultStepProps & {
firmware: Firmware,
osu: OsuFirmware,
final: FinalFirmware,
onCloseModal: () => void,
installOsuFirmware: (device: Device) => void,
installFinalFirmware: (device: Device) => void,
flashMCU: (device: Device) => void,
shouldFlashMcu: boolean,
error: ?Error,
setError: Error => void,
}
@ -75,11 +62,7 @@ type Props = {
t: T,
status: ModalStatus,
onClose: () => void,
firmware: Firmware,
shouldFlashMcu: boolean,
installOsuFirmware: (device: Device) => void,
installFinalFirmware: (device: Device) => void,
flashMCU: (device: Device) => void,
firmware: { osu: OsuFirmware, final: FinalFirmware },
stepId: StepId | string,
}
@ -98,9 +81,6 @@ class UpdateModal extends PureComponent<Props, State> {
STEPS = createSteps({
t: this.props.t,
shouldFlashMcu: this.props.firmware
? this.props.firmware.shouldFlashMcu
: this.props.shouldFlashMcu,
})
setError = (e: Error) => this.setState({ error: e })
@ -114,10 +94,10 @@ class UpdateModal extends PureComponent<Props, State> {
const { stepId, error, nonce } = this.state
const additionalProps = {
firmware,
error,
onCloseModal: onClose,
setError: this.setError,
...firmware,
...props,
}

106
src/components/modals/UpdateFirmware/steps/01-step-install-full-firmware.js

@ -3,24 +3,16 @@
import React, { PureComponent, Fragment } from 'react'
import styled from 'styled-components'
import { connect } from 'react-redux'
import { timeout } from 'rxjs/operators/timeout'
import { DEVICE_INFOS_TIMEOUT } from 'config/constants'
import getDeviceInfo from 'commands/getDeviceInfo'
import firmwareCheckId from 'commands/firmwareCheckId'
import { getCurrentDevice } from 'reducers/devices'
import { createCancelablePolling, delay } from 'helpers/promise'
import TrackPage from 'analytics/TrackPage'
import Box from 'components/base/Box'
import Text from 'components/base/Text'
import DeviceConfirm from 'components/DeviceConfirm'
import type { Device } from 'types/common'
import type { StepProps } from '../'
import Installing from '../Installing'
const Container = styled(Box).attrs({
alignItems: 'center',
fontSize: 4,
@ -55,79 +47,37 @@ type Props = StepProps & {
device: Device,
}
type State = {
installing: boolean,
}
class StepFullFirmwareInstall extends PureComponent<Props, State> {
state = {
installing: false,
}
class StepFullFirmwareInstall extends PureComponent<Props> {
componentDidMount() {
this.install()
}
const { osu, device, transitionTo, setError } = this.props
componentWillUnmount() {
if (this._unsubConnect) this._unsubConnect()
}
ensureDevice = () => {
const { unsubscribe, promise } = createCancelablePolling(async () => {
const { device } = this.props
if (!device) {
throw new Error('No device')
if (!osu) {
transitionTo('finish')
return
}
const deviceInfo = await getDeviceInfo
.send({ devicePath: device.path })
.pipe(timeout(DEVICE_INFOS_TIMEOUT))
.toPromise()
return { device, deviceInfo }
this.sub = firmwareCheckId
.send({
devicePath: device.path,
osuFirmware: osu,
})
this._unsubConnect = unsubscribe
return promise
}
install = async () => {
const {
installOsuFirmware,
installFinalFirmware,
firmware,
shouldFlashMcu,
transitionTo,
setError,
} = this.props
const { device, deviceInfo } = await this.ensureDevice()
if (deviceInfo.isBootloader) {
.subscribe({
complete: () => {
transitionTo('updateMCU')
}
try {
if (deviceInfo.isOSU) {
this.setState({ installing: true })
await installFinalFirmware(device)
transitionTo('finish')
} else {
await installOsuFirmware(device)
this.setState({ installing: true })
if (this._unsubConnect) this._unsubConnect()
if ((firmware && firmware.shouldFlashMcu) || shouldFlashMcu) {
delay(1000)
transitionTo('updateMCU')
} else {
const { device: freshDevice } = await this.ensureDevice()
await installFinalFirmware(freshDevice)
transitionTo('finish')
}
}
} catch (error) {
},
error: error => {
setError(error)
transitionTo('finish')
},
})
}
componentWillUnmount() {
if (this.sub) this.sub.unsubscribe()
}
sub: *
formatHashName = (hash: string): string => {
if (!hash) {
return ''
@ -138,11 +88,8 @@ class StepFullFirmwareInstall extends PureComponent<Props, State> {
}
renderBody = () => {
const { installing } = this.state
const { t, firmware } = this.props
return installing ? (
<Installing />
) : (
const { t, osu } = this.props
return (
<Fragment>
<Text ff="Open Sans|Regular" align="center" color="smoke">
{t('manager.modal.confirmIdentifierText')}
@ -151,7 +98,7 @@ class StepFullFirmwareInstall extends PureComponent<Props, State> {
<Text ff="Open Sans|SemiBold" align="center" color="smoke">
{t('manager.modal.identifier')}
</Text>
<Address>{firmware && this.formatHashName(firmware.hash)}</Address>
<Address>{osu && this.formatHashName(osu.hash)}</Address>
</Box>
<Box mt={5}>
<DeviceConfirm />
@ -160,14 +107,11 @@ class StepFullFirmwareInstall extends PureComponent<Props, State> {
)
}
_unsubConnect: *
render() {
const { installing } = this.state
const { t } = this.props
return (
<Container>
<Title>{installing ? '' : t('manager.modal.confirmIdentifier')}</Title>
<Title>{t('manager.modal.confirmIdentifier')}</Title>
<TrackPage category="Manager" name="InstallFirmware" />
{this.renderBody()}
</Container>

123
src/components/modals/UpdateFirmware/steps/02-step-flash-mcu.js

@ -2,21 +2,15 @@
import React, { PureComponent, Fragment } from 'react'
import styled from 'styled-components'
import { connect } from 'react-redux'
import { timeout } from 'rxjs/operators/timeout'
import { filter, tap } from 'rxjs/operators'
import { DEVICE_INFOS_TIMEOUT } from 'config/constants'
import { i } from 'helpers/staticPath'
import { getCurrentDevice } from 'reducers/devices'
import { createCancelablePolling } from 'helpers/promise'
import getDeviceInfo from 'commands/getDeviceInfo'
import firmwareMain from 'commands/firmwareMain'
import TrackPage from 'analytics/TrackPage'
import Box from 'components/base/Box'
import Text from 'components/base/Text'
import type { Device } from 'types/common'
import type { StepProps } from '../'
import Installing from '../Installing'
@ -46,107 +40,59 @@ const Separator = styled(Box).attrs({
background-color: currentColor;
`
const mapStateToProps = state => ({
device: getCurrentDevice(state),
})
type Props = StepProps & { device?: Device }
type Props = StepProps
type State = {
installing: boolean,
progress: number,
}
class StepFlashMcu extends PureComponent<Props, State> {
state = {
installing: false,
progress: 0,
}
componentDidMount() {
this.install()
}
componentWillUnmount() {
if (this._unsubConnect) this._unsubConnect()
if (this._unsubDeviceInfo) this._unsubDeviceInfo()
}
getDeviceInfo = () => {
const { unsubscribe, promise } = createCancelablePolling(async () => {
const { device } = this.props
if (!device) {
throw new Error('No device')
}
const deviceInfo = await getDeviceInfo
.send({ devicePath: device.path })
.pipe(timeout(DEVICE_INFOS_TIMEOUT))
.toPromise()
return { device, deviceInfo }
})
this._unsubDeviceInfo = unsubscribe
return promise
}
waitForDeviceInBootloader = () => {
const { unsubscribe, promise } = createCancelablePolling(async () => {
const { device } = this.props
if (!device) {
throw new Error('No device')
}
const deviceInfo = await getDeviceInfo
.send({ devicePath: device.path })
.pipe(timeout(DEVICE_INFOS_TIMEOUT))
.toPromise()
if (!deviceInfo.isBootloader) {
throw new Error('Device is not in bootloader')
}
return { device, deviceInfo }
})
this._unsubConnect = unsubscribe
return promise
}
flash = async () => {
await this.waitForDeviceInBootloader()
const { flashMCU, device } = this.props
if (device) {
this.setState({ installing: true })
await flashMCU(device)
}
}
install = async () => {
const { transitionTo, installFinalFirmware, setError } = this.props
const { deviceInfo, device } = await this.getDeviceInfo()
try {
if (deviceInfo.isBootloader) {
await this.flash()
this.install()
} else if (deviceInfo.isOSU) {
await installFinalFirmware(device)
transitionTo('finish')
const { final: finalFirmware, transitionTo, setError } = this.props
this.sub = firmwareMain
.send({ finalFirmware })
.pipe(
tap(e => console.log(e)), // eslint-disable-line no-console
// ^ TODO remove at the end
filter(e => e.type === 'bulk-progress' || e.type === 'install'),
)
.subscribe({
next: e => {
if (e.type === 'install') {
this.setState({ installing: e.step, progress: 0 })
} else {
transitionTo('finish')
this.setState({ progress: e.progress })
}
} catch (error) {
},
complete: () => {
transitionTo('finish')
},
error: error => {
setError(error)
transitionTo('finish')
}
},
})
}
firstFlash = async () => {
await this.flash()
this.install()
componentWillUnmount() {
if (this.sub) this.sub.unsubscribe()
}
sub: *
renderBody = () => {
const { installing } = this.state
const { installing, progress } = this.state
const { t } = this.props
return installing ? (
<Installing />
<Installing progress={progress} />
) : (
<Fragment>
<Box mx={7}>
@ -176,9 +122,6 @@ class StepFlashMcu extends PureComponent<Props, State> {
)
}
_unsubConnect: *
_unsubDeviceInfo: *
render() {
const { t } = this.props
const { installing } = this.state
@ -192,4 +135,4 @@ class StepFlashMcu extends PureComponent<Props, State> {
}
}
export default connect(mapStateToProps)(StepFlashMcu)
export default StepFlashMcu

41
src/helpers/devices/getDeviceInfo.js

@ -1,42 +1,5 @@
// @flow
import type Transport from '@ledgerhq/hw-transport'
import getDeviceInfo from '@ledgerhq/live-common/lib/hw/getDeviceInfo'
import getFirmwareInfo from 'helpers/firmware/getFirmwareInfo'
import { FORCE_PROVIDER } from 'config/constants'
import type { DeviceInfo } from 'helpers/types'
const PROVIDERS = {
'': 1,
das: 2,
club: 3,
shitcoins: 4,
ee: 5,
}
export default async (transport: Transport<*>): Promise<DeviceInfo> => {
const res = await getFirmwareInfo(transport)
const { seVersion } = res
const { targetId, mcuVersion, flags } = res
const parsedVersion =
seVersion.match(/([0-9]+.[0-9])+(.[0-9]+)?((?!-osu)-([a-z]+))?(-osu)?/) || []
const isOSU = typeof parsedVersion[5] !== 'undefined'
const providerName = parsedVersion[4] || ''
const providerId = FORCE_PROVIDER || PROVIDERS[providerName]
const isBootloader = targetId === 0x01000001
const majMin = parsedVersion[1]
const patch = parsedVersion[2] || '.0'
const fullVersion = `${majMin}${patch}${providerName ? `-${providerName}` : ''}`
return {
targetId,
seVersion: majMin + patch,
isOSU,
mcuVersion,
isBootloader,
providerName,
providerId,
flags,
fullVersion,
}
}
export default getDeviceInfo

76
src/helpers/devices/getLatestFirmwareForDevice.js

@ -1,76 +0,0 @@
// @flow
import network from 'api/network'
import { GET_LATEST_FIRMWARE } from 'helpers/urls'
import type {
DeviceInfo,
DeviceVersion,
FinalFirmware,
OsuFirmware,
McuVersion,
} from 'helpers/types'
import getFinalFirmwareById from 'helpers/firmware/getFinalFirmwareById'
import getMcus from 'helpers/firmware/getMcus'
import getCurrentFirmware from './getCurrentFirmware'
import getDeviceVersion from './getDeviceVersion'
type NetworkResponse = {
data: {
result: string,
se_firmware_osu_version: OsuFirmware,
},
}
type Result = ?(OsuFirmware & { shouldFlashMcu: boolean })
export default async (deviceInfo: DeviceInfo): Promise<Result> => {
// Get device infos from targetId
const deviceVersion: DeviceVersion = await getDeviceVersion(
deviceInfo.targetId,
deviceInfo.providerId,
)
// Get firmware infos with firmware name and device version
const seFirmwareVersion: FinalFirmware = await getCurrentFirmware({
fullVersion: deviceInfo.fullVersion,
deviceId: deviceVersion.id,
provider: deviceInfo.providerId,
})
// Fetch next possible firmware
const { data }: NetworkResponse = await network({
method: 'POST',
url: GET_LATEST_FIRMWARE,
data: {
current_se_firmware_final_version: seFirmwareVersion.id,
device_version: deviceVersion.id,
provider: deviceInfo.providerId,
},
})
if (data.result === 'null') {
return null
}
const { se_firmware_osu_version } = data
const { next_se_firmware_final_version } = se_firmware_osu_version
const seFirmwareFinalVersion: FinalFirmware = await getFinalFirmwareById(
next_se_firmware_final_version,
)
const mcus: Array<McuVersion> = await getMcus()
const currentMcuVersionId: Array<number> = mcus
.filter(mcu => mcu.name === deviceInfo.mcuVersion)
.map(mcu => mcu.id)
if (!seFirmwareFinalVersion.mcu_versions.includes(...currentMcuVersionId)) {
return {
...se_firmware_osu_version,
shouldFlashMcu: true,
}
}
return { ...se_firmware_osu_version, shouldFlashMcu: false }
}

49
src/helpers/devices/shouldFlashMcu.js

@ -1,49 +0,0 @@
// @flow
import network from 'api/network'
import { GET_LATEST_FIRMWARE } from 'helpers/urls'
import type { DeviceInfo } from 'helpers/types'
import getFinalFirmwareById from 'helpers/firmware/getFinalFirmwareById'
import getMcus from 'helpers/firmware/getMcus'
import getOsuFirmware from './getOsuFirmware'
import getDeviceVersion from './getDeviceVersion'
export default async (deviceInfo: DeviceInfo): Promise<boolean> => {
// Get device infos from targetId
const deviceVersion = await getDeviceVersion(deviceInfo.targetId, deviceInfo.providerId)
// Get firmware infos with firmware name and device version
const seFirmwareVersion = await getOsuFirmware({
version: deviceInfo.fullVersion,
deviceId: deviceVersion.id,
provider: deviceInfo.providerId,
})
// Fetch next possible firmware
const { data } = await network({
method: 'POST',
url: GET_LATEST_FIRMWARE,
data: {
current_se_firmware_final_version: seFirmwareVersion.id,
device_version: deviceVersion.id,
provider: deviceInfo.providerId,
},
})
if (data.result === 'null') {
return false
}
const { se_firmware_osu_version } = data
const { next_se_firmware_final_version } = se_firmware_osu_version
const seFirmwareFinalVersion = await getFinalFirmwareById(next_se_firmware_final_version)
const mcus = await getMcus()
const currentMcuVersionId = mcus
.filter(mcu => mcu.name === deviceInfo.mcuVersion)
.map(mcu => mcu.id)
return !seFirmwareFinalVersion.mcu_versions.includes(...currentMcuVersionId)
}

51
src/helpers/firmware/installFinalFirmware.js

@ -1,51 +0,0 @@
// @flow
import type Transport from '@ledgerhq/hw-transport'
import type { DeviceInfo, DeviceVersion, OsuFirmware, FinalFirmware } from 'helpers/types'
import { WS_INSTALL } from 'helpers/urls'
import { createDeviceSocket } from 'helpers/socket'
import getDeviceVersion from 'helpers/devices/getDeviceVersion'
import getOsuFirmware from 'helpers/devices/getOsuFirmware'
import getDeviceInfo from 'helpers/devices/getDeviceInfo'
import { ManagerDeviceLockedError } from '@ledgerhq/live-common/lib/errors'
import getFinalFirmwareById from './getFinalFirmwareById'
function remapSocketError(promise) {
return promise.catch((e: Error) => {
switch (true) {
case e.message.endsWith('6982'):
throw new ManagerDeviceLockedError()
default:
throw e
}
})
}
type Result = Promise<{ success: boolean }>
export default async (transport: Transport<*>): Result => {
try {
const deviceInfo: DeviceInfo = await getDeviceInfo(transport)
const device: DeviceVersion = await getDeviceVersion(deviceInfo.targetId, deviceInfo.providerId)
const firmware: OsuFirmware = await getOsuFirmware({
deviceId: device.id,
version: deviceInfo.fullVersion,
provider: deviceInfo.providerId,
})
const { next_se_firmware_final_version } = firmware
const nextFirmware: FinalFirmware = await getFinalFirmwareById(next_se_firmware_final_version)
const params = {
targetId: deviceInfo.targetId,
...nextFirmware,
firmwareKey: nextFirmware.firmware_key,
}
const url = WS_INSTALL(params)
await remapSocketError(createDeviceSocket(transport, url).toPromise())
return { success: true }
} catch (error) {
throw error
}
}

34
src/helpers/firmware/installMcu.js

@ -1,34 +0,0 @@
// @flow
import type Transport from '@ledgerhq/hw-transport'
import { WS_MCU } from 'helpers/urls'
import { createDeviceSocket } from 'helpers/socket'
import getNextMCU from 'helpers/firmware/getNextMCU'
import getDeviceInfo from 'helpers/devices/getDeviceInfo'
import { ManagerDeviceLockedError } from '@ledgerhq/live-common/lib/errors'
import type { DeviceInfo } from 'helpers/types'
function remapSocketError(promise) {
return promise.catch((e: Error) => {
switch (true) {
case e.message.endsWith('6982'):
throw new ManagerDeviceLockedError()
default:
throw e
}
})
}
type Result = Promise<void>
export default async (transport: Transport<*>): Result => {
const { seVersion: version, targetId }: DeviceInfo = await getDeviceInfo(transport)
const nextVersion = await getNextMCU(version)
const params = {
targetId,
version: nextVersion.name,
}
const url = WS_MCU(params)
await remapSocketError(createDeviceSocket(transport, url).toPromise())
}

50
src/helpers/firmware/installOsuFirmware.js

@ -1,50 +0,0 @@
// @flow
import type Transport from '@ledgerhq/hw-transport'
import { WS_INSTALL } from 'helpers/urls'
import { createDeviceSocket } from 'helpers/socket'
import type { Firmware } from 'components/modals/UpdateFirmware'
import {
ManagerNotEnoughSpaceError,
ManagerDeviceLockedError,
UserRefusedFirmwareUpdate,
} from '@ledgerhq/live-common/lib/errors'
function remapError(promise) {
return promise.catch((e: Error) => {
switch (true) {
case e.message.endsWith('6985'):
throw new UserRefusedFirmwareUpdate()
case e.message.endsWith('6982'):
throw new ManagerDeviceLockedError()
case e.message.endsWith('6a84') || e.message.endsWith('6a85'):
throw new ManagerNotEnoughSpaceError()
default:
throw e
}
})
}
type Result = Promise<{ success: boolean }>
export default async (
transport: Transport<*>,
targetId: string | number,
firmware: Firmware,
): Result => {
try {
const params = {
targetId,
...firmware,
firmwareKey: firmware.firmware_key,
}
delete params.shouldFlashMcu
const url = WS_INSTALL(params)
await remapError(createDeviceSocket(transport, url).toPromise())
return { success: true }
} catch (error) {
throw error
}
}

1
src/helpers/live-common-setup-internal-hw.js

@ -40,7 +40,6 @@ setErrorRemapping(e => {
registerTransportModule({
id: 'hid',
open: async devicePath => {
// $FlowFixMe
const t = await retry(() => TransportNodeHid.open(devicePath), { maxRetry: 2 })
t.setDebugMode(logger.apdu)
return t

4
src/helpers/live-common-setup.js

@ -1,8 +1,10 @@
// @flow
import { setNetwork } from '@ledgerhq/live-common/lib/network'
import WebSocket from 'ws'
import { setNetwork, setWebSocketImplementation } from '@ledgerhq/live-common/lib/network'
import { setEnv } from '@ledgerhq/live-common/lib/env'
import network from 'api/network'
import * as constants from 'config/constants'
setWebSocketImplementation(WebSocket)
setNetwork(network)
setEnv('FORCE_PROVIDER', constants.FORCE_PROVIDER)

9
static/i18n/en/app.json

@ -445,6 +445,11 @@
"desc": "View the user data that is stored on your computer, including your accounts, caches and settings.",
"btn": "View"
},
"repairDevice": {
"title": "Repair your Ledger device",
"desc": "If you encountered some issue while updating your device and cannot resume the update process, you can try this option to repair your device.",
"button": "Repair"
},
"exportLogs": {
"title": "Export logs",
"desc": "Exporting Ledger Live logs may be necessary for troubleshooting purposes.",
@ -841,6 +846,10 @@
"title": "Something went wrong, please reconnect your device",
"description": "{{message}}"
},
"UnexpectedBootloader": {
"title": "Opps, your device should not be in Bootloader mode",
"description": "Please restart your device or contact us"
},
"UserRefusedFirmwareUpdate": {
"title": "Firmware update refused on device",
"description": "Please retry or contact Ledger Support"

211
yarn.lock

@ -1701,9 +1701,9 @@
bip32-path "0.4.2"
"@ledgerhq/hw-transport-node-hid@^4.32.0":
version "4.32.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-node-hid/-/hw-transport-node-hid-4.32.0.tgz#75fec81c44e9f8fbe0f918080e2b70e99de2a346"
integrity sha512-uZO+52TBxaYVhGIULHbhvyZWx+uLjvflDwfLicQR1eYxbYACB6xLXwq4sz9gL5He966t637Zx9iPsLi87rtqvQ==
version "4.33.3"
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-node-hid/-/hw-transport-node-hid-4.33.3.tgz#5e96dca2be0a23d80814303f262398087b208a6a"
integrity sha512-hmNAm7k385RJXY38hVUpzYgGgyk9QjScD3erNlFCTO8FnnxmEJCFUmVhWkv4sTwufuUJSpXL3ZXXNZ44qLMJpg==
dependencies:
"@ledgerhq/hw-transport" "^4.32.0"
lodash "^4.17.11"
@ -1725,10 +1725,10 @@
bindings "^1.3.0"
nan "^2.6.2"
"@ledgerhq/live-common@4.8.0-beta.4":
version "4.8.0-beta.4"
resolved "https://registry.yarnpkg.com/@ledgerhq/live-common/-/live-common-4.8.0-beta.4.tgz#291641f42a5cac8c26cf3baf0c303542509df86c"
integrity sha512-xmNLrljtCPSDJDiJndIlSX+wsgVQBNEZH25c+Dz3/uaZVtOVldE4iav7r7qKkGVNoUwvEhoqSAcjSuqKEFiBhg==
"@ledgerhq/live-common@4.8.0-beta.12":
version "4.8.0-beta.12"
resolved "https://registry.yarnpkg.com/@ledgerhq/live-common/-/live-common-4.8.0-beta.12.tgz#4319aa397896f242d753ea63ff7ac4223788eb88"
integrity sha512-J2gaXqQkDuqZl2SgjNE7ZOSX0nMl9xqHu5jwHqiyBSlXvykdXWMmaPLcBcP8F+xszpKCIB0N6XaJFUAHHbD0Nw==
dependencies:
"@aeternity/ledger-app-api" "0.0.4"
"@ledgerhq/hw-app-btc" "^4.32.0"
@ -4119,11 +4119,16 @@ binaryextensions@2:
resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.1.1.tgz#3209a51ca4a4ad541a3b8d3d6a6d5b83a2485935"
integrity sha512-XBaoWE9RW8pPdPQNibZsW2zh8TW6gcarXp1FZPwT8Uop8ScSNldJEWf2k9l3HeTqdrEwsOsFcq74RiJECW34yA==
bindings@^1.2.1, bindings@^1.3.0:
bindings@^1.2.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.0.tgz#b346f6ecf6a95f5a815c5839fc7cdb22502f1ed7"
integrity sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw==
bindings@^1.3.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.1.tgz#21fc7c6d67c18516ec5aaa2815b145ff77b26ea5"
integrity sha512-i47mqjF9UbjxJhxGf+pZ6kSxrnI3wBLlnGI2ArWJ4r0VrvDS7ZYXkprq/pLaBWYq4GM0r4zdHY+NNRqEMU7uew==
bip32-path@0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/bip32-path/-/bip32-path-0.4.2.tgz#5db0416ad6822712f077836e2557b8697c0c7c99"
@ -4440,7 +4445,7 @@ buffer-alloc-unsafe@^1.1.0:
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
buffer-alloc@^1.1.0:
buffer-alloc@^1.1.0, buffer-alloc@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
@ -4867,10 +4872,10 @@ chokidar@^2.0.0, chokidar@^2.0.2:
optionalDependencies:
fsevents "^1.2.2"
chownr@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181"
integrity sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=
chownr@^1.0.1, chownr@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494"
integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==
chrome-trace-event@^1.0.0:
version "1.0.0"
@ -7488,6 +7493,11 @@ expand-template@^1.0.2:
resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-1.1.1.tgz#981f188c0c3a87d2e28f559bc541426ff94f21dd"
integrity sha512-cebqLtV8KOZfw0UI8TEFWxtczxxC1jvyUvx6H4fyp1K1FN7A4Q+uggVUlOsI1K8AGU0rwOGqP8nCapdrw8CYQg==
expand-template@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==
expand-tilde@^2.0.0, expand-tilde@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502"
@ -8282,7 +8292,7 @@ glob-to-regexp@^0.3.0:
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1:
glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1:
version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==
@ -8294,6 +8304,18 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1:
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.0.5:
version "7.1.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
global-dirs@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445"
@ -8997,7 +9019,7 @@ i18next@^11.2.2:
resolved "https://registry.yarnpkg.com/i18next/-/i18next-11.3.3.tgz#a6ca3c2a93237c94e242bda7df3411588ac37ea1"
integrity sha512-YR1p0IJCKbUxi9DKKb7SK5kQMVcUIUA1xxPlxr7mn3pvkFdEE1eZi/TiYC5eyOE6wvWYOb5xZc+1HVSD5dJXMg==
iconv-lite@0.4, iconv-lite@^0.4.17, iconv-lite@^0.4.22, iconv-lite@^0.4.23, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
iconv-lite@0.4, iconv-lite@^0.4.17, iconv-lite@^0.4.22, iconv-lite@^0.4.23, iconv-lite@~0.4.13:
version "0.4.23"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==
@ -9009,6 +9031,13 @@ iconv-lite@0.4.19:
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
integrity sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==
iconv-lite@^0.4.4:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
dependencies:
safer-buffer ">= 2.1.2 < 3"
icss-replace-symbols@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
@ -11114,18 +11143,18 @@ minimist@~0.0.1:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=
minipass@^2.2.1, minipass@^2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233"
integrity sha512-/jAn9/tEX4gnpyRATxgHEOV6xbcyxgT7iUnxo9Y3+OB0zX00TgKIv/2FZCf5brBbICcwbLqVv2ImjvWWrQMSYw==
minipass@^2.2.1, minipass@^2.3.4:
version "2.3.5"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848"
integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==
dependencies:
safe-buffer "^5.1.2"
yallist "^3.0.0"
minizlib@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb"
integrity sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==
minizlib@^1.1.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614"
integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==
dependencies:
minipass "^2.2.1"
@ -11220,7 +11249,12 @@ mute-stream@0.0.7:
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
nan@^2.10.0, nan@^2.2.1, nan@^2.6.2, nan@^2.8.0, nan@^2.9.2:
nan@^2.10.0, nan@^2.8.0:
version "2.12.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.0.tgz#9d443fdb5e13a20770cc5e602eee59760a685885"
integrity sha512-zT5nC0JhbljmyEf+Z456nvm7iO7XgRV2hYxoBtPpnyp+0Q4aCoP6uWNn76v/I6k2kCYNLWqWbwBWQcjsNI/bjw==
nan@^2.2.1, nan@^2.6.2, nan@^2.9.2:
version "2.10.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f"
integrity sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==
@ -11242,15 +11276,20 @@ nanomatch@^1.2.9:
snapdragon "^0.8.1"
to-regex "^3.0.1"
napi-build-utils@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.1.tgz#1381a0f92c39d66bf19852e7873432fc2123e508"
integrity sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA==
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
needle@^2.2.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d"
integrity sha512-t/ZswCM9JTWjAdXS9VpvqhI2Ct2sL2MdY4fUXqGJaGBk13ge99ObqRksRTbBE56K+wxUXwwfZYOuZHifFW9q+Q==
needle@^2.2.1:
version "2.2.4"
resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e"
integrity sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==
dependencies:
debug "^2.1.2"
iconv-lite "^0.4.4"
@ -11283,13 +11322,20 @@ no-case@^2.2.0:
dependencies:
lower-case "^1.1.1"
node-abi@^2.0.0, node-abi@^2.2.0:
node-abi@^2.0.0:
version "2.4.3"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.4.3.tgz#43666b7b17e57863e572409edbb82115ac7af28b"
integrity sha512-b656V5C0628gOOA2kwcpNA/bxdlqYF9FvxJ+qqVX0ctdXNVZpS8J6xEUYir3WAKc7U0BH/NRlSpNbGsy+azjeg==
dependencies:
semver "^5.4.1"
node-abi@^2.2.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.5.0.tgz#942e1a78bce764bc0c1672d5821e492b9d032052"
integrity sha512-9g2twBGSP6wIR5PW7tXvAWnEWKJDH/VskdXp168xsw9VVxpEGov8K4jsP4/VeoC7b2ZAyzckvMCuQuQlw44lXg==
dependencies:
semver "^5.4.1"
node-dir@0.1.8:
version "0.1.8"
resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.8.tgz#55fb8deb699070707fb67f91a460f0448294c77d"
@ -11339,13 +11385,13 @@ node-gyp@^3.6.0:
which "1"
node-hid@^0.7.2:
version "0.7.3"
resolved "https://registry.yarnpkg.com/node-hid/-/node-hid-0.7.3.tgz#736e9a4dee5eec96c20fbe301e0311bb185cb2f4"
integrity sha512-LOCqWqcOlng+Kn1Qj/54zrPVfCagg1O7RlSgMmugykBcoYvUud6BswTrJM2aXuBac+bCCm3lA2srRG8YfmyXZQ==
version "0.7.4"
resolved "https://registry.yarnpkg.com/node-hid/-/node-hid-0.7.4.tgz#2db109acee654b56bf518ffb3fd92cf9cd0647c1"
integrity sha512-gvgNDPoszObn7avIDYMUvVv1T0xQB4/CZFJWckra/LXAc0qHYho4M1LCnCKlLIocL2R5/3qGv0J4AjRMdwgjxg==
dependencies:
bindings "^1.3.0"
nan "^2.10.0"
prebuild-install "^4.0.0"
prebuild-install "^5.2.1"
node-int64@^0.4.0:
version "0.4.0"
@ -11407,13 +11453,29 @@ node-object-hash@^1.2.0:
integrity sha512-JQVqSM5/mOaUoUhCYR0t1vgm8RFo7qpJtPvnoFCLeqQh1xrfmr3BCD3nGBnACzpIEF7F7EVgqGD3O4lao/BY/A==
node-pre-gyp@^0.10.0:
version "0.10.2"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.2.tgz#e8945c20ef6795a20aac2b44f036eb13cf5146e3"
integrity sha512-16lql9QTqs6KsB9fl3neWyZm02KxIKdI9FlJjrB0y7eMTP5Nyz+xalwPbOlw3iw7EejllJPmlJSnY711PLD1ug==
version "0.10.3"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc"
integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==
dependencies:
detect-libc "^1.0.2"
mkdirp "^0.5.1"
needle "^2.2.1"
nopt "^4.0.1"
npm-packlist "^1.1.6"
npmlog "^4.0.2"
rc "^1.2.7"
rimraf "^2.6.1"
semver "^5.3.0"
tar "^4"
node-pre-gyp@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054"
integrity sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==
dependencies:
detect-libc "^1.0.2"
mkdirp "^0.5.1"
needle "^2.2.0"
needle "^2.2.1"
nopt "^4.0.1"
npm-packlist "^1.1.6"
npmlog "^4.0.2"
@ -11516,9 +11578,9 @@ normalize-url@^1.4.0, normalize-url@^1.9.1:
sort-keys "^1.0.0"
npm-bundled@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308"
integrity sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==
version "1.0.5"
resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979"
integrity sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g==
npm-install-package@~2.1.0:
version "2.1.0"
@ -11526,9 +11588,9 @@ npm-install-package@~2.1.0:
integrity sha1-1+/jz816sAYUuJbqUxGdyaslkSU=
npm-packlist@^1.1.6:
version "1.1.10"
resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.10.tgz#1039db9e985727e464df066f4cf0ab6ef85c398a"
integrity sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==
version "1.1.12"
resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.12.tgz#22bde2ebc12e72ca482abd67afc51eb49377243a"
integrity sha512-WJKFOVMeAlsU/pjXuqVdzU0WfgtIBCupkEVwn+1Y0ERAbUfWw8R4GjgVbaKnUjRoD2FoQbHOCbOyT5Mbs9Lw4g==
dependencies:
ignore-walk "^3.0.1"
npm-bundled "^1.0.1"
@ -12600,22 +12662,23 @@ prebuild-install@^2.0.0:
tunnel-agent "^0.6.0"
which-pm-runs "^1.0.0"
prebuild-install@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-4.0.0.tgz#206ce8106ce5efa4b6cf062fc8a0a7d93c17f3a8"
integrity sha512-7tayxeYboJX0RbVzdnKyGl2vhQRWr6qfClEXDhOkXjuaOKCw2q8aiuFhONRYVsG/czia7KhpykIlI2S2VaPunA==
prebuild-install@^5.2.1:
version "5.2.2"
resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.2.2.tgz#237888f21bfda441d0ee5f5612484390bccd4046"
integrity sha512-4e8VJnP3zJdZv/uP0eNWmr2r9urp4NECw7Mt1OSAi3rcLrbBRxGiAkfUFtre2MhQ5wfREAjRV+K1gubvs/GPsA==
dependencies:
detect-libc "^1.0.3"
expand-template "^1.0.2"
expand-template "^2.0.3"
github-from-package "0.0.0"
minimist "^1.2.0"
mkdirp "^0.5.1"
napi-build-utils "^1.0.1"
node-abi "^2.2.0"
noop-logger "^0.1.1"
npmlog "^4.0.1"
os-homedir "^1.0.1"
pump "^2.0.1"
rc "^1.1.6"
rc "^1.2.7"
simple-get "^2.7.0"
tar-fs "^1.13.0"
tunnel-agent "^0.6.0"
@ -14325,7 +14388,7 @@ semver-diff@^2.0.0:
dependencies:
semver "^5.0.3"
"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0:
"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==
@ -14335,6 +14398,11 @@ semver@^5.0.1:
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477"
integrity sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==
semver@^5.3.0, semver@^5.4.1:
version "5.6.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
semver@~5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
@ -15287,7 +15355,20 @@ tar-fs@^1.13.0:
pump "^1.0.0"
tar-stream "^1.1.2"
tar-stream@^1.1.2, tar-stream@^1.5.0:
tar-stream@^1.1.2:
version "1.6.2"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555"
integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==
dependencies:
bl "^1.0.0"
buffer-alloc "^1.2.0"
end-of-stream "^1.0.0"
fs-constants "^1.0.0"
readable-stream "^2.3.0"
to-buffer "^1.1.1"
xtend "^4.0.0"
tar-stream@^1.5.0:
version "1.6.1"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.1.tgz#f84ef1696269d6223ca48f6e1eeede3f7e81f395"
integrity sha512-IFLM5wp3QrJODQFPm6/to3LJZrONdBY/otxcvDIQzu217zKye6yVR3hhi9lAjrC2Z+m/j5oDxMPb1qcd8cIvpA==
@ -15310,14 +15391,14 @@ tar@^2.0.0:
inherits "2"
tar@^4:
version "4.4.4"
resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.4.tgz#ec8409fae9f665a4355cc3b4087d0820232bb8cd"
integrity sha512-mq9ixIYfNF9SK0IS/h2HKMu8Q2iaCuhDDsZhdEag/FHv8fOaYld4vN7ouMgcSSt5WKZzPs8atclTcJm36OTh4w==
version "4.4.8"
resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d"
integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==
dependencies:
chownr "^1.0.1"
chownr "^1.1.1"
fs-minipass "^1.2.5"
minipass "^2.3.3"
minizlib "^1.1.0"
minipass "^2.3.4"
minizlib "^1.1.1"
mkdirp "^0.5.0"
safe-buffer "^5.1.2"
yallist "^3.0.2"
@ -15455,7 +15536,7 @@ to-arraybuffer@^1.0.0:
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=
to-buffer@^1.1.0:
to-buffer@^1.1.0, to-buffer@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80"
integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==
@ -15977,12 +16058,12 @@ url@^0.11.0, url@~0.11.0:
querystring "0.2.0"
usb@^1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/usb/-/usb-1.3.3.tgz#4e8a4b44ab8833fa1c4fb99778ebae1d2d626970"
integrity sha512-WRBxI54yEs2QPj28G6kITI3Wu7VxrtHbqiDvDRUDKdg97lcK1pTP8y9LoDWF22OiCCrEvrdeq0lNcr84QOzjXQ==
version "1.5.0"
resolved "https://registry.yarnpkg.com/usb/-/usb-1.5.0.tgz#3e07b23c6dacf06a7c8801ae913926702a818218"
integrity sha512-/0stiQEmweuO2BKv2avzQQ8ypDUjo4Osz5sSEi+d0F4Rc+ddX1xED3uf4Tkelc1eADlfn0JQZYHP0bI7CNDA0Q==
dependencies:
nan "^2.8.0"
node-pre-gyp "^0.10.0"
node-pre-gyp "^0.11.0"
use@^3.1.0:
version "3.1.0"
@ -16791,9 +16872,9 @@ yallist@^2.1.2:
integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
yallist@^3.0.0, yallist@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9"
integrity sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=
version "3.0.3"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
yaml-loader@^0.5.0:
version "0.5.0"

Loading…
Cancel
Save