@onekeyfe/hd-core 1.2.0-alpha.86 → 1.2.0-alpha.88
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-memory-host.test.ts +5 -2
- package/__tests__/protocol-v2.test.ts +388 -0
- package/dist/api/FirmwareUpdateV4.d.ts +1 -0
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareMemoryHost.d.ts +0 -5
- package/dist/api/firmware/FirmwareMemoryHost.d.ts.map +1 -1
- package/dist/index.d.ts +2 -4
- package/dist/index.js +179 -57
- package/dist/types/api/firmwareUpdate.d.ts +1 -0
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/FirmwareUpdateV4.ts +283 -32
- package/src/api/firmware/FirmwareMemoryHost.ts +0 -37
- package/src/types/api/firmwareUpdate.ts +2 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { EDeviceType, ERRORS, HardwareError, HardwareErrorCode, wait } from '@onekeyfe/hd-shared';
|
|
2
|
+
import JSZip from 'jszip';
|
|
2
3
|
import {
|
|
3
4
|
DeviceRebootType,
|
|
4
5
|
PROTOCOL_V2_BLE_FILE_CHUNK_SIZE,
|
|
@@ -178,6 +179,10 @@ type ProtocolV2ResourceBundleSource = {
|
|
|
178
179
|
headerHash?: string;
|
|
179
180
|
};
|
|
180
181
|
|
|
182
|
+
type ProtocolV2ResourceBundleBinary = Omit<ProtocolV2ResourceBundleSource, 'source'> & {
|
|
183
|
+
binary: ArrayBuffer;
|
|
184
|
+
};
|
|
185
|
+
|
|
181
186
|
type ProtocolV2ExecutionPhaseKind =
|
|
182
187
|
| 'resource-sync'
|
|
183
188
|
| 'bootloader-install'
|
|
@@ -270,6 +275,19 @@ const PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID = new Map<number, FirmwareUpdateV4T
|
|
|
270
275
|
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE04, 'se04'],
|
|
271
276
|
]);
|
|
272
277
|
|
|
278
|
+
const PROTOCOL_V2_INSTALL_TARGET_BY_UPDATE_TARGET = new Map<
|
|
279
|
+
Exclude<FirmwareUpdateV4Target, 'resource'>,
|
|
280
|
+
ProtocolV2RemoteComponentTarget
|
|
281
|
+
>(
|
|
282
|
+
Object.values(PROTOCOL_V2_REMOTE_COMPONENT_TARGETS).map(target => [
|
|
283
|
+
PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(target.targetId) as Exclude<
|
|
284
|
+
FirmwareUpdateV4Target,
|
|
285
|
+
'resource'
|
|
286
|
+
>,
|
|
287
|
+
target,
|
|
288
|
+
])
|
|
289
|
+
);
|
|
290
|
+
|
|
273
291
|
const PROTOCOL_V2_ROMLOADER_UNSUPPORTED_MESSAGE =
|
|
274
292
|
'FW_MGMT_TARGET_ROMLOADER is not accepted by the current Pro2 bootloader update request. Flash romloader with the loader-specific flow instead of firmwareUpdateV4.';
|
|
275
293
|
|
|
@@ -541,6 +559,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
541
559
|
{ name: 'se02Binary', type: 'buffer' },
|
|
542
560
|
{ name: 'se03Binary', type: 'buffer' },
|
|
543
561
|
{ name: 'se04Binary', type: 'buffer' },
|
|
562
|
+
{ name: 'resourceArchiveBinary', type: 'buffer' },
|
|
544
563
|
{ name: 'firmwareType', type: 'string' },
|
|
545
564
|
{ name: 'targetsToUpdate', type: 'array', allowEmpty: true },
|
|
546
565
|
{ name: 'platform', type: 'string' },
|
|
@@ -558,37 +577,79 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
558
577
|
const preparedPlan = payload.preparedPlan
|
|
559
578
|
? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
|
|
560
579
|
: undefined;
|
|
580
|
+
const hasLocalArtifacts = [
|
|
581
|
+
payload.bootloaderBinary,
|
|
582
|
+
payload.romloaderBinary,
|
|
583
|
+
payload.applicationP1Binary,
|
|
584
|
+
payload.applicationP2Binary,
|
|
585
|
+
payload.coprocessorBinary,
|
|
586
|
+
payload.se01Binary,
|
|
587
|
+
payload.se02Binary,
|
|
588
|
+
payload.se03Binary,
|
|
589
|
+
payload.se04Binary,
|
|
590
|
+
payload.resourceArchiveBinary,
|
|
591
|
+
].some(Boolean);
|
|
592
|
+
if (preparedPlan && hasLocalArtifacts) {
|
|
593
|
+
throw ERRORS.TypedError(
|
|
594
|
+
HardwareErrorCode.CallMethodInvalidParameter,
|
|
595
|
+
'Prepared firmware plans cannot be combined with local firmware or resource binaries'
|
|
596
|
+
);
|
|
597
|
+
}
|
|
561
598
|
const hostBinding =
|
|
562
|
-
|
|
599
|
+
payload.hostBindingGeneration !== undefined
|
|
563
600
|
? resolveFirmwareUpdateHostBinding(
|
|
564
601
|
payload.hostBindingGeneration,
|
|
565
602
|
preparedPlan?.preparedPlanDigest
|
|
566
603
|
)
|
|
567
604
|
: undefined;
|
|
568
|
-
if (
|
|
569
|
-
const componentArtifacts = (payload.componentArtifacts ?? {}) as NonNullable<
|
|
570
|
-
FirmwareUpdateV4Params['componentArtifacts']
|
|
571
|
-
>;
|
|
605
|
+
if (preparedPlan) {
|
|
572
606
|
assertFirmwareUpdatePreparedPlanBinding({
|
|
573
|
-
preparedPlan
|
|
607
|
+
preparedPlan,
|
|
574
608
|
executor: 'v4',
|
|
575
609
|
platform: payload.platform,
|
|
576
|
-
scopeTargets: [
|
|
577
|
-
bindings: [
|
|
578
|
-
...Object.entries(componentArtifacts).flatMap(([target, artifact]) =>
|
|
579
|
-
artifact
|
|
580
|
-
? [
|
|
581
|
-
{
|
|
582
|
-
target: target as Exclude<FirmwareUpdateV4Target, 'resource'>,
|
|
583
|
-
artifact,
|
|
584
|
-
},
|
|
585
|
-
]
|
|
586
|
-
: []
|
|
587
|
-
),
|
|
588
|
-
],
|
|
610
|
+
scopeTargets: [],
|
|
611
|
+
bindings: [],
|
|
589
612
|
});
|
|
613
|
+
if (payload.componentArtifacts) {
|
|
614
|
+
const componentBindings: Array<{
|
|
615
|
+
target: Exclude<FirmwareUpdateV4Target, 'resource'>;
|
|
616
|
+
artifact: FirmwareArtifactReference;
|
|
617
|
+
}> = Object.entries(payload.componentArtifacts).flatMap(([target, artifact]) =>
|
|
618
|
+
artifact
|
|
619
|
+
? [
|
|
620
|
+
{
|
|
621
|
+
target: target as Exclude<FirmwareUpdateV4Target, 'resource'>,
|
|
622
|
+
artifact: artifact as FirmwareArtifactReference,
|
|
623
|
+
},
|
|
624
|
+
]
|
|
625
|
+
: []
|
|
626
|
+
);
|
|
627
|
+
assertFirmwareUpdatePreparedPlanBinding({
|
|
628
|
+
preparedPlan,
|
|
629
|
+
executor: 'v4',
|
|
630
|
+
platform: payload.platform,
|
|
631
|
+
scopeTargets: componentBindings.map(binding => binding.target),
|
|
632
|
+
bindings: componentBindings,
|
|
633
|
+
});
|
|
634
|
+
}
|
|
590
635
|
}
|
|
591
636
|
|
|
637
|
+
const preparedExpectedTargetVersions = preparedPlan?.artifacts.reduce<
|
|
638
|
+
NonNullable<FirmwareUpdateV4Params['expectedTargetVersions']>
|
|
639
|
+
>((result, artifact) => {
|
|
640
|
+
if (
|
|
641
|
+
artifact.role === 'component' &&
|
|
642
|
+
artifact.target !== 'resource' &&
|
|
643
|
+
artifact.targetVersion &&
|
|
644
|
+
PROTOCOL_V2_INSTALL_TARGET_BY_UPDATE_TARGET.has(
|
|
645
|
+
artifact.target as Exclude<FirmwareUpdateV4Target, 'resource'>
|
|
646
|
+
)
|
|
647
|
+
) {
|
|
648
|
+
result[artifact.target as FirmwareUpdateV4Target] = artifact.targetVersion;
|
|
649
|
+
}
|
|
650
|
+
return result;
|
|
651
|
+
}, {});
|
|
652
|
+
|
|
592
653
|
this.params = {
|
|
593
654
|
preparedPlan,
|
|
594
655
|
chunkSize: payload.chunkSize,
|
|
@@ -602,13 +663,18 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
602
663
|
se02Binary: payload.se02Binary,
|
|
603
664
|
se03Binary: payload.se03Binary,
|
|
604
665
|
se04Binary: payload.se04Binary,
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
666
|
+
resourceArchiveBinary: payload.resourceArchiveBinary,
|
|
667
|
+
firmwareType: preparedPlan?.firmwareType ?? payload.firmwareType,
|
|
668
|
+
targetsToUpdate: preparedPlan
|
|
669
|
+
? ([...preparedPlan.targetsToUpdate] as FirmwareUpdateV4Target[])
|
|
670
|
+
: payload.targetsToUpdate,
|
|
671
|
+
expectedTargetVersions: preparedPlan
|
|
672
|
+
? preparedExpectedTargetVersions
|
|
673
|
+
: payload.expectedTargetVersions,
|
|
608
674
|
platform: payload.platform,
|
|
609
675
|
expectedDeviceId: payload.expectedDeviceId,
|
|
610
676
|
artifactReader: hostBinding?.artifactReader ?? payload.artifactReader,
|
|
611
|
-
componentArtifacts: payload.componentArtifacts,
|
|
677
|
+
componentArtifacts: preparedPlan ? undefined : payload.componentArtifacts,
|
|
612
678
|
};
|
|
613
679
|
}
|
|
614
680
|
|
|
@@ -654,7 +720,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
654
720
|
const firmwareType = this.params.firmwareType ?? deviceFirmwareType;
|
|
655
721
|
this.validateExpectedTargetVersions();
|
|
656
722
|
|
|
657
|
-
|
|
723
|
+
const hasPreparedComponentArtifacts = Object.values(this.params.componentArtifacts ?? {}).some(
|
|
724
|
+
Boolean
|
|
725
|
+
);
|
|
726
|
+
if (this.params.preparedPlan || hasPreparedComponentArtifacts) {
|
|
658
727
|
return this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType);
|
|
659
728
|
}
|
|
660
729
|
const wantsResources = !!this.params.targetsToUpdate?.includes('resource');
|
|
@@ -662,6 +731,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
662
731
|
let fwBinaryMap: ProtocolV2TargetBinary[] = [];
|
|
663
732
|
let bootloaderBinary: ArrayBuffer | null = null;
|
|
664
733
|
let installItems: ProtocolV2InstallItem[] | undefined;
|
|
734
|
+
let resourceBundles: ProtocolV2ResourceBundleBinary[] = [];
|
|
665
735
|
try {
|
|
666
736
|
this.postTipMessage(FirmwareUpdateTipMessage.StartDownloadFirmware);
|
|
667
737
|
fwBinaryMap = this.collectExplicitTargetBinaries();
|
|
@@ -675,12 +745,17 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
675
745
|
? missingFirmwareTargets.length > 0
|
|
676
746
|
: explicitInstallItems.length === 0;
|
|
677
747
|
if (wantsResources) {
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
748
|
+
if (!this.params.resourceArchiveBinary) {
|
|
749
|
+
throw ERRORS.TypedError(
|
|
750
|
+
HardwareErrorCode.RuntimeError,
|
|
751
|
+
'Protocol V2 resource archive must be provided for a local resource update',
|
|
752
|
+
{
|
|
753
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
754
|
+
}
|
|
755
|
+
);
|
|
756
|
+
}
|
|
757
|
+
resourceBundles = await this.prepareProtocolV2LocalResourceArchive(
|
|
758
|
+
this.params.resourceArchiveBinary
|
|
684
759
|
);
|
|
685
760
|
}
|
|
686
761
|
if (
|
|
@@ -726,7 +801,12 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
726
801
|
throw normalizeFirmwarePreparationError(err);
|
|
727
802
|
}
|
|
728
803
|
|
|
729
|
-
if (
|
|
804
|
+
if (
|
|
805
|
+
!bootloaderBinary &&
|
|
806
|
+
fwBinaryMap.length === 0 &&
|
|
807
|
+
!installItems?.length &&
|
|
808
|
+
resourceBundles.length === 0
|
|
809
|
+
) {
|
|
730
810
|
throw ERRORS.TypedError(
|
|
731
811
|
HardwareErrorCode.FirmwareUpdateDownloadFailed,
|
|
732
812
|
'No firmware to update'
|
|
@@ -737,6 +817,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
737
817
|
fwBinaryMap,
|
|
738
818
|
bootloaderBinary,
|
|
739
819
|
...(installItems ? { installItems } : undefined),
|
|
820
|
+
...(resourceBundles.length > 0 ? { resourceBundles } : undefined),
|
|
740
821
|
});
|
|
741
822
|
}
|
|
742
823
|
|
|
@@ -779,6 +860,54 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
779
860
|
firmwareType: EFirmwareType,
|
|
780
861
|
features: Features
|
|
781
862
|
): Promise<ProtocolV2InstallSource[]> {
|
|
863
|
+
if (this.params.preparedPlan) {
|
|
864
|
+
const requestedTargets = new Set(
|
|
865
|
+
this.params.preparedPlan.targetsToUpdate.filter(
|
|
866
|
+
(target): target is Exclude<FirmwareUpdateV4Target, 'resource'> => target !== 'resource'
|
|
867
|
+
)
|
|
868
|
+
);
|
|
869
|
+
const installSources: ProtocolV2InstallSource[] = [];
|
|
870
|
+
const preparedTargets = new Set<Exclude<FirmwareUpdateV4Target, 'resource'>>();
|
|
871
|
+
for (const artifact of this.params.preparedPlan.artifacts) {
|
|
872
|
+
if (artifact.target !== 'resource') {
|
|
873
|
+
const target = artifact.target as Exclude<FirmwareUpdateV4Target, 'resource'>;
|
|
874
|
+
const installTarget = PROTOCOL_V2_INSTALL_TARGET_BY_UPDATE_TARGET.get(target);
|
|
875
|
+
if (
|
|
876
|
+
!requestedTargets.has(target) ||
|
|
877
|
+
artifact.role !== 'component' ||
|
|
878
|
+
artifact.container !== 'raw' ||
|
|
879
|
+
!installTarget ||
|
|
880
|
+
preparedTargets.has(target)
|
|
881
|
+
) {
|
|
882
|
+
throw ERRORS.TypedError(
|
|
883
|
+
HardwareErrorCode.RuntimeError,
|
|
884
|
+
`Protocol V2 prepared component artifact is invalid: ${artifact.artifactId}`,
|
|
885
|
+
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
886
|
+
);
|
|
887
|
+
}
|
|
888
|
+
installSources.push({
|
|
889
|
+
...installTarget,
|
|
890
|
+
source: await this.openProtocolV2PreparedSource(artifact.artifact),
|
|
891
|
+
});
|
|
892
|
+
preparedTargets.add(target);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
const missingTarget = Array.from(requestedTargets).find(
|
|
896
|
+
target => !preparedTargets.has(target)
|
|
897
|
+
);
|
|
898
|
+
if (missingTarget) {
|
|
899
|
+
throw ERRORS.TypedError(
|
|
900
|
+
HardwareErrorCode.RuntimeError,
|
|
901
|
+
`Protocol V2 ${missingTarget} artifact is not prepared`,
|
|
902
|
+
{
|
|
903
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
904
|
+
artifactName: missingTarget,
|
|
905
|
+
}
|
|
906
|
+
);
|
|
907
|
+
}
|
|
908
|
+
return installSources;
|
|
909
|
+
}
|
|
910
|
+
|
|
782
911
|
const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
|
|
783
912
|
if (!release) {
|
|
784
913
|
throw ERRORS.TypedError(
|
|
@@ -828,6 +957,116 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
828
957
|
return installSources;
|
|
829
958
|
}
|
|
830
959
|
|
|
960
|
+
private async prepareProtocolV2LocalResourceArchive(
|
|
961
|
+
binary: ArrayBuffer
|
|
962
|
+
): Promise<ProtocolV2ResourceBundleBinary[]> {
|
|
963
|
+
const zip = await JSZip.loadAsync(binary);
|
|
964
|
+
const entries = Object.values(zip.files).filter(entry => !entry.dir);
|
|
965
|
+
if (entries.length === 0 || entries.length > PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT + 1) {
|
|
966
|
+
throw ERRORS.TypedError(
|
|
967
|
+
HardwareErrorCode.RuntimeError,
|
|
968
|
+
'Protocol V2 local resource ZIP entry set is invalid',
|
|
969
|
+
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
970
|
+
);
|
|
971
|
+
}
|
|
972
|
+
const manifestEntry = zip.file('manifest.json');
|
|
973
|
+
if (!manifestEntry) {
|
|
974
|
+
throw ERRORS.TypedError(
|
|
975
|
+
HardwareErrorCode.RuntimeError,
|
|
976
|
+
'Protocol V2 local resource ZIP has no manifest.json',
|
|
977
|
+
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
978
|
+
);
|
|
979
|
+
}
|
|
980
|
+
const manifestBinary = await manifestEntry.async('arraybuffer');
|
|
981
|
+
if (
|
|
982
|
+
manifestBinary.byteLength <= 0 ||
|
|
983
|
+
manifestBinary.byteLength > PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES
|
|
984
|
+
) {
|
|
985
|
+
throw ERRORS.TypedError(
|
|
986
|
+
HardwareErrorCode.RuntimeError,
|
|
987
|
+
'Protocol V2 local resource manifest size is invalid',
|
|
988
|
+
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
989
|
+
);
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
let manifestValue: unknown;
|
|
993
|
+
try {
|
|
994
|
+
manifestValue = JSON.parse(new TextDecoder().decode(manifestBinary));
|
|
995
|
+
} catch (error) {
|
|
996
|
+
throw ERRORS.TypedError(
|
|
997
|
+
HardwareErrorCode.RuntimeError,
|
|
998
|
+
`Protocol V2 local resource manifest is invalid: ${String(error)}`,
|
|
999
|
+
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
1000
|
+
);
|
|
1001
|
+
}
|
|
1002
|
+
const manifest = parseProtocolV2ResourceManifest(manifestValue);
|
|
1003
|
+
const selectedFiles = selectProtocolV2ResourceManifestFiles({
|
|
1004
|
+
manifest,
|
|
1005
|
+
targetsToUpdate: this.params.targetsToUpdate ?? [],
|
|
1006
|
+
});
|
|
1007
|
+
const expectedEntryNames = new Set([
|
|
1008
|
+
'manifest.json',
|
|
1009
|
+
...selectedFiles.map(file => file.archive_path),
|
|
1010
|
+
]);
|
|
1011
|
+
if (
|
|
1012
|
+
entries.length !== expectedEntryNames.size ||
|
|
1013
|
+
entries.some(entry => !expectedEntryNames.has(entry.name))
|
|
1014
|
+
) {
|
|
1015
|
+
throw ERRORS.TypedError(
|
|
1016
|
+
HardwareErrorCode.RuntimeError,
|
|
1017
|
+
'Protocol V2 local resource ZIP contains an unexpected entry',
|
|
1018
|
+
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
let totalSize = 0;
|
|
1023
|
+
const resourceBundles: ProtocolV2ResourceBundleBinary[] = [];
|
|
1024
|
+
for (const [index, file] of selectedFiles.entries()) {
|
|
1025
|
+
const entry = zip.file(file.archive_path);
|
|
1026
|
+
if (!entry) {
|
|
1027
|
+
throw ERRORS.TypedError(
|
|
1028
|
+
HardwareErrorCode.RuntimeError,
|
|
1029
|
+
`Protocol V2 local resource ZIP is missing ${file.archive_path}`,
|
|
1030
|
+
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
1031
|
+
);
|
|
1032
|
+
}
|
|
1033
|
+
const fileBinary = await entry.async('arraybuffer');
|
|
1034
|
+
const digest = bytesToHex(sha256(new Uint8Array(fileBinary)));
|
|
1035
|
+
if (fileBinary.byteLength !== file.size || digest !== file.sha256.toLowerCase()) {
|
|
1036
|
+
throw ERRORS.TypedError(
|
|
1037
|
+
HardwareErrorCode.RuntimeError,
|
|
1038
|
+
`Protocol V2 local resource file does not match manifest: ${file.archive_path}`,
|
|
1039
|
+
{ firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' }
|
|
1040
|
+
);
|
|
1041
|
+
}
|
|
1042
|
+
totalSize += fileBinary.byteLength;
|
|
1043
|
+
if (totalSize > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
|
|
1044
|
+
throw ERRORS.TypedError(
|
|
1045
|
+
HardwareErrorCode.RuntimeError,
|
|
1046
|
+
'Protocol V2 local resource ZIP exceeds the total size limit',
|
|
1047
|
+
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
1048
|
+
);
|
|
1049
|
+
}
|
|
1050
|
+
const header =
|
|
1051
|
+
fileBinary.byteLength >= PROTOCOL_V2_OKPP_HEADER_SIZE
|
|
1052
|
+
? parseProtocolV2OkppHeader(new Uint8Array(fileBinary))
|
|
1053
|
+
: null;
|
|
1054
|
+
resourceBundles.push({
|
|
1055
|
+
name: file.original_name || `resource-${index}`,
|
|
1056
|
+
binary: fileBinary,
|
|
1057
|
+
devicePath: file.device_path,
|
|
1058
|
+
...(header
|
|
1059
|
+
? {
|
|
1060
|
+
version: header.version,
|
|
1061
|
+
payloadHash: header.payloadHash,
|
|
1062
|
+
headerHash: header.headerHash,
|
|
1063
|
+
}
|
|
1064
|
+
: {}),
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
return resourceBundles;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
831
1070
|
private async prepareProtocolV2ResourceSources(): Promise<ProtocolV2ResourceBundleSource[]> {
|
|
832
1071
|
const resourceRequested = this.params.targetsToUpdate?.includes('resource') ?? false;
|
|
833
1072
|
if (!resourceRequested) {
|
|
@@ -1669,10 +1908,12 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1669
1908
|
fwBinaryMap,
|
|
1670
1909
|
bootloaderBinary,
|
|
1671
1910
|
installItems,
|
|
1911
|
+
resourceBundles = [],
|
|
1672
1912
|
}: {
|
|
1673
1913
|
fwBinaryMap?: ProtocolV2TargetBinary[];
|
|
1674
1914
|
bootloaderBinary?: ArrayBuffer | null;
|
|
1675
1915
|
installItems?: ProtocolV2InstallItem[];
|
|
1916
|
+
resourceBundles?: ProtocolV2ResourceBundleBinary[];
|
|
1676
1917
|
}) {
|
|
1677
1918
|
const memoryInstallItems =
|
|
1678
1919
|
installItems ??
|
|
@@ -1689,9 +1930,19 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1689
1930
|
kind: item.kind,
|
|
1690
1931
|
}))
|
|
1691
1932
|
);
|
|
1933
|
+
const resourceSources = await Promise.all(
|
|
1934
|
+
resourceBundles.map(async resource => ({
|
|
1935
|
+
name: resource.name,
|
|
1936
|
+
source: await this.openProtocolV2MemorySource(resource.binary),
|
|
1937
|
+
devicePath: resource.devicePath,
|
|
1938
|
+
...(resource.version ? { version: resource.version } : {}),
|
|
1939
|
+
...(resource.payloadHash ? { payloadHash: resource.payloadHash } : {}),
|
|
1940
|
+
...(resource.headerHash ? { headerHash: resource.headerHash } : {}),
|
|
1941
|
+
}))
|
|
1942
|
+
);
|
|
1692
1943
|
return await this.executeProtocolV2Phases({
|
|
1693
1944
|
installSources,
|
|
1694
|
-
resourceSources
|
|
1945
|
+
resourceSources,
|
|
1695
1946
|
});
|
|
1696
1947
|
} finally {
|
|
1697
1948
|
await this.closeProtocolV2PreparedSources();
|
|
@@ -6,7 +6,6 @@ import type { CoreApi } from '../../types/api';
|
|
|
6
6
|
import type {
|
|
7
7
|
FirmwareArtifactReader,
|
|
8
8
|
FirmwareArtifactReference,
|
|
9
|
-
FirmwareUpdateV4Target,
|
|
10
9
|
} from '../../types/api/firmwareUpdate';
|
|
11
10
|
import type { FirmwareUpdatePlan } from '../../types/api/firmwareUpdatePlan';
|
|
12
11
|
|
|
@@ -24,33 +23,11 @@ export type FirmwareMemoryArtifact = {
|
|
|
24
23
|
export type FirmwareUpdateV4MemoryHost = {
|
|
25
24
|
preparedPlan: ReturnType<CoreApi['prepareFirmwareUpdatePlan']>;
|
|
26
25
|
hostBindingGeneration: number;
|
|
27
|
-
targetsToUpdate: FirmwareUpdateV4Target[];
|
|
28
|
-
expectedDeviceId: string;
|
|
29
|
-
expectedTargetVersions: Partial<Record<FirmwareUpdateV4Target, string>>;
|
|
30
|
-
componentArtifacts: Partial<
|
|
31
|
-
Record<Exclude<FirmwareUpdateV4Target, 'resource'>, FirmwareArtifactReference>
|
|
32
|
-
>;
|
|
33
26
|
release: () => void;
|
|
34
27
|
};
|
|
35
28
|
|
|
36
29
|
let memoryHostSequence = 0;
|
|
37
30
|
|
|
38
|
-
const FIRMWARE_UPDATE_V4_COMPONENT_TARGETS = new Set<Exclude<FirmwareUpdateV4Target, 'resource'>>([
|
|
39
|
-
'boot',
|
|
40
|
-
'app_v1',
|
|
41
|
-
'app_v2',
|
|
42
|
-
'coprocessor',
|
|
43
|
-
'se01',
|
|
44
|
-
'se02',
|
|
45
|
-
'se03',
|
|
46
|
-
'se04',
|
|
47
|
-
]);
|
|
48
|
-
|
|
49
|
-
const isFirmwareUpdateV4ComponentTarget = (
|
|
50
|
-
target: string
|
|
51
|
-
): target is Exclude<FirmwareUpdateV4Target, 'resource'> =>
|
|
52
|
-
FIRMWARE_UPDATE_V4_COMPONENT_TARGETS.has(target as Exclude<FirmwareUpdateV4Target, 'resource'>);
|
|
53
|
-
|
|
54
31
|
const createReference = (binary: ArrayBuffer, prefix: string): FirmwareArtifactReference => {
|
|
55
32
|
const digest = bytesToHex(sha256(new Uint8Array(binary)));
|
|
56
33
|
return {
|
|
@@ -148,23 +125,9 @@ export function prepareFirmwareUpdateV4MemoryHost({
|
|
|
148
125
|
artifactReader,
|
|
149
126
|
preparedPlanDigest: preparedPlan.preparedPlanDigest,
|
|
150
127
|
});
|
|
151
|
-
const componentArtifacts: FirmwareUpdateV4MemoryHost['componentArtifacts'] = {};
|
|
152
|
-
const expectedTargetVersions: FirmwareUpdateV4MemoryHost['expectedTargetVersions'] = {};
|
|
153
|
-
for (const artifact of preparedPlan.artifacts) {
|
|
154
|
-
if (artifact.role === 'component' && isFirmwareUpdateV4ComponentTarget(artifact.target)) {
|
|
155
|
-
componentArtifacts[artifact.target] = artifact.artifact;
|
|
156
|
-
}
|
|
157
|
-
if (artifact.targetVersion) {
|
|
158
|
-
expectedTargetVersions[artifact.target as FirmwareUpdateV4Target] = artifact.targetVersion;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
128
|
return {
|
|
162
129
|
preparedPlan,
|
|
163
130
|
hostBindingGeneration,
|
|
164
|
-
targetsToUpdate: [...preparedPlan.targetsToUpdate] as FirmwareUpdateV4Target[],
|
|
165
|
-
expectedDeviceId: preparedPlan.deviceIdentity,
|
|
166
|
-
expectedTargetVersions,
|
|
167
|
-
componentArtifacts,
|
|
168
131
|
release: () => {
|
|
169
132
|
sdk.unregisterFirmwareUpdateHostBinding(hostBindingGeneration);
|
|
170
133
|
readers.clear();
|
|
@@ -154,6 +154,8 @@ export interface FirmwareUpdateV4Params {
|
|
|
154
154
|
se02Binary?: ArrayBuffer;
|
|
155
155
|
se03Binary?: ArrayBuffer;
|
|
156
156
|
se04Binary?: ArrayBuffer;
|
|
157
|
+
/** Complete Protocol V2 resource ZIP for local development; never bound to a remote Plan. */
|
|
158
|
+
resourceArchiveBinary?: ArrayBuffer;
|
|
157
159
|
forcedUpdateRes?: boolean;
|
|
158
160
|
artifactReader?: FirmwareArtifactReader;
|
|
159
161
|
componentArtifacts?: Partial<
|