Browse Source

Merge pull request #628 from valpinkman/feature/new-api-server

[STAND-BY] Feature/new api server
master
Valentin D. Pinkman 7 years ago
committed by GitHub
parent
commit
1031366614
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 19
      src/commands/getCurrentFirmware.js
  2. 19
      src/commands/getFirmwareInfo.js
  3. 14
      src/commands/getIsGenuine.js
  4. 4
      src/commands/index.js
  5. 9
      src/commands/installApp.js
  6. 25
      src/commands/installMcu.js
  7. 11
      src/commands/installOsuFirmware.js
  8. 5
      src/commands/listApps.js
  9. 9
      src/commands/uninstallApp.js
  10. 17
      src/components/ManagerPage/AppSearchBar.js
  11. 41
      src/components/ManagerPage/AppsList.js
  12. 2
      src/components/ManagerPage/Dashboard.js
  13. 16
      src/components/ManagerPage/FirmwareUpdate.js
  14. 55
      src/components/ManagerPage/FlashMcu.js
  15. 5
      src/components/ManagerPage/UpdateFirmwareButton.js
  16. 7
      src/components/ManagerPage/index.js
  17. 15
      src/components/TriggerOnMount/index.js
  18. 2
      src/components/Workflow/EnsureGenuine.js
  19. 30
      src/components/Workflow/index.js
  20. 17
      src/helpers/apps/installApp.js
  21. 26
      src/helpers/apps/listApps.js
  22. 19
      src/helpers/apps/uninstallApp.js
  23. 49
      src/helpers/common.js
  24. 26
      src/helpers/devices/getCurrentFirmware.js
  25. 19
      src/helpers/devices/getDeviceVersion.js
  26. 34
      src/helpers/devices/getFirmwareInfo.js
  27. 24
      src/helpers/devices/getIsGenuine.js
  28. 37
      src/helpers/devices/getLatestFirmwareForDevice.js
  29. 7
      src/helpers/devices/getMemInfo.js
  30. 26
      src/helpers/devices/getNextMCU.js
  31. 10
      src/helpers/firmware/installFinalFirmware.js
  32. 25
      src/helpers/firmware/installMcu.js
  33. 23
      src/helpers/firmware/installOsuFirmware.js
  34. 27
      src/helpers/urls.js
  35. 1
      static/i18n/en/errors.yml

19
src/commands/getCurrentFirmware.js

@ -0,0 +1,19 @@
// @flow
import { createCommand, Command } from 'helpers/ipc'
import { fromPromise } from 'rxjs/observable/fromPromise'
import getCurrentFirmware from 'helpers/devices/getCurrentFirmware'
type Input = {
deviceId: string | number,
version: string,
}
type Result = *
const cmd: Command<Input, Result> = createCommand('getCurrentFirmware', data =>
fromPromise(getCurrentFirmware(data)),
)
export default cmd

19
src/commands/getFirmwareInfo.js

@ -1,19 +0,0 @@
// @flow
import { createCommand, Command } from 'helpers/ipc'
import { fromPromise } from 'rxjs/observable/fromPromise'
import getFirmwareInfo from 'helpers/devices/getFirmwareInfo'
type Input = {
targetId: string | number,
version: string,
}
type Result = *
const cmd: Command<Input, Result> = createCommand('getFirmwareInfo', data =>
fromPromise(getFirmwareInfo(data)),
)
export default cmd

14
src/commands/getIsGenuine.js

@ -6,11 +6,19 @@ import { fromPromise } from 'rxjs/observable/fromPromise'
import getIsGenuine from 'helpers/devices/getIsGenuine' import getIsGenuine from 'helpers/devices/getIsGenuine'
import { withDevice } from 'helpers/deviceAccess' import { withDevice } from 'helpers/deviceAccess'
type Input = * // FIXME ! type Input = {
devicePath: string,
targetId: string | number,
version: string,
}
type Result = string type Result = string
const cmd: Command<Input, Result> = createCommand('getIsGenuine', ({ devicePath, targetId }) => const cmd: Command<Input, Result> = createCommand(
fromPromise(withDevice(devicePath)(transport => getIsGenuine(transport, { targetId }))), 'getIsGenuine',
({ devicePath, targetId, version }) =>
fromPromise(
withDevice(devicePath)(transport => getIsGenuine(transport, { targetId, version })),
),
) )
export default cmd export default cmd

4
src/commands/index.js

@ -5,7 +5,7 @@ import type { Command } from 'helpers/ipc'
import getAddress from 'commands/getAddress' import getAddress from 'commands/getAddress'
import getDeviceInfo from 'commands/getDeviceInfo' import getDeviceInfo from 'commands/getDeviceInfo'
import getFirmwareInfo from 'commands/getFirmwareInfo' import getCurrentFirmware from 'commands/getCurrentFirmware'
import getIsGenuine from 'commands/getIsGenuine' import getIsGenuine from 'commands/getIsGenuine'
import getLatestFirmwareForDevice from 'commands/getLatestFirmwareForDevice' import getLatestFirmwareForDevice from 'commands/getLatestFirmwareForDevice'
import getMemInfo from 'commands/getMemInfo' import getMemInfo from 'commands/getMemInfo'
@ -32,7 +32,7 @@ import uninstallApp from 'commands/uninstallApp'
const all: Array<Command<any, any>> = [ const all: Array<Command<any, any>> = [
getAddress, getAddress,
getDeviceInfo, getDeviceInfo,
getFirmwareInfo, getCurrentFirmware,
getIsGenuine, getIsGenuine,
getLatestFirmwareForDevice, getLatestFirmwareForDevice,
getMemInfo, getMemInfo,

9
src/commands/installApp.js

@ -9,14 +9,17 @@ import installApp from 'helpers/apps/installApp'
import type { LedgerScriptParams } from 'helpers/common' import type { LedgerScriptParams } from 'helpers/common'
type Input = { type Input = {
appParams: LedgerScriptParams, app: LedgerScriptParams,
devicePath: string, devicePath: string,
targetId: string | number,
} }
type Result = * type Result = *
const cmd: Command<Input, Result> = createCommand('installApp', ({ devicePath, ...rest }) => const cmd: Command<Input, Result> = createCommand(
fromPromise(withDevice(devicePath)(transport => installApp(transport, rest))), 'installApp',
({ devicePath, targetId, ...app }) =>
fromPromise(withDevice(devicePath)(transport => installApp(transport, targetId, app))),
) )
export default cmd export default cmd

25
src/commands/installMcu.js

@ -3,24 +3,21 @@
import { createCommand, Command } from 'helpers/ipc' import { createCommand, Command } from 'helpers/ipc'
import { fromPromise } from 'rxjs/observable/fromPromise' import { fromPromise } from 'rxjs/observable/fromPromise'
// import { withDevice } from 'helpers/deviceAccess' import { withDevice } from 'helpers/deviceAccess'
import installMcu from 'helpers/firmware/installMcu' import installMcu from 'helpers/firmware/installMcu'
// type Input = { type Input = {
// devicePath: string, devicePath: string,
// firmware: Object, targetId: string | number,
// } version: string,
}
// type Result = {
// targetId: number | string,
// version: string,
// final: boolean,
// mcu: boolean,
// }
type Input = *
type Result = * type Result = *
const cmd: Command<Input, Result> = createCommand('installMcu', () => fromPromise(installMcu())) const cmd: Command<Input, Result> = createCommand(
'installMcu',
({ devicePath, targetId, version }) =>
fromPromise(withDevice(devicePath)(transport => installMcu(transport, { targetId, version }))),
)
export default cmd export default cmd

11
src/commands/installOsuFirmware.js

@ -6,17 +6,22 @@ import { fromPromise } from 'rxjs/observable/fromPromise'
import { withDevice } from 'helpers/deviceAccess' import { withDevice } from 'helpers/deviceAccess'
import installOsuFirmware from 'helpers/firmware/installOsuFirmware' import installOsuFirmware from 'helpers/firmware/installOsuFirmware'
import type { LedgerScriptParams } from 'helpers/common'
type Input = { type Input = {
devicePath: string, devicePath: string,
firmware: Object, targetId: string | number,
firmware: LedgerScriptParams,
} }
type Result = * type Result = *
const cmd: Command<Input, Result> = createCommand( const cmd: Command<Input, Result> = createCommand(
'installOsuFirmware', 'installOsuFirmware',
({ devicePath, firmware }) => ({ devicePath, firmware, targetId }) =>
fromPromise(withDevice(devicePath)(transport => installOsuFirmware(transport, firmware))), fromPromise(
withDevice(devicePath)(transport => installOsuFirmware(transport, targetId, firmware)),
),
) )
export default cmd export default cmd

5
src/commands/listApps.js

@ -7,12 +7,13 @@ import listApps from 'helpers/apps/listApps'
type Input = { type Input = {
targetId: string | number, targetId: string | number,
version: string,
} }
type Result = * type Result = *
const cmd: Command<Input, Result> = createCommand('listApps', ({ targetId }) => const cmd: Command<Input, Result> = createCommand('listApps', ({ targetId, version }) =>
fromPromise(listApps(targetId)), fromPromise(listApps(targetId, version)),
) )
export default cmd export default cmd

9
src/commands/uninstallApp.js

@ -9,14 +9,17 @@ import uninstallApp from 'helpers/apps/uninstallApp'
import type { LedgerScriptParams } from 'helpers/common' import type { LedgerScriptParams } from 'helpers/common'
type Input = { type Input = {
appParams: LedgerScriptParams, app: LedgerScriptParams,
devicePath: string, devicePath: string,
targetId: string | number,
} }
type Result = * type Result = *
const cmd: Command<Input, Result> = createCommand('uninstallApp', ({ devicePath, ...rest }) => const cmd: Command<Input, Result> = createCommand(
fromPromise(withDevice(devicePath)(transport => uninstallApp(transport, rest))), 'uninstallApp',
({ devicePath, targetId, ...rest }) =>
fromPromise(withDevice(devicePath)(transport => uninstallApp(transport, targetId, rest))),
) )
export default cmd export default cmd

17
src/components/ManagerPage/AppSearchBar.js

@ -4,6 +4,8 @@ import styled from 'styled-components'
import { color, fontSize, space } from 'styled-system' import { color, fontSize, space } from 'styled-system'
import fontFamily from 'styles/styled/fontFamily' import fontFamily from 'styles/styled/fontFamily'
import type { LedgerScriptParams } from 'helpers/common'
import { ff } from 'styles/helpers' import { ff } from 'styles/helpers'
import Box from 'components/base/Box' import Box from 'components/base/Box'
@ -12,20 +14,9 @@ import Search from 'components/base/Search'
import SearchIcon from 'icons/Search' import SearchIcon from 'icons/Search'
import CrossIcon from 'icons/Cross' import CrossIcon from 'icons/Cross'
type LedgerApp = {
name: string,
version: string,
icon: string,
app: Object,
bolos_version: {
min: number,
max: number,
},
}
type Props = { type Props = {
list: Array<LedgerApp>, list: Array<LedgerScriptParams>,
children: (list: Array<LedgerApp>) => React$Node, children: (list: Array<LedgerScriptParams>) => React$Node,
} }
type State = { type State = {

41
src/components/ManagerPage/AppsList.js

@ -6,6 +6,7 @@ import styled from 'styled-components'
import { translate } from 'react-i18next' import { translate } from 'react-i18next'
import type { Device, T } from 'types/common' import type { Device, T } from 'types/common'
import type { LedgerScriptParams } from 'helpers/common'
import listApps from 'commands/listApps' import listApps from 'commands/listApps'
import installApp from 'commands/installApp' import installApp from 'commands/installApp'
@ -43,27 +44,17 @@ const ICONS_FALLBACK = {
type Status = 'loading' | 'idle' | 'busy' | 'success' | 'error' type Status = 'loading' | 'idle' | 'busy' | 'success' | 'error'
type Mode = 'home' | 'installing' | 'uninstalling' type Mode = 'home' | 'installing' | 'uninstalling'
type LedgerApp = {
name: string,
version: string,
icon: string,
app: Object,
bolos_version: {
min: number,
max: number,
},
}
type Props = { type Props = {
device: Device, device: Device,
targetId: string | number, targetId: string | number,
t: T, t: T,
version: string,
} }
type State = { type State = {
status: Status, status: Status,
error: string | null, error: string | null,
appsList: LedgerApp[], appsList: LedgerScriptParams[] | Array<*>,
app: string, app: string,
mode: Mode, mode: Mode,
} }
@ -89,8 +80,8 @@ class AppsList extends PureComponent<Props, State> {
async fetchAppList() { async fetchAppList() {
try { try {
const { targetId } = this.props const { targetId, version } = this.props
const appsList = CACHED_APPS || (await listApps.send({ targetId }).toPromise()) const appsList = CACHED_APPS || (await listApps.send({ targetId, version }).toPromise())
CACHED_APPS = appsList CACHED_APPS = appsList
if (!this._unmounted) { if (!this._unmounted) {
this.setState({ appsList, status: 'idle' }) this.setState({ appsList, status: 'idle' })
@ -100,14 +91,14 @@ class AppsList extends PureComponent<Props, State> {
} }
} }
handleInstallApp = (args: { app: any, name: string }) => async () => { handleInstallApp = (app: LedgerScriptParams) => async () => {
const { app: appParams, name } = args this.setState({ status: 'busy', app: app.name, mode: 'installing' })
this.setState({ status: 'busy', app: name, mode: 'installing' })
try { try {
const { const {
device: { path: devicePath }, device: { path: devicePath },
targetId,
} = this.props } = this.props
const data = { appParams, devicePath } const data = { app, devicePath, targetId }
await installApp.send(data).toPromise() await installApp.send(data).toPromise()
this.setState({ status: 'success', app: '' }) this.setState({ status: 'success', app: '' })
} catch (err) { } catch (err) {
@ -115,14 +106,14 @@ class AppsList extends PureComponent<Props, State> {
} }
} }
handleUninstallApp = (args: { app: any, name: string }) => async () => { handleUninstallApp = (app: LedgerScriptParams) => async () => {
const { app: appParams, name } = args this.setState({ status: 'busy', app: app.name, mode: 'uninstalling' })
this.setState({ status: 'busy', app: name, mode: 'uninstalling' })
try { try {
const { const {
device: { path: devicePath }, device: { path: devicePath },
targetId,
} = this.props } = this.props
const data = { appParams, devicePath } const data = { app, devicePath, targetId }
await uninstallApp.send(data).toPromise() await uninstallApp.send(data).toPromise()
this.setState({ status: 'success', app: '' }) this.setState({ status: 'success', app: '' })
} catch (err) { } catch (err) {
@ -184,15 +175,15 @@ class AppsList extends PureComponent<Props, State> {
} }
renderList() { renderList() {
const { appsList } = this.state const { appsList, status } = this.state
return appsList.length > 0 ? ( return status === 'idle' ? (
<Box> <Box>
<AppSearchBar list={appsList}> <AppSearchBar list={appsList}>
{items => ( {items => (
<List> <List>
{items.map(c => ( {items.map(c => (
<ManagerApp <ManagerApp
key={`${c.name}_${c.version}_${c.bolos_version.min}`} key={`${c.name}_${c.version}`}
name={c.name} name={c.name}
version={`Version ${c.version}`} version={`Version ${c.version}`}
icon={ICONS_FALLBACK[c.icon] || c.icon} icon={ICONS_FALLBACK[c.icon] || c.icon}

2
src/components/ManagerPage/Dashboard.js

@ -43,7 +43,7 @@ const Dashboard = ({ device, deviceInfo, t }: Props) => (
/> />
</Box> </Box>
<Box mt={5}> <Box mt={5}>
<AppsList device={device} targetId={deviceInfo.targetId} /> <AppsList device={device} targetId={deviceInfo.targetId} version={deviceInfo.version} />
</Box> </Box>
</Box> </Box>
) )

16
src/components/ManagerPage/FirmwareUpdate.js

@ -10,6 +10,8 @@ import logger from 'logger'
import type { Device, T } from 'types/common' import type { Device, T } from 'types/common'
import type { LedgerScriptParams } from 'helpers/common'
import getLatestFirmwareForDevice from 'commands/getLatestFirmwareForDevice' import getLatestFirmwareForDevice from 'commands/getLatestFirmwareForDevice'
import installOsuFirmware from 'commands/installOsuFirmware' import installOsuFirmware from 'commands/installOsuFirmware'
@ -23,11 +25,6 @@ import UpdateFirmwareButton from './UpdateFirmwareButton'
let CACHED_LATEST_FIRMWARE = null let CACHED_LATEST_FIRMWARE = null
type FirmwareInfos = {
name: string,
notes: string,
}
type DeviceInfos = { type DeviceInfos = {
targetId: number | string, targetId: number | string,
version: string, version: string,
@ -40,7 +37,7 @@ type Props = {
} }
type State = { type State = {
latestFirmware: ?FirmwareInfos, latestFirmware: ?LedgerScriptParams,
} }
class FirmwareUpdate extends PureComponent<Props, State> { class FirmwareUpdate extends PureComponent<Props, State> {
@ -84,12 +81,13 @@ class FirmwareUpdate extends PureComponent<Props, State> {
installFirmware = async () => { installFirmware = async () => {
try { try {
const { latestFirmware } = this.state const { latestFirmware } = this.state
const { infos } = this.props
invariant(latestFirmware, 'did not find a new firmware or firmware is not set') invariant(latestFirmware, 'did not find a new firmware or firmware is not set')
const { const {
device: { path: devicePath }, device: { path: devicePath },
} = this.props } = this.props
const { success } = await installOsuFirmware const { success } = await installOsuFirmware
.send({ devicePath, firmware: latestFirmware }) .send({ devicePath, firmware: latestFirmware, targetId: infos.targetId })
.toPromise() .toPromise()
if (success) { if (success) {
this.fetchLatestFirmware() this.fetchLatestFirmware()
@ -119,7 +117,9 @@ class FirmwareUpdate extends PureComponent<Props, State> {
</Box> </Box>
</Box> </Box>
<Text ff="Open Sans|SemiBold" fontSize={2}> <Text ff="Open Sans|SemiBold" fontSize={2}>
{t('app:manager.firmware.installed', { version: infos.version })} {t('app:manager.firmware.installed', {
version: infos.version,
})}
</Text> </Text>
</Box> </Box>
<UpdateFirmwareButton firmware={latestFirmware} installFirmware={this.installFirmware} /> <UpdateFirmwareButton firmware={latestFirmware} installFirmware={this.installFirmware} />

55
src/components/ManagerPage/FlashMcu.js

@ -0,0 +1,55 @@
// @flow
import React, { PureComponent } from 'react'
import type { Device } from 'types/common'
import installMcu from 'commands/installMcu'
type DeviceInfo = {
targetId: number | string,
version: string,
final: boolean,
mcu: boolean,
}
type Props = {
device: Device,
deviceInfo: DeviceInfo,
}
type State = {
flashing: boolean,
}
class FlashMcu extends PureComponent<Props, State> {
state = {
flashing: false,
}
flashMCU = async () => {
const { device, deviceInfo } = this.props
const { flashing } = this.state
if (!flashing) {
this.setState({ flashing: true })
await installMcu
.send({
devicePath: device.path,
targetId: deviceInfo.targetId,
version: deviceInfo.version,
})
.toPromise()
this.setState({ flashing: false })
}
}
render() {
return (
<div>
<h1>Flashing MCU</h1>
<button onClick={this.flashMCU}>flash</button>
</div>
)
}
}
export default FlashMcu

5
src/components/ManagerPage/UpdateFirmwareButton.js

@ -18,11 +18,14 @@ type Props = {
installFirmware: () => void, installFirmware: () => void,
} }
const getCleanVersion = (input: string): string =>
input.endsWith('-osu') ? input.replace('-osu', '') : input
const UpdateFirmwareButton = ({ t, firmware, installFirmware }: Props) => const UpdateFirmwareButton = ({ t, firmware, installFirmware }: Props) =>
firmware ? ( firmware ? (
<Fragment> <Fragment>
<Text ff="Open Sans|Regular" fontSize={4} style={{ marginLeft: 'auto', marginRight: 15 }}> <Text ff="Open Sans|Regular" fontSize={4} style={{ marginLeft: 'auto', marginRight: 15 }}>
{t('app:manager.firmware.latest', { version: firmware.name })} {t('app:manager.firmware.latest', { version: getCleanVersion(firmware.name) })}
</Text> </Text>
<Button primary onClick={installFirmware}> <Button primary onClick={installFirmware}>
{t('app:manager.firmware.update')} {t('app:manager.firmware.update')}

7
src/components/ManagerPage/index.js

@ -9,6 +9,7 @@ import type { Device } from 'types/common'
import Workflow from 'components/Workflow' import Workflow from 'components/Workflow'
import WorkflowWithIcon from 'components/Workflow/WorkflowWithIcon' import WorkflowWithIcon from 'components/Workflow/WorkflowWithIcon'
import Dashboard from './Dashboard' import Dashboard from './Dashboard'
import FlashMcu from './FlashMcu'
type DeviceInfo = { type DeviceInfo = {
targetId: number | string, targetId: number | string,
@ -25,11 +26,11 @@ type Error = {
function ManagerPage(): Node { function ManagerPage(): Node {
return ( return (
<Workflow <Workflow
renderFinalUpdate={(deviceInfo: DeviceInfo) => ( renderFinalUpdate={(device: Device, deviceInfo: DeviceInfo) => (
<p>UPDATE FINAL FIRMARE (TEMPLATE + ACTION WIP) {deviceInfo.final}</p> <p>UPDATE FINAL FIRMARE (TEMPLATE + ACTION WIP) {deviceInfo.final}</p>
)} )}
renderMcuUpdate={(deviceInfo: DeviceInfo) => ( renderMcuUpdate={(device: Device, deviceInfo: DeviceInfo) => (
<p>FLASH MCU (TEMPLATE + ACTION WIP) {deviceInfo.mcu}</p> <FlashMcu device={device} deviceInfo={deviceInfo} />
)} )}
renderDashboard={(device: Device, deviceInfo: DeviceInfo) => ( renderDashboard={(device: Device, deviceInfo: DeviceInfo) => (
<Dashboard device={device} deviceInfo={deviceInfo} /> <Dashboard device={device} deviceInfo={deviceInfo} />

15
src/components/TriggerOnMount/index.js

@ -1,15 +0,0 @@
// @flow
import { PureComponent } from 'react'
type Props = {
callback: () => void,
}
class TriggerOnMount extends PureComponent<Props> {
componentDidMount() {
const { callback } = this.props
callback()
}
}
export default TriggerOnMount

2
src/components/Workflow/EnsureGenuine.js

@ -61,7 +61,7 @@ class EnsureGenuine extends PureComponent<Props, State> {
this._checking = true this._checking = true
try { try {
const res = await getIsGenuine const res = await getIsGenuine
.send({ devicePath: device.path, targetId: infos.targetId }) .send({ devicePath: device.path, targetId: infos.targetId, version: infos.version })
.pipe(timeout(GENUINE_TIMEOUT)) .pipe(timeout(GENUINE_TIMEOUT))
.toPromise() .toPromise()
if (this._unmounting) return if (this._unmounting) return

30
src/components/Workflow/index.js

@ -31,9 +31,10 @@ type Props = {
genuineError: ?Error, genuineError: ?Error,
}, },
) => Node, ) => Node,
renderMcuUpdate?: (deviceInfo: DeviceInfo) => Node, renderMcuUpdate?: (device: Device, deviceInfo: DeviceInfo) => Node,
renderFinalUpdate?: (deviceInfo: DeviceInfo) => Node, renderFinalUpdate?: (device: Device, deviceInfo: DeviceInfo) => Node,
renderDashboard?: (device: Device, deviceInfo: DeviceInfo, isGenuine: boolean) => Node, renderDashboard?: (device: Device, deviceInfo: DeviceInfo, isGenuine: boolean) => Node,
onGenuineCheck?: (isGenuine: boolean) => void,
renderError?: (dashboardError: ?Error, genuineError: ?Error) => Node, renderError?: (dashboardError: ?Error, genuineError: ?Error) => Node,
} }
type State = {} type State = {}
@ -47,12 +48,22 @@ class Workflow extends PureComponent<Props, State> {
renderMcuUpdate, renderMcuUpdate,
renderError, renderError,
renderDefault, renderDefault,
onGenuineCheck,
} = this.props } = this.props
return ( return (
<EnsureDevice> <EnsureDevice>
{(device: Device) => ( {(device: Device) => (
<EnsureDashboard device={device}> <EnsureDashboard device={device}>
{(deviceInfo: ?DeviceInfo, dashboardError: ?Error) => ( {(deviceInfo: ?DeviceInfo, dashboardError: ?Error) => {
if (deviceInfo && deviceInfo.mcu && renderMcuUpdate) {
return renderMcuUpdate(device, deviceInfo)
}
if (deviceInfo && deviceInfo.final && renderFinalUpdate) {
return renderFinalUpdate(device, deviceInfo)
}
return (
<EnsureGenuine device={device} infos={deviceInfo}> <EnsureGenuine device={device} infos={deviceInfo}>
{(isGenuine: ?boolean, genuineError: ?Error) => { {(isGenuine: ?boolean, genuineError: ?Error) => {
if (dashboardError || genuineError) { if (dashboardError || genuineError) {
@ -64,15 +75,9 @@ class Workflow extends PureComponent<Props, State> {
}) })
} }
if (deviceInfo && deviceInfo.mcu && renderMcuUpdate) {
return renderMcuUpdate(deviceInfo)
}
if (deviceInfo && deviceInfo.final && renderFinalUpdate) {
return renderFinalUpdate(deviceInfo)
}
if (isGenuine && deviceInfo && device && !dashboardError && !genuineError) { if (isGenuine && deviceInfo && device && !dashboardError && !genuineError) {
if (onGenuineCheck) onGenuineCheck(isGenuine)
if (renderDashboard) return renderDashboard(device, deviceInfo, isGenuine) if (renderDashboard) return renderDashboard(device, deviceInfo, isGenuine)
} }
@ -82,7 +87,8 @@ class Workflow extends PureComponent<Props, State> {
}) })
}} }}
</EnsureGenuine> </EnsureGenuine>
)} )
}}
</EnsureDashboard> </EnsureDashboard>
)} )}
</EnsureDevice> </EnsureDevice>

17
src/helpers/apps/installApp.js

@ -1,8 +1,10 @@
// @flow // @flow
import qs from 'qs'
import type Transport from '@ledgerhq/hw-transport' import type Transport from '@ledgerhq/hw-transport'
import { createSocketDialog } from 'helpers/common' import { BASE_SOCKET_URL_SECURE } from 'config/constants'
import { createDeviceSocket } from 'helpers/socket'
import type { LedgerScriptParams } from 'helpers/common' import type { LedgerScriptParams } from 'helpers/common'
/** /**
@ -10,7 +12,14 @@ import type { LedgerScriptParams } from 'helpers/common'
*/ */
export default async function installApp( export default async function installApp(
transport: Transport<*>, transport: Transport<*>,
{ appParams }: { appParams: LedgerScriptParams }, targetId: string | number,
{ app }: { app: LedgerScriptParams },
): Promise<*> { ): Promise<*> {
return createSocketDialog(transport, '/install', appParams) const params = {
targetId,
...app,
firmwareKey: app.firmware_key,
}
const url = `${BASE_SOCKET_URL_SECURE}/install?${qs.stringify(params)}`
return createDeviceSocket(transport, url).toPromise()
} }

26
src/helpers/apps/listApps.js

@ -1,20 +1,24 @@
// @flow // @flow
import axios from 'axios' import axios from 'axios'
import { MANAGER_API_BASE } from 'config/constants' import { APPLICATIONS_BY_DEVICE } from 'helpers/urls'
import getDeviceVersion from 'helpers/devices/getDeviceVersion'
import getCurrentFirmware from 'helpers/devices/getCurrentFirmware'
export default async (targetId: string | number) => { export default async (targetId: string | number, version: string) => {
try { try {
const { data: deviceData } = await axios.get( const provider = 1
`${MANAGER_API_BASE}/device_versions_target_id/${targetId}`, const deviceData = await getDeviceVersion(targetId)
) const firmwareData = await getCurrentFirmware({ deviceId: deviceData.id, version })
const { data } = await axios.get('https://api.ledgerwallet.com/update/applications') const params = {
provider,
if (deviceData.name in data) { current_se_firmware_final_version: firmwareData.id,
return data[deviceData.name] device_version: deviceData.id,
} }
const {
return data['nanos-1.4'] data: { application_versions },
} = await axios.post(APPLICATIONS_BY_DEVICE, params)
return application_versions.length > 0 ? application_versions : []
} catch (err) { } catch (err) {
const error = Error(err.message) const error = Error(err.message)
error.stack = err.stack error.stack = err.stack

19
src/helpers/apps/uninstallApp.js

@ -1,8 +1,10 @@
// @flow // @flow
import qs from 'qs'
import type Transport from '@ledgerhq/hw-transport' import type Transport from '@ledgerhq/hw-transport'
import { createSocketDialog } from 'helpers/common' import { BASE_SOCKET_URL_SECURE } from 'config/constants'
import { createDeviceSocket } from 'helpers/socket'
import type { LedgerScriptParams } from 'helpers/common' import type { LedgerScriptParams } from 'helpers/common'
/** /**
@ -10,12 +12,15 @@ import type { LedgerScriptParams } from 'helpers/common'
*/ */
export default async function uninstallApp( export default async function uninstallApp(
transport: Transport<*>, transport: Transport<*>,
{ appParams }: { appParams: LedgerScriptParams }, targetId: string | number,
{ app }: { app: LedgerScriptParams },
): Promise<*> { ): Promise<*> {
const params = { const params = {
...appParams, targetId,
firmware: appParams.delete, ...app,
firmwareKey: appParams.deleteKey, firmware: app.delete,
firmwareKey: app.delete_key,
} }
return createSocketDialog(transport, '/install', params) const url = `${BASE_SOCKET_URL_SECURE}/install?${qs.stringify(params)}`
return createDeviceSocket(transport, url).toPromise()
} }

49
src/helpers/common.js

@ -1,11 +1,7 @@
// @flow // @flow
// FIXME remove this file! 'helpers/common.js' RLY? :P // FIXME remove this file! 'helpers/common.js' RLY? :P
import qs from 'qs'
import type Transport from '@ledgerhq/hw-transport' import type Transport from '@ledgerhq/hw-transport'
import { BASE_SOCKET_URL, BASE_SOCKET_URL_SECURE } from 'config/constants'
import { createDeviceSocket } from './socket'
const APDUS = { const APDUS = {
GET_FIRMWARE: [0xe0, 0x01, 0x00, 0x00], GET_FIRMWARE: [0xe0, 0x01, 0x00, 0x00],
@ -16,35 +12,14 @@ const APDUS = {
export type LedgerScriptParams = { export type LedgerScriptParams = {
firmware?: string, firmware?: string,
firmwareKey?: string, firmware_key?: string,
delete?: string, delete?: string,
deleteKey?: string, delete_key?: string,
targetId?: string | number, targetId?: string | number,
} name: string,
version: string,
type FirmwareUpdateType = 'osu' | 'final' icon: string,
app?: number,
export async function getMemInfos(transport: Transport<*>): Promise<Object> {
const { targetId } = await getFirmwareInfo(transport)
// Dont ask me about this `perso_11`: I don't know. But we need it.
return createSocketDialog(transport, '/get-mem-infos', { targetId, perso: 'perso_11' })
}
/**
* Open socket connection with firmware api, and init a dialog
* with the device
*/
export async function createSocketDialog(
transport: Transport<*>,
endpoint: string,
params: LedgerScriptParams,
managerUrl: boolean = false,
): Promise<string> {
console.warn('DEPRECATED createSocketDialog: use createDeviceSocket') // eslint-disable-line
const url = `${managerUrl ? BASE_SOCKET_URL_SECURE : BASE_SOCKET_URL}${endpoint}?${qs.stringify(
params,
)}`
return createDeviceSocket(transport, url).toPromise()
} }
/** /**
@ -66,15 +41,3 @@ export async function getFirmwareInfo(transport: Transport<*>) {
throw error throw error
} }
} }
/**
* Helpers to build OSU and Final firmware params
*/
export const buildParamsFromFirmware = (type: FirmwareUpdateType): Function => (
data: any,
): LedgerScriptParams => ({
firmware: data[`${type}_firmware`],
firmwareKey: data[`${type}_firmware_key`],
perso: data[`${type}_perso`],
targetId: data[`${type}_target_id`],
})

26
src/helpers/devices/getCurrentFirmware.js

@ -0,0 +1,26 @@
// @flow
import axios from 'axios'
import { GET_CURRENT_FIRMWARE } from 'helpers/urls'
type Input = {
version: string,
deviceId: string | number,
}
let error
export default async (input: Input): Promise<*> => {
try {
const provider = 1
const { data } = await axios.post(GET_CURRENT_FIRMWARE, {
device_version: input.deviceId,
version_name: input.version,
provider,
})
return data
} catch (err) {
error = Error(err.message)
error.stack = err.stack
throw error
}
}

19
src/helpers/devices/getDeviceVersion.js

@ -0,0 +1,19 @@
// @flow
import axios from 'axios'
import { GET_DEVICE_VERSION } from 'helpers/urls'
export default async (targetId: string | number): Promise<*> => {
try {
const provider = 1
const { data } = await axios.post(GET_DEVICE_VERSION, {
provider,
target_id: targetId,
})
return data
} catch (err) {
const error = Error(err.message)
error.stack = err.stack
throw err
}
}

34
src/helpers/devices/getFirmwareInfo.js

@ -1,34 +0,0 @@
// @flow
import axios from 'axios'
import isEmpty from 'lodash/isEmpty'
import { MANAGER_API_BASE } from 'config/constants'
type Input = {
version: string,
targetId: string | number,
}
let error
export default async (data: Input) => {
try {
const { data: seFirmwareVersion } = await axios.post(
`${MANAGER_API_BASE}/firmware_versions_name`,
{
se_firmware_name: data.version,
target_id: data.targetId,
},
)
if (!isEmpty(seFirmwareVersion)) {
return seFirmwareVersion
}
error = Error('could not retrieve firmware informations, try again later')
throw error
} catch (err) {
error = Error(err.message)
error.stack = err.stack
throw error
}
}

24
src/helpers/devices/getIsGenuine.js

@ -1,12 +1,26 @@
// @flow // @flow
import type Transport from '@ledgerhq/hw-transport' import type Transport from '@ledgerhq/hw-transport'
import { createSocketDialog } from 'helpers/common'
import { SKIP_GENUINE } from 'config/constants' import { SKIP_GENUINE } from 'config/constants'
import { WS_GENUINE } from 'helpers/urls'
import { createDeviceSocket } from 'helpers/socket'
import getCurrentFirmware from './getCurrentFirmware'
import getDeviceVersion from './getDeviceVersion'
export default async ( export default async (
transport: Transport<*>, transport: Transport<*>,
{ targetId }: { targetId: string | number }, app: { targetId: string | number, version: string },
): Promise<string> => ): Promise<string> => {
SKIP_GENUINE const { targetId, version } = app
const device = await getDeviceVersion(app.targetId)
const firmware = await getCurrentFirmware({ deviceId: device.id, version })
const params = {
targetId,
version,
perso: firmware.perso,
}
const url = WS_GENUINE(params)
return SKIP_GENUINE
? new Promise(resolve => setTimeout(() => resolve('0000'), 1000)) ? new Promise(resolve => setTimeout(() => resolve('0000'), 1000))
: createSocketDialog(transport, '/genuine', { targetId }, true) : createDeviceSocket(transport, url).toPromise()
}

37
src/helpers/devices/getLatestFirmwareForDevice.js

@ -1,39 +1,38 @@
// @flow // @flow
import axios from 'axios' import axios from 'axios'
import isEmpty from 'lodash/isEmpty' import { GET_LATEST_FIRMWARE } from 'helpers/urls'
import { MANAGER_API_BASE } from 'config/constants'
import getFirmwareInfo from './getFirmwareInfo' import getCurrentFirmware from './getCurrentFirmware'
import getDeviceVersion from './getDeviceVersion'
type Input = { type Input = {
targetId: string | number,
version: string, version: string,
targetId: string | number,
} }
export default async (data: Input) => { export default async (input: Input) => {
try { try {
// Get firmware infos with firmware name and device version const provider = 1
const seFirmwareVersion = await getFirmwareInfo(data) const { targetId, version } = input
// Get device infos from targetId // Get device infos from targetId
const { data: deviceVersion } = await axios.get( const deviceVersion = await getDeviceVersion(targetId)
`${MANAGER_API_BASE}/device_versions_target_id/${data.targetId}`,
) // Get firmware infos with firmware name and device version
const seFirmwareVersion = await getCurrentFirmware({ version, deviceId: deviceVersion.id })
// Fetch next possible firmware // Fetch next possible firmware
const { data: serverData } = await axios.post(`${MANAGER_API_BASE}/get_latest_firmware`, { const { data } = await axios.post(GET_LATEST_FIRMWARE, {
current_se_firmware_version: seFirmwareVersion.id, current_se_firmware_final_version: seFirmwareVersion.id,
device_version: deviceVersion.id, device_version: deviceVersion.id,
providers: [1], provider,
}) })
const { se_firmware_version } = serverData if (data.result === 'null') {
return null
if (!isEmpty(se_firmware_version)) {
return se_firmware_version
} }
return null const { se_firmware_osu_version } = data
return se_firmware_osu_version
} catch (err) { } catch (err) {
const error = Error(err.message) const error = Error(err.message)
error.stack = err.stack error.stack = err.stack

7
src/helpers/devices/getMemInfo.js

@ -2,10 +2,9 @@
import type Transport from '@ledgerhq/hw-transport' import type Transport from '@ledgerhq/hw-transport'
import { getFirmwareInfo, createSocketDialog } from 'helpers/common' import { getFirmwareInfo } from 'helpers/common'
export default async function getMemInfos(transport: Transport<*>): Promise<Object> { export default async function getMemInfos(transport: Transport<*>): Promise<Object> {
const { targetId } = await getFirmwareInfo(transport) const { targetId } = await getFirmwareInfo(transport) // eslint-disable-line
// Dont ask me about this `perso_11`: I don't know. But we need it. return new Promise(resolve => setTimeout(() => resolve({}), 1000))
return createSocketDialog(transport, '/get-mem-infos', { targetId, perso: 'perso_11' })
} }

26
src/helpers/devices/getNextMCU.js

@ -0,0 +1,26 @@
// @flow
import axios from 'axios'
import { GET_NEXT_MCU } from 'helpers/urls'
import createCustomErrorClass from 'helpers/createCustomErrorClass'
const LatestMCUInstalledError = createCustomErrorClass('LatestMCUInstalledError')
export default async (bootloaderVersion: string): Promise<*> => {
try {
const { data } = await axios.post(GET_NEXT_MCU, {
bootloader_version: bootloaderVersion,
})
// FIXME: nextVersion will not be able to "default" when Error
// handling is standardize on the API side
if (data === 'default' || !data.name) {
throw new LatestMCUInstalledError('there is no next mcu version to install')
}
return data
} catch (err) {
const error = Error(err.message)
error.stack = err.stack
throw err
}
}

10
src/helpers/firmware/installFinalFirmware.js

@ -1,18 +1,16 @@
// @flow // @flow
import type Transport from '@ledgerhq/hw-transport' import type Transport from '@ledgerhq/hw-transport'
import { createSocketDialog, buildParamsFromFirmware } from 'helpers/common' import { WS_INSTALL } from 'helpers/urls'
import { createDeviceSocket } from 'helpers/socket'
type Input = Object type Input = Object
type Result = * type Result = *
const buildOsuParams = buildParamsFromFirmware('final')
export default async (transport: Transport<*>, firmware: Input): Result => { export default async (transport: Transport<*>, firmware: Input): Result => {
try { try {
const osuData = buildOsuParams(firmware) const url = WS_INSTALL(firmware)
await createSocketDialog(transport, '/install', osuData) await createDeviceSocket(transport, url).toPromise()
return { success: true } return { success: true }
} catch (err) { } catch (err) {
const error = Error(err.message) const error = Error(err.message)

25
src/helpers/firmware/installMcu.js

@ -1,8 +1,23 @@
// @flow // @flow
import type Transport from '@ledgerhq/hw-transport'
type Result = Promise<boolean> import { WS_MCU } from 'helpers/urls'
import { createDeviceSocket } from 'helpers/socket'
import getNextMCU from 'helpers/devices/getNextMCU'
// TODO: IMPLEMENTATION FOR FLASHING FIRMWARE type Result = Promise<*>
// GETTING APDUS FROM SERVER
// SEND THE APDUS TO DEVICE export default async (
export default async (): Result => new Promise(resolve => resolve(true)) transport: Transport<*>,
args: { targetId: string | number, version: string },
): Result => {
const { version } = args
const nextVersion = await getNextMCU(version)
const params = {
targetId: args.targetId,
version: nextVersion.name,
}
const url = WS_MCU(params)
return createDeviceSocket(transport, url).toPromise()
}

23
src/helpers/firmware/installOsuFirmware.js

@ -1,19 +1,26 @@
// @flow // @flow
import type Transport from '@ledgerhq/hw-transport' import type Transport from '@ledgerhq/hw-transport'
import { createSocketDialog, buildParamsFromFirmware } from 'helpers/common' import { WS_INSTALL } from 'helpers/urls'
import { createDeviceSocket } from 'helpers/socket'
type Input = Object import type { LedgerScriptParams } from 'helpers/common'
type Result = Promise<{ success: boolean, error?: any }> type Result = Promise<{ success: boolean, error?: any }>
const buildOsuParams = buildParamsFromFirmware('osu') export default async (
transport: Transport<*>,
export default async (transport: Transport<*>, firmware: Input): Result => { targetId: string | number,
firmware: LedgerScriptParams,
): Result => {
try { try {
const osuData = buildOsuParams(firmware) const params = {
await createSocketDialog(transport, '/install', osuData) targetId,
...firmware,
firmwareKey: firmware.firmware_key,
}
const url = WS_INSTALL(params)
await createDeviceSocket(transport, url).toPromise()
return { success: true } return { success: true }
} catch (err) { } catch (err) {
const error = Error(err.message) const error = Error(err.message)

27
src/helpers/urls.js

@ -0,0 +1,27 @@
// @flow
import qs from 'qs'
import { MANAGER_API_BASE, BASE_SOCKET_URL_SECURE } from 'config/constants'
import type { LedgerScriptParams } from 'helpers/common'
const urlBuilder = (base: string) => (endpoint: string): string => `${base}/${endpoint}`
const managerUrlbuilder = urlBuilder(MANAGER_API_BASE)
const wsURLBuilder = (endpoint: string) => (params?: Object) =>
`${BASE_SOCKET_URL_SECURE}/${endpoint}${params ? `?${qs.stringify(params)}` : ''}`
// const wsURLBuilderProxy = (endpoint: string) => (params?: Object) =>
// `ws://manager.ledger.fr:3501/${endpoint}${params ? `?${qs.stringify(params)}` : ''}`
export const GET_DEVICE_VERSION: string = managerUrlbuilder('get_device_version')
export const APPLICATIONS_BY_DEVICE: string = managerUrlbuilder('get_apps')
export const GET_CURRENT_FIRMWARE: string = managerUrlbuilder('get_firmware_version')
export const GET_LATEST_FIRMWARE: string = managerUrlbuilder('get_latest_firmware')
export const GET_NEXT_MCU: string = managerUrlbuilder('mcu_versions_bootloader')
export const WS_INSTALL: (arg: LedgerScriptParams) => string = wsURLBuilder('install')
export const WS_GENUINE: (arg: { targetId: string | number }) => string = wsURLBuilder('genuine')
export const WS_MCU: (arg: { targetId: string | number, version: string }) => string = wsURLBuilder(
'mcu',
)

1
static/i18n/en/errors.yml

@ -19,3 +19,4 @@ WebsocketConnectionFailed: Failed to establish a socket connection
DeviceSocketFail: Device socket failure DeviceSocketFail: Device socket failure
DeviceSocketNoBulkStatus: Device socket failure (bulk) DeviceSocketNoBulkStatus: Device socket failure (bulk)
DeviceSocketNoHandler: Device socket failure (handler {{query}}) DeviceSocketNoHandler: Device socket failure (handler {{query}})
LatestMCUInstalledError: The latest MCU is already installed on the Device

Loading…
Cancel
Save