@onekeyfe/hd-core 1.2.0-alpha.27 → 1.2.0-alpha.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__tests__/firmware-update/check-all-firmware-release.test.ts +17 -1
- package/__tests__/firmware-update/firmware-preparation-error.test.ts +27 -0
- package/__tests__/firmware-update/firmware-update-plan.test.ts +169 -0
- package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +20 -1
- package/__tests__/open-wallet-session.test.ts +1 -7
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/OpenWalletSession.d.ts.map +1 -1
- package/dist/api/firmware/FirmwarePreparationError.d.ts +3 -0
- package/dist/api/firmware/FirmwarePreparationError.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +1 -0
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.js +96 -23
- package/dist/types/api/openWalletSession.d.ts +0 -1
- package/dist/types/api/openWalletSession.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/CheckAllFirmwareRelease.ts +7 -2
- package/src/api/FirmwareUpdateV2.ts +3 -5
- package/src/api/FirmwareUpdateV3.ts +3 -2
- package/src/api/FirmwareUpdateV4.ts +2 -1
- package/src/api/OpenWalletSession.ts +1 -10
- package/src/api/firmware/FirmwarePreparationError.ts +12 -0
- package/src/api/firmware/FirmwareUpdatePlan.ts +119 -12
- package/src/types/api/openWalletSession.ts +0 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { EDeviceType, EFirmwareType, ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
2
|
|
|
3
3
|
import CheckAllFirmwareRelease from '../../src/api/CheckAllFirmwareRelease';
|
|
4
4
|
import { buildFirmwareUpdatePlan } from '../../src/api/firmware/FirmwareUpdatePlan';
|
|
@@ -15,6 +15,7 @@ jest.mock('../../src/data/config', () => ({
|
|
|
15
15
|
|
|
16
16
|
jest.mock('../../src/api/firmware/FirmwareUpdatePlan', () => ({
|
|
17
17
|
buildFirmwareUpdatePlan: jest.fn(),
|
|
18
|
+
validateFirmwareUpdatePlanForceTargets: jest.fn(value => value ?? []),
|
|
18
19
|
}));
|
|
19
20
|
|
|
20
21
|
jest.mock('../../src/api/firmware/releaseHelper', () => ({
|
|
@@ -147,6 +148,21 @@ describe('CheckAllFirmwareRelease', () => {
|
|
|
147
148
|
);
|
|
148
149
|
});
|
|
149
150
|
|
|
151
|
+
test('does not hide a Plan failure for an explicitly forced target', async () => {
|
|
152
|
+
const planError = ERRORS.TypedError(
|
|
153
|
+
HardwareErrorCode.RuntimeError,
|
|
154
|
+
'Forced firmware target is unavailable',
|
|
155
|
+
{
|
|
156
|
+
firmwareUpdateCode: 'FirmwarePlanInvalid',
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
mockBuildFirmwareUpdatePlan.mockImplementation(() => {
|
|
160
|
+
throw planError;
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
await expect(createMethodWithForceTargets().run()).rejects.toBe(planError);
|
|
164
|
+
});
|
|
165
|
+
|
|
150
166
|
test('does not hide unexpected Plan builder failures', async () => {
|
|
151
167
|
const unexpectedError = new Error('unexpected builder failure');
|
|
152
168
|
mockBuildFirmwareUpdatePlan.mockImplementation(() => {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
+
|
|
3
|
+
import { normalizeFirmwarePreparationError } from '../../src/api/firmware/FirmwarePreparationError';
|
|
4
|
+
|
|
5
|
+
describe('normalizeFirmwarePreparationError', () => {
|
|
6
|
+
test('preserves structured firmware invariant errors', () => {
|
|
7
|
+
const error = ERRORS.TypedError(
|
|
8
|
+
HardwareErrorCode.RuntimeError,
|
|
9
|
+
'Firmware must be prepared by the external firmware host',
|
|
10
|
+
{
|
|
11
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
12
|
+
artifactName: 'firmware',
|
|
13
|
+
}
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
expect(normalizeFirmwarePreparationError(error)).toBe(error);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('wraps ordinary preparation failures as firmware download errors', () => {
|
|
20
|
+
const error = normalizeFirmwarePreparationError(new Error('request failed'));
|
|
21
|
+
|
|
22
|
+
expect(error).toMatchObject({
|
|
23
|
+
errorCode: HardwareErrorCode.FirmwareUpdateDownloadFailed,
|
|
24
|
+
message: 'request failed',
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -25,6 +25,63 @@ const noUpdate = {
|
|
|
25
25
|
release: undefined,
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
+
const expectFirmwarePlanInvalid = (build: () => unknown, expectedMessage?: string) => {
|
|
29
|
+
let thrown: unknown;
|
|
30
|
+
try {
|
|
31
|
+
build();
|
|
32
|
+
} catch (error) {
|
|
33
|
+
thrown = error;
|
|
34
|
+
}
|
|
35
|
+
expect(thrown).toMatchObject({
|
|
36
|
+
params: {
|
|
37
|
+
firmwareUpdateCode: 'FirmwarePlanInvalid',
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
if (expectedMessage) {
|
|
41
|
+
expect(thrown).toBeInstanceOf(Error);
|
|
42
|
+
expect((thrown as Error).message).toContain(expectedMessage);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
type BuildPlanInput = Parameters<typeof buildFirmwareUpdatePlan>[0];
|
|
47
|
+
|
|
48
|
+
const createLegacyForceInput = (
|
|
49
|
+
forceUpdateTargets: unknown,
|
|
50
|
+
release: Record<string, unknown> = {
|
|
51
|
+
url: 'https://firmware.onekey.so/pro/firmware.bin',
|
|
52
|
+
version: [4, 21, 0],
|
|
53
|
+
}
|
|
54
|
+
): BuildPlanInput => ({
|
|
55
|
+
features: createFeatures({
|
|
56
|
+
deviceType: EDeviceType.Pro,
|
|
57
|
+
firmwareVersion: '4.21.0',
|
|
58
|
+
bootloaderVersion: '2.8.4',
|
|
59
|
+
}),
|
|
60
|
+
firmwareType: EFirmwareType.Universal,
|
|
61
|
+
platform: 'desktop',
|
|
62
|
+
firmware: { status: 'valid', release },
|
|
63
|
+
ble: noUpdate,
|
|
64
|
+
bootloader: noUpdate,
|
|
65
|
+
forceUpdateTargets: forceUpdateTargets as BuildPlanInput['forceUpdateTargets'],
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const createProtocolV2ForceInput = (
|
|
69
|
+
forceUpdateTargets: unknown,
|
|
70
|
+
release: Record<string, unknown>
|
|
71
|
+
): BuildPlanInput => ({
|
|
72
|
+
features: createFeatures({
|
|
73
|
+
deviceType: EDeviceType.Pro2,
|
|
74
|
+
firmwareVersion: '1.0.0',
|
|
75
|
+
bootloaderVersion: '1.0.0',
|
|
76
|
+
}),
|
|
77
|
+
firmwareType: EFirmwareType.Universal,
|
|
78
|
+
platform: 'desktop',
|
|
79
|
+
firmware: { status: 'valid', release },
|
|
80
|
+
ble: noUpdate,
|
|
81
|
+
bootloader: noUpdate,
|
|
82
|
+
forceUpdateTargets: forceUpdateTargets as BuildPlanInput['forceUpdateTargets'],
|
|
83
|
+
});
|
|
84
|
+
|
|
28
85
|
describe('buildFirmwareUpdatePlan', () => {
|
|
29
86
|
test('selects all legacy artifacts before execution and chooses the desktop full resource', () => {
|
|
30
87
|
const plan = buildFirmwareUpdatePlan({
|
|
@@ -192,6 +249,118 @@ describe('buildFirmwareUpdatePlan', () => {
|
|
|
192
249
|
expect(plan.targetsToUpdate).toEqual(['firmware']);
|
|
193
250
|
});
|
|
194
251
|
|
|
252
|
+
test.each([
|
|
253
|
+
{
|
|
254
|
+
label: 'a non-array value',
|
|
255
|
+
forceUpdateTargets: 'firmware',
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
label: 'an unknown target',
|
|
259
|
+
forceUpdateTargets: ['firmware', 'unknown'],
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
label: 'a duplicate target',
|
|
263
|
+
forceUpdateTargets: ['firmware', 'firmware'],
|
|
264
|
+
},
|
|
265
|
+
])('rejects $label in forceUpdateTargets', ({ forceUpdateTargets }) => {
|
|
266
|
+
expectFirmwarePlanInvalid(() =>
|
|
267
|
+
buildFirmwareUpdatePlan(createLegacyForceInput(forceUpdateTargets))
|
|
268
|
+
);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
test('rejects an explicitly forced legacy resource without a resource artifact', () => {
|
|
272
|
+
expectFirmwarePlanInvalid(() => buildFirmwareUpdatePlan(createLegacyForceInput(['resource'])));
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
test.each(['ble', 'bootloader'] as const)(
|
|
276
|
+
'rejects the unsupported Pro2 %s force target',
|
|
277
|
+
forceTarget => {
|
|
278
|
+
expectFirmwarePlanInvalid(
|
|
279
|
+
() =>
|
|
280
|
+
buildFirmwareUpdatePlan(
|
|
281
|
+
createProtocolV2ForceInput([forceTarget], {
|
|
282
|
+
components: {
|
|
283
|
+
applicationP1: {
|
|
284
|
+
target: 'APPLICATION_P1',
|
|
285
|
+
url: 'https://firmware.onekey.so/pro2/application-p1.bin',
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
})
|
|
289
|
+
),
|
|
290
|
+
'does not support forced'
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
test.each([
|
|
296
|
+
{
|
|
297
|
+
forceTarget: 'firmware' as const,
|
|
298
|
+
release: {
|
|
299
|
+
components: {},
|
|
300
|
+
resourceBundles: [
|
|
301
|
+
{
|
|
302
|
+
name: 'images',
|
|
303
|
+
url: 'https://firmware.onekey.so/pro2/images.okpkg',
|
|
304
|
+
},
|
|
305
|
+
],
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
forceTarget: 'resource' as const,
|
|
310
|
+
release: {
|
|
311
|
+
components: {
|
|
312
|
+
applicationP1: {
|
|
313
|
+
target: 'APPLICATION_P1',
|
|
314
|
+
url: 'https://firmware.onekey.so/pro2/application-p1.bin',
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
])(
|
|
320
|
+
'rejects a Pro2 $forceTarget force target not represented by an artifact',
|
|
321
|
+
({ forceTarget, release }) => {
|
|
322
|
+
expectFirmwarePlanInvalid(() =>
|
|
323
|
+
buildFirmwareUpdatePlan(createProtocolV2ForceInput([forceTarget], release))
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
test.each([
|
|
329
|
+
{
|
|
330
|
+
forceTarget: 'firmware' as const,
|
|
331
|
+
expectedArtifactIds: ['component:app_v1'],
|
|
332
|
+
expectedTargets: ['app_v1'],
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
forceTarget: 'resource' as const,
|
|
336
|
+
expectedArtifactIds: ['resourceBundle:images'],
|
|
337
|
+
expectedTargets: ['resource'],
|
|
338
|
+
},
|
|
339
|
+
])(
|
|
340
|
+
'limits a Pro2 $forceTarget force to the selected artifact role',
|
|
341
|
+
({ forceTarget, expectedArtifactIds, expectedTargets }) => {
|
|
342
|
+
const plan = buildFirmwareUpdatePlan(
|
|
343
|
+
createProtocolV2ForceInput([forceTarget], {
|
|
344
|
+
components: {
|
|
345
|
+
applicationP1: {
|
|
346
|
+
target: 'APPLICATION_P1',
|
|
347
|
+
url: 'https://firmware.onekey.so/pro2/application-p1.bin',
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
resourceBundles: [
|
|
351
|
+
{
|
|
352
|
+
name: 'images',
|
|
353
|
+
url: 'https://firmware.onekey.so/pro2/images.okpkg',
|
|
354
|
+
},
|
|
355
|
+
],
|
|
356
|
+
})
|
|
357
|
+
);
|
|
358
|
+
|
|
359
|
+
expect(plan.artifacts.map(artifact => artifact.artifactId)).toEqual(expectedArtifactIds);
|
|
360
|
+
expect(plan.targetsToUpdate).toEqual(expectedTargets);
|
|
361
|
+
}
|
|
362
|
+
);
|
|
363
|
+
|
|
195
364
|
test('rejects a prepared native plan without a stable device identity', () => {
|
|
196
365
|
const features = createFeatures({
|
|
197
366
|
deviceType: EDeviceType.Classic1s,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EDeviceType, EFirmwareType, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
1
|
+
import { EDeviceType, EFirmwareType, ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
2
|
|
|
3
3
|
import FirmwareUpdateV2 from '../../src/api/FirmwareUpdateV2';
|
|
4
4
|
import { getBinary } from '../../src/api/firmware/getBinary';
|
|
@@ -181,6 +181,25 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
|
|
|
181
181
|
expect(mockUploadFirmwareFromSource).not.toHaveBeenCalled();
|
|
182
182
|
});
|
|
183
183
|
|
|
184
|
+
it('preserves structured preparation errors before any firmware mutation', async () => {
|
|
185
|
+
const preparationError = ERRORS.TypedError(
|
|
186
|
+
HardwareErrorCode.RuntimeError,
|
|
187
|
+
'Firmware must be prepared by the external firmware host',
|
|
188
|
+
{
|
|
189
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
190
|
+
artifactName: 'firmware',
|
|
191
|
+
}
|
|
192
|
+
);
|
|
193
|
+
mockGetBinary.mockRejectedValue(preparationError);
|
|
194
|
+
const { method, typedCall, acquire } = createMethod();
|
|
195
|
+
|
|
196
|
+
await expect(method.run()).rejects.toBe(preparationError);
|
|
197
|
+
|
|
198
|
+
expectNoFirmwareMutationCalls(typedCall);
|
|
199
|
+
expect(acquire).not.toHaveBeenCalled();
|
|
200
|
+
expect(mockUploadFirmwareFromSource).not.toHaveBeenCalled();
|
|
201
|
+
});
|
|
202
|
+
|
|
184
203
|
it.each([
|
|
185
204
|
{
|
|
186
205
|
mode: 'firmware release.url',
|
|
@@ -184,7 +184,6 @@ describe('openWalletSession', () => {
|
|
|
184
184
|
walletType: 'standard',
|
|
185
185
|
deviceId: 'device-1',
|
|
186
186
|
passphraseState: null,
|
|
187
|
-
sessionId: 'main-wallet-session',
|
|
188
187
|
resumed: false,
|
|
189
188
|
});
|
|
190
189
|
expect(method.payload.useEmptyPassphrase).toBe(true);
|
|
@@ -261,7 +260,6 @@ describe('openWalletSession', () => {
|
|
|
261
260
|
walletType: 'hidden',
|
|
262
261
|
deviceId: 'device-1',
|
|
263
262
|
passphraseState: 'hidden-state-after-unlock',
|
|
264
|
-
sessionId: 'hidden-session-after-unlock',
|
|
265
263
|
resumed: false,
|
|
266
264
|
});
|
|
267
265
|
expect(device.unlockDevice).toHaveBeenCalledWith(DeviceSessionPinType.Main);
|
|
@@ -295,7 +293,6 @@ describe('openWalletSession', () => {
|
|
|
295
293
|
walletType: 'hidden',
|
|
296
294
|
deviceId: 'device-1',
|
|
297
295
|
passphraseState: 'new-hidden-state',
|
|
298
|
-
sessionId: 'new-hidden-session',
|
|
299
296
|
resumed: false,
|
|
300
297
|
});
|
|
301
298
|
expect(typedCall).toHaveBeenCalledWith('ProtocolInfoRequest', 'ProtocolInfo', {
|
|
@@ -369,7 +366,6 @@ describe('openWalletSession', () => {
|
|
|
369
366
|
walletType: 'hidden',
|
|
370
367
|
deviceId: 'device-1',
|
|
371
368
|
passphraseState: 'hidden-state',
|
|
372
|
-
sessionId: 'renewed-session',
|
|
373
369
|
resumed: true,
|
|
374
370
|
});
|
|
375
371
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
@@ -567,7 +563,7 @@ describe('openWalletSession', () => {
|
|
|
567
563
|
expect(device.clearInternalState).toHaveBeenCalled();
|
|
568
564
|
});
|
|
569
565
|
|
|
570
|
-
test('selects a hidden wallet
|
|
566
|
+
test('selects a hidden wallet without exposing the internal device session', async () => {
|
|
571
567
|
const typedCall = jest
|
|
572
568
|
.fn()
|
|
573
569
|
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
@@ -592,7 +588,6 @@ describe('openWalletSession', () => {
|
|
|
592
588
|
walletType: 'hidden',
|
|
593
589
|
deviceId: 'device-1',
|
|
594
590
|
passphraseState: 'hidden-state',
|
|
595
|
-
sessionId: 'hidden-session',
|
|
596
591
|
resumed: false,
|
|
597
592
|
});
|
|
598
593
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {});
|
|
@@ -759,7 +754,6 @@ describe('openWalletSession', () => {
|
|
|
759
754
|
walletType: 'hidden',
|
|
760
755
|
deviceId: 'device-1',
|
|
761
756
|
passphraseState: 'hidden-state',
|
|
762
|
-
sessionId: 'renewed-session',
|
|
763
757
|
resumed: true,
|
|
764
758
|
});
|
|
765
759
|
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CheckAllFirmwareRelease.d.ts","sourceRoot":"","sources":["../../src/api/CheckAllFirmwareRelease.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"CheckAllFirmwareRelease.d.ts","sourceRoot":"","sources":["../../src/api/CheckAllFirmwareRelease.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAoB1C,OAAO,KAAK,EACV,kBAAkB,EAEnB,MAAM,sCAAsC,CAAC;AAK9C,MAAM,CAAC,OAAO,OAAO,uBAAwB,SAAQ,UAAU;IAC7D,IAAI;IAME,GAAG;CAkFV"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FirmwareUpdateV2.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV2.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,QAAQ,EAEb,KAAK,aAAa,EAKnB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"FirmwareUpdateV2.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV2.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,QAAQ,EAEb,KAAK,aAAa,EAKnB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAuB1C,OAAO,KAAK,EAAE,QAAQ,EAAe,MAAM,UAAU,CAAC;AAEtD,OAAO,KAAK,EACV,sBAAsB,EACtB,yBAAyB,EAC1B,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,yCAAyC,CAAC;AAE1F,KAAK,MAAM,GAAG;IACZ,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,CAAC,EAAE,yBAAyB,CAAC;IACrC,gBAAgB,CAAC,EAAE,yBAAyB,CAAC;IAC7C,eAAe,CAAC,EAAE,KAAK,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,yBAAyB,CAAC;KACrC,CAAC,CAAC;IACH,cAAc,CAAC,EAAE,sBAAsB,CAAC;IACxC,YAAY,CAAC,EAAE,0BAA0B,CAAC;IAC1C,QAAQ,CAAC,EAAE,0BAA0B,CAAC,UAAU,CAAC,CAAC;IAClD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,EAAE,UAAU,GAAG,KAAK,CAAC;IAC/B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,YAAY,CAAC,EAAE,aAAa,CAAC;CAC9B,CAAC;AAkFF,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,UAAU,CAAC,MAAM,CAAC;IAC9D,YAAY,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAQ;IAE1C,IAAI;IA6EJ,cAAc,YAAa,MAAM,UAS/B;YAEY,qCAAqC;IAkBnD,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS;YAkFvC,4BAA4B;IAuB1C,qBAAqB;IAUrB,uBAAuB,CAAC,UAAU,EAAE,MAAM;IAc1C,gCAAgC,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,EAAE,YAAY,EAAE,aAAa;IAwBtF,GAAG;CAyQV"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FirmwareUpdateV3.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV3.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FirmwareUpdateV3.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV3.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAY/E,OAAO,KAAK,EAEV,sBAAsB,EACvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,QAAQ,EAAiB,MAAM,qBAAqB,CAAC;AAMnE,eAAO,MAAM,gCAAgC,UAAU,CAAC;AAaxD,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,wBAAwB,CAAC,sBAAsB,CAAC;IAC5F,YAAY,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAQ;IAE1C,OAAO,CAAC,gBAAgB,CAAS;IAEjC,OAAO,CAAC,eAAe,CAA4B;IAEnD,IAAI;IAmFE,GAAG;;;;;YAQK,aAAa;IA6D3B,OAAO,CAAC,wBAAwB;YAiBlB,kBAAkB;YAelB,oBAAoB;IAKlC,OAAO,CAAC,wBAAwB;YAgBlB,oBAAoB;YA2DpB,uBAAuB;YAuBvB,4BAA4B;YA+E5B,aAAa;IAwN3B,OAAO,CAAC,yBAAyB;IAajC,OAAO,CAAC,yBAAyB;IAQjC,OAAO,CAAC,qBAAqB;IAmB7B,OAAO,CAAC,sCAAsC;IAexC,sBAAsB,CAAC,OAAO,EAAE,MAAM;CAuE7C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FirmwareUpdateV4.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV4.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FirmwareUpdateV4.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV4.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAkB/E,OAAO,KAAK,EAEV,sBAAsB,EAEvB,MAAM,6BAA6B,CAAC;AA4VrC,eAAO,MAAM,iCAAiC,0BACrB,MAAM,uBACR,MAAM,SAc5B,CAAC;AAUF,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,wBAAwB,CAAC,sBAAsB,CAAC;IAC5F,OAAO,CAAC,8BAA8B,CAAC,CAAS;IAEhD,qBAAqB;IAIrB,OAAO,CAAC,yBAAyB,CAA4B;IAE7D,OAAO,CAAC,2BAA2B,CAAS;IAE5C,OAAO,CAAC,iCAAiC,CAA6B;IAEtE,OAAO,CAAC,6BAA6B,CAAC,CAAW;IAEjD,OAAO,CAAC,6BAA6B,CAAS;IAE9C,IAAI;IAoHJ,OAAO,CAAC,8BAA8B;IAoBhC,GAAG;;;;;YAKK,aAAa;YAsEb,4BAA4B;YAkB5B,0BAA0B;YAY1B,8BAA8B;YAK9B,+BAA+B;YAqD/B,gCAAgC;YAmDhC,8BAA8B;IAsB5C,OAAO,CAAC,8BAA8B;IA0BtC,OAAO,CAAC,kCAAkC;IAc1C,OAAO,CAAC,gCAAgC;IAsDxC,OAAO,CAAC,6BAA6B;YAsBvB,2BAA2B;IAWzC,OAAO,CAAC,yBAAyB;IAKjC,OAAO,CAAC,kCAAkC;YAO5B,iCAAiC;YAOjC,iCAAiC;YAgBjC,iCAAiC;IAM/C,OAAO,CAAC,uBAAuB;IAI/B,OAAO,CAAC,4BAA4B;IAQpC,OAAO,CAAC,2BAA2B;IAsBnC,OAAO,CAAC,yBAAyB;IAiBjC,OAAO,CAAC,wBAAwB;IAkBhC,OAAO,CAAC,6BAA6B;YAMvB,8BAA8B;YA6C9B,iCAAiC;YAmBjC,+BAA+B;IA+D7C,OAAO,CAAC,gCAAgC;YAyC1B,oCAAoC;YAkCpC,kCAAkC;IAgChD,OAAO,CAAC,0BAA0B;IAO5B,6BAA6B;YA0BrB,+BAA+B;IA4C7C,OAAO,CAAC,6BAA6B;IAkCrC,OAAO,CAAC,8BAA8B;YA8CxB,uBAAuB;YAiCvB,6BAA6B;YAa7B,uBAAuB;YA6CvB,8BAA8B;YA2D9B,6BAA6B;IA0D3C,OAAO,CAAC,mCAAmC;YAI7B,0BAA0B;IAaxC,OAAO,CAAC,4BAA4B;YA+FtB,uCAAuC;YA4GvC,gCAAgC;YAShC,8BAA8B;YAsB9B,mCAAmC;YAWnC,qCAAqC;YA2CrC,yBAAyB;YAiDzB,8BAA8B;IAU5C,OAAO,CAAC,kCAAkC;YAI5B,cAAc;YA+Bd,6BAA6B;YAU7B,0BAA0B;YAS1B,6BAA6B;YAmB7B,gBAAgB;IAiB9B,OAAO,CAAC,qBAAqB;CAM9B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OpenWalletSession.d.ts","sourceRoot":"","sources":["../../src/api/OpenWalletSession.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,OAAO,KAAK,EACV,uBAAuB,EACvB,wBAAwB,EACzB,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"OpenWalletSession.d.ts","sourceRoot":"","sources":["../../src/api/OpenWalletSession.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,OAAO,KAAK,EACV,uBAAuB,EACvB,wBAAwB,EACzB,MAAM,gCAAgC,CAAC;AA+DxC,MAAM,CAAC,OAAO,OAAO,iBAAkB,SAAQ,UAAU,CAAC,uBAAuB,CAAC;IAChF,qBAAqB;IAIrB,IAAI;IAOE,GAAG,IAAI,OAAO,CAAC,wBAAwB,CAAC;CAmH/C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FirmwarePreparationError.d.ts","sourceRoot":"","sources":["../../../src/api/firmware/FirmwarePreparationError.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,aAAa,EAAqB,MAAM,qBAAqB,CAAC;AAE/E,eAAO,MAAM,iCAAiC,UAAW,OAAO,kBAS/D,CAAC"}
|
|
@@ -8,6 +8,7 @@ type ReleaseSelection = {
|
|
|
8
8
|
release?: unknown;
|
|
9
9
|
};
|
|
10
10
|
export declare const digestFirmwareUpdateContract: (value: unknown) => string;
|
|
11
|
+
export declare const validateFirmwareUpdatePlanForceTargets: (value: unknown) => FirmwareUpdatePlanForceTarget[];
|
|
11
12
|
export declare const FIRMWARE_UPDATE_PLAN_TARGETS: Set<FirmwareUpdatePlanTarget>;
|
|
12
13
|
export declare const FIRMWARE_UPDATE_PLAN_ROLES: Set<string>;
|
|
13
14
|
export declare const assertFirmwareUpdatePlan: (value: unknown) => FirmwareUpdatePlan;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FirmwareUpdatePlan.d.ts","sourceRoot":"","sources":["../../../src/api/firmware/FirmwareUpdatePlan.ts"],"names":[],"mappings":"AAEA,OAAO,EAAe,aAAa,EAA6B,MAAM,qBAAqB,CAAC;AAS5F,OAAO,KAAK,EACV,kBAAkB,EAElB,6BAA6B,EAC7B,wBAAwB,EACzB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,KAAK,sBAAsB,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG,WAAW,CAAC;AAyBjF,KAAK,gBAAgB,GAAG;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AA0GF,eAAO,MAAM,4BAA4B,UAAW,OAAO,KAAG,MAG3D,CAAC;
|
|
1
|
+
{"version":3,"file":"FirmwareUpdatePlan.d.ts","sourceRoot":"","sources":["../../../src/api/firmware/FirmwareUpdatePlan.ts"],"names":[],"mappings":"AAEA,OAAO,EAAe,aAAa,EAA6B,MAAM,qBAAqB,CAAC;AAS5F,OAAO,KAAK,EACV,kBAAkB,EAElB,6BAA6B,EAC7B,wBAAwB,EACzB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,KAAK,sBAAsB,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG,WAAW,CAAC;AAyBjF,KAAK,gBAAgB,GAAG;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AA0GF,eAAO,MAAM,4BAA4B,UAAW,OAAO,KAAG,MAG3D,CAAC;AAkBJ,eAAO,MAAM,sCAAsC,UAC1C,OAAO,KACb,6BAA6B,EAa/B,CAAC;AAuBF,eAAO,MAAM,4BAA4B,+BAavC,CAAC;AAEH,eAAO,MAAM,0BAA0B,aAOrC,CAAC;AAYH,eAAO,MAAM,wBAAwB,UAAW,OAAO,KAAG,kBAoHzD,CAAC;AA4NF,eAAO,MAAM,uBAAuB;cASxB,QAAQ;kBACJ,aAAa;cACjB,sBAAsB;cACtB,gBAAgB;SACrB,gBAAgB;;;MAGnB,kBAiJH,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1423,8 +1423,6 @@ type OpenWalletSessionPayloadBase = {
|
|
|
1423
1423
|
protocol: 'V1' | 'V2';
|
|
1424
1424
|
deviceId: string;
|
|
1425
1425
|
resumed: boolean;
|
|
1426
|
-
/** Forwarded only when the firmware response contains a wallet session id. */
|
|
1427
|
-
sessionId?: string;
|
|
1428
1426
|
};
|
|
1429
1427
|
type OpenWalletSessionPayload = OpenWalletSessionPayloadBase & ({
|
|
1430
1428
|
walletType: 'standard';
|
package/dist/index.js
CHANGED
|
@@ -564,6 +564,24 @@ const planError = (message) => {
|
|
|
564
564
|
firmwareUpdateCode: 'FirmwarePlanInvalid',
|
|
565
565
|
});
|
|
566
566
|
};
|
|
567
|
+
const FIRMWARE_UPDATE_PLAN_FORCE_TARGETS = new Set([
|
|
568
|
+
'firmware',
|
|
569
|
+
'ble',
|
|
570
|
+
'bootloader',
|
|
571
|
+
'resource',
|
|
572
|
+
]);
|
|
573
|
+
const validateFirmwareUpdatePlanForceTargets = (value) => {
|
|
574
|
+
if (value === undefined) {
|
|
575
|
+
return [];
|
|
576
|
+
}
|
|
577
|
+
if (!Array.isArray(value) ||
|
|
578
|
+
value.length > FIRMWARE_UPDATE_PLAN_FORCE_TARGETS.size ||
|
|
579
|
+
value.some(target => !FIRMWARE_UPDATE_PLAN_FORCE_TARGETS.has(target)) ||
|
|
580
|
+
new Set(value).size !== value.length) {
|
|
581
|
+
return planError('Firmware update force targets are invalid');
|
|
582
|
+
}
|
|
583
|
+
return [...value];
|
|
584
|
+
};
|
|
567
585
|
const assertExactKeys = (value, required, optional = []) => {
|
|
568
586
|
const allowed = new Set([...required, ...optional]);
|
|
569
587
|
if (required.some(key => !Object.prototype.hasOwnProperty.call(value, key)) ||
|
|
@@ -736,24 +754,23 @@ const getExecutor = (features) => {
|
|
|
736
754
|
}
|
|
737
755
|
return 'v2';
|
|
738
756
|
};
|
|
739
|
-
const buildProtocolV2Artifacts = (release) => {
|
|
757
|
+
const buildProtocolV2Artifacts = (release, { includeComponents = true, includeResources = true, } = {}) => {
|
|
740
758
|
var _a;
|
|
741
759
|
const components = asRecord(release.components);
|
|
742
|
-
if (!components) {
|
|
760
|
+
if (includeComponents && !components) {
|
|
743
761
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 release has no component set', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
744
762
|
}
|
|
745
763
|
const installOrder = Array.isArray(release.installOrder)
|
|
746
764
|
? release.installOrder.filter((key) => typeof key === 'string')
|
|
747
765
|
: [];
|
|
748
|
-
const componentKeys =
|
|
749
|
-
...installOrder,
|
|
750
|
-
|
|
751
|
-
];
|
|
766
|
+
const componentKeys = includeComponents && components
|
|
767
|
+
? [...installOrder, ...Object.keys(components).filter(key => !installOrder.includes(key))]
|
|
768
|
+
: [];
|
|
752
769
|
const artifacts = [];
|
|
753
770
|
const targets = [];
|
|
754
771
|
const componentTargets = new Set();
|
|
755
772
|
for (const key of componentKeys) {
|
|
756
|
-
const component = asRecord(components[key]);
|
|
773
|
+
const component = asRecord(components === null || components === void 0 ? void 0 : components[key]);
|
|
757
774
|
const targetName = (_a = asString(component === null || component === void 0 ? void 0 : component.target)) === null || _a === void 0 ? void 0 : _a.toUpperCase();
|
|
758
775
|
if (targetName === 'ROMLOADER') {
|
|
759
776
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 ROMLOADER requires its dedicated loader flow', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
@@ -772,7 +789,7 @@ const buildProtocolV2Artifacts = (release) => {
|
|
|
772
789
|
})), (asVersion(component.version) ? { targetVersion: asVersion(component.version) } : {})));
|
|
773
790
|
targets.push(target);
|
|
774
791
|
}
|
|
775
|
-
const bundles = Array.isArray(release.resourceBundles) ? release.resourceBundles : [];
|
|
792
|
+
const bundles = includeResources && Array.isArray(release.resourceBundles) ? release.resourceBundles : [];
|
|
776
793
|
const resourceBundleNames = new Set();
|
|
777
794
|
for (const value of bundles) {
|
|
778
795
|
const bundle = asRecord(value);
|
|
@@ -794,17 +811,51 @@ const buildProtocolV2Artifacts = (release) => {
|
|
|
794
811
|
}
|
|
795
812
|
return { artifacts, targets: [...new Set(targets)] };
|
|
796
813
|
};
|
|
814
|
+
const isForcedTargetRepresented = ({ executor, forcedTarget, artifacts, targetsToUpdate, }) => {
|
|
815
|
+
if (executor !== 'v4') {
|
|
816
|
+
return artifacts.some(artifact => artifact.target === forcedTarget && targetsToUpdate.includes(forcedTarget));
|
|
817
|
+
}
|
|
818
|
+
if (forcedTarget === 'firmware') {
|
|
819
|
+
return artifacts.some(artifact => artifact.role === 'component' && targetsToUpdate.includes(artifact.target));
|
|
820
|
+
}
|
|
821
|
+
if (forcedTarget === 'resource') {
|
|
822
|
+
return artifacts.some(artifact => artifact.role === 'resourceBundle' &&
|
|
823
|
+
artifact.target === 'resource' &&
|
|
824
|
+
targetsToUpdate.includes('resource'));
|
|
825
|
+
}
|
|
826
|
+
return false;
|
|
827
|
+
};
|
|
828
|
+
const assertForcedTargetsRepresented = ({ executor, forcedTargets, artifacts, targetsToUpdate, }) => {
|
|
829
|
+
for (const forcedTarget of forcedTargets) {
|
|
830
|
+
if (!isForcedTargetRepresented({
|
|
831
|
+
executor,
|
|
832
|
+
forcedTarget,
|
|
833
|
+
artifacts,
|
|
834
|
+
targetsToUpdate,
|
|
835
|
+
})) {
|
|
836
|
+
planError(`Forced firmware update target ${forcedTarget} is not represented by the plan`);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
};
|
|
797
840
|
const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, ble, bootloader, forceUpdateTargets, }) => {
|
|
798
841
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
799
842
|
const executor = getExecutor(features);
|
|
800
843
|
let artifacts = [];
|
|
801
844
|
let targetsToUpdate = [];
|
|
802
845
|
const firmwareRelease = asRelease(firmware);
|
|
803
|
-
const
|
|
846
|
+
const validatedForceTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
|
|
847
|
+
const forcedTargets = new Set(validatedForceTargets);
|
|
804
848
|
const shouldUpdateFirmware = isUpgrade(firmware) || forcedTargets.has('firmware');
|
|
805
849
|
const shouldUpdateResource = isUpgrade(firmware) || forcedTargets.has('resource');
|
|
850
|
+
if (executor === 'v4' &&
|
|
851
|
+
validatedForceTargets.some(target => target === 'ble' || target === 'bootloader')) {
|
|
852
|
+
planError('Protocol V2 does not support forced BLE or legacy bootloader targets');
|
|
853
|
+
}
|
|
806
854
|
if (executor === 'v4' && (shouldUpdateFirmware || shouldUpdateResource)) {
|
|
807
|
-
const protocolV2 = buildProtocolV2Artifacts(firmwareRelease !== null && firmwareRelease !== void 0 ? firmwareRelease : {}
|
|
855
|
+
const protocolV2 = buildProtocolV2Artifacts(firmwareRelease !== null && firmwareRelease !== void 0 ? firmwareRelease : {}, {
|
|
856
|
+
includeComponents: shouldUpdateFirmware,
|
|
857
|
+
includeResources: shouldUpdateResource,
|
|
858
|
+
});
|
|
808
859
|
artifacts = protocolV2.artifacts;
|
|
809
860
|
targetsToUpdate = protocolV2.targets;
|
|
810
861
|
}
|
|
@@ -862,6 +913,12 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
|
|
|
862
913
|
}
|
|
863
914
|
targetsToUpdate = [...new Set(artifacts.map(artifact => artifact.target))];
|
|
864
915
|
}
|
|
916
|
+
assertForcedTargetsRepresented({
|
|
917
|
+
executor,
|
|
918
|
+
forcedTargets: validatedForceTargets,
|
|
919
|
+
artifacts,
|
|
920
|
+
targetsToUpdate,
|
|
921
|
+
});
|
|
865
922
|
const deviceIdentity = getDeviceUUID(features);
|
|
866
923
|
if (artifacts.length > 0 &&
|
|
867
924
|
(platform === 'native' || platform === 'desktop') &&
|
|
@@ -878,7 +935,7 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
|
|
|
878
935
|
artifacts,
|
|
879
936
|
targetsToUpdate,
|
|
880
937
|
};
|
|
881
|
-
return Object.assign(Object.assign({}, planWithoutDigest), { planDigest: digestFirmwareUpdatePlan(planWithoutDigest) });
|
|
938
|
+
return assertFirmwareUpdatePlan(Object.assign(Object.assign({}, planWithoutDigest), { planDigest: digestFirmwareUpdatePlan(planWithoutDigest) }));
|
|
882
939
|
};
|
|
883
940
|
|
|
884
941
|
const preparedPlanError = (message) => {
|
|
@@ -45796,12 +45853,13 @@ const wasResumed = (session) => !!session &&
|
|
|
45796
45853
|
typeof session === 'object' &&
|
|
45797
45854
|
'resumed' in session &&
|
|
45798
45855
|
session.resumed === true;
|
|
45799
|
-
const forwardSessionId = (session) => session.newSession ? { sessionId: session.newSession } : {};
|
|
45800
45856
|
const requireHiddenWalletResponse = (session) => {
|
|
45801
45857
|
if (!session.passphraseState) {
|
|
45802
45858
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInitializeFailed, 'Hidden wallet response is missing passphraseState');
|
|
45803
45859
|
}
|
|
45804
|
-
return
|
|
45860
|
+
return {
|
|
45861
|
+
passphraseState: session.passphraseState,
|
|
45862
|
+
};
|
|
45805
45863
|
};
|
|
45806
45864
|
const normalizeParams = (payload) => {
|
|
45807
45865
|
if (payload.mode === undefined) {
|
|
@@ -45873,7 +45931,13 @@ class OpenWalletSession extends BaseMethod {
|
|
|
45873
45931
|
this.device.clearInternalState();
|
|
45874
45932
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckUnlockTypeError);
|
|
45875
45933
|
}
|
|
45876
|
-
return
|
|
45934
|
+
return {
|
|
45935
|
+
protocol,
|
|
45936
|
+
walletType: 'standard',
|
|
45937
|
+
deviceId,
|
|
45938
|
+
passphraseState: null,
|
|
45939
|
+
resumed: wasResumed(session),
|
|
45940
|
+
};
|
|
45877
45941
|
}
|
|
45878
45942
|
if (this.params.mode === 'resume-hidden') {
|
|
45879
45943
|
if (isProtocolV2) {
|
|
@@ -45925,7 +45989,7 @@ class OpenWalletSession extends BaseMethod {
|
|
|
45925
45989
|
resumed: wasResumed(session),
|
|
45926
45990
|
};
|
|
45927
45991
|
return this.device.getCurrentPassphraseProtection() === false
|
|
45928
|
-
? Object.assign(Object.assign(
|
|
45992
|
+
? Object.assign(Object.assign({}, responseBase), { walletType: 'standard', passphraseState: null }) : Object.assign(Object.assign(Object.assign({}, responseBase), { walletType: 'hidden' }), requireHiddenWalletResponse(session));
|
|
45929
45993
|
});
|
|
45930
45994
|
}
|
|
45931
45995
|
}
|
|
@@ -46172,6 +46236,7 @@ class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
46172
46236
|
return __awaiter(this, void 0, void 0, function* () {
|
|
46173
46237
|
const { features } = this.device;
|
|
46174
46238
|
const { checkBridgeRelease, firmwareType: firmwareTypeParams, platform, forceUpdateTargets, } = this.payload;
|
|
46239
|
+
const validatedForceUpdateTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
|
|
46175
46240
|
if (!features) {
|
|
46176
46241
|
return Promise.resolve(null);
|
|
46177
46242
|
}
|
|
@@ -46205,11 +46270,12 @@ class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
46205
46270
|
firmware: firmwareRelease,
|
|
46206
46271
|
ble: bleFirmwareReleaseInfo,
|
|
46207
46272
|
bootloader: bootloaderRelease,
|
|
46208
|
-
forceUpdateTargets,
|
|
46273
|
+
forceUpdateTargets: validatedForceUpdateTargets,
|
|
46209
46274
|
});
|
|
46210
46275
|
}
|
|
46211
46276
|
catch (error) {
|
|
46212
|
-
if (
|
|
46277
|
+
if (validatedForceUpdateTargets.length > 0 ||
|
|
46278
|
+
!(error instanceof hdShared.HardwareError) ||
|
|
46213
46279
|
((_c = error.params) === null || _c === void 0 ? void 0 : _c.firmwareUpdateCode) !== 'FirmwarePlanInvalid') {
|
|
46214
46280
|
throw error;
|
|
46215
46281
|
}
|
|
@@ -48369,6 +48435,14 @@ class FirmwareUpdate extends BaseMethod {
|
|
|
48369
48435
|
}
|
|
48370
48436
|
}
|
|
48371
48437
|
|
|
48438
|
+
const normalizeFirmwarePreparationError = (error) => {
|
|
48439
|
+
var _a;
|
|
48440
|
+
if (error instanceof hdShared.HardwareError && ((_a = error.params) === null || _a === void 0 ? void 0 : _a.firmwareUpdateCode)) {
|
|
48441
|
+
return error;
|
|
48442
|
+
}
|
|
48443
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, error instanceof Error ? error.message : String(error));
|
|
48444
|
+
};
|
|
48445
|
+
|
|
48372
48446
|
const Log$7 = getLogger(exports.LoggerNames.Method);
|
|
48373
48447
|
const FIRMWARE_DOWNLOAD_REQUEST_OPTIONS = {
|
|
48374
48448
|
connectTimeoutMs: 60000,
|
|
@@ -48651,7 +48725,6 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
48651
48725
|
let preparedSource;
|
|
48652
48726
|
try {
|
|
48653
48727
|
const acquireFirmwareSource = () => __awaiter(this, void 0, void 0, function* () {
|
|
48654
|
-
var _k;
|
|
48655
48728
|
try {
|
|
48656
48729
|
if (preparedSource) {
|
|
48657
48730
|
return preparedSource;
|
|
@@ -48715,7 +48788,7 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
48715
48788
|
return source;
|
|
48716
48789
|
}
|
|
48717
48790
|
catch (err) {
|
|
48718
|
-
throw
|
|
48791
|
+
throw normalizeFirmwarePreparationError(err);
|
|
48719
48792
|
}
|
|
48720
48793
|
});
|
|
48721
48794
|
if (!device.isBootloader() && features) {
|
|
@@ -48916,7 +48989,7 @@ class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod {
|
|
|
48916
48989
|
});
|
|
48917
48990
|
}
|
|
48918
48991
|
runProtocolV1() {
|
|
48919
|
-
var _a, _b
|
|
48992
|
+
var _a, _b;
|
|
48920
48993
|
return __awaiter(this, void 0, void 0, function* () {
|
|
48921
48994
|
const { device } = this;
|
|
48922
48995
|
const { features } = device;
|
|
@@ -48950,7 +49023,7 @@ class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod {
|
|
|
48950
49023
|
}
|
|
48951
49024
|
catch (err) {
|
|
48952
49025
|
yield this.closeArtifactSources();
|
|
48953
|
-
throw
|
|
49026
|
+
throw normalizeFirmwarePreparationError(err);
|
|
48954
49027
|
}
|
|
48955
49028
|
if (!bootloaderSource && fwSources.length === 0) {
|
|
48956
49029
|
yield this.closeArtifactSources();
|
|
@@ -49874,7 +49947,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
49874
49947
|
});
|
|
49875
49948
|
}
|
|
49876
49949
|
runProtocolV2() {
|
|
49877
|
-
var _a, _b
|
|
49950
|
+
var _a, _b;
|
|
49878
49951
|
return __awaiter(this, void 0, void 0, function* () {
|
|
49879
49952
|
yield this.captureProtocolV2PhysicalIdentity();
|
|
49880
49953
|
const deviceFeatures = yield this.getProtocolV2DeviceFeatures();
|
|
@@ -49912,7 +49985,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
49912
49985
|
this.postTipMessage(exports.FirmwareUpdateTipMessage.FinishDownloadFirmware);
|
|
49913
49986
|
}
|
|
49914
49987
|
catch (err) {
|
|
49915
|
-
throw
|
|
49988
|
+
throw normalizeFirmwarePreparationError(err);
|
|
49916
49989
|
}
|
|
49917
49990
|
if (!bootloaderBinary && fwBinaryMap.length === 0 && !(resourceBundles === null || resourceBundles === void 0 ? void 0 : resourceBundles.length)) {
|
|
49918
49991
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, 'No firmware to update');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openWalletSession.d.ts","sourceRoot":"","sources":["../../../src/types/api/openWalletSession.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAExD,MAAM,MAAM,uBAAuB,GAC/B;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,eAAe,CAAC,EAAE,KAAK,CAAC;CACzB,GACD;IACE,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,eAAe,CAAC,EAAE,KAAK,CAAC;CACzB,GACD;IACE,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEN,KAAK,4BAA4B,GAAG;IAClC,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"openWalletSession.d.ts","sourceRoot":"","sources":["../../../src/types/api/openWalletSession.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAExD,MAAM,MAAM,uBAAuB,GAC/B;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,eAAe,CAAC,EAAE,KAAK,CAAC;CACzB,GACD;IACE,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,eAAe,CAAC,EAAE,KAAK,CAAC;CACzB,GACD;IACE,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEN,KAAK,4BAA4B,GAAG;IAClC,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,4BAA4B,GACjE,CACI;IACE,UAAU,EAAE,UAAU,CAAC;IACvB,eAAe,EAAE,IAAI,CAAC;CACvB,GACD;IACE,UAAU,EAAE,QAAQ,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;CACzB,CACJ,CAAC;AAMJ,MAAM,CAAC,OAAO,UAAU,iBAAiB,CACvC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,GAAG,uBAAuB,GAC7C,QAAQ,CAAC,wBAAwB,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-core",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
3
|
+
"version": "1.2.0-alpha.29",
|
|
4
4
|
"description": "Core processes and APIs for communicating with OneKey hardware devices.",
|
|
5
5
|
"author": "OneKey",
|
|
6
6
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"url": "https://github.com/OneKeyHQ/hardware-js-sdk/issues"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@onekeyfe/hd-shared": "1.2.0-alpha.
|
|
29
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
28
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.29",
|
|
29
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.29",
|
|
30
30
|
"axios": "1.15.2",
|
|
31
31
|
"bignumber.js": "^9.0.2",
|
|
32
32
|
"bytebuffer": "^5.0.1",
|
|
@@ -44,5 +44,5 @@
|
|
|
44
44
|
"@types/w3c-web-usb": "^1.0.10",
|
|
45
45
|
"@types/web-bluetooth": "^0.0.21"
|
|
46
46
|
},
|
|
47
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "4a4019e439cc472f89fd15ab47e84ef0ed43166a"
|
|
48
48
|
}
|
|
@@ -7,7 +7,10 @@ import {
|
|
|
7
7
|
getBootloaderReleaseInfo,
|
|
8
8
|
getFirmwareReleaseInfo,
|
|
9
9
|
} from './firmware/releaseHelper';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
buildFirmwareUpdatePlan,
|
|
12
|
+
validateFirmwareUpdatePlanForceTargets,
|
|
13
|
+
} from './firmware/FirmwareUpdatePlan';
|
|
11
14
|
import { getBridgeReleaseInfo } from '../utils/bridgeUpdate';
|
|
12
15
|
import {
|
|
13
16
|
LoggerNames,
|
|
@@ -40,6 +43,7 @@ export default class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
40
43
|
platform,
|
|
41
44
|
forceUpdateTargets,
|
|
42
45
|
} = this.payload as CheckAllFirmwareReleaseParams;
|
|
46
|
+
const validatedForceUpdateTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
|
|
43
47
|
|
|
44
48
|
if (!features) {
|
|
45
49
|
return Promise.resolve(null);
|
|
@@ -79,10 +83,11 @@ export default class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
79
83
|
firmware: firmwareRelease,
|
|
80
84
|
ble: bleFirmwareReleaseInfo,
|
|
81
85
|
bootloader: bootloaderRelease,
|
|
82
|
-
forceUpdateTargets,
|
|
86
|
+
forceUpdateTargets: validatedForceUpdateTargets,
|
|
83
87
|
});
|
|
84
88
|
} catch (error) {
|
|
85
89
|
if (
|
|
90
|
+
validatedForceUpdateTargets.length > 0 ||
|
|
86
91
|
!(error instanceof HardwareError) ||
|
|
87
92
|
error.params?.firmwareUpdateCode !== 'FirmwarePlanInvalid'
|
|
88
93
|
) {
|
|
@@ -14,6 +14,7 @@ import { BaseMethod } from './BaseMethod';
|
|
|
14
14
|
import { validateParams } from './helpers/paramsValidator';
|
|
15
15
|
import { DevicePool } from '../device/DevicePool';
|
|
16
16
|
import { getBinary, getInfo, getSysResourceBinary } from './firmware/getBinary';
|
|
17
|
+
import { normalizeFirmwarePreparationError } from './firmware/FirmwarePreparationError';
|
|
17
18
|
import {
|
|
18
19
|
updateResources,
|
|
19
20
|
updateResourcesFromSources,
|
|
@@ -27,8 +28,8 @@ import { DEVICE } from '../events';
|
|
|
27
28
|
import { type FirmwareByteSource, openFirmwareByteSource } from './firmware/FirmwareArtifactSource';
|
|
28
29
|
import { resolveFirmwareUpdateHostBinding } from './firmware/FirmwareHostBinding';
|
|
29
30
|
import {
|
|
30
|
-
assertFirmwareUpdatePreparedPlanDeviceIdentity,
|
|
31
31
|
assertFirmwareUpdatePreparedPlanBinding,
|
|
32
|
+
assertFirmwareUpdatePreparedPlanDeviceIdentity,
|
|
32
33
|
getFirmwareUpdateResourceName,
|
|
33
34
|
} from './firmware/FirmwareUpdatePreparedPlan';
|
|
34
35
|
|
|
@@ -503,10 +504,7 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
|
|
|
503
504
|
this.postTipMessage('DownloadFirmwareSuccess');
|
|
504
505
|
return source;
|
|
505
506
|
} catch (err) {
|
|
506
|
-
throw
|
|
507
|
-
HardwareErrorCode.FirmwareUpdateDownloadFailed,
|
|
508
|
-
err.message ?? err
|
|
509
|
-
);
|
|
507
|
+
throw normalizeFirmwarePreparationError(err);
|
|
510
508
|
}
|
|
511
509
|
};
|
|
512
510
|
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
getLogger,
|
|
14
14
|
} from '../utils';
|
|
15
15
|
import { getBinary, getSysResourceBinary } from './firmware/getBinary';
|
|
16
|
+
import { normalizeFirmwarePreparationError } from './firmware/FirmwarePreparationError';
|
|
16
17
|
import { DataManager } from '../data-manager';
|
|
17
18
|
import { FirmwareUpdateBaseMethod } from './firmware/FirmwareUpdateBaseMethod';
|
|
18
19
|
import { DevicePool } from '../device/DevicePool';
|
|
@@ -21,8 +22,8 @@ import { buildProtocolV1FeaturesPayload } from '../deviceProfile';
|
|
|
21
22
|
import { openFirmwareByteSource } from './firmware/FirmwareArtifactSource';
|
|
22
23
|
import { resolveFirmwareUpdateHostBinding } from './firmware/FirmwareHostBinding';
|
|
23
24
|
import {
|
|
24
|
-
assertFirmwareUpdatePreparedPlanDeviceIdentity,
|
|
25
25
|
assertFirmwareUpdatePreparedPlanBinding,
|
|
26
|
+
assertFirmwareUpdatePreparedPlanDeviceIdentity,
|
|
26
27
|
getFirmwareUpdateResourceName,
|
|
27
28
|
} from './firmware/FirmwareUpdatePreparedPlan';
|
|
28
29
|
|
|
@@ -184,7 +185,7 @@ export default class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
184
185
|
this.postTipMessage(FirmwareUpdateTipMessage.FinishDownloadFirmware);
|
|
185
186
|
} catch (err) {
|
|
186
187
|
await this.closeArtifactSources();
|
|
187
|
-
throw
|
|
188
|
+
throw normalizeFirmwarePreparationError(err);
|
|
188
189
|
}
|
|
189
190
|
|
|
190
191
|
if (!bootloaderSource && fwSources.length === 0) {
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
getLogger,
|
|
19
19
|
} from '../utils';
|
|
20
20
|
import { getSysResourceBinary } from './firmware/getBinary';
|
|
21
|
+
import { normalizeFirmwarePreparationError } from './firmware/FirmwarePreparationError';
|
|
21
22
|
import { DataManager } from '../data-manager';
|
|
22
23
|
import { FirmwareUpdateBaseMethod } from './firmware/FirmwareUpdateBaseMethod';
|
|
23
24
|
import { DevicePool } from '../device/DevicePool';
|
|
@@ -625,7 +626,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
625
626
|
: undefined;
|
|
626
627
|
this.postTipMessage(FirmwareUpdateTipMessage.FinishDownloadFirmware);
|
|
627
628
|
} catch (err) {
|
|
628
|
-
throw
|
|
629
|
+
throw normalizeFirmwarePreparationError(err);
|
|
629
630
|
}
|
|
630
631
|
|
|
631
632
|
if (!bootloaderBinary && fwBinaryMap.length === 0 && !resourceBundles?.length) {
|
|
@@ -27,13 +27,7 @@ const wasResumed = (session: unknown) =>
|
|
|
27
27
|
'resumed' in session &&
|
|
28
28
|
(session as { resumed?: unknown }).resumed === true;
|
|
29
29
|
|
|
30
|
-
const
|
|
31
|
-
session.newSession ? { sessionId: session.newSession } : {};
|
|
32
|
-
|
|
33
|
-
const requireHiddenWalletResponse = (session: {
|
|
34
|
-
passphraseState?: string;
|
|
35
|
-
newSession?: string;
|
|
36
|
-
}) => {
|
|
30
|
+
const requireHiddenWalletResponse = (session: { passphraseState?: string }) => {
|
|
37
31
|
if (!session.passphraseState) {
|
|
38
32
|
throw ERRORS.TypedError(
|
|
39
33
|
HardwareErrorCode.DeviceInitializeFailed,
|
|
@@ -42,7 +36,6 @@ const requireHiddenWalletResponse = (session: {
|
|
|
42
36
|
}
|
|
43
37
|
return {
|
|
44
38
|
passphraseState: session.passphraseState,
|
|
45
|
-
...forwardSessionId(session),
|
|
46
39
|
};
|
|
47
40
|
};
|
|
48
41
|
|
|
@@ -132,7 +125,6 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
|
|
|
132
125
|
walletType: 'standard',
|
|
133
126
|
deviceId,
|
|
134
127
|
passphraseState: null,
|
|
135
|
-
...forwardSessionId(session),
|
|
136
128
|
resumed: wasResumed(session),
|
|
137
129
|
};
|
|
138
130
|
}
|
|
@@ -200,7 +192,6 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
|
|
|
200
192
|
...responseBase,
|
|
201
193
|
walletType: 'standard',
|
|
202
194
|
passphraseState: null,
|
|
203
|
-
...forwardSessionId(session),
|
|
204
195
|
}
|
|
205
196
|
: {
|
|
206
197
|
...responseBase,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ERRORS, HardwareError, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
+
|
|
3
|
+
export const normalizeFirmwarePreparationError = (error: unknown) => {
|
|
4
|
+
if (error instanceof HardwareError && error.params?.firmwareUpdateCode) {
|
|
5
|
+
return error;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return ERRORS.TypedError(
|
|
9
|
+
HardwareErrorCode.FirmwareUpdateDownloadFailed,
|
|
10
|
+
error instanceof Error ? error.message : String(error)
|
|
11
|
+
);
|
|
12
|
+
};
|
|
@@ -166,6 +166,30 @@ const planError = (message: string): never => {
|
|
|
166
166
|
});
|
|
167
167
|
};
|
|
168
168
|
|
|
169
|
+
const FIRMWARE_UPDATE_PLAN_FORCE_TARGETS = new Set<FirmwareUpdatePlanForceTarget>([
|
|
170
|
+
'firmware',
|
|
171
|
+
'ble',
|
|
172
|
+
'bootloader',
|
|
173
|
+
'resource',
|
|
174
|
+
]);
|
|
175
|
+
|
|
176
|
+
export const validateFirmwareUpdatePlanForceTargets = (
|
|
177
|
+
value: unknown
|
|
178
|
+
): FirmwareUpdatePlanForceTarget[] => {
|
|
179
|
+
if (value === undefined) {
|
|
180
|
+
return [];
|
|
181
|
+
}
|
|
182
|
+
if (
|
|
183
|
+
!Array.isArray(value) ||
|
|
184
|
+
value.length > FIRMWARE_UPDATE_PLAN_FORCE_TARGETS.size ||
|
|
185
|
+
value.some(target => !FIRMWARE_UPDATE_PLAN_FORCE_TARGETS.has(target)) ||
|
|
186
|
+
new Set(value).size !== value.length
|
|
187
|
+
) {
|
|
188
|
+
return planError('Firmware update force targets are invalid');
|
|
189
|
+
}
|
|
190
|
+
return [...value] as FirmwareUpdatePlanForceTarget[];
|
|
191
|
+
};
|
|
192
|
+
|
|
169
193
|
const assertExactKeys = (
|
|
170
194
|
value: Record<string, unknown>,
|
|
171
195
|
required: readonly string[],
|
|
@@ -388,13 +412,20 @@ const getExecutor = (features: Features): FirmwareUpdatePlan['executor'] => {
|
|
|
388
412
|
};
|
|
389
413
|
|
|
390
414
|
const buildProtocolV2Artifacts = (
|
|
391
|
-
release: ReleaseRecord
|
|
415
|
+
release: ReleaseRecord,
|
|
416
|
+
{
|
|
417
|
+
includeComponents = true,
|
|
418
|
+
includeResources = true,
|
|
419
|
+
}: {
|
|
420
|
+
includeComponents?: boolean;
|
|
421
|
+
includeResources?: boolean;
|
|
422
|
+
} = {}
|
|
392
423
|
): {
|
|
393
424
|
artifacts: FirmwareUpdatePlanArtifact[];
|
|
394
425
|
targets: FirmwareUpdatePlanTarget[];
|
|
395
426
|
} => {
|
|
396
427
|
const components = asRecord(release.components);
|
|
397
|
-
if (!components) {
|
|
428
|
+
if (includeComponents && !components) {
|
|
398
429
|
throw ERRORS.TypedError(
|
|
399
430
|
HardwareErrorCode.RuntimeError,
|
|
400
431
|
'Protocol V2 release has no component set',
|
|
@@ -404,15 +435,15 @@ const buildProtocolV2Artifacts = (
|
|
|
404
435
|
const installOrder = Array.isArray(release.installOrder)
|
|
405
436
|
? release.installOrder.filter((key): key is string => typeof key === 'string')
|
|
406
437
|
: [];
|
|
407
|
-
const componentKeys =
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
438
|
+
const componentKeys =
|
|
439
|
+
includeComponents && components
|
|
440
|
+
? [...installOrder, ...Object.keys(components).filter(key => !installOrder.includes(key))]
|
|
441
|
+
: [];
|
|
411
442
|
const artifacts: FirmwareUpdatePlanArtifact[] = [];
|
|
412
443
|
const targets: FirmwareUpdatePlanTarget[] = [];
|
|
413
444
|
const componentTargets = new Set<FirmwareUpdatePlanTarget>();
|
|
414
445
|
for (const key of componentKeys) {
|
|
415
|
-
const component = asRecord(components[key]);
|
|
446
|
+
const component = asRecord(components?.[key]);
|
|
416
447
|
const targetName = asString(component?.target)?.toUpperCase();
|
|
417
448
|
if (targetName === 'ROMLOADER') {
|
|
418
449
|
throw ERRORS.TypedError(
|
|
@@ -453,7 +484,8 @@ const buildProtocolV2Artifacts = (
|
|
|
453
484
|
targets.push(target);
|
|
454
485
|
}
|
|
455
486
|
|
|
456
|
-
const bundles =
|
|
487
|
+
const bundles =
|
|
488
|
+
includeResources && Array.isArray(release.resourceBundles) ? release.resourceBundles : [];
|
|
457
489
|
const resourceBundleNames = new Set<string>();
|
|
458
490
|
for (const value of bundles) {
|
|
459
491
|
const bundle = asRecord(value);
|
|
@@ -492,6 +524,63 @@ const buildProtocolV2Artifacts = (
|
|
|
492
524
|
return { artifacts, targets: [...new Set(targets)] };
|
|
493
525
|
};
|
|
494
526
|
|
|
527
|
+
const isForcedTargetRepresented = ({
|
|
528
|
+
executor,
|
|
529
|
+
forcedTarget,
|
|
530
|
+
artifacts,
|
|
531
|
+
targetsToUpdate,
|
|
532
|
+
}: {
|
|
533
|
+
executor: FirmwareUpdatePlan['executor'];
|
|
534
|
+
forcedTarget: FirmwareUpdatePlanForceTarget;
|
|
535
|
+
artifacts: readonly FirmwareUpdatePlanArtifact[];
|
|
536
|
+
targetsToUpdate: readonly FirmwareUpdatePlanTarget[];
|
|
537
|
+
}): boolean => {
|
|
538
|
+
if (executor !== 'v4') {
|
|
539
|
+
return artifacts.some(
|
|
540
|
+
artifact => artifact.target === forcedTarget && targetsToUpdate.includes(forcedTarget)
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
if (forcedTarget === 'firmware') {
|
|
544
|
+
return artifacts.some(
|
|
545
|
+
artifact => artifact.role === 'component' && targetsToUpdate.includes(artifact.target)
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
if (forcedTarget === 'resource') {
|
|
549
|
+
return artifacts.some(
|
|
550
|
+
artifact =>
|
|
551
|
+
artifact.role === 'resourceBundle' &&
|
|
552
|
+
artifact.target === 'resource' &&
|
|
553
|
+
targetsToUpdate.includes('resource')
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
return false;
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
const assertForcedTargetsRepresented = ({
|
|
560
|
+
executor,
|
|
561
|
+
forcedTargets,
|
|
562
|
+
artifacts,
|
|
563
|
+
targetsToUpdate,
|
|
564
|
+
}: {
|
|
565
|
+
executor: FirmwareUpdatePlan['executor'];
|
|
566
|
+
forcedTargets: readonly FirmwareUpdatePlanForceTarget[];
|
|
567
|
+
artifacts: readonly FirmwareUpdatePlanArtifact[];
|
|
568
|
+
targetsToUpdate: readonly FirmwareUpdatePlanTarget[];
|
|
569
|
+
}) => {
|
|
570
|
+
for (const forcedTarget of forcedTargets) {
|
|
571
|
+
if (
|
|
572
|
+
!isForcedTargetRepresented({
|
|
573
|
+
executor,
|
|
574
|
+
forcedTarget,
|
|
575
|
+
artifacts,
|
|
576
|
+
targetsToUpdate,
|
|
577
|
+
})
|
|
578
|
+
) {
|
|
579
|
+
planError(`Forced firmware update target ${forcedTarget} is not represented by the plan`);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
|
|
495
584
|
export const buildFirmwareUpdatePlan = ({
|
|
496
585
|
features,
|
|
497
586
|
firmwareType,
|
|
@@ -513,12 +602,23 @@ export const buildFirmwareUpdatePlan = ({
|
|
|
513
602
|
let artifacts: FirmwareUpdatePlanArtifact[] = [];
|
|
514
603
|
let targetsToUpdate: FirmwareUpdatePlanTarget[] = [];
|
|
515
604
|
const firmwareRelease = asRelease(firmware);
|
|
516
|
-
const
|
|
605
|
+
const validatedForceTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
|
|
606
|
+
const forcedTargets = new Set(validatedForceTargets);
|
|
517
607
|
const shouldUpdateFirmware = isUpgrade(firmware) || forcedTargets.has('firmware');
|
|
518
608
|
const shouldUpdateResource = isUpgrade(firmware) || forcedTargets.has('resource');
|
|
519
609
|
|
|
610
|
+
if (
|
|
611
|
+
executor === 'v4' &&
|
|
612
|
+
validatedForceTargets.some(target => target === 'ble' || target === 'bootloader')
|
|
613
|
+
) {
|
|
614
|
+
planError('Protocol V2 does not support forced BLE or legacy bootloader targets');
|
|
615
|
+
}
|
|
616
|
+
|
|
520
617
|
if (executor === 'v4' && (shouldUpdateFirmware || shouldUpdateResource)) {
|
|
521
|
-
const protocolV2 = buildProtocolV2Artifacts(firmwareRelease ?? {}
|
|
618
|
+
const protocolV2 = buildProtocolV2Artifacts(firmwareRelease ?? {}, {
|
|
619
|
+
includeComponents: shouldUpdateFirmware,
|
|
620
|
+
includeResources: shouldUpdateResource,
|
|
621
|
+
});
|
|
522
622
|
artifacts = protocolV2.artifacts;
|
|
523
623
|
targetsToUpdate = protocolV2.targets;
|
|
524
624
|
} else {
|
|
@@ -609,6 +709,13 @@ export const buildFirmwareUpdatePlan = ({
|
|
|
609
709
|
targetsToUpdate = [...new Set(artifacts.map(artifact => artifact.target))];
|
|
610
710
|
}
|
|
611
711
|
|
|
712
|
+
assertForcedTargetsRepresented({
|
|
713
|
+
executor,
|
|
714
|
+
forcedTargets: validatedForceTargets,
|
|
715
|
+
artifacts,
|
|
716
|
+
targetsToUpdate,
|
|
717
|
+
});
|
|
718
|
+
|
|
612
719
|
const deviceIdentity = getDeviceUUID(features);
|
|
613
720
|
if (
|
|
614
721
|
artifacts.length > 0 &&
|
|
@@ -631,8 +738,8 @@ export const buildFirmwareUpdatePlan = ({
|
|
|
631
738
|
artifacts,
|
|
632
739
|
targetsToUpdate,
|
|
633
740
|
};
|
|
634
|
-
return {
|
|
741
|
+
return assertFirmwareUpdatePlan({
|
|
635
742
|
...planWithoutDigest,
|
|
636
743
|
planDigest: digestFirmwareUpdatePlan(planWithoutDigest),
|
|
637
|
-
};
|
|
744
|
+
});
|
|
638
745
|
};
|
|
@@ -21,8 +21,6 @@ type OpenWalletSessionPayloadBase = {
|
|
|
21
21
|
protocol: 'V1' | 'V2';
|
|
22
22
|
deviceId: string;
|
|
23
23
|
resumed: boolean;
|
|
24
|
-
/** Forwarded only when the firmware response contains a wallet session id. */
|
|
25
|
-
sessionId?: string;
|
|
26
24
|
};
|
|
27
25
|
|
|
28
26
|
export type OpenWalletSessionPayload = OpenWalletSessionPayloadBase &
|