Browse Source

Merge pull request #653 from gre/fix/circular-ref-error

Polishes, Bugfixes around genuine & manager
master
Gaëtan Renaudeau 7 years ago
committed by GitHub
parent
commit
d7f13a99a2
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 114
      src/components/ManagerPage/AppsList.js
  2. 17
      src/components/ManagerPage/Dashboard.js
  3. 8
      src/components/modals/ReleaseNotes.js
  4. 1
      src/config/constants.js
  5. 15
      src/helpers/apps/installApp.js
  6. 4
      src/helpers/apps/listApps.js
  7. 14
      src/helpers/apps/uninstallApp.js
  8. 14
      src/helpers/devices/getCurrentFirmware.js
  9. 21
      src/helpers/devices/getDeviceVersion.js
  10. 14
      src/helpers/devices/getLatestFirmwareForDevice.js
  11. 10
      src/helpers/devices/getNextMCU.js
  12. 21
      src/helpers/devices/getOsuFirmware.js
  13. 13
      src/helpers/firmware/getFinalFirmwareById.js
  14. 4
      src/helpers/firmware/installFinalFirmware.js
  15. 1
      src/helpers/firmware/installMcu.js
  16. 4
      src/helpers/firmware/installOsuFirmware.js
  17. 1
      src/icons/Trash.js
  18. 4
      static/i18n/en/errors.yml

114
src/components/ManagerPage/AppsList.js

@ -1,7 +1,7 @@
// @flow
/* eslint-disable react/jsx-no-literals */ // FIXME
import React, { PureComponent } from 'react'
import React, { PureComponent, Fragment } from 'react'
import styled from 'styled-components'
import { translate } from 'react-i18next'
@ -13,14 +13,16 @@ import installApp from 'commands/installApp'
import uninstallApp from 'commands/uninstallApp'
import Box from 'components/base/Box'
import Modal, { ModalBody } from 'components/base/Modal'
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 Spinner from 'components/base/Spinner'
import Button from 'components/base/Button'
import TranslatedError from 'components/TranslatedError'
import ExclamationCircle from 'icons/ExclamationCircle'
import ExclamationCircleThin from 'icons/ExclamationCircleThin'
import Update from 'icons/Update'
import Trash from 'icons/Trash'
import CheckCircle from 'icons/CheckCircle'
@ -89,7 +91,7 @@ class AppsList extends PureComponent<Props, State> {
this.setState({ appsList, status: 'idle', appsLoaded: true })
}
} catch (err) {
this.setState({ status: 'error', error: err.message })
this.setState({ status: 'error', error: err })
}
}
@ -119,7 +121,7 @@ class AppsList extends PureComponent<Props, State> {
await uninstallApp.send(data).toPromise()
this.setState({ status: 'success', app: '' })
} catch (err) {
this.setState({ status: 'error', error: err.message, app: '', mode: 'home' })
this.setState({ status: 'error', error: err, app: '', mode: 'home' })
}
}
@ -132,42 +134,80 @@ class AppsList extends PureComponent<Props, State> {
<Modal
isOpened={status !== 'idle' && status !== 'loading'}
render={() => (
<ModalBody p={6} align="center" justify="center" style={{ height: 300 }}>
<ModalBody align="center" justify="center" style={{ height: 300 }}>
{status === 'busy' || status === 'idle' ? (
<Box align="center" justify="center" flow={3}>
{mode === 'installing' ? <Update size={30} /> : <Trash size={30} />}
<Text ff="Museo Sans|Regular" fontSize={6} color="dark">
{t(`app:manager.apps.${mode}`, { app })}
</Text>
<Box my={5} style={{ width: 250 }}>
<Progress style={{ width: '100%' }} infinite />
</Box>
</Box>
<Fragment>
<ModalTitle>
{mode === 'installing' ? (
<Box color="grey">
<Update size={30} />
</Box>
) : (
<Box color="grey">
<Trash size={30} />
</Box>
)}
</ModalTitle>
<ModalContent>
<Text ff="Museo Sans|Regular" fontSize={6} color="dark">
{t(`app:manager.apps.${mode}`, { app })}
</Text>
<Box mt={6}>
<Progress style={{ width: '100%' }} infinite />
</Box>
</ModalContent>
</Fragment>
) : status === 'error' ? (
<Box align="center" justify="center" flow={3}>
<div>{'error happened'}</div>
{error}
<Button primary onClick={this.handleCloseModal}>
close
</Button>
</Box>
<Fragment>
<ModalContent grow align="center" justify="center" mt={3}>
<Box color="alertRed">
<ExclamationCircleThin size={44} />
</Box>
<Box
color="black"
mt={4}
fontSize={6}
ff="Museo Sans|Regular"
textAlign="center"
style={{ maxWidth: 350 }}
>
<TranslatedError error={error} />
</Box>
</ModalContent>
<ModalFooter horizontal justifyContent="flex-end" style={{ width: '100%' }}>
<Button primary padded onClick={this.handleCloseModal}>
{t('app:common.close')}
</Button>
</ModalFooter>
</Fragment>
) : status === 'success' ? (
<Box align="center" justify="center" flow={3}>
<Box color="positiveGreen">
<CheckCircle size={30} />
</Box>
<Text ff="Museo Sans|Regular" fontSize={6} color="dark">
{t(
`app:manager.apps.${
mode === 'installing' ? 'installSuccess' : 'uninstallSuccess'
}`,
{ app },
)}
</Text>
<Button primary onClick={this.handleCloseModal}>
close
</Button>
</Box>
<Fragment>
<ModalContent grow align="center" justify="center" mt={3}>
<Box color="positiveGreen">
<CheckCircle size={44} />
</Box>
<Box
color="black"
mt={4}
fontSize={6}
ff="Museo Sans|Regular"
textAlign="center"
style={{ maxWidth: 350 }}
>
{t(
`app:manager.apps.${
mode === 'installing' ? 'installSuccess' : 'uninstallSuccess'
}`,
{ app },
)}
</Box>
</ModalContent>
<ModalFooter horizontal justifyContent="flex-end" style={{ width: '100%' }}>
<Button primary padded onClick={this.handleCloseModal}>
{t('app:common.close')}
</Button>
</ModalFooter>
</Fragment>
) : null}
</ModalBody>
)}

17
src/components/ManagerPage/Dashboard.js

@ -2,6 +2,7 @@
import React from 'react'
import { translate } from 'react-i18next'
import { EXPERIMENTAL_FIRMWARE_UPDATE } from 'config/constants'
import type { T, Device } from 'types/common'
import Box from 'components/base/Box'
@ -34,13 +35,15 @@ const Dashboard = ({ device, deviceInfo, t }: Props) => (
</Text>
</Box>
<Box mt={5}>
<FirmwareUpdate
infos={{
targetId: deviceInfo.targetId,
version: deviceInfo.version,
}}
device={device}
/>
{EXPERIMENTAL_FIRMWARE_UPDATE ? (
<FirmwareUpdate
infos={{
targetId: deviceInfo.targetId,
version: deviceInfo.version,
}}
device={device}
/>
) : null}
</Box>
<Box mt={5}>
<AppsList device={device} targetId={deviceInfo.targetId} version={deviceInfo.version} />

8
src/components/modals/ReleaseNotes.js

@ -3,7 +3,7 @@ import React, { PureComponent } from 'react'
import { translate } from 'react-i18next'
import ReactMarkdown from 'react-markdown'
import styled from 'styled-components'
import axios from 'axios'
import network from 'api/network'
import { MODAL_RELEASES_NOTES } from 'config/constants'
import Modal, { ModalBody, ModalTitle, ModalContent, ModalFooter } from 'components/base/Modal'
@ -160,8 +160,10 @@ class ReleaseNotes extends PureComponent<Props, State> {
if (!this.loading) {
this.loading = true
axios
.get(`https://api.github.com/repos/LedgerHQ/ledger-live-desktop/releases/tags/v${version}`)
network({
method: 'GET',
url: `https://api.github.com/repos/LedgerHQ/ledger-live-desktop/releases/tags/v${version}`,
})
.then(response => {
const { body } = response.data

1
src/config/constants.js

@ -67,6 +67,7 @@ export const SHOW_LEGACY_NEW_ACCOUNT = boolFromEnv('SHOW_LEGACY_NEW_ACCOUNT')
export const HIGHLIGHT_I18N = boolFromEnv('HIGHLIGHT_I18N')
export const DISABLE_ACTIVITY_INDICATORS = boolFromEnv('DISABLE_ACTIVITY_INDICATORS')
export const EXPERIMENTAL_CENTER_MODAL = boolFromEnv('EXPERIMENTAL_CENTER_MODAL')
export const EXPERIMENTAL_FIRMWARE_UPDATE = boolFromEnv('EXPERIMENTAL_FIRMWARE_UPDATE')
// Other constants

15
src/helpers/apps/installApp.js

@ -7,6 +7,19 @@ import { createDeviceSocket } from 'helpers/socket'
import type { LedgerScriptParams } from 'helpers/common'
import createCustomErrorClass from '../createCustomErrorClass'
const CannotInstall = createCustomErrorClass('CannotInstall')
function remapError(promise) {
return promise.catch((e: Error) => {
if (e.message.endsWith('6982')) {
throw new CannotInstall()
}
throw e
})
}
/**
* Install an app on the device
*/
@ -21,5 +34,5 @@ export default async function installApp(
firmwareKey: app.firmware_key,
}
const url = `${BASE_SOCKET_URL_SECURE}/install?${qs.stringify(params)}`
return createDeviceSocket(transport, url).toPromise()
return remapError(createDeviceSocket(transport, url).toPromise())
}

4
src/helpers/apps/listApps.js

@ -1,5 +1,5 @@
// @flow
import axios from 'axios'
import network from 'api/network'
import { APPLICATIONS_BY_DEVICE } from 'helpers/urls'
import getDeviceVersion from 'helpers/devices/getDeviceVersion'
@ -17,7 +17,7 @@ export default async (targetId: string | number, version: string) => {
}
const {
data: { application_versions },
} = await axios.post(APPLICATIONS_BY_DEVICE, params)
} = await network({ method: 'POST', url: APPLICATIONS_BY_DEVICE, data: params })
return application_versions.length > 0 ? application_versions : []
} catch (err) {
const error = Error(err.message)

14
src/helpers/apps/uninstallApp.js

@ -6,6 +6,18 @@ import { BASE_SOCKET_URL_SECURE } from 'config/constants'
import { createDeviceSocket } from 'helpers/socket'
import type { LedgerScriptParams } from 'helpers/common'
import createCustomErrorClass from '../createCustomErrorClass'
const CannotUninstall = createCustomErrorClass('CannotUninstall')
function remapError(promise) {
return promise.catch((e: Error) => {
if (e.message.endsWith('6a83')) {
throw new CannotUninstall()
}
throw e
})
}
/**
* Install an app on the device
@ -22,5 +34,5 @@ export default async function uninstallApp(
firmwareKey: app.delete_key,
}
const url = `${BASE_SOCKET_URL_SECURE}/install?${qs.stringify(params)}`
return createDeviceSocket(transport, url).toPromise()
return remapError(createDeviceSocket(transport, url).toPromise())
}

14
src/helpers/devices/getCurrentFirmware.js

@ -1,5 +1,5 @@
// @flow
import axios from 'axios'
import network from 'api/network'
import { GET_CURRENT_FIRMWARE } from 'helpers/urls'
@ -12,10 +12,14 @@ 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,
const { data } = await network({
method: 'POST',
url: GET_CURRENT_FIRMWARE,
data: {
device_version: input.deviceId,
version_name: input.version,
provider,
},
})
return data
} catch (err) {

21
src/helpers/devices/getDeviceVersion.js

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

14
src/helpers/devices/getLatestFirmwareForDevice.js

@ -1,5 +1,5 @@
// @flow
import axios from 'axios'
import network from 'api/network'
import { GET_LATEST_FIRMWARE } from 'helpers/urls'
import getCurrentFirmware from './getCurrentFirmware'
@ -21,10 +21,14 @@ export default async (input: Input) => {
const seFirmwareVersion = await getCurrentFirmware({ version, deviceId: deviceVersion.id })
// Fetch next possible firmware
const { data } = await axios.post(GET_LATEST_FIRMWARE, {
current_se_firmware_final_version: seFirmwareVersion.id,
device_version: deviceVersion.id,
provider,
const { data } = await network({
method: 'POST',
url: GET_LATEST_FIRMWARE,
data: {
current_se_firmware_final_version: seFirmwareVersion.id,
device_version: deviceVersion.id,
provider,
},
})
if (data.result === 'null') {

10
src/helpers/devices/getNextMCU.js

@ -1,5 +1,5 @@
// @flow
import axios from 'axios'
import network from 'api/network'
import { GET_NEXT_MCU } from 'helpers/urls'
import createCustomErrorClass from 'helpers/createCustomErrorClass'
@ -8,8 +8,12 @@ const LatestMCUInstalledError = createCustomErrorClass('LatestMCUInstalledError'
export default async (bootloaderVersion: string): Promise<*> => {
try {
const { data } = await axios.post(GET_NEXT_MCU, {
bootloader_version: bootloaderVersion,
const { data } = await network({
method: 'POST',
url: GET_NEXT_MCU,
data: {
bootloader_version: bootloaderVersion,
},
})
// FIXME: nextVersion will not be able to "default" when Error

21
src/helpers/devices/getOsuFirmware.js

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

13
src/helpers/firmware/getFinalFirmwareById.js

@ -1,15 +1,8 @@
// @flow
import axios from 'axios'
import network from 'api/network'
import { GET_FINAL_FIRMWARE } from 'helpers/urls'
export default async (id: number) => {
try {
const { data } = await axios.get(`${GET_FINAL_FIRMWARE}/${id}`)
return data
} catch (err) {
const error = Error(err.message)
error.stack = err.stack
throw err
}
const { data } = await network({ method: 'GET', url: `${GET_FINAL_FIRMWARE}/${id}` })
return data
}

4
src/helpers/firmware/installFinalFirmware.js

@ -30,9 +30,7 @@ export default async (transport: Transport<*>, app: Input): Result => {
const url = WS_INSTALL(params)
await createDeviceSocket(transport, url).toPromise()
return { success: true }
} catch (err) {
const error = Error(err.message)
error.stack = err.stack
} catch (error) {
const result = { success: false, error }
throw result
}

1
src/helpers/firmware/installMcu.js

@ -13,7 +13,6 @@ export default async (
): Result => {
const { version } = args
const nextVersion = await getNextMCU(version)
const params = {
targetId: args.targetId,
version: nextVersion.name,

4
src/helpers/firmware/installOsuFirmware.js

@ -22,9 +22,7 @@ export default async (
const url = WS_INSTALL(params)
await createDeviceSocket(transport, url).toPromise()
return { success: true }
} catch (err) {
const error = Error(err.message)
error.stack = err.stack
} catch (error) {
const result = { success: false, error }
throw result
}

1
src/icons/Trash.js

@ -5,6 +5,7 @@ import React from 'react'
const path = (
<g transform="translate(670.57 190.38)">
<path
fill="currentColor"
d="m-658.54-187.18h3.2002a0.80037 0.80037 0 0 1 0 1.5993h-0.80049v10.4a2.3999 2.3999 0 0 1-2.3999 2.3999h-8.0001a2.3999 2.3999 0 0 1-2.3999-2.3999v-10.4h-0.79878a0.80037 0.80037 0 1 1 0-1.5993h3.1991v-0.80049a2.3999 2.3999 0 0 1 2.3999-2.3999h3.2003a2.3999 2.3999 0 0 1 2.3999 2.3999zm-1.5993 0v-0.80049a0.80037 0.80037 0 0 0-0.80049-0.80049h-3.2003a0.80037 0.80037 0 0 0-0.79878 0.80049v0.80049zm0.80049 1.5993a0.84357 0.84357 0 0 1-1e-3 0h-6.3995a0.84357 0.84357 0 0 1-2e-3 0h-1.5976v10.4c0 0.44224 0.35825 0.79877 0.79878 0.79877h8.0001a0.80037 0.80037 0 0 0 0.8005-0.79877v-10.4zm-5.6004 3.2003a0.80037 0.80037 0 1 1 1.5993 0v4.7997a0.80037 0.80037 0 0 1-1.5993 0zm3.1992 0a0.80049 0.80049 0 1 1 1.601 0v4.7997a0.80049 0.80049 0 0 1-1.601 0z"
strokeWidth="1.2"
/>

4
static/i18n/en/errors.yml

@ -16,8 +16,10 @@ NoAddressesFound: 'No accounts found'
UserRefusedOnDevice: Transaction have been aborted
WebsocketConnectionError: An error occurred with the socket connection
WebsocketConnectionFailed: Failed to establish a socket connection
DeviceSocketFail: Device socket failure
DeviceSocketFail: 'Device socket failure ({{message}})'
DeviceSocketNoBulkStatus: Device socket failure (bulk)
DeviceSocketNoHandler: Device socket failure (handler {{query}})
LatestMCUInstalledError: The latest MCU is already installed on the Device
HardResetFail: Hard reset failure
CannotUninstall: Cannot uninstall app
CannotInstall: Cannot install app

Loading…
Cancel
Save