@onekeyfe/hd-core 1.2.0-alpha.81 → 1.2.0-alpha.84
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__/check-all-firmware-release-protocol-v2.test.ts +266 -0
- package/__tests__/check-firmware-release-protocol-v2.test.ts +36 -0
- package/__tests__/protocol-v2.test.ts +181 -2
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/CheckBLEFirmwareRelease.d.ts +1 -1
- package/dist/api/CheckBLEFirmwareRelease.d.ts.map +1 -1
- package/dist/api/CheckBootloaderRelease.d.ts +1 -1
- package/dist/api/CheckBootloaderRelease.d.ts.map +1 -1
- package/dist/api/CheckFirmwareRelease.d.ts +1 -1
- package/dist/api/CheckFirmwareRelease.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +1 -0
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +33 -0
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -1
- package/dist/api/firmware/protocolV2Release.d.ts.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +202 -66
- package/dist/types/api/checkAllFirmwareRelease.d.ts +1 -0
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/checkBLEFirmwareRelease.d.ts +1 -1
- package/dist/types/api/checkBLEFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/checkBootloaderRelease.d.ts +1 -1
- package/dist/types/api/checkBootloaderRelease.d.ts.map +1 -1
- package/dist/types/api/checkFirmwareRelease.d.ts +1 -1
- package/dist/types/api/checkFirmwareRelease.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/CheckAllFirmwareRelease.ts +76 -5
- package/src/api/CheckBLEFirmwareRelease.ts +4 -10
- package/src/api/CheckBootloaderRelease.ts +1 -8
- package/src/api/CheckFirmwareRelease.ts +6 -12
- package/src/api/FirmwareUpdateV4.ts +61 -21
- package/src/api/firmware/FirmwareUpdatePlan.ts +154 -37
- package/src/api/firmware/protocolV2Release.ts +2 -0
- package/src/types/api/checkAllFirmwareRelease.ts +1 -0
- package/src/types/api/checkBLEFirmwareRelease.ts +1 -1
- package/src/types/api/checkBootloaderRelease.ts +1 -1
- package/src/types/api/checkFirmwareRelease.ts +1 -1
- package/src/utils/deviceFeaturesUtils.ts +2 -2
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.84",
|
|
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.84",
|
|
29
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.84",
|
|
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": "577746142ef64d2c97de487c7a9cc8a5a0422e0b"
|
|
48
48
|
}
|
|
@@ -11,7 +11,9 @@ import {
|
|
|
11
11
|
} from './firmware/releaseHelper';
|
|
12
12
|
import {
|
|
13
13
|
buildFirmwareUpdatePlan,
|
|
14
|
+
buildProtocolV2FirmwareUpdatePlan,
|
|
14
15
|
validateFirmwareUpdatePlanForceTargets,
|
|
16
|
+
validateProtocolV2FirmwareUpdateTargets,
|
|
15
17
|
} from './firmware/FirmwareUpdatePlan';
|
|
16
18
|
import {
|
|
17
19
|
PROTOCOL_V2_BLE_TARGETS,
|
|
@@ -26,6 +28,7 @@ import { getBridgeReleaseInfo } from '../utils/bridgeUpdate';
|
|
|
26
28
|
import {
|
|
27
29
|
LoggerNames,
|
|
28
30
|
getDeviceFirmwareVersion,
|
|
31
|
+
getDeviceSerialNo,
|
|
29
32
|
getDeviceType,
|
|
30
33
|
getFirmwareType,
|
|
31
34
|
getLogger,
|
|
@@ -384,8 +387,17 @@ export default class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
384
387
|
}
|
|
385
388
|
|
|
386
389
|
private async runProtocolV2(): Promise<AllFirmwareRelease> {
|
|
387
|
-
const {
|
|
388
|
-
|
|
390
|
+
const {
|
|
391
|
+
checkFirmwareHash = false,
|
|
392
|
+
firmwareType: firmwareTypeParam,
|
|
393
|
+
platform,
|
|
394
|
+
forceUpdateTargets,
|
|
395
|
+
protocolV2ForceUpdateTargets,
|
|
396
|
+
} = this.payload as CheckAllFirmwareReleaseParams;
|
|
397
|
+
const validatedForceUpdateTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
|
|
398
|
+
const validatedProtocolV2ForceUpdateTargets = validateProtocolV2FirmwareUpdateTargets(
|
|
399
|
+
protocolV2ForceUpdateTargets
|
|
400
|
+
);
|
|
389
401
|
const { state, features, firmwareType, release } = await loadProtocolV2FirmwareReleaseContext({
|
|
390
402
|
device: this.device,
|
|
391
403
|
firmwareType: firmwareTypeParam,
|
|
@@ -405,12 +417,70 @@ export default class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
405
417
|
const resourceSource = DataManager.getProtocolV2ResourceSource(resourceDeviceType);
|
|
406
418
|
const resourceStatus = 'unknown' as const;
|
|
407
419
|
const resourcePreparationRequired = !!resourceSource;
|
|
420
|
+
const detectedComponentTargets = validatedForceUpdateTargets.includes('firmware')
|
|
421
|
+
? plan.components.flatMap(component =>
|
|
422
|
+
component.updateTarget ? [component.updateTarget] : []
|
|
423
|
+
)
|
|
424
|
+
: plan.targetsToUpdate;
|
|
425
|
+
const componentTargetsToUpdate = Array.from(
|
|
426
|
+
new Set([
|
|
427
|
+
...detectedComponentTargets,
|
|
428
|
+
...validatedProtocolV2ForceUpdateTargets.filter(target => target !== 'resource'),
|
|
429
|
+
])
|
|
430
|
+
);
|
|
431
|
+
const forceResourceUpdate =
|
|
432
|
+
validatedForceUpdateTargets.includes('resource') ||
|
|
433
|
+
validatedProtocolV2ForceUpdateTargets.includes('resource');
|
|
408
434
|
const targetsToUpdate = Array.from(
|
|
409
435
|
new Set([
|
|
410
|
-
...
|
|
411
|
-
...(resourcePreparationRequired ? (['resource'] as const) : []),
|
|
436
|
+
...componentTargetsToUpdate,
|
|
437
|
+
...(resourcePreparationRequired || forceResourceUpdate ? (['resource'] as const) : []),
|
|
412
438
|
])
|
|
413
439
|
);
|
|
440
|
+
let firmwareUpdatePlan: FirmwareUpdatePlan | undefined;
|
|
441
|
+
try {
|
|
442
|
+
const shouldBuildFirmwareUpdatePlan =
|
|
443
|
+
componentTargetsToUpdate.length > 0 ||
|
|
444
|
+
validatedForceUpdateTargets.some(target => target !== 'resource') ||
|
|
445
|
+
validatedProtocolV2ForceUpdateTargets.some(target => target !== 'resource') ||
|
|
446
|
+
(forceResourceUpdate && !resourcePreparationRequired);
|
|
447
|
+
const requestedPlatform = platform ?? 'web';
|
|
448
|
+
const requiresDeviceIdentity =
|
|
449
|
+
requestedPlatform === 'native' || requestedPlatform === 'desktop';
|
|
450
|
+
const canBindPreparedPlan = !requiresDeviceIdentity || !!getDeviceSerialNo(features);
|
|
451
|
+
if (shouldBuildFirmwareUpdatePlan) {
|
|
452
|
+
const validatedPlan = buildProtocolV2FirmwareUpdatePlan({
|
|
453
|
+
features,
|
|
454
|
+
firmwareType,
|
|
455
|
+
platform: canBindPreparedPlan ? requestedPlatform : 'web',
|
|
456
|
+
release,
|
|
457
|
+
targetsToUpdate,
|
|
458
|
+
forceUpdateTargets: validatedForceUpdateTargets,
|
|
459
|
+
resourceArchiveAvailable: resourcePreparationRequired,
|
|
460
|
+
});
|
|
461
|
+
firmwareUpdatePlan = canBindPreparedPlan ? validatedPlan : undefined;
|
|
462
|
+
if (!canBindPreparedPlan) {
|
|
463
|
+
Log.warn(
|
|
464
|
+
'[CheckAllFirmwareRelease] Protocol V2 device identity is unavailable; using the release result without a prepared Plan'
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
} else {
|
|
468
|
+
firmwareUpdatePlan = undefined;
|
|
469
|
+
}
|
|
470
|
+
} catch (error) {
|
|
471
|
+
if (
|
|
472
|
+
validatedForceUpdateTargets.length > 0 ||
|
|
473
|
+
validatedProtocolV2ForceUpdateTargets.length > 0 ||
|
|
474
|
+
!(error instanceof HardwareError) ||
|
|
475
|
+
error.params?.firmwareUpdateCode !== 'FirmwarePlanInvalid'
|
|
476
|
+
) {
|
|
477
|
+
throw error;
|
|
478
|
+
}
|
|
479
|
+
Log.warn(
|
|
480
|
+
'[CheckAllFirmwareRelease] Optional Protocol V2 firmware Plan is unavailable; using the release result'
|
|
481
|
+
);
|
|
482
|
+
firmwareUpdatePlan = undefined;
|
|
483
|
+
}
|
|
414
484
|
const firmwarePlan = summarizeProtocolV2FirmwareRelease(
|
|
415
485
|
plan,
|
|
416
486
|
PROTOCOL_V2_MAIN_FIRMWARE_TARGETS
|
|
@@ -442,8 +512,9 @@ export default class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
442
512
|
resourceStatus,
|
|
443
513
|
resourceArchive: resourceSource,
|
|
444
514
|
resourcePreparationRequired,
|
|
445
|
-
hasUpgrade:
|
|
515
|
+
hasUpgrade: targetsToUpdate.length > 0,
|
|
446
516
|
targetsToUpdate,
|
|
517
|
+
firmwareUpdatePlan,
|
|
447
518
|
};
|
|
448
519
|
}
|
|
449
520
|
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
-
|
|
3
1
|
import { BaseMethod } from './BaseMethod';
|
|
4
2
|
import { UI_REQUEST } from '../constants/ui-request';
|
|
5
3
|
import { getBleFirmwareReleaseInfo } from './firmware/releaseHelper';
|
|
@@ -28,6 +26,8 @@ export default class CheckBLEFirmwareRelease extends BaseMethod {
|
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
async run() {
|
|
29
|
+
if (!this.device.features) return null;
|
|
30
|
+
|
|
31
31
|
if (this.device.isProtocolV2()) {
|
|
32
32
|
const { state, firmwareType, release } = await loadProtocolV2FirmwareReleaseContext({
|
|
33
33
|
device: this.device,
|
|
@@ -49,13 +49,7 @@ export default class CheckBLEFirmwareRelease extends BaseMethod {
|
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return releaseInfo;
|
|
55
|
-
}
|
|
56
|
-
throw ERRORS.TypedError(
|
|
57
|
-
HardwareErrorCode.RuntimeError,
|
|
58
|
-
'checkBLEFirmwareRelease requires initialized device features'
|
|
59
|
-
);
|
|
52
|
+
const releaseInfo = getBleFirmwareReleaseInfo(this.device.features);
|
|
53
|
+
return releaseInfo;
|
|
60
54
|
}
|
|
61
55
|
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
-
|
|
3
1
|
import { BaseMethod } from './BaseMethod';
|
|
4
2
|
import { UI_REQUEST } from '../constants/ui-request';
|
|
5
3
|
import { getBootloaderReleaseInfo } from './firmware/releaseHelper';
|
|
@@ -26,12 +24,7 @@ export default class CheckBootloaderRelease extends BaseMethod {
|
|
|
26
24
|
}
|
|
27
25
|
|
|
28
26
|
async run() {
|
|
29
|
-
if (!this.device.features)
|
|
30
|
-
throw ERRORS.TypedError(
|
|
31
|
-
HardwareErrorCode.RuntimeError,
|
|
32
|
-
'checkBootloaderRelease requires initialized device features'
|
|
33
|
-
);
|
|
34
|
-
}
|
|
27
|
+
if (!this.device.features) return null;
|
|
35
28
|
const { features } = this.device;
|
|
36
29
|
const payload = this.payload as CheckBootloaderReleaseParams;
|
|
37
30
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
-
|
|
3
1
|
import { BaseMethod } from './BaseMethod';
|
|
4
2
|
import { UI_REQUEST } from '../constants/ui-request';
|
|
5
3
|
import { getFirmwareReleaseInfo } from './firmware/releaseHelper';
|
|
@@ -31,6 +29,8 @@ export default class CheckFirmwareRelease extends BaseMethod {
|
|
|
31
29
|
async run() {
|
|
32
30
|
const payload = this.payload as CheckFirmwareReleaseParams;
|
|
33
31
|
|
|
32
|
+
if (!this.device.features) return null;
|
|
33
|
+
|
|
34
34
|
if (this.device.isProtocolV2()) {
|
|
35
35
|
const { state, firmwareType, release } = await loadProtocolV2FirmwareReleaseContext({
|
|
36
36
|
device: this.device,
|
|
@@ -49,16 +49,10 @@ export default class CheckFirmwareRelease extends BaseMethod {
|
|
|
49
49
|
return toProtocolV2FirmwareReleaseInfo({ plan, state, release });
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const firmwareType = payload.firmwareType ?? deviceFirmwareType;
|
|
52
|
+
const deviceFirmwareType = this.device.getCurrentFirmwareType();
|
|
53
|
+
const firmwareType = payload.firmwareType ?? deviceFirmwareType;
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
throw ERRORS.TypedError(
|
|
60
|
-
HardwareErrorCode.RuntimeError,
|
|
61
|
-
'checkFirmwareRelease requires initialized device features'
|
|
62
|
-
);
|
|
55
|
+
const releaseInfo = getFirmwareReleaseInfo(this.device.features, firmwareType);
|
|
56
|
+
return releaseInfo;
|
|
63
57
|
}
|
|
64
58
|
}
|
|
@@ -683,7 +683,14 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
683
683
|
resourceBundles = this.prepareExplicitProtocolV2ResourceFiles();
|
|
684
684
|
fwBinaryMap = this.collectExplicitTargetBinaries();
|
|
685
685
|
bootloaderBinary = this.prepareBootloaderBinary();
|
|
686
|
-
const
|
|
686
|
+
const explicitInstallItems = this.buildProtocolV2InstallItems({
|
|
687
|
+
bootloaderBinary,
|
|
688
|
+
fwBinaryMap,
|
|
689
|
+
});
|
|
690
|
+
const missingFirmwareTargets = this.getMissingProtocolV2FirmwareTargets(explicitInstallItems);
|
|
691
|
+
const needsRemoteFirmware = this.params.targetsToUpdate?.length
|
|
692
|
+
? missingFirmwareTargets.length > 0
|
|
693
|
+
: !this.hasExplicitProtocolV2Payload(explicitInstallItems);
|
|
687
694
|
if (needsPreparedResources) {
|
|
688
695
|
throw ERRORS.TypedError(
|
|
689
696
|
HardwareErrorCode.RuntimeError,
|
|
@@ -713,7 +720,8 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
713
720
|
if (needsRemoteFirmware) {
|
|
714
721
|
const remoteBinaries = await this.prepareRemoteProtocolV2Binaries(
|
|
715
722
|
firmwareType,
|
|
716
|
-
deviceFeatures
|
|
723
|
+
deviceFeatures,
|
|
724
|
+
explicitInstallItems
|
|
717
725
|
);
|
|
718
726
|
bootloaderBinary = remoteBinaries.bootloaderBinary;
|
|
719
727
|
fwBinaryMap = remoteBinaries.fwBinaryMap;
|
|
@@ -1110,11 +1118,19 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1110
1118
|
return this.params.bootloaderBinary ?? null;
|
|
1111
1119
|
}
|
|
1112
1120
|
|
|
1113
|
-
private hasExplicitProtocolV2Payload(
|
|
1114
|
-
return
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1121
|
+
private hasExplicitProtocolV2Payload(installItems: ProtocolV2InstallItem[]) {
|
|
1122
|
+
return !!this.params.resourceFiles?.length || installItems.length > 0;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
private getMissingProtocolV2FirmwareTargets(installItems: ProtocolV2InstallItem[]) {
|
|
1126
|
+
const preparedTargets = new Set(
|
|
1127
|
+
installItems.flatMap(item => {
|
|
1128
|
+
const target = PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(item.targetId);
|
|
1129
|
+
return target ? [target] : [];
|
|
1130
|
+
})
|
|
1131
|
+
);
|
|
1132
|
+
return (this.params.targetsToUpdate ?? []).filter(
|
|
1133
|
+
target => target !== 'resource' && !preparedTargets.has(target)
|
|
1118
1134
|
);
|
|
1119
1135
|
}
|
|
1120
1136
|
|
|
@@ -1210,7 +1226,11 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1210
1226
|
};
|
|
1211
1227
|
}
|
|
1212
1228
|
|
|
1213
|
-
private async prepareRemoteProtocolV2Binaries(
|
|
1229
|
+
private async prepareRemoteProtocolV2Binaries(
|
|
1230
|
+
firmwareType: EFirmwareType,
|
|
1231
|
+
features: Features,
|
|
1232
|
+
explicitInstallItems: ProtocolV2InstallItem[] = []
|
|
1233
|
+
) {
|
|
1214
1234
|
const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
|
|
1215
1235
|
|
|
1216
1236
|
let bootloaderBinary: ArrayBuffer | null = null;
|
|
@@ -1218,6 +1238,15 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1218
1238
|
const installItems: ProtocolV2InstallItem[] = [];
|
|
1219
1239
|
|
|
1220
1240
|
if (!release) {
|
|
1241
|
+
const missingFirmwareTargets = this.getMissingProtocolV2FirmwareTargets(explicitInstallItems);
|
|
1242
|
+
if (missingFirmwareTargets.length > 0) {
|
|
1243
|
+
throw ERRORS.TypedError(
|
|
1244
|
+
HardwareErrorCode.RuntimeError,
|
|
1245
|
+
`Protocol V2 firmware release is unavailable for requested targets: ${missingFirmwareTargets.join(
|
|
1246
|
+
', '
|
|
1247
|
+
)}`
|
|
1248
|
+
);
|
|
1249
|
+
}
|
|
1221
1250
|
return {
|
|
1222
1251
|
bootloaderBinary,
|
|
1223
1252
|
fwBinaryMap,
|
|
@@ -1227,6 +1256,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1227
1256
|
|
|
1228
1257
|
const entries = this.getRemoteComponentEntries(release);
|
|
1229
1258
|
const targetsToUpdate = new Set(this.params.targetsToUpdate ?? []);
|
|
1259
|
+
const explicitInstallItemByTargetId = new Map(
|
|
1260
|
+
explicitInstallItems.map(item => [item.targetId, item] as const)
|
|
1261
|
+
);
|
|
1262
|
+
const preparedTargets = new Set<FirmwareUpdateV4Target>();
|
|
1230
1263
|
|
|
1231
1264
|
for (const [key, component] of entries) {
|
|
1232
1265
|
const targetName = component.target?.toUpperCase();
|
|
@@ -1235,27 +1268,34 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1235
1268
|
? PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(target.targetId)
|
|
1236
1269
|
: undefined;
|
|
1237
1270
|
if (updateTarget && targetsToUpdate.has(updateTarget)) {
|
|
1238
|
-
const
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
binary: remoteBinary.binary,
|
|
1244
|
-
targetId: remoteBinary.targetId,
|
|
1245
|
-
kind: remoteBinary.kind,
|
|
1246
|
-
});
|
|
1271
|
+
const explicitInstallItem = explicitInstallItemByTargetId.get(target.targetId);
|
|
1272
|
+
const installItem =
|
|
1273
|
+
explicitInstallItem ?? (await this.downloadRemoteProtocolV2Component(key, component));
|
|
1274
|
+
if (installItem.kind === 'bootloader') {
|
|
1275
|
+
bootloaderBinary = installItem.binary;
|
|
1247
1276
|
} else {
|
|
1248
1277
|
const binaryEntry = {
|
|
1249
|
-
fileName:
|
|
1250
|
-
binary:
|
|
1251
|
-
targetId:
|
|
1278
|
+
fileName: installItem.fileName,
|
|
1279
|
+
binary: installItem.binary,
|
|
1280
|
+
targetId: installItem.targetId,
|
|
1252
1281
|
};
|
|
1253
1282
|
fwBinaryMap.push(binaryEntry);
|
|
1254
|
-
installItems.push({ ...binaryEntry, kind: remoteBinary.kind });
|
|
1255
1283
|
}
|
|
1284
|
+
installItems.push({ ...installItem });
|
|
1285
|
+
preparedTargets.add(updateTarget);
|
|
1256
1286
|
}
|
|
1257
1287
|
}
|
|
1258
1288
|
|
|
1289
|
+
const missingTarget = Array.from(targetsToUpdate).find(
|
|
1290
|
+
target => target !== 'resource' && !preparedTargets.has(target)
|
|
1291
|
+
);
|
|
1292
|
+
if (missingTarget) {
|
|
1293
|
+
throw ERRORS.TypedError(
|
|
1294
|
+
HardwareErrorCode.RuntimeError,
|
|
1295
|
+
`Protocol V2 release does not contain requested target ${missingTarget}`
|
|
1296
|
+
);
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1259
1299
|
return {
|
|
1260
1300
|
bootloaderBinary,
|
|
1261
1301
|
fwBinaryMap,
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
getDeviceFirmwareVersion,
|
|
11
11
|
} from '../../utils/deviceVersionUtils';
|
|
12
12
|
|
|
13
|
+
import type { FirmwareUpdateV4Target } from '../../types/api/firmwareUpdate';
|
|
13
14
|
import type {
|
|
14
15
|
FirmwareUpdatePlan,
|
|
15
16
|
FirmwareUpdatePlanArtifact,
|
|
@@ -62,6 +63,11 @@ const PROTOCOL_V2_TARGETS: Readonly<
|
|
|
62
63
|
SE04: 'se04',
|
|
63
64
|
};
|
|
64
65
|
|
|
66
|
+
const PROTOCOL_V2_FIRMWARE_UPDATE_TARGETS = new Set<FirmwareUpdateV4Target>([
|
|
67
|
+
...Object.values(PROTOCOL_V2_TARGETS),
|
|
68
|
+
'resource',
|
|
69
|
+
]);
|
|
70
|
+
|
|
65
71
|
const asRecord = (value: unknown): Record<string, unknown> | undefined =>
|
|
66
72
|
value && typeof value === 'object' && !Array.isArray(value)
|
|
67
73
|
? (value as Record<string, unknown>)
|
|
@@ -191,6 +197,23 @@ export const validateFirmwareUpdatePlanForceTargets = (
|
|
|
191
197
|
return [...value] as FirmwareUpdatePlanForceTarget[];
|
|
192
198
|
};
|
|
193
199
|
|
|
200
|
+
export const validateProtocolV2FirmwareUpdateTargets = (
|
|
201
|
+
value: unknown
|
|
202
|
+
): FirmwareUpdateV4Target[] => {
|
|
203
|
+
if (value === undefined) {
|
|
204
|
+
return [];
|
|
205
|
+
}
|
|
206
|
+
if (
|
|
207
|
+
!Array.isArray(value) ||
|
|
208
|
+
value.length > PROTOCOL_V2_FIRMWARE_UPDATE_TARGETS.size ||
|
|
209
|
+
value.some(target => !PROTOCOL_V2_FIRMWARE_UPDATE_TARGETS.has(target)) ||
|
|
210
|
+
new Set(value).size !== value.length
|
|
211
|
+
) {
|
|
212
|
+
return planError('Protocol V2 firmware update targets are invalid');
|
|
213
|
+
}
|
|
214
|
+
return [...value] as FirmwareUpdateV4Target[];
|
|
215
|
+
};
|
|
216
|
+
|
|
194
217
|
const assertExactKeys = (
|
|
195
218
|
value: Record<string, unknown>,
|
|
196
219
|
required: readonly string[],
|
|
@@ -405,7 +428,7 @@ const selectResourceUrl = ({
|
|
|
405
428
|
|
|
406
429
|
const getExecutor = (features: Features): FirmwareUpdatePlan['executor'] => {
|
|
407
430
|
const deviceType = getDeviceType(features);
|
|
408
|
-
if (deviceType === EDeviceType.Pro2) {
|
|
431
|
+
if (deviceType === EDeviceType.Pro2 || deviceType === EDeviceType.Neo) {
|
|
409
432
|
return 'v4';
|
|
410
433
|
}
|
|
411
434
|
if (
|
|
@@ -422,9 +445,11 @@ const buildProtocolV2Artifacts = (
|
|
|
422
445
|
{
|
|
423
446
|
includeComponents = true,
|
|
424
447
|
includeResources = true,
|
|
448
|
+
componentTargets: selectedComponentTargets,
|
|
425
449
|
}: {
|
|
426
450
|
includeComponents?: boolean;
|
|
427
451
|
includeResources?: boolean;
|
|
452
|
+
componentTargets?: ReadonlySet<FirmwareUpdatePlanTarget>;
|
|
428
453
|
} = {}
|
|
429
454
|
): {
|
|
430
455
|
artifacts: FirmwareUpdatePlanArtifact[];
|
|
@@ -445,12 +470,21 @@ const buildProtocolV2Artifacts = (
|
|
|
445
470
|
includeComponents && components
|
|
446
471
|
? [...installOrder, ...Object.keys(components).filter(key => !installOrder.includes(key))]
|
|
447
472
|
: [];
|
|
473
|
+
const selectedComponentKeys = selectedComponentTargets
|
|
474
|
+
? componentKeys.filter(key => {
|
|
475
|
+
const component = asRecord(components?.[key]);
|
|
476
|
+
const targetName = asString(component?.target)?.toUpperCase();
|
|
477
|
+
const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
|
|
478
|
+
return !!target && selectedComponentTargets.has(target);
|
|
479
|
+
})
|
|
480
|
+
: componentKeys;
|
|
448
481
|
const artifacts: FirmwareUpdatePlanArtifact[] = [];
|
|
449
482
|
const targets: FirmwareUpdatePlanTarget[] = [];
|
|
450
|
-
const
|
|
451
|
-
for (const key of
|
|
483
|
+
const componentTargetSet = new Set<FirmwareUpdatePlanTarget>();
|
|
484
|
+
for (const key of selectedComponentKeys) {
|
|
452
485
|
const component = asRecord(components?.[key]);
|
|
453
486
|
const targetName = asString(component?.target)?.toUpperCase();
|
|
487
|
+
const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
|
|
454
488
|
if (targetName === 'ROMLOADER') {
|
|
455
489
|
throw ERRORS.TypedError(
|
|
456
490
|
HardwareErrorCode.RuntimeError,
|
|
@@ -458,7 +492,6 @@ const buildProtocolV2Artifacts = (
|
|
|
458
492
|
{ firmwareUpdateCode: 'FirmwarePlanInvalid' }
|
|
459
493
|
);
|
|
460
494
|
}
|
|
461
|
-
const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
|
|
462
495
|
if (!component || !target) {
|
|
463
496
|
throw ERRORS.TypedError(
|
|
464
497
|
HardwareErrorCode.RuntimeError,
|
|
@@ -466,14 +499,14 @@ const buildProtocolV2Artifacts = (
|
|
|
466
499
|
{ firmwareUpdateCode: 'FirmwarePlanInvalid' }
|
|
467
500
|
);
|
|
468
501
|
}
|
|
469
|
-
if (
|
|
502
|
+
if (componentTargetSet.has(target)) {
|
|
470
503
|
throw ERRORS.TypedError(
|
|
471
504
|
HardwareErrorCode.RuntimeError,
|
|
472
505
|
`Protocol V2 component ${key} duplicates target ${target}`,
|
|
473
506
|
{ firmwareUpdateCode: 'FirmwarePlanInvalid' }
|
|
474
507
|
);
|
|
475
508
|
}
|
|
476
|
-
|
|
509
|
+
componentTargetSet.add(target);
|
|
477
510
|
artifacts.push({
|
|
478
511
|
artifactId: `component:${target}`,
|
|
479
512
|
role: 'component',
|
|
@@ -587,6 +620,119 @@ const assertForcedTargetsRepresented = ({
|
|
|
587
620
|
}
|
|
588
621
|
};
|
|
589
622
|
|
|
623
|
+
const finalizeFirmwareUpdatePlan = ({
|
|
624
|
+
features,
|
|
625
|
+
firmwareType,
|
|
626
|
+
platform,
|
|
627
|
+
artifacts,
|
|
628
|
+
targetsToUpdate,
|
|
629
|
+
}: {
|
|
630
|
+
features: Features;
|
|
631
|
+
firmwareType: EFirmwareType;
|
|
632
|
+
platform: FirmwareUpdatePlatform;
|
|
633
|
+
artifacts: FirmwareUpdatePlanArtifact[];
|
|
634
|
+
targetsToUpdate: FirmwareUpdatePlanTarget[];
|
|
635
|
+
}): FirmwareUpdatePlan => {
|
|
636
|
+
const executor = getExecutor(features);
|
|
637
|
+
const bootloaderMode = resolveDeviceBootloaderMode(features);
|
|
638
|
+
// 'unavailable' is the reserved degraded-identity sentinel; a device-reported
|
|
639
|
+
// serial must never be able to collide with it.
|
|
640
|
+
const reportedIdentity = getDeviceUUID(features);
|
|
641
|
+
const deviceIdentity = reportedIdentity === 'unavailable' ? '' : reportedIdentity;
|
|
642
|
+
// Bootloader-mode classic-family devices (executor v2, e.g. classic1s) cannot report
|
|
643
|
+
// a serial number, so their recovery plans fall back to the degraded 'unavailable'
|
|
644
|
+
// identity. Binding is then enforced against the live device at install time instead
|
|
645
|
+
// (assertFirmwareUpdatePreparedPlanDeviceIdentity), and plan integrity by the digest.
|
|
646
|
+
// Pro (v3), Pro2, and Neo (v4) report a serial even in loader mode and stay strict.
|
|
647
|
+
if (
|
|
648
|
+
artifacts.length > 0 &&
|
|
649
|
+
(platform === 'native' || platform === 'desktop') &&
|
|
650
|
+
!deviceIdentity &&
|
|
651
|
+
!(bootloaderMode && executor === 'v2')
|
|
652
|
+
) {
|
|
653
|
+
throw ERRORS.TypedError(
|
|
654
|
+
HardwareErrorCode.RuntimeError,
|
|
655
|
+
'Prepared firmware update requires a stable device identity',
|
|
656
|
+
{ firmwareUpdateCode: 'FirmwarePlanInvalid' }
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
const planWithoutDigest: Omit<FirmwareUpdatePlan, 'planDigest'> = {
|
|
660
|
+
schemaVersion: 2,
|
|
661
|
+
executor,
|
|
662
|
+
deviceIdentity: deviceIdentity || 'unavailable',
|
|
663
|
+
deviceModel: String(getDeviceType(features)),
|
|
664
|
+
firmwareType,
|
|
665
|
+
platform,
|
|
666
|
+
artifacts,
|
|
667
|
+
targetsToUpdate,
|
|
668
|
+
};
|
|
669
|
+
return assertFirmwareUpdatePlan({
|
|
670
|
+
...planWithoutDigest,
|
|
671
|
+
planDigest: digestFirmwareUpdatePlan(planWithoutDigest),
|
|
672
|
+
});
|
|
673
|
+
};
|
|
674
|
+
|
|
675
|
+
export const buildProtocolV2FirmwareUpdatePlan = ({
|
|
676
|
+
features,
|
|
677
|
+
firmwareType,
|
|
678
|
+
platform,
|
|
679
|
+
release,
|
|
680
|
+
targetsToUpdate,
|
|
681
|
+
forceUpdateTargets,
|
|
682
|
+
resourceArchiveAvailable,
|
|
683
|
+
}: {
|
|
684
|
+
features: Features;
|
|
685
|
+
firmwareType: EFirmwareType;
|
|
686
|
+
platform: FirmwareUpdatePlatform;
|
|
687
|
+
release: ReleaseRecord | undefined;
|
|
688
|
+
targetsToUpdate: readonly FirmwareUpdateV4Target[];
|
|
689
|
+
forceUpdateTargets?: FirmwareUpdatePlanForceTarget[];
|
|
690
|
+
resourceArchiveAvailable: boolean;
|
|
691
|
+
}): FirmwareUpdatePlan => {
|
|
692
|
+
const validatedForceTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
|
|
693
|
+
if (validatedForceTargets.some(target => target === 'ble' || target === 'bootloader')) {
|
|
694
|
+
planError('Protocol V2 does not support forced BLE or legacy bootloader targets');
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
const requestedComponentTargets = new Set<FirmwareUpdatePlanTarget>(
|
|
698
|
+
targetsToUpdate.filter(target => target !== 'resource')
|
|
699
|
+
);
|
|
700
|
+
if (
|
|
701
|
+
getDeviceType(features) === EDeviceType.Neo &&
|
|
702
|
+
(requestedComponentTargets.has('se03') || requestedComponentTargets.has('se04'))
|
|
703
|
+
) {
|
|
704
|
+
planError('Neo does not support Protocol V2 targets se03 or se04');
|
|
705
|
+
}
|
|
706
|
+
const protocolV2 = buildProtocolV2Artifacts(release ?? {}, {
|
|
707
|
+
includeComponents: requestedComponentTargets.size > 0,
|
|
708
|
+
includeResources: false,
|
|
709
|
+
componentTargets: requestedComponentTargets,
|
|
710
|
+
});
|
|
711
|
+
const representedTargets = new Set(protocolV2.targets);
|
|
712
|
+
const missingTarget = Array.from(requestedComponentTargets).find(
|
|
713
|
+
target => !representedTargets.has(target)
|
|
714
|
+
);
|
|
715
|
+
if (missingTarget) {
|
|
716
|
+
planError(`Protocol V2 release does not contain requested target ${missingTarget}`);
|
|
717
|
+
}
|
|
718
|
+
if (validatedForceTargets.includes('firmware') && protocolV2.targets.length === 0) {
|
|
719
|
+
planError('Forced firmware update target firmware is not represented by the plan');
|
|
720
|
+
}
|
|
721
|
+
if (validatedForceTargets.includes('resource') && !resourceArchiveAvailable) {
|
|
722
|
+
planError('Forced firmware update target resource has no Protocol V2 resource archive');
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// Protocol V2 resource archives are materialized by the host into explicit
|
|
726
|
+
// resourceFiles. The prepared artifact plan therefore binds firmware components only.
|
|
727
|
+
return finalizeFirmwareUpdatePlan({
|
|
728
|
+
features,
|
|
729
|
+
firmwareType,
|
|
730
|
+
platform,
|
|
731
|
+
artifacts: protocolV2.artifacts,
|
|
732
|
+
targetsToUpdate: protocolV2.targets,
|
|
733
|
+
});
|
|
734
|
+
};
|
|
735
|
+
|
|
590
736
|
export const buildFirmwareUpdatePlan = ({
|
|
591
737
|
features,
|
|
592
738
|
firmwareType,
|
|
@@ -733,40 +879,11 @@ export const buildFirmwareUpdatePlan = ({
|
|
|
733
879
|
artifacts,
|
|
734
880
|
targetsToUpdate,
|
|
735
881
|
});
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
// serial must never be able to collide with it.
|
|
739
|
-
const reportedIdentity = getDeviceUUID(features);
|
|
740
|
-
const deviceIdentity = reportedIdentity === 'unavailable' ? '' : reportedIdentity;
|
|
741
|
-
// Bootloader-mode classic-family devices (executor v2, e.g. classic1s) cannot report
|
|
742
|
-
// a serial number, so their recovery plans fall back to the degraded 'unavailable'
|
|
743
|
-
// identity. Binding is then enforced against the live device at install time instead
|
|
744
|
-
// (assertFirmwareUpdatePreparedPlanDeviceIdentity), and plan integrity by the digest.
|
|
745
|
-
// Pro (v3) and Pro2 (v4) report a serial even in bootloader mode and stay strict.
|
|
746
|
-
if (
|
|
747
|
-
artifacts.length > 0 &&
|
|
748
|
-
(platform === 'native' || platform === 'desktop') &&
|
|
749
|
-
!deviceIdentity &&
|
|
750
|
-
!(bootloaderMode && executor === 'v2')
|
|
751
|
-
) {
|
|
752
|
-
throw ERRORS.TypedError(
|
|
753
|
-
HardwareErrorCode.RuntimeError,
|
|
754
|
-
'Prepared firmware update requires a stable device identity',
|
|
755
|
-
{ firmwareUpdateCode: 'FirmwarePlanInvalid' }
|
|
756
|
-
);
|
|
757
|
-
}
|
|
758
|
-
const planWithoutDigest: Omit<FirmwareUpdatePlan, 'planDigest'> = {
|
|
759
|
-
schemaVersion: 2,
|
|
760
|
-
executor,
|
|
761
|
-
deviceIdentity: deviceIdentity || 'unavailable',
|
|
762
|
-
deviceModel: String(getDeviceType(features)),
|
|
882
|
+
return finalizeFirmwareUpdatePlan({
|
|
883
|
+
features,
|
|
763
884
|
firmwareType,
|
|
764
885
|
platform,
|
|
765
886
|
artifacts,
|
|
766
887
|
targetsToUpdate,
|
|
767
|
-
};
|
|
768
|
-
return assertFirmwareUpdatePlan({
|
|
769
|
-
...planWithoutDigest,
|
|
770
|
-
planDigest: digestFirmwareUpdatePlan(planWithoutDigest),
|
|
771
888
|
});
|
|
772
889
|
};
|
|
@@ -135,6 +135,8 @@ export function toProtocolV2FirmwareReleaseInfo({
|
|
|
135
135
|
return {
|
|
136
136
|
shouldUpdate: plan.hasUpgrade,
|
|
137
137
|
status: plan.status === 'unavailable' ? 'unknown' : plan.status,
|
|
138
|
+
// Protocol V2 components share package-set release notes. The optional
|
|
139
|
+
// bootloaderChangelog field belongs to the legacy Protocol V1 release model.
|
|
138
140
|
changelog: plan.release ? [plan.release.changelog] : [],
|
|
139
141
|
release,
|
|
140
142
|
bootloaderMode: state.status.mode === 'bootloader' || state.status.mode === 'romloader',
|
|
@@ -89,6 +89,7 @@ export type CheckAllFirmwareReleaseParams = {
|
|
|
89
89
|
firmwareType?: EFirmwareType;
|
|
90
90
|
platform?: 'native' | 'desktop' | 'ext' | 'web' | 'web-embed';
|
|
91
91
|
forceUpdateTargets?: FirmwareUpdatePlanForceTarget[];
|
|
92
|
+
protocolV2ForceUpdateTargets?: FirmwareUpdateV4Target[];
|
|
92
93
|
};
|
|
93
94
|
|
|
94
95
|
export declare function checkAllFirmwareRelease(
|
|
@@ -2,7 +2,7 @@ import type { EFirmwareType } from '@onekeyfe/hd-shared';
|
|
|
2
2
|
import type { CommonParams, Response } from '../params';
|
|
3
3
|
import type { FirmwareReleaseCheckResult } from './checkAllFirmwareRelease';
|
|
4
4
|
|
|
5
|
-
export type CheckBootloaderReleaseResponse = FirmwareReleaseCheckResult;
|
|
5
|
+
export type CheckBootloaderReleaseResponse = FirmwareReleaseCheckResult | null;
|
|
6
6
|
|
|
7
7
|
export type CheckBootloaderReleaseParams = {
|
|
8
8
|
willUpdateFirmwareVersion?: string;
|