Skip to content
This repository was archived by the owner on Jul 15, 2022. It is now read-only.

Commit f715322

Browse files
grevalpinkman
andauthored
Reimplement getVersion and add more type in DeviceInfo (#1348)
* Reimplement getVersion and add more type in DeviceInfo * add new path for fw repair of new LNX version * v21.2.0-lnx2fwrepair * fix lint * bump * v21.2.0-lnx2fwrepair.2 * fix deviceId in getCurrentFirmware call * v21.2.0-lnx2fwrepair.3 * fix repair feature * v21.2.0-lnx2fwrepair.4 * v21.2.0-lnx2fwrepair.5 * fix observable return * v21.2.0-lnx2fwrepair.6 * add logging * bump * fix comparing version * v21.2.0-lnx2fwrepair.8 * fix length checking * v21.2.0-lnx2fwrepair.9 Co-authored-by: Valentin D. Pinkman <[email protected]> Co-authored-by: Valentin D. Pinkman <[email protected]>
1 parent 376bf92 commit f715322

9 files changed

+299
-83
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"type": "git",
99
"url": "https://github.com/LedgerHQ/ledger-live-common"
1010
},
11-
"version": "21.2.2",
11+
"version": "21.2.0-lnx2fwrepair.9",
1212
"main": "lib/index.js",
1313
"types": "lib/index.d.ts",
1414
"license": "Apache-2.0",

src/__tests__/hw/getDeviceInfo.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,3 +463,55 @@ test("nanoS das", async () => {
463463
version: "1.4.2-das",
464464
});
465465
});
466+
467+
test("Nano X BL < 2", async () => {
468+
const t = await openTransportReplayer(
469+
RecordStore.fromString(`
470+
=> b001000000
471+
<= 6e00
472+
=> e001000000
473+
<= 0501000203312e3404f4d8aa43043300000404f13089749000
474+
`)
475+
);
476+
const res = await getDeviceInfo(t);
477+
expect(res).toMatchObject({
478+
version: "1.4",
479+
mcuBlVersion: "1.4",
480+
seVersion: undefined,
481+
majMin: "1.4",
482+
providerName: null,
483+
targetId: 83951618,
484+
seTargetId: 855638020,
485+
mcuTargetId: 83951618,
486+
isOSU: false,
487+
isBootloader: true,
488+
managerAllowed: false,
489+
pinValidated: true,
490+
});
491+
});
492+
493+
test("Nano X BL >= 2", async () => {
494+
const t = await openTransportReplayer(
495+
RecordStore.fromString(`
496+
=> b001000000
497+
<= 6e00
498+
=> e001000000
499+
<= 0501000203312e3404f4d8aa4305322e302e3004330000049000
500+
`)
501+
);
502+
const res = await getDeviceInfo(t);
503+
expect(res).toMatchObject({
504+
version: "1.4",
505+
mcuBlVersion: "1.4",
506+
seVersion: "2.0.0",
507+
majMin: "1.4",
508+
providerName: null,
509+
targetId: 83951618,
510+
seTargetId: 855638020,
511+
mcuTargetId: 83951618,
512+
isOSU: false,
513+
isBootloader: true,
514+
managerAllowed: false,
515+
pinValidated: true,
516+
});
517+
});

src/api/Manager.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ const compatibleMCUForDeviceInfo = (
186186
m.providers.includes(provider)
187187
);
188188

189-
const findBestMCU = (compatibleMCU: McuVersion[]) => {
189+
const findBestMCU = (compatibleMCU: McuVersion[]): McuVersion | undefined => {
190190
let best = compatibleMCU[0];
191191

192192
for (let i = 1; i < compatibleMCU.length; i++) {
@@ -383,7 +383,7 @@ const genuineCheck = (
383383
targetId: any;
384384
perso: any;
385385
}
386-
): Observable<SocketEvent> => {
386+
): Observable<any> => {
387387
if (getEnv("MOCK")) {
388388
return createMockSocket(secureChannelMock(false), resultMock("0000"));
389389
}
@@ -491,8 +491,8 @@ const installMcu = (
491491
targetId,
492492
version,
493493
}: {
494-
targetId: any;
495-
version: any;
494+
targetId: number | string;
495+
version: string;
496496
}
497497
): Observable<any> => {
498498
if (getEnv("MOCK")) {
@@ -503,6 +503,7 @@ const installMcu = (
503503
targetId,
504504
version,
505505
});
506+
506507
return createDeviceSocket(transport, {
507508
url: URL.format({
508509
pathname: `${getEnv("BASE_SOCKET_URL")}/mcu`,

src/hw/firmwareUpdate-main.ts

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { log } from "@ledgerhq/logs";
2-
import { Observable, from, of, empty, concat, throwError } from "rxjs";
2+
import { Observable, from, of, EMPTY, concat, throwError } from "rxjs";
33
import {
44
concatMap,
55
delay,
@@ -41,43 +41,44 @@ const main = (
4141

4242
const waitForBootloader = withDeviceInfo.pipe(
4343
concatMap((deviceInfo) =>
44-
deviceInfo.isBootloader ? empty() : concat(wait2s, waitForBootloader)
44+
deviceInfo.isBootloader ? EMPTY : concat(wait2s, waitForBootloader)
4545
)
4646
);
4747
const potentialAutoFlash = withDeviceInfo.pipe(
4848
concatMap((deviceInfo) =>
4949
deviceInfo.isOSU
50-
? empty()
51-
: withDevice(deviceId)((transport) =>
52-
Observable.create((o) => {
53-
const timeout = setTimeout(() => {
54-
log("firmware", "potentialAutoFlash timeout");
55-
o.complete();
56-
}, 20000);
50+
? EMPTY
51+
: withDevice(deviceId)(
52+
(transport) =>
53+
new Observable((o) => {
54+
const timeout = setTimeout(() => {
55+
log("firmware", "potentialAutoFlash timeout");
56+
o.complete();
57+
}, 20000);
5758

58-
const disconnect = () => {
59-
log("firmware", "potentialAutoFlash disconnect");
60-
o.complete();
61-
};
59+
const disconnect = () => {
60+
log("firmware", "potentialAutoFlash disconnect");
61+
o.complete();
62+
};
6263

63-
transport.on("disconnect", disconnect);
64-
return () => {
65-
clearTimeout(timeout);
66-
transport.off("disconnect", disconnect);
67-
};
68-
})
64+
transport.on("disconnect", disconnect);
65+
return () => {
66+
clearTimeout(timeout);
67+
transport.off("disconnect", disconnect);
68+
};
69+
})
6970
)
7071
)
7172
);
7273
const bootloaderLoop = withDeviceInfo.pipe(
7374
concatMap((deviceInfo) =>
7475
!deviceInfo.isBootloader
75-
? empty()
76+
? EMPTY
7677
: concat(withDeviceInstall(flash(final)), wait2s, bootloaderLoop)
7778
)
7879
);
7980
const finalStep = !withFinal
80-
? empty()
81+
? EMPTY
8182
: withDeviceInfo.pipe(
8283
concatMap((deviceInfo) =>
8384
!deviceInfo.isOSU

src/hw/firmwareUpdate-repair.ts

Lines changed: 112 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
import { log } from "@ledgerhq/logs";
22
import { MCUNotGenuineToDashboard } from "@ledgerhq/errors";
33
import { Observable, from, of, EMPTY, concat, throwError } from "rxjs";
4-
import { concatMap, delay, filter, map, throttleTime } from "rxjs/operators";
4+
import {
5+
concatMap,
6+
delay,
7+
filter,
8+
map,
9+
mergeMap,
10+
throttleTime,
11+
} from "rxjs/operators";
12+
import semver from "semver";
513
import ManagerAPI from "../api/Manager";
614
import { withDevicePolling, withDevice } from "./deviceAccess";
715
import { getProviderId } from "../manager/provider";
@@ -12,6 +20,7 @@ import {
1220
followDeviceRepair,
1321
followDeviceUpdate,
1422
} from "../deviceWordings";
23+
import { DeviceVersion, FinalFirmware } from "../types/manager";
1524
const wait2s = of({
1625
type: "wait",
1726
}).pipe(delay(2000));
@@ -38,6 +47,11 @@ export const repairChoices = [
3847
},
3948
];
4049

50+
const filterMCUForDeviceInfo = (deviceInfo) => {
51+
const provider = getProviderId(deviceInfo);
52+
return (mcu) => mcu.providers.includes(provider);
53+
};
54+
4155
const repair = (
4256
deviceId: string,
4357
forceMCU_: string | null | undefined
@@ -105,14 +119,103 @@ const repair = (
105119
default:
106120
return from(mcusPromise).pipe(
107121
concatMap((mcus) => {
108-
const next = ManagerAPI.findBestMCU(
109-
ManagerAPI.compatibleMCUForDeviceInfo(
110-
mcus,
111-
deviceInfo,
112-
getProviderId(deviceInfo)
113-
)
114-
);
115-
if (next) return installMcu(next.name);
122+
let next;
123+
const { seVersion, seTargetId, mcuBlVersion } = deviceInfo;
124+
125+
// This is a special case where a user with LNX version >= 2.0.0
126+
// comes back with a broken updated device. We need to be able
127+
// to patch MCU or Bootloader if needed
128+
if (seVersion && seTargetId) {
129+
log(
130+
"hw",
131+
"firmwareUpdate-repair seVersion and seTargetId found",
132+
{ seVersion, seTargetId }
133+
);
134+
const validMcusForDeviceInfo = mcus
135+
.filter(filterMCUForDeviceInfo(deviceInfo))
136+
.filter((mcu) => mcu.from_bootloader_version !== "none");
137+
138+
log("hw", "firmwareUpdate-repair valid mcus for device", {
139+
validMcusForDeviceInfo,
140+
});
141+
142+
return from(
143+
ManagerAPI.getDeviceVersion(
144+
seTargetId,
145+
getProviderId(deviceInfo)
146+
)
147+
).pipe(
148+
mergeMap((deviceVersion: DeviceVersion) =>
149+
from(
150+
ManagerAPI.getCurrentFirmware({
151+
deviceId: deviceVersion.id,
152+
version: seVersion,
153+
provider: getProviderId(deviceInfo),
154+
})
155+
)
156+
),
157+
mergeMap((finalFirmware: FinalFirmware) => {
158+
log("hw", "firmwareUpdate-repair got final firmware", {
159+
finalFirmware,
160+
});
161+
162+
const mcu = ManagerAPI.findBestMCU(
163+
finalFirmware.mcu_versions
164+
.map((id) =>
165+
validMcusForDeviceInfo.find((mcu) => mcu.id === id)
166+
)
167+
.filter(Boolean)
168+
);
169+
170+
log("hw", "firmwareUpdate-repair got mcu", { mcu });
171+
172+
if (!mcu) return EMPTY;
173+
const expectedBootloaderVersion = semver.coerce(
174+
mcu.from_bootloader_version
175+
).version;
176+
const currentBootloaderVersion =
177+
semver.coerce(mcuBlVersion).version;
178+
179+
log("hw", "firmwareUpdate-repair bootloader versions", {
180+
currentBootloaderVersion,
181+
expectedBootloaderVersion,
182+
});
183+
184+
if (
185+
expectedBootloaderVersion === currentBootloaderVersion
186+
) {
187+
next = mcu;
188+
log(
189+
"hw",
190+
"firmwareUpdate-repair bootloader versions are the same",
191+
{ next }
192+
);
193+
} else {
194+
next = {
195+
name: mcu.from_bootloader_version,
196+
};
197+
log(
198+
"hw",
199+
"firmwareUpdate-repair bootloader versions are different",
200+
{ next }
201+
);
202+
}
203+
204+
return installMcu(next.name);
205+
})
206+
);
207+
} else {
208+
next = ManagerAPI.findBestMCU(
209+
ManagerAPI.compatibleMCUForDeviceInfo(
210+
mcus,
211+
deviceInfo,
212+
getProviderId(deviceInfo)
213+
)
214+
);
215+
216+
if (next) return installMcu(next.name);
217+
}
218+
116219
return EMPTY;
117220
})
118221
);

src/hw/flash.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { log } from "@ledgerhq/logs";
22
import Transport from "@ledgerhq/hw-transport";
3-
import { Observable, from, of, concat, empty } from "rxjs";
3+
import { Observable, from, of, concat, EMPTY } from "rxjs";
44
import { mergeMap } from "rxjs/operators";
55
import ManagerAPI from "../api/Manager";
66
import { getProviderId } from "../manager/provider";
@@ -38,7 +38,7 @@ export default (finalFirmware: FinalFirmware) =>
3838
)
3939
).pipe(
4040
mergeMap((mcuVersion: (McuVersion | null | undefined) | string) => {
41-
if (!mcuVersion) return empty();
41+
if (!mcuVersion) return EMPTY;
4242
let version;
4343
let isMCU = false;
4444

src/hw/getDeviceInfo.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,22 @@ export default async function getDeviceInfo(
3838
}
3939

4040
const res = await getVersion(transport);
41-
const { seVersion } = res;
42-
const { targetId, mcuVersion, flags } = res;
43-
const isOSU = seVersion.includes("-osu");
44-
const version = seVersion.replace("-osu", "");
45-
const m = seVersion.match(/([0-9]+.[0-9]+)(.[0-9]+)?(-(.*))?/);
41+
const {
42+
isBootloader,
43+
rawVersion,
44+
targetId,
45+
seVersion,
46+
seTargetId,
47+
mcuBlVersion,
48+
mcuVersion,
49+
mcuTargetId,
50+
flags,
51+
} = res;
52+
const isOSU = rawVersion.includes("-osu");
53+
const version = rawVersion.replace("-osu", "");
54+
const m = rawVersion.match(/([0-9]+.[0-9]+)(.[0-9]+)?(-(.*))?/);
4655
const [, majMin, , , postDash] = m || [];
4756
const providerName = PROVIDERS[postDash] ? postDash : null;
48-
const isBootloader = (targetId & 0xf0000000) !== 0x30000000;
4957
const flag = flags.length > 0 ? flags[0] : 0;
5058
const managerAllowed = !!(flag & ManagerAllowedFlag);
5159
const pinValidated = !!(flag & PinValidatedFlag);
@@ -60,9 +68,13 @@ export default async function getDeviceInfo(
6068
return {
6169
version,
6270
mcuVersion,
71+
seVersion,
72+
mcuBlVersion,
6373
majMin,
6474
providerName: providerName || null,
6575
targetId,
76+
seTargetId,
77+
mcuTargetId,
6678
isOSU,
6779
isBootloader,
6880
managerAllowed,

0 commit comments

Comments
 (0)