Gaëtan Renaudeau
6 years ago
41 changed files with 38 additions and 780 deletions
@ -1,21 +0,0 @@ |
|||
// @flow
|
|||
|
|||
import { createCommand, Command } from 'helpers/ipc' |
|||
import { fromPromise } from 'rxjs/observable/fromPromise' |
|||
|
|||
import getCurrentFirmware from 'helpers/devices/getCurrentFirmware' |
|||
import type { FinalFirmware } from 'helpers/types' |
|||
|
|||
type Input = { |
|||
deviceId: string | number, |
|||
fullVersion: string, |
|||
provider: number, |
|||
} |
|||
|
|||
type Result = FinalFirmware |
|||
|
|||
const cmd: Command<Input, Result> = createCommand('getCurrentFirmware', data => |
|||
fromPromise(getCurrentFirmware(data)), |
|||
) |
|||
|
|||
export default cmd |
@ -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 getMemInfo from 'helpers/devices/getMemInfo' |
|||
|
|||
type Input = { |
|||
devicePath: string, |
|||
} |
|||
|
|||
type Result = * |
|||
|
|||
const cmd: Command<Input, Result> = createCommand('getMemInfo', ({ devicePath }) => |
|||
withDevice(devicePath)(transport => from(getMemInfo(transport))), |
|||
) |
|||
|
|||
export default cmd |
@ -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 isDashboardOpen from '../helpers/devices/isDashboardOpen' |
|||
|
|||
type Input = { |
|||
devicePath: string, |
|||
} |
|||
|
|||
type Result = boolean |
|||
|
|||
const cmd: Command<Input, Result> = createCommand('isDashboardOpen', ({ devicePath }) => |
|||
withDevice(devicePath)(transport => from(isDashboardOpen(transport))), |
|||
) |
|||
|
|||
export default cmd |
@ -1,15 +0,0 @@ |
|||
// @flow
|
|||
|
|||
import { createCommand, Command } from 'helpers/ipc' |
|||
import { fromPromise } from 'rxjs/observable/fromPromise' |
|||
import type { DeviceInfo, ApplicationVersion } from 'helpers/types' |
|||
|
|||
import listAppVersions from 'helpers/apps/listAppVersions' |
|||
|
|||
type Result = Array<ApplicationVersion> |
|||
|
|||
const cmd: Command<DeviceInfo, Result> = createCommand('listAppVersions', deviceInfo => |
|||
fromPromise(listAppVersions(deviceInfo)), |
|||
) |
|||
|
|||
export default cmd |
@ -1,15 +0,0 @@ |
|||
// @flow
|
|||
|
|||
import { createCommand, Command } from 'helpers/ipc' |
|||
import { fromPromise } from 'rxjs/observable/fromPromise' |
|||
|
|||
import listApps from 'helpers/apps/listApps' |
|||
import type { Application } from 'helpers/types' |
|||
|
|||
type Input = void |
|||
|
|||
type Result = Array<Application> |
|||
|
|||
const cmd: Command<Input, Result> = createCommand('listApps', () => fromPromise(listApps())) |
|||
|
|||
export default cmd |
@ -1,17 +0,0 @@ |
|||
// @flow
|
|||
|
|||
import { createCommand, Command } from 'helpers/ipc' |
|||
import { fromPromise } from 'rxjs/observable/fromPromise' |
|||
|
|||
import listCategories from 'helpers/apps/listCategories' |
|||
import type { Category } from 'helpers/types' |
|||
|
|||
type Input = void |
|||
|
|||
type Result = Array<Category> |
|||
|
|||
const cmd: Command<Input, Result> = createCommand('listCategories', () => |
|||
fromPromise(listCategories()), |
|||
) |
|||
|
|||
export default cmd |
@ -1,52 +0,0 @@ |
|||
// @flow
|
|||
import type Transport from '@ledgerhq/hw-transport' |
|||
|
|||
import { createDeviceSocket } from 'helpers/socket' |
|||
|
|||
import type { ApplicationVersion } from 'helpers/types' |
|||
import { WS_INSTALL } from 'helpers/urls' |
|||
|
|||
import { |
|||
ManagerNotEnoughSpaceError, |
|||
ManagerDeviceLockedError, |
|||
ManagerAppAlreadyInstalledError, |
|||
ManagerAppRelyOnBTCError, |
|||
} from '@ledgerhq/live-common/lib/errors' |
|||
|
|||
function remapError(promise) { |
|||
return promise.catch((e: Error) => { |
|||
switch (true) { |
|||
case e.message.endsWith('6982'): |
|||
throw new ManagerDeviceLockedError() |
|||
case e.message.endsWith('6a84') || e.message.endsWith('6a85'): |
|||
throw new ManagerNotEnoughSpaceError() |
|||
case e.message.endsWith('6a80') || e.message.endsWith('6a81'): |
|||
throw new ManagerAppAlreadyInstalledError() |
|||
case e.message.endsWith('6a83'): |
|||
throw new ManagerAppRelyOnBTCError() |
|||
default: |
|||
throw e |
|||
} |
|||
}) |
|||
} |
|||
|
|||
/** |
|||
* Install an app on the device |
|||
*/ |
|||
export default async function installApp( |
|||
transport: Transport<*>, |
|||
targetId: string | number, |
|||
{ app }: { app: ApplicationVersion }, |
|||
): Promise<void> { |
|||
const params = { |
|||
targetId, |
|||
perso: app.perso, |
|||
deleteKey: app.delete_key, |
|||
firmware: app.firmware, |
|||
firmwareKey: app.firmware_key, |
|||
hash: app.hash, |
|||
} |
|||
|
|||
const url = WS_INSTALL(params) |
|||
await remapError(createDeviceSocket(transport, url).toPromise()) |
|||
} |
@ -1,30 +0,0 @@ |
|||
// @flow
|
|||
import network from 'api/network' |
|||
import type { DeviceInfo, DeviceVersion, FinalFirmware, ApplicationVersion } from 'helpers/types' |
|||
|
|||
import { APPLICATIONS_BY_DEVICE } from 'helpers/urls' |
|||
import getDeviceVersion from 'helpers/devices/getDeviceVersion' |
|||
import getCurrentFirmware from 'helpers/devices/getCurrentFirmware' |
|||
|
|||
type NetworkResponse = { data: { application_versions: Array<ApplicationVersion> } } |
|||
|
|||
export default async (deviceInfo: DeviceInfo): Promise<Array<ApplicationVersion>> => { |
|||
const deviceData: DeviceVersion = await getDeviceVersion( |
|||
deviceInfo.targetId, |
|||
deviceInfo.providerId, |
|||
) |
|||
const firmwareData: FinalFirmware = await getCurrentFirmware({ |
|||
deviceId: deviceData.id, |
|||
fullVersion: deviceInfo.fullVersion, |
|||
provider: deviceInfo.providerId, |
|||
}) |
|||
const params = { |
|||
provider: deviceInfo.providerId, |
|||
current_se_firmware_final_version: firmwareData.id, |
|||
device_version: deviceData.id, |
|||
} |
|||
const { |
|||
data: { application_versions }, |
|||
}: NetworkResponse = await network({ method: 'POST', url: APPLICATIONS_BY_DEVICE, data: params }) |
|||
return application_versions.length > 0 ? application_versions : [] |
|||
} |
@ -1,10 +0,0 @@ |
|||
// @flow
|
|||
import network from 'api/network' |
|||
|
|||
import { GET_APPLICATIONS } from 'helpers/urls' |
|||
import type { Application } from 'helpers/types' |
|||
|
|||
export default async (): Promise<Array<Application>> => { |
|||
const { data } = await network({ method: 'GET', url: GET_APPLICATIONS }) |
|||
return data.length > 0 ? data : [] |
|||
} |
@ -1,10 +0,0 @@ |
|||
// @flow
|
|||
import network from 'api/network' |
|||
|
|||
import { GET_CATEGORIES } from 'helpers/urls' |
|||
import type { Category } from 'helpers/types' |
|||
|
|||
export default async (): Promise<Array<Category>> => { |
|||
const { data }: { data: Array<Category> } = await network({ method: 'GET', url: GET_CATEGORIES }) |
|||
return data.length > 0 ? data : [] |
|||
} |
@ -1,41 +0,0 @@ |
|||
// @flow
|
|||
import type Transport from '@ledgerhq/hw-transport' |
|||
|
|||
import { createDeviceSocket } from 'helpers/socket' |
|||
|
|||
import type { ApplicationVersion } from 'helpers/types' |
|||
import { ManagerDeviceLockedError, ManagerUninstallBTCDep } from '@ledgerhq/live-common/lib/errors' |
|||
import { WS_INSTALL } from 'helpers/urls' |
|||
|
|||
function remapError(promise) { |
|||
return promise.catch((e: Error) => { |
|||
switch (true) { |
|||
case e.message.endsWith('6982'): |
|||
throw new ManagerDeviceLockedError() |
|||
case e.message.endsWith('6a83'): |
|||
throw new ManagerUninstallBTCDep() |
|||
default: |
|||
throw e |
|||
} |
|||
}) |
|||
} |
|||
|
|||
/** |
|||
* Install an app on the device |
|||
*/ |
|||
export default async function uninstallApp( |
|||
transport: Transport<*>, |
|||
targetId: string | number, |
|||
{ app }: { app: ApplicationVersion }, |
|||
): Promise<void> { |
|||
const params = { |
|||
targetId, |
|||
perso: app.perso, |
|||
deleteKey: app.delete_key, |
|||
firmware: app.delete, |
|||
firmwareKey: app.delete_key, |
|||
hash: app.hash, |
|||
} |
|||
const url = WS_INSTALL(params) |
|||
await remapError(createDeviceSocket(transport, url).toPromise()) |
|||
} |
@ -1,9 +0,0 @@ |
|||
// @flow
|
|||
|
|||
import type Transport from '@ledgerhq/hw-transport' |
|||
|
|||
export default async (transport: Transport<*>) => { |
|||
const r = await transport.send(0xe0, 0xc4, 0, 0) |
|||
const version = `${r[2]}.${r[3]}.${r[4]}` |
|||
return { version } |
|||
} |
@ -1,10 +0,0 @@ |
|||
// @flow
|
|||
|
|||
import Eth from '@ledgerhq/hw-app-eth' |
|||
import type Transport from '@ledgerhq/hw-transport' |
|||
|
|||
export default async (transport: Transport<*>) => { |
|||
const eth = new Eth(transport) |
|||
const { version } = await eth.getAppConfiguration() |
|||
return { version } |
|||
} |
@ -1,29 +0,0 @@ |
|||
// @flow
|
|||
|
|||
import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types' |
|||
import invariant from 'invariant' |
|||
import type Transport from '@ledgerhq/hw-transport' |
|||
import bitcoin from './btc' |
|||
import ethereum from './ethereum' |
|||
import ripple from './ripple' |
|||
|
|||
type Resolver = ( |
|||
transport: Transport<*>, |
|||
currency: CryptoCurrency, |
|||
) => Promise<{ |
|||
version?: string, |
|||
}> |
|||
|
|||
const perFamily: { [_: string]: * } = { |
|||
bitcoin, |
|||
ethereum, |
|||
ripple, |
|||
} |
|||
|
|||
const proxy: Resolver = (transport, currency) => { |
|||
const getAddress = perFamily[currency.family] |
|||
invariant(getAddress, `getAddress not implemented for ${currency.id}`) |
|||
return getAddress(transport) |
|||
} |
|||
|
|||
export default proxy |
@ -1,10 +0,0 @@ |
|||
// @flow
|
|||
|
|||
import Xrp from '@ledgerhq/hw-app-xrp' |
|||
import type Transport from '@ledgerhq/hw-transport' |
|||
|
|||
export default async (transport: Transport<*>) => { |
|||
const xrp = new Xrp(transport) |
|||
const { version } = await xrp.getAppConfiguration() |
|||
return { version } |
|||
} |
@ -1,21 +0,0 @@ |
|||
// @flow
|
|||
|
|||
import type Transport from '@ledgerhq/hw-transport' |
|||
|
|||
const getBitcoinLikeInfo = ( |
|||
transport: Transport<any>, |
|||
): Promise<{ |
|||
P2PKH: number, |
|||
P2SH: number, |
|||
message: Buffer, |
|||
short: Buffer, |
|||
}> => |
|||
transport.send(0xe0, 0x16, 0x00, 0x00).then(res => { |
|||
const P2PKH = res.readUInt16BE(0) |
|||
const P2SH = res.readUInt16BE(2) |
|||
const message = res.slice(5, res.readUInt8(4)) |
|||
const short = res.slice(5 + message.length + 1, res.readUInt8(5 + message.length)) |
|||
return { P2PKH, P2SH, message, short } |
|||
}) |
|||
|
|||
export default getBitcoinLikeInfo |
@ -1,24 +0,0 @@ |
|||
// @flow
|
|||
import network from 'api/network' |
|||
|
|||
import { GET_CURRENT_FIRMWARE } from 'helpers/urls' |
|||
import type { FinalFirmware } from 'helpers/types' |
|||
|
|||
type Input = { |
|||
fullVersion: string, |
|||
deviceId: string | number, |
|||
provider: number, |
|||
} |
|||
|
|||
export default async (input: Input): Promise<FinalFirmware> => { |
|||
const { data }: { data: FinalFirmware } = await network({ |
|||
method: 'POST', |
|||
url: GET_CURRENT_FIRMWARE, |
|||
data: { |
|||
device_version: input.deviceId, |
|||
version_name: input.fullVersion, |
|||
provider: input.provider, |
|||
}, |
|||
}) |
|||
return data |
|||
} |
@ -1,5 +0,0 @@ |
|||
// @flow
|
|||
|
|||
import getDeviceInfo from '@ledgerhq/live-common/lib/hw/getDeviceInfo' |
|||
|
|||
export default getDeviceInfo |
@ -1,17 +0,0 @@ |
|||
// @flow
|
|||
import { GET_DEVICE_VERSION } from 'helpers/urls' |
|||
import network from 'api/network' |
|||
|
|||
import type { DeviceVersion } from 'helpers/types' |
|||
|
|||
export default async (targetId: string | number, provider: number): Promise<DeviceVersion> => { |
|||
const { data }: { data: DeviceVersion } = await network({ |
|||
method: 'POST', |
|||
url: GET_DEVICE_VERSION, |
|||
data: { |
|||
provider, |
|||
target_id: targetId, |
|||
}, |
|||
}) |
|||
return data |
|||
} |
@ -1,32 +0,0 @@ |
|||
// @flow
|
|||
import type Transport from '@ledgerhq/hw-transport' |
|||
import { SKIP_GENUINE } from 'config/constants' |
|||
import { WS_GENUINE } from 'helpers/urls' |
|||
import type { DeviceInfo, FinalFirmware, DeviceVersion } from 'helpers/types' |
|||
|
|||
import { createDeviceSocket } from 'helpers/socket' |
|||
import getCurrentFirmware from './getCurrentFirmware' |
|||
import getDeviceVersion from './getDeviceVersion' |
|||
|
|||
export default async (transport: Transport<*>, deviceInfo: DeviceInfo): Promise<string> => { |
|||
const deviceVersion: DeviceVersion = await getDeviceVersion( |
|||
deviceInfo.targetId, |
|||
deviceInfo.providerId, |
|||
) |
|||
|
|||
const firmware: FinalFirmware = await getCurrentFirmware({ |
|||
deviceId: deviceVersion.id, |
|||
fullVersion: deviceInfo.fullVersion, |
|||
provider: deviceInfo.providerId, |
|||
}) |
|||
|
|||
const params = { |
|||
targetId: deviceInfo.targetId, |
|||
perso: firmware.perso, |
|||
} |
|||
|
|||
const url = WS_GENUINE(params) |
|||
return SKIP_GENUINE |
|||
? new Promise(resolve => setTimeout(() => resolve('0000'), 1000)) |
|||
: createDeviceSocket(transport, url).toPromise() |
|||
} |
@ -1,10 +0,0 @@ |
|||
// @flow
|
|||
|
|||
import type Transport from '@ledgerhq/hw-transport' |
|||
|
|||
import getFirmwareInfo from 'helpers/firmware/getFirmwareInfo' |
|||
|
|||
export default async function getMemInfos(transport: Transport<*>): Promise<Object> { |
|||
const { targetId } = await getFirmwareInfo(transport) // eslint-disable-line
|
|||
return new Promise(resolve => setTimeout(() => resolve({}), 1000)) |
|||
} |
@ -1,23 +0,0 @@ |
|||
// @flow
|
|||
import network from 'api/network' |
|||
|
|||
import { GET_CURRENT_OSU } from 'helpers/urls' |
|||
|
|||
type Input = { |
|||
version: string, |
|||
deviceId: string | number, |
|||
provider: number, |
|||
} |
|||
|
|||
export default async (input: Input): Promise<*> => { |
|||
const { data } = await network({ |
|||
method: 'POST', |
|||
url: GET_CURRENT_OSU, |
|||
data: { |
|||
device_version: input.deviceId, |
|||
version_name: `${input.version}-osu`, |
|||
provider: input.provider, |
|||
}, |
|||
}) |
|||
return data |
|||
} |
@ -1,16 +0,0 @@ |
|||
// @flow
|
|||
|
|||
import type Transport from '@ledgerhq/hw-transport' |
|||
|
|||
import getFirmwareInfo from 'helpers/firmware/getFirmwareInfo' |
|||
|
|||
type Result = boolean |
|||
|
|||
export default async (transport: Transport<*>): Promise<Result> => { |
|||
const { targetId, seVersion } = await getFirmwareInfo(transport) |
|||
if (targetId && seVersion) { |
|||
return true |
|||
} |
|||
|
|||
return false |
|||
} |
@ -1,8 +0,0 @@ |
|||
// @flow
|
|||
import network from 'api/network' |
|||
import { GET_FINAL_FIRMWARE } from 'helpers/urls' |
|||
|
|||
export default async (id: number) => { |
|||
const { data } = await network({ method: 'GET', url: `${GET_FINAL_FIRMWARE}/${id}` }) |
|||
return data |
|||
} |
@ -1,51 +0,0 @@ |
|||
// @flow
|
|||
|
|||
import type Transport from '@ledgerhq/hw-transport' |
|||
import type { FirmwareInfo } from 'helpers/types' |
|||
|
|||
const APDUS = { |
|||
GET_FIRMWARE: [0xe0, 0x01, 0x00, 0x00], |
|||
// we dont have common call that works inside app & dashboard
|
|||
// TODO: this should disappear.
|
|||
GET_FIRMWARE_FALLBACK: [0xe0, 0xc4, 0x00, 0x00], |
|||
} |
|||
|
|||
/** |
|||
* Retrieve targetId and firmware version from device |
|||
*/ |
|||
export default async function getFirmwareInfo(transport: Transport<*>): Promise<FirmwareInfo> { |
|||
const res = await transport.send(...APDUS.GET_FIRMWARE) |
|||
const byteArray = [...res] |
|||
const data = byteArray.slice(0, byteArray.length - 2) |
|||
const targetIdStr = Buffer.from(data.slice(0, 4)) |
|||
const targetId = targetIdStr.readUIntBE(0, 4) |
|||
const seVersionLength = data[4] |
|||
const seVersion = Buffer.from(data.slice(5, 5 + seVersionLength)).toString() |
|||
const flagsLength = data[5 + seVersionLength] |
|||
const flags = Buffer.from( |
|||
data.slice(5 + seVersionLength + 1, 5 + seVersionLength + 1 + flagsLength), |
|||
).toString() |
|||
|
|||
const mcuVersionLength = data[5 + seVersionLength + 1 + flagsLength] |
|||
let mcuVersion = Buffer.from( |
|||
data.slice( |
|||
7 + seVersionLength + flagsLength, |
|||
7 + seVersionLength + flagsLength + mcuVersionLength, |
|||
), |
|||
) |
|||
if (mcuVersion[mcuVersion.length - 1] === 0) { |
|||
mcuVersion = mcuVersion.slice(0, mcuVersion.length - 1) |
|||
} |
|||
mcuVersion = mcuVersion.toString() |
|||
|
|||
if (!seVersionLength) { |
|||
return { |
|||
targetId, |
|||
seVersion: '0.0.0', |
|||
flags: '', |
|||
mcuVersion: '', |
|||
} |
|||
} |
|||
|
|||
return { targetId, seVersion, flags, mcuVersion } |
|||
} |
@ -1,13 +0,0 @@ |
|||
// @flow
|
|||
import network from 'api/network' |
|||
|
|||
import { GET_MCUS } from 'helpers/urls' |
|||
|
|||
export default async (): Promise<*> => { |
|||
const { data } = await network({ |
|||
method: 'GET', |
|||
url: GET_MCUS, |
|||
}) |
|||
|
|||
return data |
|||
} |
@ -1,25 +0,0 @@ |
|||
// @flow
|
|||
import network from 'api/network' |
|||
|
|||
import { GET_NEXT_MCU } from 'helpers/urls' |
|||
import type { OsuFirmware } from 'helpers/types' |
|||
import { LatestMCUInstalledError } from '@ledgerhq/live-common/lib/errors' |
|||
|
|||
type NetworkResponse = { data: OsuFirmware | 'default' } |
|||
|
|||
export default async (bootloaderVersion: string): Promise<*> => { |
|||
const { data }: NetworkResponse = await network({ |
|||
method: 'POST', |
|||
url: GET_NEXT_MCU, |
|||
data: { |
|||
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 |
|||
} |
@ -1,132 +0,0 @@ |
|||
// @flow
|
|||
|
|||
import invariant from 'invariant' |
|||
import logger from 'logger' |
|||
import Websocket from 'ws' |
|||
import type Transport from '@ledgerhq/hw-transport' |
|||
import { Observable } from 'rxjs' |
|||
import { |
|||
WebsocketConnectionError, |
|||
WebsocketConnectionFailed, |
|||
DeviceSocketFail, |
|||
DeviceSocketNoBulkStatus, |
|||
DeviceSocketNoHandler, |
|||
} from '@ledgerhq/live-common/lib/errors' |
|||
|
|||
/** |
|||
* use Ledger WebSocket API to exchange data with the device |
|||
* Returns an Observable of the final result |
|||
*/ |
|||
export const createDeviceSocket = (transport: Transport<*>, url: string) => |
|||
Observable.create(o => { |
|||
let ws |
|||
let lastMessage: ?string |
|||
|
|||
try { |
|||
ws = new Websocket(url) |
|||
} catch (err) { |
|||
o.error(new WebsocketConnectionFailed(err.message, { url })) |
|||
return () => {} |
|||
} |
|||
invariant(ws, 'websocket is available') |
|||
|
|||
ws.on('open', () => { |
|||
logger.websocket('OPENED', { url }) |
|||
}) |
|||
|
|||
ws.on('error', e => { |
|||
logger.websocket('ERROR', { message: e.message, stack: e.stack }) |
|||
o.error(new WebsocketConnectionError(e.message, { url })) |
|||
}) |
|||
|
|||
ws.on('close', () => { |
|||
logger.websocket('CLOSE') |
|||
o.next(lastMessage || '') |
|||
o.complete() |
|||
}) |
|||
|
|||
const send = (nonce, response, data) => { |
|||
const msg = { |
|||
nonce, |
|||
response, |
|||
data, |
|||
} |
|||
logger.websocket('SEND', msg) |
|||
const strMsg = JSON.stringify(msg) |
|||
ws.send(strMsg) |
|||
} |
|||
|
|||
const handlers = { |
|||
exchange: async input => { |
|||
const { data, nonce } = input |
|||
const r: Buffer = await transport.exchange(Buffer.from(data, 'hex')) |
|||
const status = r.slice(r.length - 2) |
|||
const buffer = r.slice(0, r.length - 2) |
|||
const strStatus = status.toString('hex') |
|||
send(nonce, strStatus === '9000' ? 'success' : 'error', buffer.toString('hex')) |
|||
}, |
|||
|
|||
bulk: async input => { |
|||
const { data, nonce } = input |
|||
|
|||
// Execute all apdus and collect last status
|
|||
let lastStatus = null |
|||
for (const apdu of data) { |
|||
const r: Buffer = await transport.exchange(Buffer.from(apdu, 'hex')) |
|||
lastStatus = r.slice(r.length - 2) |
|||
|
|||
if (lastStatus.toString('hex') !== '9000') break |
|||
} |
|||
|
|||
if (!lastStatus) { |
|||
throw new DeviceSocketNoBulkStatus() |
|||
} |
|||
|
|||
const strStatus = lastStatus.toString('hex') |
|||
|
|||
send( |
|||
nonce, |
|||
strStatus === '9000' ? 'success' : 'error', |
|||
strStatus === '9000' ? '' : strStatus, |
|||
) |
|||
}, |
|||
|
|||
success: msg => { |
|||
lastMessage = msg.data || msg.result |
|||
ws.close() |
|||
}, |
|||
|
|||
error: msg => { |
|||
logger.websocket('ERROR', { data: msg.data }) |
|||
throw new DeviceSocketFail(msg.data, { url }) |
|||
}, |
|||
} |
|||
|
|||
const stackMessage = async rawMsg => { |
|||
try { |
|||
const msg = JSON.parse(rawMsg) |
|||
if (!(msg.query in handlers)) { |
|||
throw new DeviceSocketNoHandler(`Cannot handle msg of type ${msg.query}`, { |
|||
query: msg.query, |
|||
url, |
|||
}) |
|||
} |
|||
logger.websocket('RECEIVE', msg) |
|||
await handlers[msg.query](msg) |
|||
} catch (err) { |
|||
logger.websocket('ERROR', { message: err.message, stack: err.stack }) |
|||
o.error(err) |
|||
} |
|||
} |
|||
|
|||
ws.on('message', async rawMsg => { |
|||
stackMessage(rawMsg) |
|||
}) |
|||
|
|||
return () => { |
|||
if (ws.readyState === 1) { |
|||
lastMessage = null |
|||
ws.close() |
|||
} |
|||
} |
|||
}) |
@ -1,37 +0,0 @@ |
|||
// @flow
|
|||
import qs from 'qs' |
|||
|
|||
import { MANAGER_API_BASE, BASE_SOCKET_URL } from 'config/constants' |
|||
import type { LedgerScriptParams } from 'helpers/types' |
|||
|
|||
const urlBuilder = (base: string) => (endpoint: string): string => `${base}/${endpoint}` |
|||
|
|||
const managerUrlbuilder = urlBuilder(MANAGER_API_BASE) |
|||
|
|||
const wsURLBuilder = (endpoint: string) => (params?: Object) => |
|||
`${BASE_SOCKET_URL}/${endpoint}${params ? `?${qs.stringify(params)}` : ''}` |
|||
|
|||
// const wsURLBuilderProxy = (endpoint: string) => (params?: Object) =>
|
|||
// `ws://manager.ledger.fr:3501/${endpoint}${params ? `?${qs.stringify(params)}` : ''}`
|
|||
|
|||
// FIXME we shouldn't do this here. we should just collocate these where it's used.
|
|||
|
|||
export const GET_FINAL_FIRMWARE: string = managerUrlbuilder('firmware_final_versions') |
|||
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_CURRENT_OSU: string = managerUrlbuilder('get_osu_version') |
|||
export const GET_LATEST_FIRMWARE: string = managerUrlbuilder('get_latest_firmware') |
|||
export const GET_NEXT_MCU: string = managerUrlbuilder('mcu_versions_bootloader') |
|||
export const GET_MCUS: string = managerUrlbuilder('mcu_versions') |
|||
export const GET_CATEGORIES: string = managerUrlbuilder('categories') |
|||
export const GET_APPLICATIONS: string = managerUrlbuilder('applications') |
|||
|
|||
export const WS_INSTALL: (arg: LedgerScriptParams) => string = wsURLBuilder('install') |
|||
export const WS_GENUINE: (arg: { |
|||
targetId: string | number, |
|||
perso: string, |
|||
}) => string = wsURLBuilder('genuine') |
|||
export const WS_MCU: (arg: { targetId: string | number, version: string }) => string = wsURLBuilder( |
|||
'mcu', |
|||
) |
Loading…
Reference in new issue