@onekeyfe/hd-core 1.2.0-alpha.97 → 1.2.0-alpha.98
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 +404 -84
- package/__tests__/check-firmware-release-protocol-v2.test.ts +199 -0
- package/__tests__/firmware-memory-host.test.ts +112 -0
- package/__tests__/firmware-update/device-update-bootloader.test.ts +13 -2
- package/__tests__/firmware-update/firmware-host-binding.test.ts +9 -0
- package/__tests__/firmware-update/firmware-prepared-host-digest.test.ts +573 -0
- package/__tests__/firmware-update/firmware-prepared-resource-archive.test.ts +150 -0
- package/__tests__/firmware-update/firmware-update-plan.test.ts +232 -70
- package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +53 -1
- package/__tests__/firmware-update/firmware-update-prepared-resource-executors.test.ts +326 -0
- package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +2 -2
- package/__tests__/protocol-v2-resources.test.ts +148 -232
- package/__tests__/protocol-v2.test.ts +1236 -516
- package/dist/api/CheckAllFirmwareRelease.d.ts +2 -3
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/CheckBLEFirmwareRelease.d.ts +3 -2
- package/dist/api/CheckBLEFirmwareRelease.d.ts.map +1 -1
- package/dist/api/CheckBootloaderRelease.d.ts +2 -1
- package/dist/api/CheckBootloaderRelease.d.ts.map +1 -1
- package/dist/api/CheckFirmwareRelease.d.ts +3 -2
- package/dist/api/CheckFirmwareRelease.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV2.d.ts +1 -0
- package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +8 -8
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/UploadPortfolio.d.ts.map +1 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareHostBinding.d.ts +1 -1
- package/dist/api/firmware/FirmwareHostBinding.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareMemoryHost.d.ts +22 -0
- package/dist/api/firmware/FirmwareMemoryHost.d.ts.map +1 -0
- package/dist/api/firmware/FirmwarePreparedResourceArchive.d.ts +11 -0
- package/dist/api/firmware/FirmwarePreparedResourceArchive.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +48 -1
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +6 -1
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -1
- package/dist/api/firmware/getBinary.d.ts +0 -1
- package/dist/api/firmware/getBinary.d.ts.map +1 -1
- package/dist/api/firmware/protocolV2Release.d.ts +33 -0
- package/dist/api/firmware/protocolV2Release.d.ts.map +1 -0
- package/dist/data-manager/DataManager.d.ts +4 -3
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/index.d.ts +108 -114
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1633 -967
- package/dist/protocols/protocol-v2/resources.d.ts +10 -28
- package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
- package/dist/types/api/checkAllFirmwareRelease.d.ts +20 -8
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/checkBLEFirmwareRelease.d.ts +2 -13
- package/dist/types/api/checkBLEFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/checkBootloaderRelease.d.ts +2 -6
- package/dist/types/api/checkBootloaderRelease.d.ts.map +1 -1
- package/dist/types/api/checkFirmwareRelease.d.ts +2 -13
- package/dist/types/api/checkFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/checkFirmwareTypeAvailable.d.ts +2 -2
- package/dist/types/api/checkFirmwareTypeAvailable.d.ts.map +1 -1
- package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
- package/dist/types/api/export.d.ts +1 -1
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdate.d.ts +4 -12
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdatePlan.d.ts +2 -2
- package/dist/types/api/firmwareUpdatePlan.d.ts.map +1 -1
- package/dist/types/settings.d.ts +35 -36
- package/dist/types/settings.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/CheckAllFirmwareRelease.ts +108 -80
- package/src/api/CheckBLEFirmwareRelease.ts +37 -5
- package/src/api/CheckBootloaderRelease.ts +35 -3
- package/src/api/CheckFirmwareRelease.ts +35 -7
- package/src/api/FirmwareUpdateV2.ts +108 -73
- package/src/api/FirmwareUpdateV3.ts +101 -56
- package/src/api/FirmwareUpdateV4.ts +885 -403
- package/src/api/UploadPortfolio.ts +18 -0
- package/src/api/device/DeviceUpdateBootloader.ts +37 -11
- package/src/api/firmware/FirmwareHostBinding.ts +16 -3
- package/src/api/firmware/FirmwareMemoryHost.ts +142 -0
- package/src/api/firmware/FirmwarePreparedResourceArchive.ts +207 -0
- package/src/api/firmware/FirmwareUpdatePlan.ts +282 -122
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +27 -3
- package/src/api/firmware/protocolV2Release.ts +168 -0
- package/src/data-manager/DataManager.ts +35 -19
- package/src/index.ts +10 -0
- package/src/protocols/protocol-v2/resources.ts +157 -341
- package/src/types/api/checkAllFirmwareRelease.ts +27 -12
- package/src/types/api/checkBLEFirmwareRelease.ts +4 -13
- package/src/types/api/checkBootloaderRelease.ts +2 -6
- package/src/types/api/checkFirmwareRelease.ts +2 -13
- package/src/types/api/checkFirmwareTypeAvailable.ts +2 -2
- package/src/types/api/deviceUpdateBootloader.ts +1 -0
- package/src/types/api/export.ts +6 -1
- package/src/types/api/firmwareUpdate.ts +12 -17
- package/src/types/api/firmwareUpdatePlan.ts +2 -2
- package/src/types/settings.ts +35 -61
- package/src/utils/deviceFeaturesUtils.ts +2 -2
package/dist/index.js
CHANGED
|
@@ -522,6 +522,10 @@ const PROTOCOL_V2_TARGETS = {
|
|
|
522
522
|
SE03: 'se03',
|
|
523
523
|
SE04: 'se04',
|
|
524
524
|
};
|
|
525
|
+
const PROTOCOL_V2_FIRMWARE_UPDATE_TARGETS = new Set([
|
|
526
|
+
...Object.values(PROTOCOL_V2_TARGETS),
|
|
527
|
+
'resource',
|
|
528
|
+
]);
|
|
525
529
|
const asRecord = (value) => value && typeof value === 'object' && !Array.isArray(value)
|
|
526
530
|
? value
|
|
527
531
|
: undefined;
|
|
@@ -591,6 +595,16 @@ const planError = (message) => {
|
|
|
591
595
|
firmwareUpdateCode: 'FirmwarePlanInvalid',
|
|
592
596
|
});
|
|
593
597
|
};
|
|
598
|
+
const requireArtifactIntegrity = (input, label) => {
|
|
599
|
+
const integrity = asIntegrity(input);
|
|
600
|
+
if (integrity.expectedSize === undefined || integrity.expectedSha256 === undefined) {
|
|
601
|
+
return planError(`${label} integrity metadata is invalid`);
|
|
602
|
+
}
|
|
603
|
+
return {
|
|
604
|
+
expectedSize: integrity.expectedSize,
|
|
605
|
+
expectedSha256: integrity.expectedSha256,
|
|
606
|
+
};
|
|
607
|
+
};
|
|
594
608
|
const FIRMWARE_UPDATE_PLAN_FORCE_TARGETS = new Set([
|
|
595
609
|
'firmware',
|
|
596
610
|
'ble',
|
|
@@ -609,6 +623,18 @@ const validateFirmwareUpdatePlanForceTargets = (value) => {
|
|
|
609
623
|
}
|
|
610
624
|
return [...value];
|
|
611
625
|
};
|
|
626
|
+
const validateProtocolV2FirmwareUpdateTargets = (value) => {
|
|
627
|
+
if (value === undefined) {
|
|
628
|
+
return [];
|
|
629
|
+
}
|
|
630
|
+
if (!Array.isArray(value) ||
|
|
631
|
+
value.length > PROTOCOL_V2_FIRMWARE_UPDATE_TARGETS.size ||
|
|
632
|
+
value.some(target => !PROTOCOL_V2_FIRMWARE_UPDATE_TARGETS.has(target)) ||
|
|
633
|
+
new Set(value).size !== value.length) {
|
|
634
|
+
return planError('Protocol V2 firmware update targets are invalid');
|
|
635
|
+
}
|
|
636
|
+
return [...value];
|
|
637
|
+
};
|
|
612
638
|
const assertExactKeys = (value, required, optional = []) => {
|
|
613
639
|
const allowed = new Set([...required, ...optional]);
|
|
614
640
|
if (required.some(key => !Object.prototype.hasOwnProperty.call(value, key)) ||
|
|
@@ -689,7 +715,7 @@ const assertFirmwareUpdatePlan = (value) => {
|
|
|
689
715
|
if (!artifact) {
|
|
690
716
|
return planError('Firmware update plan artifact is invalid');
|
|
691
717
|
}
|
|
692
|
-
assertExactKeys(artifact, ['artifactId', 'role', 'target', 'url', 'container'
|
|
718
|
+
assertExactKeys(artifact, ['artifactId', 'role', 'target', 'url', 'container', 'expectedSize', 'expectedSha256'], ['logicalName', 'targetVersion']);
|
|
693
719
|
const artifactId = assertBoundedString(artifact.artifactId, 'artifact id', 160);
|
|
694
720
|
if (artifactIds.has(artifactId)) {
|
|
695
721
|
return planError('Firmware update plan contains duplicate artifact ids');
|
|
@@ -705,13 +731,11 @@ const assertFirmwareUpdatePlan = (value) => {
|
|
|
705
731
|
if (artifact.logicalName !== undefined) {
|
|
706
732
|
assertBoundedString(artifact.logicalName, 'logical name', 256);
|
|
707
733
|
}
|
|
708
|
-
if (artifact.expectedSize
|
|
709
|
-
(!Number.isSafeInteger(artifact.expectedSize) || artifact.expectedSize <= 0)) {
|
|
734
|
+
if (!Number.isSafeInteger(artifact.expectedSize) || artifact.expectedSize <= 0) {
|
|
710
735
|
return planError('Firmware update plan artifact size is invalid');
|
|
711
736
|
}
|
|
712
|
-
if (artifact.expectedSha256 !==
|
|
713
|
-
(
|
|
714
|
-
!/^[a-f0-9]{64}$/u.test(artifact.expectedSha256))) {
|
|
737
|
+
if (typeof artifact.expectedSha256 !== 'string' ||
|
|
738
|
+
!/^[a-f0-9]{64}$/u.test(artifact.expectedSha256)) {
|
|
715
739
|
return planError('Firmware update plan artifact digest is invalid');
|
|
716
740
|
}
|
|
717
741
|
if (artifact.targetVersion !== undefined) {
|
|
@@ -738,7 +762,7 @@ const assertFirmwareUpdatePlan = (value) => {
|
|
|
738
762
|
plan.targetsToUpdate.some(target => legacyOnlyTargets.has(target))) ||
|
|
739
763
|
(plan.artifacts.length > 0 &&
|
|
740
764
|
(plan.platform === 'native' || plan.platform === 'desktop') &&
|
|
741
|
-
plan.executor
|
|
765
|
+
plan.executor === 'v3' &&
|
|
742
766
|
plan.deviceIdentity === 'unavailable')) {
|
|
743
767
|
return planError('Firmware update plan executor contract is invalid');
|
|
744
768
|
}
|
|
@@ -773,7 +797,7 @@ const selectResourceUrl = ({ release, features, platform, }) => {
|
|
|
773
797
|
};
|
|
774
798
|
const getExecutor = (features) => {
|
|
775
799
|
const deviceType = getDeviceType(features);
|
|
776
|
-
if (deviceType === hdShared.EDeviceType.Pro2) {
|
|
800
|
+
if (deviceType === hdShared.EDeviceType.Pro2 || deviceType === hdShared.EDeviceType.Neo) {
|
|
777
801
|
return 'v4';
|
|
778
802
|
}
|
|
779
803
|
if (deviceType === hdShared.EDeviceType.Pro &&
|
|
@@ -782,7 +806,7 @@ const getExecutor = (features) => {
|
|
|
782
806
|
}
|
|
783
807
|
return 'v2';
|
|
784
808
|
};
|
|
785
|
-
const buildProtocolV2Artifacts = (release, { includeComponents = true,
|
|
809
|
+
const buildProtocolV2Artifacts = (release, { includeComponents = true, componentTargets: selectedComponentTargets, } = {}) => {
|
|
786
810
|
var _a;
|
|
787
811
|
const components = asRecord(release.components);
|
|
788
812
|
if (includeComponents && !components) {
|
|
@@ -794,49 +818,36 @@ const buildProtocolV2Artifacts = (release, { includeComponents = true, includeRe
|
|
|
794
818
|
const componentKeys = includeComponents && components
|
|
795
819
|
? [...installOrder, ...Object.keys(components).filter(key => !installOrder.includes(key))]
|
|
796
820
|
: [];
|
|
821
|
+
const selectedComponentKeys = selectedComponentTargets
|
|
822
|
+
? componentKeys.filter(key => {
|
|
823
|
+
var _a;
|
|
824
|
+
const component = asRecord(components === null || components === void 0 ? void 0 : components[key]);
|
|
825
|
+
const targetName = (_a = asString(component === null || component === void 0 ? void 0 : component.target)) === null || _a === void 0 ? void 0 : _a.toUpperCase();
|
|
826
|
+
const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
|
|
827
|
+
return !!target && selectedComponentTargets.has(target);
|
|
828
|
+
})
|
|
829
|
+
: componentKeys;
|
|
797
830
|
const artifacts = [];
|
|
798
831
|
const targets = [];
|
|
799
|
-
const
|
|
800
|
-
for (const key of
|
|
832
|
+
const componentTargetSet = new Set();
|
|
833
|
+
for (const key of selectedComponentKeys) {
|
|
801
834
|
const component = asRecord(components === null || components === void 0 ? void 0 : components[key]);
|
|
802
835
|
const targetName = (_a = asString(component === null || component === void 0 ? void 0 : component.target)) === null || _a === void 0 ? void 0 : _a.toUpperCase();
|
|
836
|
+
const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
|
|
803
837
|
if (targetName === 'ROMLOADER') {
|
|
804
838
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 ROMLOADER requires its dedicated loader flow', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
805
839
|
}
|
|
806
|
-
const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
|
|
807
840
|
if (!component || !target) {
|
|
808
841
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 component ${key} has an unsupported target`, { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
809
842
|
}
|
|
810
|
-
if (
|
|
843
|
+
if (componentTargetSet.has(target)) {
|
|
811
844
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 component ${key} duplicates target ${target}`, { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
812
845
|
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
sha256: component.fingerprint,
|
|
817
|
-
})), (asVersion(component.version) ? { targetVersion: asVersion(component.version) } : {})));
|
|
846
|
+
componentTargetSet.add(target);
|
|
847
|
+
const integrity = requireArtifactIntegrity({ size: component.expectedSize, sha256: component.fingerprint }, `Protocol V2 component ${key}`);
|
|
848
|
+
artifacts.push(Object.assign(Object.assign({ artifactId: `component:${target}`, role: 'component', target, url: assertArtifactUrl(component.url, `Protocol V2 component ${key}`), container: 'raw', logicalName: key }, integrity), (asVersion(component.version) ? { targetVersion: asVersion(component.version) } : {})));
|
|
818
849
|
targets.push(target);
|
|
819
850
|
}
|
|
820
|
-
const bundles = includeResources && Array.isArray(release.resourceBundles) ? release.resourceBundles : [];
|
|
821
|
-
const resourceBundleNames = new Set();
|
|
822
|
-
for (const value of bundles) {
|
|
823
|
-
const bundle = asRecord(value);
|
|
824
|
-
const name = asString(bundle === null || bundle === void 0 ? void 0 : bundle.name);
|
|
825
|
-
if (!bundle || !name) {
|
|
826
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource bundle is invalid', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
827
|
-
}
|
|
828
|
-
if (resourceBundleNames.has(name)) {
|
|
829
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 resource bundle duplicates name ${name}`, { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
830
|
-
}
|
|
831
|
-
resourceBundleNames.add(name);
|
|
832
|
-
artifacts.push(Object.assign({ artifactId: `resourceBundle:${name}`, role: 'resourceBundle', target: 'resource', url: assertArtifactUrl(bundle.url, `Protocol V2 resource bundle ${name}`), container: 'raw', logicalName: name }, asIntegrity({
|
|
833
|
-
size: bundle.expectedSize,
|
|
834
|
-
sha256: bundle.fingerprint,
|
|
835
|
-
})));
|
|
836
|
-
}
|
|
837
|
-
if (bundles.length > 0) {
|
|
838
|
-
targets.push('resource');
|
|
839
|
-
}
|
|
840
851
|
return { artifacts, targets: [...new Set(targets)] };
|
|
841
852
|
};
|
|
842
853
|
const isForcedTargetRepresented = ({ executor, forcedTarget, artifacts, targetsToUpdate, }) => {
|
|
@@ -865,8 +876,91 @@ const assertForcedTargetsRepresented = ({ executor, forcedTargets, artifacts, ta
|
|
|
865
876
|
}
|
|
866
877
|
}
|
|
867
878
|
};
|
|
879
|
+
const finalizeFirmwareUpdatePlan = ({ features, firmwareType, platform, artifacts, targetsToUpdate, }) => {
|
|
880
|
+
const executor = getExecutor(features);
|
|
881
|
+
const bootloaderMode = resolveDeviceBootloaderMode(features);
|
|
882
|
+
const reportedIdentity = getDeviceUUID(features);
|
|
883
|
+
const deviceIdentity = reportedIdentity === 'unavailable' ? '' : reportedIdentity;
|
|
884
|
+
const allowsUnavailableIdentity = (bootloaderMode && executor === 'v2') || executor === 'v4';
|
|
885
|
+
if (artifacts.length > 0 &&
|
|
886
|
+
(platform === 'native' || platform === 'desktop') &&
|
|
887
|
+
!deviceIdentity &&
|
|
888
|
+
!allowsUnavailableIdentity) {
|
|
889
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Prepared firmware update requires a stable device identity', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
890
|
+
}
|
|
891
|
+
const planWithoutDigest = {
|
|
892
|
+
schemaVersion: 2,
|
|
893
|
+
executor,
|
|
894
|
+
deviceIdentity: deviceIdentity || 'unavailable',
|
|
895
|
+
deviceModel: String(getDeviceType(features)),
|
|
896
|
+
firmwareType,
|
|
897
|
+
platform,
|
|
898
|
+
artifacts,
|
|
899
|
+
targetsToUpdate,
|
|
900
|
+
};
|
|
901
|
+
return assertFirmwareUpdatePlan(Object.assign(Object.assign({}, planWithoutDigest), { planDigest: digestFirmwareUpdatePlan(planWithoutDigest) }));
|
|
902
|
+
};
|
|
903
|
+
const buildProtocolV2LocalFirmwareUpdatePlan = ({ features, firmwareType, platform, artifacts, }) => {
|
|
904
|
+
if (artifacts.length === 0) {
|
|
905
|
+
return planError('Protocol V2 local firmware plan has no artifacts');
|
|
906
|
+
}
|
|
907
|
+
const plan = finalizeFirmwareUpdatePlan({
|
|
908
|
+
features,
|
|
909
|
+
firmwareType,
|
|
910
|
+
platform,
|
|
911
|
+
artifacts: artifacts.map(artifact => (Object.assign(Object.assign({}, artifact), { role: artifact.target === 'resource' ? 'resourceBundle' : 'component', url: `https://local-firmware.invalid/${encodeURIComponent(artifact.artifactId)}` }))),
|
|
912
|
+
targetsToUpdate: artifacts.map(artifact => artifact.target),
|
|
913
|
+
});
|
|
914
|
+
if (plan.executor !== 'v4') {
|
|
915
|
+
return planError('Protocol V2 local firmware plan requires executor v4');
|
|
916
|
+
}
|
|
917
|
+
return plan;
|
|
918
|
+
};
|
|
919
|
+
const buildProtocolV2FirmwareUpdatePlan = ({ features, firmwareType, platform, release, targetsToUpdate, forceUpdateTargets, resourceArchive, }) => {
|
|
920
|
+
const validatedForceTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
|
|
921
|
+
if (validatedForceTargets.some(target => target === 'ble' || target === 'bootloader')) {
|
|
922
|
+
planError('Protocol V2 does not support forced BLE or legacy bootloader targets');
|
|
923
|
+
}
|
|
924
|
+
const requestedComponentTargets = new Set(targetsToUpdate.filter(target => target !== 'resource'));
|
|
925
|
+
if (getDeviceType(features) === hdShared.EDeviceType.Neo &&
|
|
926
|
+
(requestedComponentTargets.has('se03') || requestedComponentTargets.has('se04'))) {
|
|
927
|
+
planError('Neo does not support Protocol V2 targets se03 or se04');
|
|
928
|
+
}
|
|
929
|
+
const protocolV2 = buildProtocolV2Artifacts(release !== null && release !== void 0 ? release : {}, {
|
|
930
|
+
includeComponents: requestedComponentTargets.size > 0,
|
|
931
|
+
componentTargets: requestedComponentTargets,
|
|
932
|
+
});
|
|
933
|
+
const resourceRequested = targetsToUpdate.includes('resource');
|
|
934
|
+
if (resourceRequested) {
|
|
935
|
+
const archive = resourceArchive;
|
|
936
|
+
if (!archive) {
|
|
937
|
+
return planError('Protocol V2 resource target has no resource archive');
|
|
938
|
+
}
|
|
939
|
+
const integrity = requireArtifactIntegrity({ size: archive.archiveSize, sha256: archive.archiveSha256 }, 'Protocol V2 resource archive');
|
|
940
|
+
protocolV2.artifacts.push(Object.assign({ artifactId: 'resource:archive', role: 'resourceBundle', target: 'resource', url: assertArtifactUrl(archive.archiveUrl, 'Protocol V2 resource archive'), container: 'zip', logicalName: 'protocol-v2-resource-archive' }, integrity));
|
|
941
|
+
protocolV2.targets.push('resource');
|
|
942
|
+
}
|
|
943
|
+
const representedTargets = new Set(protocolV2.targets);
|
|
944
|
+
const missingTarget = Array.from(requestedComponentTargets).find(target => !representedTargets.has(target));
|
|
945
|
+
if (missingTarget) {
|
|
946
|
+
planError(`Protocol V2 release does not contain requested target ${missingTarget}`);
|
|
947
|
+
}
|
|
948
|
+
if (validatedForceTargets.includes('firmware') && protocolV2.targets.length === 0) {
|
|
949
|
+
planError('Forced firmware update target firmware is not represented by the plan');
|
|
950
|
+
}
|
|
951
|
+
if (validatedForceTargets.includes('resource') && !resourceArchive) {
|
|
952
|
+
planError('Forced firmware update target resource has no Protocol V2 resource archive');
|
|
953
|
+
}
|
|
954
|
+
return finalizeFirmwareUpdatePlan({
|
|
955
|
+
features,
|
|
956
|
+
firmwareType,
|
|
957
|
+
platform,
|
|
958
|
+
artifacts: protocolV2.artifacts,
|
|
959
|
+
targetsToUpdate: protocolV2.targets,
|
|
960
|
+
});
|
|
961
|
+
};
|
|
868
962
|
const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, ble, bootloader, forceUpdateTargets, }) => {
|
|
869
|
-
var _a, _b
|
|
963
|
+
var _a, _b;
|
|
870
964
|
const executor = getExecutor(features);
|
|
871
965
|
let artifacts = [];
|
|
872
966
|
let targetsToUpdate = [];
|
|
@@ -878,7 +972,8 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
|
|
|
878
972
|
((release === null || release === void 0 ? void 0 : release.status) === 'none' || (release === null || release === void 0 ? void 0 : release.status) === 'unknown') &&
|
|
879
973
|
!!asRelease(release);
|
|
880
974
|
const shouldUpdateFirmware = isUpgrade(firmware) || isRecoveryInstall(firmware) || forcedTargets.has('firmware');
|
|
881
|
-
const shouldUpdateResource =
|
|
975
|
+
const shouldUpdateResource = !(executor === 'v2' && bootloaderMode) &&
|
|
976
|
+
(isUpgrade(firmware) || forcedTargets.has('resource'));
|
|
882
977
|
if (executor === 'v4' &&
|
|
883
978
|
validatedForceTargets.some(target => target === 'ble' || target === 'bootloader')) {
|
|
884
979
|
planError('Protocol V2 does not support forced BLE or legacy bootloader targets');
|
|
@@ -886,19 +981,20 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
|
|
|
886
981
|
if (executor === 'v4' && (shouldUpdateFirmware || shouldUpdateResource)) {
|
|
887
982
|
const protocolV2 = buildProtocolV2Artifacts(firmwareRelease !== null && firmwareRelease !== void 0 ? firmwareRelease : {}, {
|
|
888
983
|
includeComponents: shouldUpdateFirmware,
|
|
889
|
-
includeResources: shouldUpdateResource,
|
|
890
984
|
});
|
|
891
985
|
artifacts = protocolV2.artifacts;
|
|
892
986
|
targetsToUpdate = protocolV2.targets;
|
|
893
987
|
}
|
|
894
988
|
else {
|
|
895
989
|
if (isUpgrade(bootloader) || forcedTargets.has('bootloader')) {
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
990
|
+
const bootloaderRelease = asRelease(bootloader);
|
|
991
|
+
const integrity = requireArtifactIntegrity({
|
|
992
|
+
size: bootloaderRelease === null || bootloaderRelease === void 0 ? void 0 : bootloaderRelease.bootloaderExpectedSize,
|
|
993
|
+
sha256: bootloaderRelease === null || bootloaderRelease === void 0 ? void 0 : bootloaderRelease.bootloaderFingerprint,
|
|
994
|
+
}, 'Bootloader release');
|
|
995
|
+
artifacts.push(Object.assign(Object.assign({ artifactId: 'bootloader', role: 'bootloader', target: 'bootloader', url: assertArtifactUrl(bootloaderRelease === null || bootloaderRelease === void 0 ? void 0 : bootloaderRelease.bootloaderResource, 'Bootloader release'), container: 'raw' }, integrity), (asVersion(bootloaderRelease === null || bootloaderRelease === void 0 ? void 0 : bootloaderRelease.bootloaderVersion)
|
|
900
996
|
? {
|
|
901
|
-
targetVersion: asVersion(
|
|
997
|
+
targetVersion: asVersion(bootloaderRelease === null || bootloaderRelease === void 0 ? void 0 : bootloaderRelease.bootloaderVersion),
|
|
902
998
|
}
|
|
903
999
|
: {})));
|
|
904
1000
|
}
|
|
@@ -909,10 +1005,8 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
|
|
|
909
1005
|
});
|
|
910
1006
|
}
|
|
911
1007
|
if (shouldUpdateFirmware) {
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
sha256: firmwareRelease.fingerprint,
|
|
915
|
-
})), (asVersion(firmwareRelease.version)
|
|
1008
|
+
const integrity = requireArtifactIntegrity({ size: firmwareRelease.expectedSize, sha256: firmwareRelease.fingerprint }, 'Firmware release');
|
|
1009
|
+
artifacts.push(Object.assign(Object.assign({ artifactId: 'firmware', role: 'firmware', target: 'firmware', url: assertArtifactUrl(firmwareRelease.url, 'Firmware release'), container: 'raw' }, integrity), (asVersion(firmwareRelease.version)
|
|
916
1010
|
? { targetVersion: asVersion(firmwareRelease.version) }
|
|
917
1011
|
: {})));
|
|
918
1012
|
}
|
|
@@ -923,23 +1017,25 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
|
|
|
923
1017
|
platform,
|
|
924
1018
|
});
|
|
925
1019
|
if (resourceUrl) {
|
|
926
|
-
|
|
1020
|
+
const integrity = requireArtifactIntegrity({
|
|
927
1021
|
size: resourceUrl === asString(firmwareRelease.fullResource)
|
|
928
1022
|
? firmwareRelease.fullResourceExpectedSize
|
|
929
1023
|
: firmwareRelease.resourceExpectedSize,
|
|
930
1024
|
sha256: resourceUrl === asString(firmwareRelease.fullResource)
|
|
931
1025
|
? firmwareRelease.fullResourceFingerprint
|
|
932
1026
|
: firmwareRelease.resourceFingerprint,
|
|
933
|
-
})
|
|
1027
|
+
}, 'Legacy resource archive');
|
|
1028
|
+
artifacts.push(Object.assign({ artifactId: 'resource', role: 'resource', target: 'resource', url: assertArtifactUrl(resourceUrl, 'Firmware resource release'), container: 'zip' }, integrity));
|
|
934
1029
|
}
|
|
935
1030
|
}
|
|
936
1031
|
}
|
|
937
1032
|
if (isUpgrade(ble) || isRecoveryInstall(ble) || forcedTargets.has('ble')) {
|
|
938
1033
|
const bleRelease = asRelease(ble);
|
|
939
|
-
|
|
1034
|
+
const integrity = requireArtifactIntegrity({
|
|
940
1035
|
size: bleRelease === null || bleRelease === void 0 ? void 0 : bleRelease.expectedSize,
|
|
941
|
-
sha256: (
|
|
942
|
-
}
|
|
1036
|
+
sha256: (_a = bleRelease === null || bleRelease === void 0 ? void 0 : bleRelease.fingerprintWeb) !== null && _a !== void 0 ? _a : bleRelease === null || bleRelease === void 0 ? void 0 : bleRelease.fingerprint,
|
|
1037
|
+
}, 'BLE release');
|
|
1038
|
+
artifacts.push(Object.assign(Object.assign({ artifactId: 'ble', role: 'ble', target: 'ble', url: assertArtifactUrl((_b = bleRelease === null || bleRelease === void 0 ? void 0 : bleRelease.webUpdate) !== null && _b !== void 0 ? _b : bleRelease === null || bleRelease === void 0 ? void 0 : bleRelease.url, 'BLE release'), container: 'raw' }, integrity), (asVersion(bleRelease === null || bleRelease === void 0 ? void 0 : bleRelease.version)
|
|
943
1039
|
? { targetVersion: asVersion(bleRelease === null || bleRelease === void 0 ? void 0 : bleRelease.version) }
|
|
944
1040
|
: {})));
|
|
945
1041
|
}
|
|
@@ -951,25 +1047,13 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
|
|
|
951
1047
|
artifacts,
|
|
952
1048
|
targetsToUpdate,
|
|
953
1049
|
});
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
if (artifacts.length > 0 &&
|
|
957
|
-
(platform === 'native' || platform === 'desktop') &&
|
|
958
|
-
!deviceIdentity &&
|
|
959
|
-
!(bootloaderMode && executor === 'v2')) {
|
|
960
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Prepared firmware update requires a stable device identity', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
961
|
-
}
|
|
962
|
-
const planWithoutDigest = {
|
|
963
|
-
schemaVersion: 2,
|
|
964
|
-
executor,
|
|
965
|
-
deviceIdentity: deviceIdentity || 'unavailable',
|
|
966
|
-
deviceModel: String(getDeviceType(features)),
|
|
1050
|
+
return finalizeFirmwareUpdatePlan({
|
|
1051
|
+
features,
|
|
967
1052
|
firmwareType,
|
|
968
1053
|
platform,
|
|
969
1054
|
artifacts,
|
|
970
1055
|
targetsToUpdate,
|
|
971
|
-
};
|
|
972
|
-
return assertFirmwareUpdatePlan(Object.assign(Object.assign({}, planWithoutDigest), { planDigest: digestFirmwareUpdatePlan(planWithoutDigest) }));
|
|
1056
|
+
});
|
|
973
1057
|
};
|
|
974
1058
|
|
|
975
1059
|
const preparedPlanError = (message) => {
|
|
@@ -1090,7 +1174,7 @@ const prepareFirmwareUpdatePlan = ({ plan: value, leaseRef, artifacts, }) => {
|
|
|
1090
1174
|
return Object.assign(Object.assign({}, planWithoutDigest), { preparedPlanDigest: digestPreparedPlan(planWithoutDigest) });
|
|
1091
1175
|
};
|
|
1092
1176
|
const validateFirmwareUpdatePreparedPlan = (value) => {
|
|
1093
|
-
var _a, _b, _c;
|
|
1177
|
+
var _a, _b, _c, _d;
|
|
1094
1178
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
1095
1179
|
return preparedPlanError('Firmware prepared plan must be an object');
|
|
1096
1180
|
}
|
|
@@ -1170,7 +1254,13 @@ const validateFirmwareUpdatePreparedPlan = (value) => {
|
|
|
1170
1254
|
artifactIds.add(artifact.artifactId);
|
|
1171
1255
|
artifactTargets.add(artifact.target);
|
|
1172
1256
|
assertFirmwareArtifactReference(artifact.artifact);
|
|
1173
|
-
(_c = artifact.materializedEntries) === null || _c === void 0 ? void 0 : _c.
|
|
1257
|
+
const materializedEntryNames = (_d = (_c = artifact.materializedEntries) === null || _c === void 0 ? void 0 : _c.map(entry => {
|
|
1258
|
+
assertPreparedEntry(entry);
|
|
1259
|
+
return getFirmwareUpdateResourceName(entry.entryName).toLowerCase();
|
|
1260
|
+
})) !== null && _d !== void 0 ? _d : [];
|
|
1261
|
+
if (new Set(materializedEntryNames).size !== materializedEntryNames.length) {
|
|
1262
|
+
return preparedPlanError('Firmware prepared plan contains duplicate entry names');
|
|
1263
|
+
}
|
|
1174
1264
|
}
|
|
1175
1265
|
if (preparedPlan.targetsToUpdate.some(target => !FIRMWARE_UPDATE_PLAN_TARGETS.has(target)) ||
|
|
1176
1266
|
new Set(preparedPlan.targetsToUpdate).size !== preparedPlan.targetsToUpdate.length ||
|
|
@@ -1184,6 +1274,14 @@ const validateFirmwareUpdatePreparedPlan = (value) => {
|
|
|
1184
1274
|
}
|
|
1185
1275
|
return preparedPlan;
|
|
1186
1276
|
};
|
|
1277
|
+
const getFirmwareUpdatePreparedRawArtifact = ({ preparedPlan: value, target, role, }) => {
|
|
1278
|
+
const preparedPlan = validateFirmwareUpdatePreparedPlan(value);
|
|
1279
|
+
const artifacts = preparedPlan.artifacts.filter(artifact => artifact.target === target);
|
|
1280
|
+
if (artifacts.length !== 1 || artifacts[0].role !== role || artifacts[0].container !== 'raw') {
|
|
1281
|
+
return preparedPlanError(`Firmware prepared plan ${target} artifact is invalid`);
|
|
1282
|
+
}
|
|
1283
|
+
return artifacts[0];
|
|
1284
|
+
};
|
|
1187
1285
|
const degradedPlanIdentityPins = new Map();
|
|
1188
1286
|
const DEGRADED_PLAN_IDENTITY_PIN_LIMIT = 32;
|
|
1189
1287
|
const pinDegradedPlanIdentity = (leaseRef, deviceIdentity) => {
|
|
@@ -1204,7 +1302,7 @@ const assertFirmwareUpdatePreparedPlanDeviceIdentity = ({ preparedPlan: value, d
|
|
|
1204
1302
|
}
|
|
1205
1303
|
const pinnedIdentity = degradedPlanIdentityPins.get(preparedPlan.leaseRef);
|
|
1206
1304
|
if (!deviceIdentity) {
|
|
1207
|
-
if (bootloaderMode !== true) {
|
|
1305
|
+
if (preparedPlan.executor !== 'v4' && bootloaderMode !== true) {
|
|
1208
1306
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckDeviceIdError);
|
|
1209
1307
|
}
|
|
1210
1308
|
return preparedPlan;
|
|
@@ -1277,6 +1375,8 @@ class FirmwareHostBindingRegistry {
|
|
|
1277
1375
|
register(binding) {
|
|
1278
1376
|
var _a;
|
|
1279
1377
|
if (!binding ||
|
|
1378
|
+
typeof binding.preparedPlanDigest !== 'string' ||
|
|
1379
|
+
!/^[0-9a-f]{64}$/i.test(binding.preparedPlanDigest) ||
|
|
1280
1380
|
typeof ((_a = binding.artifactReader) === null || _a === void 0 ? void 0 : _a.open) !== 'function' ||
|
|
1281
1381
|
typeof binding.artifactReader.read !== 'function' ||
|
|
1282
1382
|
typeof binding.artifactReader.close !== 'function') {
|
|
@@ -1297,7 +1397,7 @@ class FirmwareHostBindingRegistry {
|
|
|
1297
1397
|
getGeneration() {
|
|
1298
1398
|
return this.generation;
|
|
1299
1399
|
}
|
|
1300
|
-
resolve(generation) {
|
|
1400
|
+
resolve(generation, preparedPlanDigest) {
|
|
1301
1401
|
if (!Number.isSafeInteger(generation) ||
|
|
1302
1402
|
generation <= 0 ||
|
|
1303
1403
|
generation !== this.generation ||
|
|
@@ -1305,12 +1405,17 @@ class FirmwareHostBindingRegistry {
|
|
|
1305
1405
|
return bindingError(`Firmware host binding generation ${generation} is stale`);
|
|
1306
1406
|
}
|
|
1307
1407
|
const { binding } = this;
|
|
1408
|
+
if (preparedPlanDigest !== undefined &&
|
|
1409
|
+
binding.preparedPlanDigest.toLowerCase() !== preparedPlanDigest.toLowerCase()) {
|
|
1410
|
+
return bindingError(`Firmware host binding generation ${generation} does not match the prepared plan`);
|
|
1411
|
+
}
|
|
1308
1412
|
const assertCurrent = () => {
|
|
1309
1413
|
if (generation !== this.generation || binding !== this.binding) {
|
|
1310
1414
|
bindingError(`Firmware host binding generation ${generation} is stale`);
|
|
1311
1415
|
}
|
|
1312
1416
|
};
|
|
1313
1417
|
return {
|
|
1418
|
+
preparedPlanDigest: binding.preparedPlanDigest,
|
|
1314
1419
|
artifactReader: {
|
|
1315
1420
|
open: (input) => __awaiter(this, void 0, void 0, function* () {
|
|
1316
1421
|
assertCurrent();
|
|
@@ -1343,7 +1448,7 @@ const firmwareHostBindingRegistry = new FirmwareHostBindingRegistry();
|
|
|
1343
1448
|
const registerFirmwareUpdateHostBinding = (binding) => firmwareHostBindingRegistry.register(binding);
|
|
1344
1449
|
const unregisterFirmwareUpdateHostBinding = (generation) => firmwareHostBindingRegistry.unregister(generation);
|
|
1345
1450
|
const getFirmwareUpdateHostBindingGeneration = () => firmwareHostBindingRegistry.getGeneration();
|
|
1346
|
-
const resolveFirmwareUpdateHostBinding = (generation) => firmwareHostBindingRegistry.resolve(generation !== null && generation !== void 0 ? generation : Number.NaN);
|
|
1451
|
+
const resolveFirmwareUpdateHostBinding = (generation, preparedPlanDigest) => firmwareHostBindingRegistry.resolve(generation !== null && generation !== void 0 ? generation : Number.NaN, preparedPlanDigest);
|
|
1347
1452
|
|
|
1348
1453
|
const callbackManager = new Map();
|
|
1349
1454
|
const generateCallbackId = () => `callback_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
|
|
@@ -40504,143 +40609,8 @@ const findLatestRelease = (releases) => {
|
|
|
40504
40609
|
return leastRelease;
|
|
40505
40610
|
};
|
|
40506
40611
|
|
|
40507
|
-
const
|
|
40508
|
-
'images',
|
|
40509
|
-
'animation',
|
|
40510
|
-
'wallpaper',
|
|
40511
|
-
'translations',
|
|
40512
|
-
'roobert',
|
|
40513
|
-
'noto',
|
|
40514
|
-
'firmware_logo',
|
|
40515
|
-
];
|
|
40516
|
-
const PROTOCOL_V2_RESOURCE_DEVICE_PATHS = {
|
|
40517
|
-
images: 'vol0:/bundles/images/images.okpkg',
|
|
40518
|
-
animation: 'vol0:/bundles/images/animation.okpkg',
|
|
40519
|
-
wallpaper: 'vol0:/bundles/images/wallpaper.okpkg',
|
|
40520
|
-
translations: 'vol0:/bundles/translations/translations.okpkg',
|
|
40521
|
-
roobert: 'vol0:/bundles/font/roobert.okpkg',
|
|
40522
|
-
noto: 'vol0:/bundles/font/noto.okpkg',
|
|
40523
|
-
firmware_logo: 'vol0:/bundles/firmware_logo.okpkg',
|
|
40524
|
-
};
|
|
40525
|
-
const RESOURCE_TYPE_SET = new Set(PROTOCOL_V2_RESOURCE_TYPES);
|
|
40612
|
+
const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1 = 'vol0:/loaders/bootloader/boot_resource.okpkg';
|
|
40526
40613
|
const SHA256_HEX_LENGTH = 64;
|
|
40527
|
-
const SHA3_512_HEX_LENGTH = 128;
|
|
40528
|
-
const PROTOCOL_V2_OKPP_HEADER_SIZE$1 = 0x52a0;
|
|
40529
|
-
const PROTOCOL_V2_OKPP_TYPE_OFFSET = 0x08;
|
|
40530
|
-
const PROTOCOL_V2_OKPP_HEADER_LENGTH_OFFSET = 0x0c;
|
|
40531
|
-
const PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET$1 = 0x240;
|
|
40532
|
-
const PROTOCOL_V2_OKPP_HASH_SIZE$1 = 64;
|
|
40533
|
-
const PROTOCOL_V2_RESOURCE_IDENTITY_READ_SIZE = PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET$1 + PROTOCOL_V2_OKPP_HASH_SIZE$1;
|
|
40534
|
-
const PROTOCOL_V2_MIN_FILE_READ_CHUNK_SIZE = 64;
|
|
40535
|
-
const PROTOCOL_V2_RESOURCE_INVENTORY_TIMEOUT_MS = 5 * 1000;
|
|
40536
|
-
function toFiniteNumber(value) {
|
|
40537
|
-
if (typeof value === 'number' && Number.isFinite(value))
|
|
40538
|
-
return value;
|
|
40539
|
-
if (typeof value === 'string') {
|
|
40540
|
-
const numeric = Number(value);
|
|
40541
|
-
return Number.isFinite(numeric) ? numeric : undefined;
|
|
40542
|
-
}
|
|
40543
|
-
if (value && typeof value === 'object') {
|
|
40544
|
-
const longLike = value;
|
|
40545
|
-
if (typeof longLike.toNumber === 'function') {
|
|
40546
|
-
const numeric = longLike.toNumber();
|
|
40547
|
-
return Number.isFinite(numeric) ? numeric : undefined;
|
|
40548
|
-
}
|
|
40549
|
-
}
|
|
40550
|
-
return undefined;
|
|
40551
|
-
}
|
|
40552
|
-
function toUint8Array(value) {
|
|
40553
|
-
if (value instanceof Uint8Array)
|
|
40554
|
-
return value;
|
|
40555
|
-
if (value instanceof ArrayBuffer)
|
|
40556
|
-
return new Uint8Array(value);
|
|
40557
|
-
if (ArrayBuffer.isView(value)) {
|
|
40558
|
-
return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
40559
|
-
}
|
|
40560
|
-
if (typeof value === 'string') {
|
|
40561
|
-
const hex = value.replace(/^0x/i, '');
|
|
40562
|
-
if (!hex || hex.length % 2 !== 0 || /[^0-9a-f]/i.test(hex)) {
|
|
40563
|
-
return new Uint8Array(0);
|
|
40564
|
-
}
|
|
40565
|
-
const bytes = new Uint8Array(hex.length / 2);
|
|
40566
|
-
for (let index = 0; index < bytes.length; index += 1) {
|
|
40567
|
-
bytes[index] = Number.parseInt(hex.slice(index * 2, index * 2 + 2), 16);
|
|
40568
|
-
}
|
|
40569
|
-
return bytes;
|
|
40570
|
-
}
|
|
40571
|
-
return new Uint8Array(0);
|
|
40572
|
-
}
|
|
40573
|
-
function readAscii(bytes, offset, length) {
|
|
40574
|
-
return Array.from(bytes.slice(offset, offset + length), byte => String.fromCharCode(byte)).join('');
|
|
40575
|
-
}
|
|
40576
|
-
function parseProtocolV2ResourceHeaderHash(bytes) {
|
|
40577
|
-
if (bytes.byteLength < PROTOCOL_V2_RESOURCE_IDENTITY_READ_SIZE)
|
|
40578
|
-
return undefined;
|
|
40579
|
-
if (readAscii(bytes, 0, 4) !== 'OKPP')
|
|
40580
|
-
return undefined;
|
|
40581
|
-
if (readAscii(bytes, PROTOCOL_V2_OKPP_TYPE_OFFSET, 4) !== 'RESC')
|
|
40582
|
-
return undefined;
|
|
40583
|
-
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
40584
|
-
if (view.getUint32(PROTOCOL_V2_OKPP_HEADER_LENGTH_OFFSET, true) !== PROTOCOL_V2_OKPP_HEADER_SIZE$1) {
|
|
40585
|
-
return undefined;
|
|
40586
|
-
}
|
|
40587
|
-
return bytesToHex$3(bytes.slice(PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET$1, PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET$1 + PROTOCOL_V2_OKPP_HASH_SIZE$1));
|
|
40588
|
-
}
|
|
40589
|
-
function readProtocolV2ResourceIdentity({ commands, resource, chunkSize, timeoutMs = PROTOCOL_V2_RESOURCE_INVENTORY_TIMEOUT_MS, }) {
|
|
40590
|
-
var _a, _b, _c, _d;
|
|
40591
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
40592
|
-
const path = PROTOCOL_V2_RESOURCE_DEVICE_PATHS[resource.type];
|
|
40593
|
-
const pathInfo = yield commands.typedCall('FilesystemPathInfoQuery', 'FilesystemPathInfo', { path }, { timeoutMs });
|
|
40594
|
-
const size = toFiniteNumber((_a = pathInfo.message) === null || _a === void 0 ? void 0 : _a.size);
|
|
40595
|
-
if (!((_b = pathInfo.message) === null || _b === void 0 ? void 0 : _b.exist) ||
|
|
40596
|
-
((_c = pathInfo.message) === null || _c === void 0 ? void 0 : _c.directory) ||
|
|
40597
|
-
!Number.isSafeInteger(size) ||
|
|
40598
|
-
size !== resource.size ||
|
|
40599
|
-
size < PROTOCOL_V2_OKPP_HEADER_SIZE$1) {
|
|
40600
|
-
return undefined;
|
|
40601
|
-
}
|
|
40602
|
-
const header = new Uint8Array(PROTOCOL_V2_RESOURCE_IDENTITY_READ_SIZE);
|
|
40603
|
-
let offset = 0;
|
|
40604
|
-
while (offset < header.byteLength) {
|
|
40605
|
-
const readLength = Math.min(chunkSize, header.byteLength - offset);
|
|
40606
|
-
const response = yield commands.typedCall('FilesystemFileRead', 'FilesystemFile', {
|
|
40607
|
-
file: { path, offset, total_size: 0 },
|
|
40608
|
-
chunk_len: readLength,
|
|
40609
|
-
}, { timeoutMs });
|
|
40610
|
-
const data = toUint8Array((_d = response.message) === null || _d === void 0 ? void 0 : _d.data);
|
|
40611
|
-
if (data.byteLength === 0)
|
|
40612
|
-
return undefined;
|
|
40613
|
-
const copied = Math.min(data.byteLength, header.byteLength - offset);
|
|
40614
|
-
header.set(data.subarray(0, copied), offset);
|
|
40615
|
-
offset += copied;
|
|
40616
|
-
}
|
|
40617
|
-
const headerHash = parseProtocolV2ResourceHeaderHash(header);
|
|
40618
|
-
return headerHash ? { type: resource.type, size, headerHash } : undefined;
|
|
40619
|
-
});
|
|
40620
|
-
}
|
|
40621
|
-
function readProtocolV2ResourceInventory({ commands, resources, chunkSize = hdTransport.PROTOCOL_V2_BLE_FILE_READ_CHUNK_SIZE, timeoutMs = PROTOCOL_V2_RESOURCE_INVENTORY_TIMEOUT_MS, }) {
|
|
40622
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
40623
|
-
const normalizedChunkSize = Number.isFinite(chunkSize)
|
|
40624
|
-
? Math.max(Math.floor(chunkSize), PROTOCOL_V2_MIN_FILE_READ_CHUNK_SIZE)
|
|
40625
|
-
: hdTransport.PROTOCOL_V2_BLE_FILE_READ_CHUNK_SIZE;
|
|
40626
|
-
const inventory = [];
|
|
40627
|
-
for (const resource of resources) {
|
|
40628
|
-
try {
|
|
40629
|
-
const item = yield readProtocolV2ResourceIdentity({
|
|
40630
|
-
commands,
|
|
40631
|
-
resource,
|
|
40632
|
-
chunkSize: normalizedChunkSize,
|
|
40633
|
-
timeoutMs,
|
|
40634
|
-
});
|
|
40635
|
-
if (item)
|
|
40636
|
-
inventory.push(item);
|
|
40637
|
-
}
|
|
40638
|
-
catch (_a) {
|
|
40639
|
-
}
|
|
40640
|
-
}
|
|
40641
|
-
return inventory;
|
|
40642
|
-
});
|
|
40643
|
-
}
|
|
40644
40614
|
function normalizeHex$1(value, expectedLength, field) {
|
|
40645
40615
|
if (typeof value !== 'string') {
|
|
40646
40616
|
throw new Error(`Invalid Pro2 resource ${field}: expected a hexadecimal string`);
|
|
@@ -40651,132 +40621,158 @@ function normalizeHex$1(value, expectedLength, field) {
|
|
|
40651
40621
|
}
|
|
40652
40622
|
return normalized;
|
|
40653
40623
|
}
|
|
40654
|
-
function
|
|
40624
|
+
function parseProtocolV2Resources(value) {
|
|
40625
|
+
if (value === undefined)
|
|
40626
|
+
return undefined;
|
|
40655
40627
|
if (!value || typeof value !== 'object') {
|
|
40656
|
-
throw new Error(
|
|
40628
|
+
throw new Error('Invalid Pro2 resources config');
|
|
40657
40629
|
}
|
|
40658
|
-
const
|
|
40659
|
-
if (typeof
|
|
40660
|
-
throw new Error(
|
|
40630
|
+
const { source } = value;
|
|
40631
|
+
if (!source || typeof source !== 'object') {
|
|
40632
|
+
throw new Error('Invalid Pro2 resources config: source is required');
|
|
40661
40633
|
}
|
|
40662
|
-
|
|
40663
|
-
|
|
40634
|
+
const { archiveUrl, archiveSha256, archiveSize } = source;
|
|
40635
|
+
if (typeof archiveUrl !== 'string' || !archiveUrl.startsWith('https://')) {
|
|
40636
|
+
throw new Error('Invalid Pro2 resources config: source.archiveUrl must use HTTPS');
|
|
40664
40637
|
}
|
|
40665
|
-
if (
|
|
40666
|
-
throw new Error(
|
|
40638
|
+
if (typeof archiveSha256 !== 'string' || !/^[0-9a-fA-F]{64}$/.test(archiveSha256)) {
|
|
40639
|
+
throw new Error('Invalid Pro2 resources config: source.archiveSha256 must be a SHA-256 digest');
|
|
40640
|
+
}
|
|
40641
|
+
if (!Number.isSafeInteger(archiveSize) || archiveSize <= 0) {
|
|
40642
|
+
throw new Error('Invalid Pro2 resources config: source.archiveSize must be a positive integer');
|
|
40667
40643
|
}
|
|
40668
40644
|
return {
|
|
40669
|
-
|
|
40670
|
-
|
|
40671
|
-
|
|
40672
|
-
|
|
40673
|
-
|
|
40645
|
+
source: {
|
|
40646
|
+
archiveUrl,
|
|
40647
|
+
archiveSha256: archiveSha256.toLowerCase(),
|
|
40648
|
+
archiveSize: archiveSize,
|
|
40649
|
+
},
|
|
40674
40650
|
};
|
|
40675
40651
|
}
|
|
40676
|
-
|
|
40677
|
-
|
|
40678
|
-
|
|
40652
|
+
const PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS = [
|
|
40653
|
+
'vol0:/bundles/',
|
|
40654
|
+
'vol0:/loaders/rom/',
|
|
40655
|
+
];
|
|
40656
|
+
function isAllowedManifestDevicePath(path) {
|
|
40657
|
+
if (!path.endsWith('.okpkg') ||
|
|
40658
|
+
path.includes('\\') ||
|
|
40659
|
+
path.includes('//') ||
|
|
40660
|
+
path.split('/').some(part => part === '.' || part === '..')) {
|
|
40661
|
+
return false;
|
|
40679
40662
|
}
|
|
40680
|
-
|
|
40681
|
-
|
|
40682
|
-
throw new Error('Invalid Pro2 boot resources required flag: expected false');
|
|
40663
|
+
if (path === PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) {
|
|
40664
|
+
return true;
|
|
40683
40665
|
}
|
|
40684
|
-
|
|
40685
|
-
|
|
40666
|
+
return PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS.some(root => path.startsWith(root));
|
|
40667
|
+
}
|
|
40668
|
+
function assertManifestString(value, field) {
|
|
40669
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
40670
|
+
throw new Error(`Invalid Pro2 resource manifest ${field}`);
|
|
40686
40671
|
}
|
|
40687
|
-
|
|
40688
|
-
|
|
40689
|
-
|
|
40672
|
+
return value;
|
|
40673
|
+
}
|
|
40674
|
+
function assertManifestRelativePath(value, field) {
|
|
40675
|
+
const path = assertManifestString(value, field);
|
|
40676
|
+
if (path.startsWith('/') ||
|
|
40677
|
+
path.includes('\\') ||
|
|
40678
|
+
path.includes(':') ||
|
|
40679
|
+
path.split('/').some(part => !part || part === '.' || part === '..')) {
|
|
40680
|
+
throw new Error(`Invalid Pro2 resource manifest ${field}`);
|
|
40681
|
+
}
|
|
40682
|
+
return path;
|
|
40683
|
+
}
|
|
40684
|
+
function parseProtocolV2ResourceManifestFile(value, index) {
|
|
40685
|
+
var _a;
|
|
40686
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
40687
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}]`);
|
|
40690
40688
|
}
|
|
40691
|
-
|
|
40692
|
-
|
|
40689
|
+
const file = value;
|
|
40690
|
+
const archivePath = assertManifestRelativePath(file.archive_path, `files[${index}].archive_path`);
|
|
40691
|
+
const originalName = assertManifestRelativePath(file.original_name, `files[${index}].original_name`);
|
|
40692
|
+
if (originalName.includes('/')) {
|
|
40693
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].original_name`);
|
|
40693
40694
|
}
|
|
40694
|
-
const
|
|
40695
|
-
|
|
40696
|
-
|
|
40697
|
-
}
|
|
40698
|
-
const file = value;
|
|
40699
|
-
if (typeof file.url !== 'string' || !file.url.startsWith('https://')) {
|
|
40700
|
-
throw new Error(`Invalid Pro2 boot resource url at files[${index}]`);
|
|
40701
|
-
}
|
|
40702
|
-
if (typeof file.devicePath !== 'string' ||
|
|
40703
|
-
!file.devicePath.startsWith('vol0:/') ||
|
|
40704
|
-
file.devicePath.includes('..') ||
|
|
40705
|
-
file.devicePath.includes('\\')) {
|
|
40706
|
-
throw new Error(`Invalid Pro2 boot resource devicePath at files[${index}]`);
|
|
40707
|
-
}
|
|
40708
|
-
if (!Number.isSafeInteger(file.size) || Number(file.size) <= 0) {
|
|
40709
|
-
throw new Error(`Invalid Pro2 boot resource size at files[${index}]`);
|
|
40710
|
-
}
|
|
40711
|
-
return Object.assign(Object.assign({}, (typeof file.name === 'string' && file.name ? { name: file.name } : undefined)), { url: file.url, devicePath: file.devicePath, size: Number(file.size), fileHash: normalizeHex$1(file.fileHash, SHA256_HEX_LENGTH, `boot files[${index}].fileHash`) });
|
|
40712
|
-
});
|
|
40713
|
-
if (new Set(files.map(file => file.devicePath)).size !== files.length) {
|
|
40714
|
-
throw new Error('Invalid Pro2 boot resources files: duplicate devicePath');
|
|
40695
|
+
const devicePath = assertManifestString(file.device_path, `files[${index}].device_path`);
|
|
40696
|
+
if (!isAllowedManifestDevicePath(devicePath)) {
|
|
40697
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].device_path`);
|
|
40715
40698
|
}
|
|
40716
|
-
|
|
40717
|
-
}
|
|
40718
|
-
function parseProtocolV2Resources(value) {
|
|
40719
|
-
if (value === undefined)
|
|
40720
|
-
return undefined;
|
|
40721
|
-
if (!value ||
|
|
40722
|
-
typeof value !== 'object' ||
|
|
40723
|
-
!Array.isArray(value.stable)) {
|
|
40724
|
-
throw new Error('Invalid Pro2 resources config: stable must be an array');
|
|
40699
|
+
if (!Number.isSafeInteger(file.size) || Number(file.size) <= 0) {
|
|
40700
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].size`);
|
|
40725
40701
|
}
|
|
40726
|
-
const
|
|
40727
|
-
|
|
40728
|
-
|
|
40729
|
-
if (stable.length !== PROTOCOL_V2_RESOURCE_TYPES.length || types.size !== stable.length) {
|
|
40730
|
-
throw new Error(`Invalid Pro2 resources config: stable must contain ${PROTOCOL_V2_RESOURCE_TYPES.length} unique resource types`);
|
|
40702
|
+
const digest = normalizeHex$1(file.sha256, SHA256_HEX_LENGTH, `files[${index}].sha256`);
|
|
40703
|
+
if (file.signed !== true) {
|
|
40704
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].signed`);
|
|
40731
40705
|
}
|
|
40732
|
-
|
|
40733
|
-
|
|
40734
|
-
throw new Error(`Invalid Pro2 resources config: stable is missing ${type}`);
|
|
40735
|
-
}
|
|
40706
|
+
if (file.sig_algo !== 'ed25519' && file.sig_algo !== 'mldsa65') {
|
|
40707
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].sig_algo`);
|
|
40736
40708
|
}
|
|
40737
|
-
|
|
40738
|
-
|
|
40739
|
-
const resource = stable.find(item => item.type === type);
|
|
40740
|
-
if (!resource) {
|
|
40741
|
-
throw new Error(`Invalid Pro2 resources config: stable is missing ${type}`);
|
|
40742
|
-
}
|
|
40743
|
-
return resource;
|
|
40744
|
-
}) }, (boot ? { boot } : undefined));
|
|
40745
|
-
}
|
|
40746
|
-
function buildProtocolV2ResourceUpdatePlan({ resources, inventory, mode, forced = false, }) {
|
|
40747
|
-
if (forced) {
|
|
40748
|
-
return {
|
|
40749
|
-
status: resources.length > 0 ? 'outdated' : 'valid',
|
|
40750
|
-
resources: [...resources],
|
|
40751
|
-
};
|
|
40709
|
+
if (file.payload_version !== null && typeof file.payload_version !== 'string') {
|
|
40710
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].payload_version`);
|
|
40752
40711
|
}
|
|
40753
|
-
if (!
|
|
40754
|
-
|
|
40755
|
-
? {
|
|
40756
|
-
status: resources.length > 0 ? 'outdated' : 'valid',
|
|
40757
|
-
resources: [...resources],
|
|
40758
|
-
}
|
|
40759
|
-
: { status: 'unknown', resources: [] };
|
|
40712
|
+
if (!archivePath.endsWith('.okpkg') || !originalName.endsWith('.okpkg')) {
|
|
40713
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}] package extension`);
|
|
40760
40714
|
}
|
|
40761
|
-
const inventoryByType = new Map(inventory.map(item => [item.type, item]));
|
|
40762
|
-
const changedResources = resources.filter(resource => {
|
|
40763
|
-
const current = inventoryByType.get(resource.type);
|
|
40764
|
-
return (!current ||
|
|
40765
|
-
current.size !== resource.size ||
|
|
40766
|
-
current.headerHash.toLowerCase() !== resource.headerHash.toLowerCase());
|
|
40767
|
-
});
|
|
40768
40715
|
return {
|
|
40769
|
-
|
|
40770
|
-
|
|
40716
|
+
archive_path: archivePath,
|
|
40717
|
+
original_name: originalName,
|
|
40718
|
+
device_path: devicePath,
|
|
40719
|
+
size: Number(file.size),
|
|
40720
|
+
sha256: digest,
|
|
40721
|
+
signed: true,
|
|
40722
|
+
sig_algo: file.sig_algo,
|
|
40723
|
+
payload_version: (_a = file.payload_version) !== null && _a !== void 0 ? _a : null,
|
|
40771
40724
|
};
|
|
40772
40725
|
}
|
|
40773
|
-
function
|
|
40774
|
-
|
|
40726
|
+
function parseProtocolV2ResourceManifest(value) {
|
|
40727
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
40728
|
+
throw new Error('Invalid Pro2 resource manifest');
|
|
40729
|
+
}
|
|
40730
|
+
const manifest = value;
|
|
40731
|
+
if (manifest.schema !== 1 ||
|
|
40732
|
+
manifest.variant !== 'resource' ||
|
|
40733
|
+
manifest.device_root !== 'vol0:' ||
|
|
40734
|
+
manifest.restore_mode !== 'bootloader_update' ||
|
|
40735
|
+
!Array.isArray(manifest.trees) ||
|
|
40736
|
+
!Array.isArray(manifest.files)) {
|
|
40737
|
+
throw new Error('Invalid Pro2 resource manifest contract');
|
|
40738
|
+
}
|
|
40739
|
+
const files = manifest.files.map(parseProtocolV2ResourceManifestFile);
|
|
40740
|
+
const devicePaths = new Set(files.map(file => file.device_path));
|
|
40741
|
+
const archivePaths = new Set(files.map(file => file.archive_path));
|
|
40742
|
+
if (files.length === 0 ||
|
|
40743
|
+
devicePaths.size !== files.length ||
|
|
40744
|
+
archivePaths.size !== files.length ||
|
|
40745
|
+
!devicePaths.has(PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) ||
|
|
40746
|
+
!files.some(file => file.device_path.startsWith('vol0:/bundles/'))) {
|
|
40747
|
+
throw new Error('Invalid Pro2 resource manifest file set');
|
|
40748
|
+
}
|
|
40749
|
+
return {
|
|
40750
|
+
schema: 1,
|
|
40751
|
+
artifact_name: assertManifestString(manifest.artifact_name, 'artifact_name'),
|
|
40752
|
+
release_name: assertManifestString(manifest.release_name, 'release_name'),
|
|
40753
|
+
variant: 'resource',
|
|
40754
|
+
commit: assertManifestString(manifest.commit, 'commit'),
|
|
40755
|
+
short_sha: assertManifestString(manifest.short_sha, 'short_sha'),
|
|
40756
|
+
timestamp_utc: assertManifestString(manifest.timestamp_utc, 'timestamp_utc'),
|
|
40757
|
+
core_version: assertManifestString(manifest.core_version, 'core_version'),
|
|
40758
|
+
key_set: assertManifestString(manifest.key_set, 'key_set'),
|
|
40759
|
+
device_root: 'vol0:',
|
|
40760
|
+
restore_mode: 'bootloader_update',
|
|
40761
|
+
trees: manifest.trees.map((tree, index) => {
|
|
40762
|
+
if (!tree || typeof tree !== 'object') {
|
|
40763
|
+
throw new Error(`Invalid Pro2 resource manifest trees[${index}]`);
|
|
40764
|
+
}
|
|
40765
|
+
const item = tree;
|
|
40766
|
+
return {
|
|
40767
|
+
path: assertManifestRelativePath(item.path, `trees[${index}].path`),
|
|
40768
|
+
device: assertManifestString(item.device, `trees[${index}].device`),
|
|
40769
|
+
};
|
|
40770
|
+
}),
|
|
40771
|
+
files,
|
|
40772
|
+
};
|
|
40775
40773
|
}
|
|
40776
|
-
function
|
|
40777
|
-
|
|
40778
|
-
return false;
|
|
40779
|
-
return bytesToHex$3(sha256.sha256(new Uint8Array(binary))) === resource.fileHash.toLowerCase();
|
|
40774
|
+
function selectProtocolV2ResourceManifestFiles({ manifest, targetsToUpdate, }) {
|
|
40775
|
+
return targetsToUpdate.includes('resource') ? [...manifest.files] : [];
|
|
40780
40776
|
}
|
|
40781
40777
|
|
|
40782
40778
|
var _a$1;
|
|
@@ -40837,6 +40833,7 @@ class DataManager {
|
|
|
40837
40833
|
return __awaiter(this, void 0, void 0, function* () {
|
|
40838
40834
|
this.settings = settings;
|
|
40839
40835
|
this.protocolV2ResourcesConfigError = undefined;
|
|
40836
|
+
this.protocolV2NeoResourcesConfigError = undefined;
|
|
40840
40837
|
const manifestMode = (_b = settings.firmwareManifestMode) !== null && _b !== void 0 ? _b : (settings.fetchConfig ? 'sdk-managed' : undefined);
|
|
40841
40838
|
if (settings.preloadedConfig) {
|
|
40842
40839
|
this.applyRemoteConfig(settings.preloadedConfig);
|
|
@@ -40897,12 +40894,19 @@ class DataManager {
|
|
|
40897
40894
|
let neoResources;
|
|
40898
40895
|
try {
|
|
40899
40896
|
pro2Resources = parseProtocolV2Resources((_b = data.pro2) === null || _b === void 0 ? void 0 : _b.resources);
|
|
40900
|
-
neoResources = parseProtocolV2Resources((_c = data.neo) === null || _c === void 0 ? void 0 : _c.resources);
|
|
40901
40897
|
}
|
|
40902
40898
|
catch (error) {
|
|
40903
40899
|
this.protocolV2ResourcesConfigError =
|
|
40904
40900
|
error instanceof Error ? error : new Error(String(error));
|
|
40905
|
-
Log$k.warn('[DataConfig] Ignoring invalid
|
|
40901
|
+
Log$k.warn('[DataConfig] Ignoring invalid Pro2 resources config:', error);
|
|
40902
|
+
}
|
|
40903
|
+
try {
|
|
40904
|
+
neoResources = parseProtocolV2Resources((_c = data.neo) === null || _c === void 0 ? void 0 : _c.resources);
|
|
40905
|
+
}
|
|
40906
|
+
catch (error) {
|
|
40907
|
+
this.protocolV2NeoResourcesConfigError =
|
|
40908
|
+
error instanceof Error ? error : new Error(String(error));
|
|
40909
|
+
Log$k.warn('[DataConfig] Ignoring invalid Neo resources config:', error);
|
|
40906
40910
|
}
|
|
40907
40911
|
const enrichedPro2Config = this.enrichFirmwareReleaseInfo(data.pro2);
|
|
40908
40912
|
const enrichedNeoConfig = this.enrichFirmwareReleaseInfo(data.neo);
|
|
@@ -40940,16 +40944,20 @@ class DataManager {
|
|
|
40940
40944
|
}
|
|
40941
40945
|
});
|
|
40942
40946
|
}
|
|
40943
|
-
static forceReloadData({ requireResources = false, } = {}) {
|
|
40947
|
+
static forceReloadData({ requireResources = false, resourceDeviceType = hdShared.EDeviceType.Pro2, } = {}) {
|
|
40944
40948
|
return __awaiter(this, void 0, void 0, function* () {
|
|
40949
|
+
const resourceDeviceName = resourceDeviceType === hdShared.EDeviceType.Pro2 ? 'Pro2' : 'Neo';
|
|
40945
40950
|
if (!this.settings) {
|
|
40946
40951
|
throw new Error('Remote config settings are not initialized');
|
|
40947
40952
|
}
|
|
40948
40953
|
const hasFreshConfig = this.lastCheckTimestamp > 0 &&
|
|
40949
40954
|
getTimeStamp() - this.lastCheckTimestamp <= FIRMWARE_UPDATE_CONFIG_FRESHNESS_MS;
|
|
40950
40955
|
if (hasFreshConfig) {
|
|
40951
|
-
|
|
40952
|
-
|
|
40956
|
+
const resourcesConfigError = resourceDeviceType === hdShared.EDeviceType.Pro2
|
|
40957
|
+
? this.protocolV2ResourcesConfigError
|
|
40958
|
+
: this.protocolV2NeoResourcesConfigError;
|
|
40959
|
+
if (requireResources && resourcesConfigError) {
|
|
40960
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, `Invalid ${resourceDeviceName} resources config: ${resourcesConfigError.message}`);
|
|
40953
40961
|
}
|
|
40954
40962
|
return;
|
|
40955
40963
|
}
|
|
@@ -40957,19 +40965,18 @@ class DataManager {
|
|
|
40957
40965
|
if (!loaded) {
|
|
40958
40966
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.NetworkError, 'Unable to refresh the latest remote config');
|
|
40959
40967
|
}
|
|
40960
|
-
|
|
40961
|
-
|
|
40968
|
+
const resourcesConfigError = resourceDeviceType === hdShared.EDeviceType.Pro2
|
|
40969
|
+
? this.protocolV2ResourcesConfigError
|
|
40970
|
+
: this.protocolV2NeoResourcesConfigError;
|
|
40971
|
+
if (requireResources && resourcesConfigError) {
|
|
40972
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, `Invalid ${resourceDeviceName} resources config: ${resourcesConfigError.message}`);
|
|
40962
40973
|
}
|
|
40963
40974
|
this.lastCheckTimestamp = getTimeStamp();
|
|
40964
40975
|
});
|
|
40965
40976
|
}
|
|
40966
|
-
static
|
|
40967
|
-
var _b, _c;
|
|
40968
|
-
return (_c = (_b = this.deviceMap[deviceType]) === null || _b === void 0 ? void 0 : _b.resources) === null || _c === void 0 ? void 0 : _c.stable;
|
|
40969
|
-
}
|
|
40970
|
-
static getProtocolV2BootResources(deviceType = hdShared.EDeviceType.Pro2) {
|
|
40977
|
+
static getProtocolV2ResourceSource(deviceType = hdShared.EDeviceType.Pro2) {
|
|
40971
40978
|
var _b, _c;
|
|
40972
|
-
return (_c = (_b = this.deviceMap[deviceType]) === null || _b === void 0 ? void 0 : _b.resources) === null || _c === void 0 ? void 0 : _c.
|
|
40979
|
+
return (_c = (_b = this.deviceMap[deviceType]) === null || _b === void 0 ? void 0 : _b.resources) === null || _c === void 0 ? void 0 : _c.source;
|
|
40973
40980
|
}
|
|
40974
40981
|
static getProtobufMessages(schema = 'v1CurrentSchema') {
|
|
40975
40982
|
return this.messages[schema];
|
|
@@ -41006,12 +41013,10 @@ DataManager.deviceMap = {
|
|
|
41006
41013
|
ble: [],
|
|
41007
41014
|
},
|
|
41008
41015
|
[hdShared.EDeviceType.Pro2]: {
|
|
41009
|
-
firmware: [],
|
|
41010
|
-
ble: [],
|
|
41016
|
+
'firmware-v1': [],
|
|
41011
41017
|
},
|
|
41012
41018
|
[hdShared.EDeviceType.Neo]: {
|
|
41013
|
-
firmware: [],
|
|
41014
|
-
ble: [],
|
|
41019
|
+
'firmware-v1': [],
|
|
41015
41020
|
},
|
|
41016
41021
|
[hdShared.EDeviceType.ClassicPure]: {
|
|
41017
41022
|
firmware: [],
|
|
@@ -42008,7 +42013,7 @@ const getFirmwareUpdateField = ({ features, updateType, targetVersion, firmwareT
|
|
|
42008
42013
|
if (deviceType === hdShared.EDeviceType.Pro) {
|
|
42009
42014
|
return latestFirmwareField;
|
|
42010
42015
|
}
|
|
42011
|
-
if (deviceType === hdShared.EDeviceType.Pro2) {
|
|
42016
|
+
if (deviceType === hdShared.EDeviceType.Pro2 || deviceType === hdShared.EDeviceType.Neo) {
|
|
42012
42017
|
return 'firmware-v1';
|
|
42013
42018
|
}
|
|
42014
42019
|
return 'firmware';
|
|
@@ -42040,7 +42045,7 @@ const getFirmwareUpdateFieldArray = (features, updateType) => {
|
|
|
42040
42045
|
if (deviceType === 'pro') {
|
|
42041
42046
|
return ['firmware-v8'];
|
|
42042
42047
|
}
|
|
42043
|
-
if (deviceType === 'pro2') {
|
|
42048
|
+
if (deviceType === 'pro2' || deviceType === 'neo') {
|
|
42044
42049
|
return ['firmware-v1'];
|
|
42045
42050
|
}
|
|
42046
42051
|
return ['firmware'];
|
|
@@ -47383,76 +47388,93 @@ class ClearSessionCache extends BaseMethod {
|
|
|
47383
47388
|
}
|
|
47384
47389
|
}
|
|
47385
47390
|
|
|
47386
|
-
|
|
47387
|
-
|
|
47388
|
-
|
|
47389
|
-
|
|
47390
|
-
|
|
47391
|
-
|
|
47392
|
-
|
|
47393
|
-
|
|
47394
|
-
|
|
47395
|
-
|
|
47396
|
-
|
|
47397
|
-
|
|
47398
|
-
|
|
47399
|
-
|
|
47400
|
-
|
|
47401
|
-
|
|
47402
|
-
|
|
47403
|
-
|
|
47391
|
+
const PROTOCOL_V2_MAIN_FIRMWARE_TARGETS = [
|
|
47392
|
+
'APPLICATION_P1',
|
|
47393
|
+
'APPLICATION_P2',
|
|
47394
|
+
'SE01',
|
|
47395
|
+
'SE02',
|
|
47396
|
+
'SE03',
|
|
47397
|
+
'SE04',
|
|
47398
|
+
];
|
|
47399
|
+
const PROTOCOL_V2_BLE_TARGETS = [
|
|
47400
|
+
'COPROCESSOR',
|
|
47401
|
+
];
|
|
47402
|
+
const PROTOCOL_V2_BOOTLOADER_TARGETS = [
|
|
47403
|
+
'BOOTLOADER',
|
|
47404
|
+
];
|
|
47405
|
+
function loadProtocolV2FirmwareReleaseContext({ device, firmwareType: firmwareTypeParam, checkFirmwareHash = false, methodName, }) {
|
|
47406
|
+
var _a;
|
|
47407
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
47408
|
+
const state = yield device.getDeviceState({
|
|
47409
|
+
refreshSections: checkFirmwareHash
|
|
47410
|
+
? ['identity', 'versions', 'verification']
|
|
47411
|
+
: ['identity', 'versions'],
|
|
47412
|
+
});
|
|
47413
|
+
if (state.identity.deviceType !== 'pro2' && state.identity.deviceType !== 'neo') {
|
|
47414
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotSupportMethod, `${methodName} requires a Pro2 or Neo device for Protocol V2`);
|
|
47404
47415
|
}
|
|
47405
|
-
|
|
47406
|
-
|
|
47416
|
+
const { features } = device;
|
|
47417
|
+
if (!features) {
|
|
47418
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `${methodName} requires initialized device features`);
|
|
47419
|
+
}
|
|
47420
|
+
const firmwareType = (_a = firmwareTypeParam !== null && firmwareTypeParam !== void 0 ? firmwareTypeParam : state.identity.firmwareType) !== null && _a !== void 0 ? _a : hdShared.EFirmwareType.Universal;
|
|
47421
|
+
return {
|
|
47422
|
+
state: state,
|
|
47423
|
+
features,
|
|
47424
|
+
firmwareType,
|
|
47425
|
+
release: DataManager.getFirmwareLatestRelease(features, firmwareType),
|
|
47426
|
+
};
|
|
47427
|
+
});
|
|
47407
47428
|
}
|
|
47408
|
-
|
|
47409
|
-
|
|
47410
|
-
|
|
47411
|
-
|
|
47412
|
-
|
|
47413
|
-
|
|
47414
|
-
|
|
47415
|
-
|
|
47416
|
-
|
|
47417
|
-
|
|
47429
|
+
function summarizeProtocolV2FirmwareRelease(plan, componentTargets) {
|
|
47430
|
+
var _a;
|
|
47431
|
+
const targetSet = new Set(componentTargets);
|
|
47432
|
+
const components = plan.components.filter(component => targetSet.has(component.componentTarget));
|
|
47433
|
+
const targetsToUpdate = Array.from(new Set(components.flatMap(component => component.status === 'outdated' && component.updateTarget ? [component.updateTarget] : [])));
|
|
47434
|
+
const hasUpgrade = targetsToUpdate.length > 0;
|
|
47435
|
+
const required = !!((_a = plan.release) === null || _a === void 0 ? void 0 : _a.required) && hasUpgrade;
|
|
47436
|
+
let status = 'valid';
|
|
47437
|
+
if (!plan.release || components.length === 0) {
|
|
47438
|
+
status = 'unavailable';
|
|
47418
47439
|
}
|
|
47419
|
-
|
|
47420
|
-
|
|
47421
|
-
|
|
47422
|
-
|
|
47423
|
-
|
|
47424
|
-
|
|
47440
|
+
else if (required) {
|
|
47441
|
+
status = 'required';
|
|
47442
|
+
}
|
|
47443
|
+
else if (hasUpgrade) {
|
|
47444
|
+
status = 'outdated';
|
|
47445
|
+
}
|
|
47446
|
+
else if (components.some(component => component.status === 'unknown')) {
|
|
47447
|
+
status = 'unknown';
|
|
47448
|
+
}
|
|
47449
|
+
else if (components.every(component => component.status === 'unsupported')) {
|
|
47450
|
+
status = 'unavailable';
|
|
47425
47451
|
}
|
|
47452
|
+
return Object.assign(Object.assign({}, plan), { status,
|
|
47453
|
+
hasUpgrade,
|
|
47454
|
+
required,
|
|
47455
|
+
components,
|
|
47456
|
+
targetsToUpdate });
|
|
47426
47457
|
}
|
|
47427
|
-
|
|
47428
|
-
|
|
47429
|
-
|
|
47430
|
-
|
|
47431
|
-
|
|
47432
|
-
|
|
47458
|
+
function toProtocolV2FirmwareReleaseInfo({ plan, state, release, }) {
|
|
47459
|
+
return {
|
|
47460
|
+
shouldUpdate: plan.hasUpgrade,
|
|
47461
|
+
status: plan.status === 'unavailable' ? 'unknown' : plan.status,
|
|
47462
|
+
changelog: plan.release ? [plan.release.changelog] : [],
|
|
47463
|
+
release,
|
|
47464
|
+
bootloaderMode: state.status.mode === 'bootloader' || state.status.mode === 'romloader',
|
|
47465
|
+
};
|
|
47466
|
+
}
|
|
47467
|
+
function getProtocolV2ComponentReleaseInfo(plan, componentTarget) {
|
|
47468
|
+
var _a;
|
|
47469
|
+
const componentRelease = plan.components.find(component => component.componentTarget === componentTarget);
|
|
47470
|
+
if (!componentRelease || !plan.release) {
|
|
47471
|
+
return undefined;
|
|
47433
47472
|
}
|
|
47434
|
-
|
|
47435
|
-
|
|
47436
|
-
|
|
47437
|
-
axios__default["default"]
|
|
47438
|
-
.request({
|
|
47439
|
-
url: 'http://localhost:21320',
|
|
47440
|
-
method: 'POST',
|
|
47441
|
-
withCredentials: false,
|
|
47442
|
-
timeout: 3000,
|
|
47443
|
-
})
|
|
47444
|
-
.then(() => resolve(true))
|
|
47445
|
-
.catch(e => {
|
|
47446
|
-
if (e.code === 'ECONNABORTED') {
|
|
47447
|
-
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BridgeTimeoutError));
|
|
47448
|
-
}
|
|
47449
|
-
else {
|
|
47450
|
-
resolve(false);
|
|
47451
|
-
}
|
|
47452
|
-
});
|
|
47453
|
-
});
|
|
47454
|
-
});
|
|
47473
|
+
const component = (_a = plan.release.components) === null || _a === void 0 ? void 0 : _a[componentRelease.configKey];
|
|
47474
|
+
if (!component) {
|
|
47475
|
+
return undefined;
|
|
47455
47476
|
}
|
|
47477
|
+
return Object.assign(Object.assign({}, component), { protocol: 'V2', configKey: componentRelease.configKey, componentTarget, required: plan.release.required, changelog: plan.release.changelog });
|
|
47456
47478
|
}
|
|
47457
47479
|
|
|
47458
47480
|
const REQUIRED_BRIDGE_VERSION = '2.2.0';
|
|
@@ -47509,56 +47531,6 @@ function getBridgeReleaseInfo({ deviceType, currentFirmwareVersion, willUpdateFi
|
|
|
47509
47531
|
});
|
|
47510
47532
|
}
|
|
47511
47533
|
|
|
47512
|
-
class CheckBridgeRelease extends BaseMethod {
|
|
47513
|
-
init() {
|
|
47514
|
-
this.allowDeviceMode = [...this.allowDeviceMode, UI_REQUEST.BOOTLOADER];
|
|
47515
|
-
this.useDevicePassphraseState = false;
|
|
47516
|
-
this.skipForceUpdateCheck = true;
|
|
47517
|
-
}
|
|
47518
|
-
run() {
|
|
47519
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
47520
|
-
if (!this.device.features) {
|
|
47521
|
-
return null;
|
|
47522
|
-
}
|
|
47523
|
-
const { willUpdateFirmwareVersion } = this.payload;
|
|
47524
|
-
const { features } = this.device;
|
|
47525
|
-
const deviceType = getDeviceType(features);
|
|
47526
|
-
const currentFirmwareVersion = getDeviceFirmwareVersion(features).join('.');
|
|
47527
|
-
return getBridgeReleaseInfo({
|
|
47528
|
-
deviceType,
|
|
47529
|
-
currentFirmwareVersion,
|
|
47530
|
-
willUpdateFirmwareVersion,
|
|
47531
|
-
});
|
|
47532
|
-
});
|
|
47533
|
-
}
|
|
47534
|
-
}
|
|
47535
|
-
|
|
47536
|
-
class CheckBootloaderRelease extends BaseMethod {
|
|
47537
|
-
init() {
|
|
47538
|
-
this.allowDeviceMode = [...this.allowDeviceMode, UI_REQUEST.BOOTLOADER];
|
|
47539
|
-
this.useDevicePassphraseState = false;
|
|
47540
|
-
this.skipForceUpdateCheck = true;
|
|
47541
|
-
}
|
|
47542
|
-
run() {
|
|
47543
|
-
var _a;
|
|
47544
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
47545
|
-
if (!this.device.features) {
|
|
47546
|
-
return null;
|
|
47547
|
-
}
|
|
47548
|
-
const { features } = this.device;
|
|
47549
|
-
const payload = this.payload;
|
|
47550
|
-
const deviceFirmwareType = this.device.getCurrentFirmwareType();
|
|
47551
|
-
const firmwareType = (_a = payload.firmwareType) !== null && _a !== void 0 ? _a : deviceFirmwareType;
|
|
47552
|
-
const releaseInfo = getBootloaderReleaseInfo({
|
|
47553
|
-
features,
|
|
47554
|
-
willUpdateFirmwareVersion: payload.willUpdateFirmwareVersion,
|
|
47555
|
-
firmwareType,
|
|
47556
|
-
});
|
|
47557
|
-
return Promise.resolve(releaseInfo);
|
|
47558
|
-
});
|
|
47559
|
-
}
|
|
47560
|
-
}
|
|
47561
|
-
|
|
47562
47534
|
const UPDATE_TARGET_BY_COMPONENT_TARGET = {
|
|
47563
47535
|
BOOTLOADER: 'boot',
|
|
47564
47536
|
APPLICATION_P1: 'app_v1',
|
|
@@ -47806,22 +47778,15 @@ class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
47806
47778
|
runProtocolV2() {
|
|
47807
47779
|
var _a;
|
|
47808
47780
|
return __awaiter(this, void 0, void 0, function* () {
|
|
47809
|
-
const { checkFirmwareHash = false, firmwareType: firmwareTypeParam } = this
|
|
47810
|
-
|
|
47811
|
-
const
|
|
47812
|
-
|
|
47813
|
-
|
|
47814
|
-
|
|
47781
|
+
const { checkFirmwareHash = false, firmwareType: firmwareTypeParam, platform, forceUpdateTargets, protocolV2ForceUpdateTargets, } = this.payload;
|
|
47782
|
+
const validatedForceUpdateTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
|
|
47783
|
+
const validatedProtocolV2ForceUpdateTargets = validateProtocolV2FirmwareUpdateTargets(protocolV2ForceUpdateTargets);
|
|
47784
|
+
const { state, features, firmwareType, release } = yield loadProtocolV2FirmwareReleaseContext({
|
|
47785
|
+
device: this.device,
|
|
47786
|
+
firmwareType: firmwareTypeParam,
|
|
47787
|
+
checkFirmwareHash,
|
|
47788
|
+
methodName: 'checkAllFirmwareRelease',
|
|
47815
47789
|
});
|
|
47816
|
-
if (state.identity.deviceType !== 'pro2' && state.identity.deviceType !== 'neo') {
|
|
47817
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotSupportMethod, 'checkAllFirmwareRelease requires a Pro2 or Neo device for Protocol V2');
|
|
47818
|
-
}
|
|
47819
|
-
const { features } = this.device;
|
|
47820
|
-
if (!features) {
|
|
47821
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'checkAllFirmwareRelease requires initialized device features');
|
|
47822
|
-
}
|
|
47823
|
-
const firmwareType = (_a = firmwareTypeParam !== null && firmwareTypeParam !== void 0 ? firmwareTypeParam : state.identity.firmwareType) !== null && _a !== void 0 ? _a : hdShared.EFirmwareType.Universal;
|
|
47824
|
-
const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
|
|
47825
47790
|
const plan = buildProtocolV2FirmwareRelease({
|
|
47826
47791
|
currentVersions: state.versions,
|
|
47827
47792
|
currentVerification: checkFirmwareHash ? state.verification : undefined,
|
|
@@ -47831,48 +47796,250 @@ class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
47831
47796
|
deviceType: state.identity.deviceType,
|
|
47832
47797
|
});
|
|
47833
47798
|
const resourceDeviceType = state.identity.deviceType === 'neo' ? hdShared.EDeviceType.Neo : hdShared.EDeviceType.Pro2;
|
|
47834
|
-
const
|
|
47835
|
-
|
|
47836
|
-
|
|
47837
|
-
|
|
47838
|
-
|
|
47839
|
-
|
|
47840
|
-
|
|
47841
|
-
|
|
47842
|
-
|
|
47843
|
-
|
|
47844
|
-
|
|
47845
|
-
|
|
47846
|
-
|
|
47847
|
-
|
|
47848
|
-
|
|
47799
|
+
const resourceSource = DataManager.getProtocolV2ResourceSource(resourceDeviceType);
|
|
47800
|
+
const resourceStatus = 'unknown';
|
|
47801
|
+
const detectedComponentTargets = validatedForceUpdateTargets.includes('firmware')
|
|
47802
|
+
? plan.components.flatMap(component => component.updateTarget ? [component.updateTarget] : [])
|
|
47803
|
+
: plan.targetsToUpdate;
|
|
47804
|
+
const componentTargetsToUpdate = Array.from(new Set([
|
|
47805
|
+
...detectedComponentTargets,
|
|
47806
|
+
...validatedProtocolV2ForceUpdateTargets.filter(target => target !== 'resource'),
|
|
47807
|
+
]));
|
|
47808
|
+
const forceResourceUpdate = validatedForceUpdateTargets.includes('resource') ||
|
|
47809
|
+
validatedProtocolV2ForceUpdateTargets.includes('resource');
|
|
47810
|
+
const targetsToUpdate = Array.from(new Set([
|
|
47811
|
+
...componentTargetsToUpdate,
|
|
47812
|
+
...(forceResourceUpdate ? ['resource'] : []),
|
|
47813
|
+
]));
|
|
47814
|
+
let firmwareUpdatePlan;
|
|
47815
|
+
const shouldBuildFirmwareUpdatePlan = targetsToUpdate.length > 0;
|
|
47816
|
+
const requestedPlatform = platform !== null && platform !== void 0 ? platform : 'web';
|
|
47817
|
+
const requiresPreparedPlan = shouldBuildFirmwareUpdatePlan &&
|
|
47818
|
+
(requestedPlatform === 'native' || requestedPlatform === 'desktop');
|
|
47819
|
+
try {
|
|
47820
|
+
if (shouldBuildFirmwareUpdatePlan) {
|
|
47821
|
+
const validatedPlan = buildProtocolV2FirmwareUpdatePlan({
|
|
47822
|
+
features,
|
|
47823
|
+
firmwareType,
|
|
47824
|
+
platform: requestedPlatform,
|
|
47825
|
+
release,
|
|
47826
|
+
targetsToUpdate,
|
|
47827
|
+
forceUpdateTargets: validatedForceUpdateTargets,
|
|
47828
|
+
resourceArchive: resourceSource,
|
|
47829
|
+
});
|
|
47830
|
+
firmwareUpdatePlan = validatedPlan;
|
|
47831
|
+
}
|
|
47832
|
+
else {
|
|
47833
|
+
firmwareUpdatePlan = undefined;
|
|
47834
|
+
}
|
|
47835
|
+
}
|
|
47836
|
+
catch (error) {
|
|
47837
|
+
if (requiresPreparedPlan ||
|
|
47838
|
+
validatedForceUpdateTargets.length > 0 ||
|
|
47839
|
+
validatedProtocolV2ForceUpdateTargets.length > 0 ||
|
|
47840
|
+
!(error instanceof hdShared.HardwareError) ||
|
|
47841
|
+
((_a = error.params) === null || _a === void 0 ? void 0 : _a.firmwareUpdateCode) !== 'FirmwarePlanInvalid') {
|
|
47842
|
+
throw error;
|
|
47843
|
+
}
|
|
47844
|
+
Log$c.warn('[CheckAllFirmwareRelease] Optional Protocol V2 firmware Plan is unavailable; using the release result');
|
|
47845
|
+
firmwareUpdatePlan = undefined;
|
|
47846
|
+
}
|
|
47847
|
+
const firmwarePlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_MAIN_FIRMWARE_TARGETS);
|
|
47848
|
+
const blePlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_BLE_TARGETS);
|
|
47849
|
+
const bootloaderPlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_BOOTLOADER_TARGETS);
|
|
47850
|
+
const { status } = plan;
|
|
47851
|
+
return Object.assign(Object.assign({ firmware: toProtocolV2FirmwareReleaseInfo({ plan: firmwarePlan, state, release }), ble: toProtocolV2FirmwareReleaseInfo({
|
|
47852
|
+
plan: blePlan,
|
|
47853
|
+
state,
|
|
47854
|
+
release: getProtocolV2ComponentReleaseInfo(plan, 'COPROCESSOR'),
|
|
47855
|
+
}), bootloader: toProtocolV2FirmwareReleaseInfo({
|
|
47856
|
+
plan: bootloaderPlan,
|
|
47857
|
+
state,
|
|
47858
|
+
release: getProtocolV2ComponentReleaseInfo(plan, 'BOOTLOADER'),
|
|
47859
|
+
}), features, protocol: 'V2', deviceType: state.identity.deviceType }, plan), { status,
|
|
47860
|
+
resourceStatus, resourceArchive: resourceSource, hasUpgrade: targetsToUpdate.length > 0, targetsToUpdate,
|
|
47861
|
+
firmwareUpdatePlan });
|
|
47862
|
+
});
|
|
47863
|
+
}
|
|
47864
|
+
}
|
|
47865
|
+
|
|
47866
|
+
class CheckFirmwareRelease extends BaseMethod {
|
|
47867
|
+
getSupportedProtocols() {
|
|
47868
|
+
return ['V1', 'V2'];
|
|
47869
|
+
}
|
|
47870
|
+
init() {
|
|
47871
|
+
this.allowDeviceMode = [
|
|
47872
|
+
...this.allowDeviceMode,
|
|
47873
|
+
UI_REQUEST.NOT_INITIALIZE,
|
|
47874
|
+
UI_REQUEST.BOOTLOADER,
|
|
47875
|
+
];
|
|
47876
|
+
this.useDevicePassphraseState = false;
|
|
47877
|
+
this.skipForceUpdateCheck = true;
|
|
47878
|
+
}
|
|
47879
|
+
run() {
|
|
47880
|
+
var _a;
|
|
47881
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
47882
|
+
const payload = this.payload;
|
|
47883
|
+
if (!this.device.features)
|
|
47884
|
+
return null;
|
|
47885
|
+
if (this.device.isProtocolV2()) {
|
|
47886
|
+
const { state, firmwareType, release } = yield loadProtocolV2FirmwareReleaseContext({
|
|
47887
|
+
device: this.device,
|
|
47888
|
+
firmwareType: payload.firmwareType,
|
|
47889
|
+
methodName: 'checkFirmwareRelease',
|
|
47890
|
+
});
|
|
47891
|
+
const plan = summarizeProtocolV2FirmwareRelease(buildProtocolV2FirmwareRelease({
|
|
47892
|
+
currentVersions: state.versions,
|
|
47893
|
+
firmwareType,
|
|
47894
|
+
release,
|
|
47895
|
+
deviceType: state.identity.deviceType,
|
|
47896
|
+
}), PROTOCOL_V2_MAIN_FIRMWARE_TARGETS);
|
|
47897
|
+
return toProtocolV2FirmwareReleaseInfo({ plan, state, release });
|
|
47898
|
+
}
|
|
47899
|
+
const deviceFirmwareType = this.device.getCurrentFirmwareType();
|
|
47900
|
+
const firmwareType = (_a = payload.firmwareType) !== null && _a !== void 0 ? _a : deviceFirmwareType;
|
|
47901
|
+
const releaseInfo = getFirmwareReleaseInfo(this.device.features, firmwareType);
|
|
47902
|
+
return releaseInfo;
|
|
47903
|
+
});
|
|
47904
|
+
}
|
|
47905
|
+
}
|
|
47906
|
+
|
|
47907
|
+
class CheckBLEFirmwareRelease extends BaseMethod {
|
|
47908
|
+
getSupportedProtocols() {
|
|
47909
|
+
return ['V1', 'V2'];
|
|
47910
|
+
}
|
|
47911
|
+
init() {
|
|
47912
|
+
this.allowDeviceMode = [
|
|
47913
|
+
...this.allowDeviceMode,
|
|
47914
|
+
UI_REQUEST.NOT_INITIALIZE,
|
|
47915
|
+
UI_REQUEST.BOOTLOADER,
|
|
47916
|
+
];
|
|
47917
|
+
this.useDevicePassphraseState = false;
|
|
47918
|
+
this.skipForceUpdateCheck = true;
|
|
47919
|
+
}
|
|
47920
|
+
run() {
|
|
47921
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
47922
|
+
if (!this.device.features)
|
|
47923
|
+
return null;
|
|
47924
|
+
if (this.device.isProtocolV2()) {
|
|
47925
|
+
const { state, firmwareType, release } = yield loadProtocolV2FirmwareReleaseContext({
|
|
47926
|
+
device: this.device,
|
|
47927
|
+
methodName: 'checkBLEFirmwareRelease',
|
|
47928
|
+
});
|
|
47929
|
+
const plan = summarizeProtocolV2FirmwareRelease(buildProtocolV2FirmwareRelease({
|
|
47930
|
+
currentVersions: state.versions,
|
|
47931
|
+
firmwareType,
|
|
47932
|
+
release,
|
|
47933
|
+
deviceType: state.identity.deviceType,
|
|
47934
|
+
}), PROTOCOL_V2_BLE_TARGETS);
|
|
47935
|
+
return toProtocolV2FirmwareReleaseInfo({
|
|
47936
|
+
plan,
|
|
47937
|
+
state,
|
|
47938
|
+
release: getProtocolV2ComponentReleaseInfo(plan, 'COPROCESSOR'),
|
|
47939
|
+
});
|
|
47940
|
+
}
|
|
47941
|
+
const releaseInfo = getBleFirmwareReleaseInfo(this.device.features);
|
|
47942
|
+
return releaseInfo;
|
|
47943
|
+
});
|
|
47944
|
+
}
|
|
47945
|
+
}
|
|
47946
|
+
|
|
47947
|
+
class CheckBridgeStatus extends BaseMethod {
|
|
47948
|
+
init() {
|
|
47949
|
+
this.useDevice = false;
|
|
47950
|
+
this.useDevicePassphraseState = false;
|
|
47951
|
+
this.skipForceUpdateCheck = true;
|
|
47952
|
+
}
|
|
47953
|
+
run() {
|
|
47954
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
47955
|
+
return new Promise((resolve, reject) => {
|
|
47956
|
+
axios__default["default"]
|
|
47957
|
+
.request({
|
|
47958
|
+
url: 'http://localhost:21320',
|
|
47959
|
+
method: 'POST',
|
|
47960
|
+
withCredentials: false,
|
|
47961
|
+
timeout: 3000,
|
|
47962
|
+
})
|
|
47963
|
+
.then(() => resolve(true))
|
|
47964
|
+
.catch(e => {
|
|
47965
|
+
if (e.code === 'ECONNABORTED') {
|
|
47966
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BridgeTimeoutError));
|
|
47849
47967
|
}
|
|
47850
|
-
|
|
47851
|
-
|
|
47852
|
-
resources,
|
|
47853
|
-
mode: 'bootloader-recovery',
|
|
47854
|
-
}).status;
|
|
47968
|
+
else {
|
|
47969
|
+
resolve(false);
|
|
47855
47970
|
}
|
|
47856
|
-
}
|
|
47971
|
+
});
|
|
47972
|
+
});
|
|
47973
|
+
});
|
|
47974
|
+
}
|
|
47975
|
+
}
|
|
47976
|
+
|
|
47977
|
+
class CheckBridgeRelease extends BaseMethod {
|
|
47978
|
+
init() {
|
|
47979
|
+
this.allowDeviceMode = [...this.allowDeviceMode, UI_REQUEST.BOOTLOADER];
|
|
47980
|
+
this.useDevicePassphraseState = false;
|
|
47981
|
+
this.skipForceUpdateCheck = true;
|
|
47982
|
+
}
|
|
47983
|
+
run() {
|
|
47984
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
47985
|
+
if (!this.device.features) {
|
|
47986
|
+
return null;
|
|
47857
47987
|
}
|
|
47858
|
-
const
|
|
47859
|
-
|
|
47860
|
-
|
|
47861
|
-
|
|
47862
|
-
|
|
47863
|
-
|
|
47864
|
-
|
|
47865
|
-
|
|
47866
|
-
|
|
47867
|
-
|
|
47868
|
-
|
|
47869
|
-
|
|
47870
|
-
|
|
47871
|
-
|
|
47872
|
-
|
|
47873
|
-
|
|
47874
|
-
|
|
47875
|
-
|
|
47988
|
+
const { willUpdateFirmwareVersion } = this.payload;
|
|
47989
|
+
const { features } = this.device;
|
|
47990
|
+
const deviceType = getDeviceType(features);
|
|
47991
|
+
const currentFirmwareVersion = getDeviceFirmwareVersion(features).join('.');
|
|
47992
|
+
return getBridgeReleaseInfo({
|
|
47993
|
+
deviceType,
|
|
47994
|
+
currentFirmwareVersion,
|
|
47995
|
+
willUpdateFirmwareVersion,
|
|
47996
|
+
});
|
|
47997
|
+
});
|
|
47998
|
+
}
|
|
47999
|
+
}
|
|
48000
|
+
|
|
48001
|
+
class CheckBootloaderRelease extends BaseMethod {
|
|
48002
|
+
getSupportedProtocols() {
|
|
48003
|
+
return ['V1', 'V2'];
|
|
48004
|
+
}
|
|
48005
|
+
init() {
|
|
48006
|
+
this.allowDeviceMode = [...this.allowDeviceMode, UI_REQUEST.BOOTLOADER];
|
|
48007
|
+
this.useDevicePassphraseState = false;
|
|
48008
|
+
this.skipForceUpdateCheck = true;
|
|
48009
|
+
}
|
|
48010
|
+
run() {
|
|
48011
|
+
var _a;
|
|
48012
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
48013
|
+
if (!this.device.features)
|
|
48014
|
+
return null;
|
|
48015
|
+
const { features } = this.device;
|
|
48016
|
+
const payload = this.payload;
|
|
48017
|
+
if (this.device.isProtocolV2()) {
|
|
48018
|
+
const { state, firmwareType, release } = yield loadProtocolV2FirmwareReleaseContext({
|
|
48019
|
+
device: this.device,
|
|
48020
|
+
firmwareType: payload.firmwareType,
|
|
48021
|
+
methodName: 'checkBootloaderRelease',
|
|
48022
|
+
});
|
|
48023
|
+
const plan = summarizeProtocolV2FirmwareRelease(buildProtocolV2FirmwareRelease({
|
|
48024
|
+
currentVersions: state.versions,
|
|
48025
|
+
firmwareType,
|
|
48026
|
+
release,
|
|
48027
|
+
deviceType: state.identity.deviceType,
|
|
48028
|
+
}), PROTOCOL_V2_BOOTLOADER_TARGETS);
|
|
48029
|
+
return toProtocolV2FirmwareReleaseInfo({
|
|
48030
|
+
plan,
|
|
48031
|
+
state,
|
|
48032
|
+
release: getProtocolV2ComponentReleaseInfo(plan, 'BOOTLOADER'),
|
|
48033
|
+
});
|
|
48034
|
+
}
|
|
48035
|
+
const deviceFirmwareType = this.device.getCurrentFirmwareType();
|
|
48036
|
+
const firmwareType = (_a = payload.firmwareType) !== null && _a !== void 0 ? _a : deviceFirmwareType;
|
|
48037
|
+
const releaseInfo = getBootloaderReleaseInfo({
|
|
48038
|
+
features,
|
|
48039
|
+
willUpdateFirmwareVersion: payload.willUpdateFirmwareVersion,
|
|
48040
|
+
firmwareType,
|
|
48041
|
+
});
|
|
48042
|
+
return Promise.resolve(releaseInfo);
|
|
47876
48043
|
});
|
|
47877
48044
|
}
|
|
47878
48045
|
}
|
|
@@ -49619,35 +49786,52 @@ class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod {
|
|
|
49619
49786
|
});
|
|
49620
49787
|
}
|
|
49621
49788
|
run() {
|
|
49622
|
-
var _a, _b
|
|
49789
|
+
var _a, _b;
|
|
49623
49790
|
return __awaiter(this, void 0, void 0, function* () {
|
|
49624
49791
|
const { device } = this;
|
|
49625
49792
|
const { features } = device;
|
|
49626
49793
|
const payload = this.payload;
|
|
49627
|
-
const
|
|
49628
|
-
|
|
49794
|
+
const hasPreparedPlan = payload.preparedPlan !== undefined;
|
|
49795
|
+
if (hasPreparedPlan && payload.binary !== undefined) {
|
|
49796
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Prepared bootloader plans cannot be combined with a legacy binary');
|
|
49797
|
+
}
|
|
49798
|
+
if (!hasPreparedPlan && payload.artifact !== undefined) {
|
|
49799
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Bootloader artifacts require a prepared plan');
|
|
49800
|
+
}
|
|
49801
|
+
const preparedPlan = hasPreparedPlan
|
|
49802
|
+
? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
|
|
49629
49803
|
: undefined;
|
|
49630
|
-
const
|
|
49631
|
-
|
|
49804
|
+
const plannedArtifact = preparedPlan
|
|
49805
|
+
? getFirmwareUpdatePreparedRawArtifact({
|
|
49806
|
+
preparedPlan,
|
|
49807
|
+
target: 'bootloader',
|
|
49808
|
+
role: 'bootloader',
|
|
49809
|
+
}).artifact
|
|
49810
|
+
: undefined;
|
|
49811
|
+
const artifactReader = preparedPlan
|
|
49812
|
+
? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration, preparedPlan.preparedPlanDigest).artifactReader
|
|
49813
|
+
: payload.artifactReader;
|
|
49814
|
+
const executionParams = Object.assign(Object.assign({}, payload), { artifactReader });
|
|
49815
|
+
if (preparedPlan && plannedArtifact) {
|
|
49632
49816
|
assertFirmwareUpdatePreparedPlanDeviceIdentity({
|
|
49633
|
-
preparedPlan
|
|
49817
|
+
preparedPlan,
|
|
49634
49818
|
deviceIdentity: getDeviceUUID(features) || undefined,
|
|
49635
49819
|
bootloaderMode: resolveDeviceBootloaderMode(features),
|
|
49636
49820
|
deviceModel: String(getDeviceType(features)),
|
|
49637
49821
|
});
|
|
49638
49822
|
assertFirmwareUpdatePreparedPlanBinding({
|
|
49639
|
-
preparedPlan
|
|
49823
|
+
preparedPlan,
|
|
49640
49824
|
executor: 'v2',
|
|
49641
49825
|
scopeTargets: ['bootloader'],
|
|
49642
49826
|
bindings: [
|
|
49643
49827
|
{
|
|
49644
49828
|
target: 'bootloader',
|
|
49645
|
-
artifact: payload.artifact,
|
|
49829
|
+
artifact: (_a = payload.artifact) !== null && _a !== void 0 ? _a : plannedArtifact,
|
|
49646
49830
|
},
|
|
49647
49831
|
],
|
|
49648
49832
|
});
|
|
49649
49833
|
const source = yield openFirmwareByteSource({
|
|
49650
|
-
artifact:
|
|
49834
|
+
artifact: plannedArtifact,
|
|
49651
49835
|
reader: executionParams.artifactReader,
|
|
49652
49836
|
});
|
|
49653
49837
|
if (!source) {
|
|
@@ -49655,13 +49839,11 @@ class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod {
|
|
|
49655
49839
|
}
|
|
49656
49840
|
try {
|
|
49657
49841
|
const deviceType = device.getCurrentDeviceType();
|
|
49658
|
-
const deviceFirmwareType = device.getCurrentFirmwareType();
|
|
49659
|
-
const firmwareType = (_b = payload.firmwareType) !== null && _b !== void 0 ? _b : deviceFirmwareType;
|
|
49660
49842
|
if (DeviceModelToTypes.model_touch.includes(deviceType)) {
|
|
49661
49843
|
return yield this.updateTouchBootloader({
|
|
49662
49844
|
device,
|
|
49663
49845
|
features,
|
|
49664
|
-
firmwareType,
|
|
49846
|
+
firmwareType: preparedPlan.firmwareType,
|
|
49665
49847
|
source,
|
|
49666
49848
|
});
|
|
49667
49849
|
}
|
|
@@ -49674,7 +49856,7 @@ class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod {
|
|
|
49674
49856
|
const { binary } = payload;
|
|
49675
49857
|
const deviceType = device.getCurrentDeviceType();
|
|
49676
49858
|
const deviceFirmwareType = device.getCurrentFirmwareType();
|
|
49677
|
-
const firmwareType = (
|
|
49859
|
+
const firmwareType = (_b = payload.firmwareType) !== null && _b !== void 0 ? _b : deviceFirmwareType;
|
|
49678
49860
|
if (DeviceModelToTypes.model_touch.includes(deviceType)) {
|
|
49679
49861
|
return this.updateTouchBootloader({
|
|
49680
49862
|
device,
|
|
@@ -49935,6 +50117,119 @@ const normalizeFirmwarePreparationError = (error) => {
|
|
|
49935
50117
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, error instanceof Error ? error.message : String(error));
|
|
49936
50118
|
};
|
|
49937
50119
|
|
|
50120
|
+
const PREPARED_RESOURCE_ARCHIVE_MAX_BYTES = 256 * 1024 * 1024;
|
|
50121
|
+
const PREPARED_RESOURCE_ENTRY_MAX_COUNT = 512;
|
|
50122
|
+
const resourceArchiveError = (message, firmwareUpdateCode) => {
|
|
50123
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, message, { firmwareUpdateCode });
|
|
50124
|
+
};
|
|
50125
|
+
const getZipEntrySizes = (entry) => {
|
|
50126
|
+
var _a;
|
|
50127
|
+
const { compressedSize, uncompressedSize } = (_a = entry._data) !== null && _a !== void 0 ? _a : {};
|
|
50128
|
+
if (!Number.isSafeInteger(compressedSize) ||
|
|
50129
|
+
Number(compressedSize) < 0 ||
|
|
50130
|
+
!Number.isSafeInteger(uncompressedSize) ||
|
|
50131
|
+
Number(uncompressedSize) <= 0) {
|
|
50132
|
+
return resourceArchiveError(`Firmware prepared resource ZIP entry size is invalid: ${entry.name}`, 'FirmwareArtifactsNotPrepared');
|
|
50133
|
+
}
|
|
50134
|
+
return {
|
|
50135
|
+
compressedSize: Number(compressedSize),
|
|
50136
|
+
uncompressedSize: Number(uncompressedSize),
|
|
50137
|
+
};
|
|
50138
|
+
};
|
|
50139
|
+
const readVerifiedPreparedResourceArchive = ({ preparedPlan, reader, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
50140
|
+
const resourceArtifacts = preparedPlan.artifacts.filter(artifact => artifact.target === 'resource');
|
|
50141
|
+
if (!preparedPlan.targetsToUpdate.includes('resource')) {
|
|
50142
|
+
if (resourceArtifacts.length > 0) {
|
|
50143
|
+
return resourceArchiveError('Firmware prepared resource artifact is outside the approved targets', 'FirmwareArtifactsNotPrepared');
|
|
50144
|
+
}
|
|
50145
|
+
return [];
|
|
50146
|
+
}
|
|
50147
|
+
if (resourceArtifacts.length !== 1) {
|
|
50148
|
+
return resourceArchiveError('Firmware prepared plan must contain exactly one materialized resource ZIP', 'FirmwareArtifactsNotPrepared');
|
|
50149
|
+
}
|
|
50150
|
+
const archiveArtifact = resourceArtifacts[0];
|
|
50151
|
+
const preparedEntries = archiveArtifact.materializedEntries;
|
|
50152
|
+
if (archiveArtifact.role !== 'resource' ||
|
|
50153
|
+
archiveArtifact.container !== 'zip' ||
|
|
50154
|
+
!(preparedEntries === null || preparedEntries === void 0 ? void 0 : preparedEntries.length)) {
|
|
50155
|
+
return resourceArchiveError('Firmware prepared plan must contain exactly one materialized resource ZIP', 'FirmwareArtifactsNotPrepared');
|
|
50156
|
+
}
|
|
50157
|
+
const archiveSource = yield openFirmwareByteSource({
|
|
50158
|
+
artifact: archiveArtifact.artifact,
|
|
50159
|
+
reader,
|
|
50160
|
+
});
|
|
50161
|
+
if (!archiveSource) {
|
|
50162
|
+
return resourceArchiveError('Firmware prepared resource ZIP is unavailable', 'FirmwareArtifactsNotPrepared');
|
|
50163
|
+
}
|
|
50164
|
+
if (archiveSource.size > PREPARED_RESOURCE_ARCHIVE_MAX_BYTES) {
|
|
50165
|
+
yield archiveSource.close().catch(() => undefined);
|
|
50166
|
+
return resourceArchiveError('Firmware prepared resource ZIP exceeds the archive size limit', 'FirmwareArtifactsNotPrepared');
|
|
50167
|
+
}
|
|
50168
|
+
let archiveBinary;
|
|
50169
|
+
try {
|
|
50170
|
+
archiveBinary = yield readFirmwareByteSourceFully(archiveSource);
|
|
50171
|
+
}
|
|
50172
|
+
finally {
|
|
50173
|
+
yield archiveSource.close().catch(() => undefined);
|
|
50174
|
+
}
|
|
50175
|
+
const archiveDigest = utils.bytesToHex(sha256.sha256(new Uint8Array(archiveBinary)));
|
|
50176
|
+
if (archiveDigest !== archiveArtifact.artifact.sha256.toLowerCase()) {
|
|
50177
|
+
return resourceArchiveError('Firmware prepared resource ZIP does not match its approved receipt', 'FirmwareArtifactReceiptMismatch');
|
|
50178
|
+
}
|
|
50179
|
+
let zip;
|
|
50180
|
+
try {
|
|
50181
|
+
zip = yield JSZip__default["default"].loadAsync(archiveBinary);
|
|
50182
|
+
}
|
|
50183
|
+
catch (_a) {
|
|
50184
|
+
return resourceArchiveError('Firmware prepared resource ZIP cannot be parsed', 'FirmwareArtifactsNotPrepared');
|
|
50185
|
+
}
|
|
50186
|
+
const zipEntries = Object.values(zip.files);
|
|
50187
|
+
if (zipEntries.some(entry => entry.unsafeOriginalName && entry.unsafeOriginalName !== entry.name)) {
|
|
50188
|
+
return resourceArchiveError('Firmware prepared resource ZIP contains an unsafe entry path', 'FirmwareArtifactsNotPrepared');
|
|
50189
|
+
}
|
|
50190
|
+
const files = zipEntries.filter(entry => !entry.dir);
|
|
50191
|
+
if (files.length === 0 || files.length > PREPARED_RESOURCE_ENTRY_MAX_COUNT) {
|
|
50192
|
+
return resourceArchiveError('Firmware prepared resource ZIP entry set is invalid', 'FirmwareArtifactsNotPrepared');
|
|
50193
|
+
}
|
|
50194
|
+
let totalSize = 0;
|
|
50195
|
+
const canonicalNames = new Set();
|
|
50196
|
+
for (const entry of files) {
|
|
50197
|
+
const { compressedSize, uncompressedSize } = getZipEntrySizes(entry);
|
|
50198
|
+
const resourceName = getFirmwareUpdateResourceName(entry.name);
|
|
50199
|
+
const canonicalName = resourceName.toLowerCase();
|
|
50200
|
+
totalSize += uncompressedSize;
|
|
50201
|
+
if (compressedSize > archiveBinary.byteLength ||
|
|
50202
|
+
uncompressedSize > PREPARED_RESOURCE_ARCHIVE_MAX_BYTES ||
|
|
50203
|
+
totalSize > PREPARED_RESOURCE_ARCHIVE_MAX_BYTES ||
|
|
50204
|
+
canonicalNames.has(canonicalName)) {
|
|
50205
|
+
return resourceArchiveError(`Firmware prepared resource ZIP entry bounds are invalid: ${entry.name}`, 'FirmwareArtifactsNotPrepared');
|
|
50206
|
+
}
|
|
50207
|
+
canonicalNames.add(canonicalName);
|
|
50208
|
+
}
|
|
50209
|
+
const preparedEntriesByName = new Map(preparedEntries.map(entry => [entry.entryName, entry]));
|
|
50210
|
+
if (preparedEntriesByName.size !== files.length || preparedEntries.length !== files.length) {
|
|
50211
|
+
return resourceArchiveError('Firmware prepared resource entries do not match the approved ZIP', 'FirmwareArtifactReceiptMismatch');
|
|
50212
|
+
}
|
|
50213
|
+
const verifiedEntries = [];
|
|
50214
|
+
for (const entry of files) {
|
|
50215
|
+
const { uncompressedSize } = getZipEntrySizes(entry);
|
|
50216
|
+
const binary = yield entry.async('arraybuffer');
|
|
50217
|
+
const preparedEntry = preparedEntriesByName.get(entry.name);
|
|
50218
|
+
const digest = utils.bytesToHex(sha256.sha256(new Uint8Array(binary)));
|
|
50219
|
+
if (binary.byteLength !== uncompressedSize ||
|
|
50220
|
+
!preparedEntry ||
|
|
50221
|
+
preparedEntry.artifact.size !== binary.byteLength ||
|
|
50222
|
+
preparedEntry.artifact.sha256.toLowerCase() !== digest) {
|
|
50223
|
+
return resourceArchiveError(`Firmware prepared resource entry does not match the approved ZIP: ${entry.name}`, 'FirmwareArtifactReceiptMismatch');
|
|
50224
|
+
}
|
|
50225
|
+
verifiedEntries.push({
|
|
50226
|
+
entryName: getFirmwareUpdateResourceName(entry.name),
|
|
50227
|
+
binary,
|
|
50228
|
+
});
|
|
50229
|
+
}
|
|
50230
|
+
return verifiedEntries;
|
|
50231
|
+
});
|
|
50232
|
+
|
|
49938
50233
|
const Log$8 = getLogger(exports.LoggerNames.Method);
|
|
49939
50234
|
const FIRMWARE_DOWNLOAD_REQUEST_OPTIONS = {
|
|
49940
50235
|
connectTimeoutMs: 60000,
|
|
@@ -50009,7 +50304,7 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50009
50304
|
};
|
|
50010
50305
|
}
|
|
50011
50306
|
init() {
|
|
50012
|
-
var _a;
|
|
50307
|
+
var _a, _b;
|
|
50013
50308
|
this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
|
|
50014
50309
|
this.requireDeviceMode = [];
|
|
50015
50310
|
this.useDevicePassphraseState = false;
|
|
@@ -50022,11 +50317,12 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50022
50317
|
{ name: 'platform', type: 'string', required: true },
|
|
50023
50318
|
{ name: 'firmwareType', type: 'string' },
|
|
50024
50319
|
]);
|
|
50025
|
-
|
|
50026
|
-
|
|
50027
|
-
'
|
|
50028
|
-
|
|
50029
|
-
|
|
50320
|
+
const hasPreparedPlan = payload.preparedPlan !== undefined;
|
|
50321
|
+
if (hasPreparedPlan && (payload.binary !== undefined || payload.version !== undefined)) {
|
|
50322
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Prepared firmware plans cannot be combined with legacy firmware inputs');
|
|
50323
|
+
}
|
|
50324
|
+
if (!hasPreparedPlan && payload.artifact !== undefined) {
|
|
50325
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Firmware artifacts require a prepared plan');
|
|
50030
50326
|
}
|
|
50031
50327
|
if (!payload.updateType) {
|
|
50032
50328
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'updateType is required');
|
|
@@ -50036,28 +50332,37 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50036
50332
|
forcedUpdateRes: payload.forcedUpdateRes,
|
|
50037
50333
|
isUpdateBootloader: payload.isUpdateBootloader,
|
|
50038
50334
|
};
|
|
50039
|
-
if ('version' in payload) {
|
|
50335
|
+
if (!hasPreparedPlan && 'version' in payload) {
|
|
50040
50336
|
this.params = Object.assign(Object.assign({}, this.params), { version: payload.version, firmwareType: payload.firmwareType });
|
|
50041
50337
|
}
|
|
50042
|
-
if ('binary' in payload) {
|
|
50338
|
+
if (!hasPreparedPlan && 'binary' in payload) {
|
|
50043
50339
|
this.params = Object.assign(Object.assign({}, this.params), { binary: payload.binary });
|
|
50044
50340
|
}
|
|
50045
|
-
if (
|
|
50046
|
-
const
|
|
50341
|
+
if (hasPreparedPlan) {
|
|
50342
|
+
const preparedPlan = validateFirmwareUpdatePreparedPlan(payload.preparedPlan);
|
|
50343
|
+
const hostBinding = resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration, preparedPlan.preparedPlanDigest);
|
|
50047
50344
|
const target = payload.isUpdateBootloader ? 'bootloader' : payload.updateType;
|
|
50345
|
+
const plannedArtifact = getFirmwareUpdatePreparedRawArtifact({
|
|
50346
|
+
preparedPlan,
|
|
50347
|
+
target,
|
|
50348
|
+
role: target,
|
|
50349
|
+
}).artifact;
|
|
50048
50350
|
const resourceBindings = ((_a = payload.resourceEntries) !== null && _a !== void 0 ? _a : []).map((entry) => ({
|
|
50049
50351
|
target: 'resource',
|
|
50050
50352
|
entryName: entry.entryName,
|
|
50051
50353
|
artifact: entry.artifact,
|
|
50052
50354
|
}));
|
|
50053
50355
|
assertFirmwareUpdatePreparedPlanBinding({
|
|
50054
|
-
preparedPlan
|
|
50356
|
+
preparedPlan,
|
|
50055
50357
|
executor: 'v2',
|
|
50056
50358
|
platform: payload.platform,
|
|
50057
|
-
scopeTargets: [
|
|
50058
|
-
|
|
50359
|
+
scopeTargets: [
|
|
50360
|
+
target,
|
|
50361
|
+
...(target === 'firmware' && resourceBindings.length ? ['resource'] : []),
|
|
50362
|
+
],
|
|
50363
|
+
bindings: [{ target, artifact: (_b = payload.artifact) !== null && _b !== void 0 ? _b : plannedArtifact }, ...resourceBindings],
|
|
50059
50364
|
});
|
|
50060
|
-
this.params = Object.assign(Object.assign({}, this.params), { preparedPlan
|
|
50365
|
+
this.params = Object.assign(Object.assign({}, this.params), { preparedPlan, artifact: plannedArtifact, artifactReader: hostBinding.artifactReader, firmwareType: preparedPlan.firmwareType });
|
|
50061
50366
|
}
|
|
50062
50367
|
}
|
|
50063
50368
|
_promptDeviceInBootloaderForWebDevice() {
|
|
@@ -50207,7 +50512,7 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50207
50512
|
}
|
|
50208
50513
|
}
|
|
50209
50514
|
run() {
|
|
50210
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
50515
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
50211
50516
|
return __awaiter(this, void 0, void 0, function* () {
|
|
50212
50517
|
const { device, params } = this;
|
|
50213
50518
|
const { features, commands } = device;
|
|
@@ -50295,13 +50600,48 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50295
50600
|
throw normalizeFirmwarePreparationError(err);
|
|
50296
50601
|
}
|
|
50297
50602
|
});
|
|
50603
|
+
const preparedResourceRequested = !params.isUpdateBootloader &&
|
|
50604
|
+
params.updateType === 'firmware' &&
|
|
50605
|
+
((_c = (_b = params.preparedPlan) === null || _b === void 0 ? void 0 : _b.targetsToUpdate.includes('resource')) !== null && _c !== void 0 ? _c : false);
|
|
50606
|
+
if (preparedResourceRequested && device.isBootloader()) {
|
|
50607
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Prepared firmware resources require the device application mode', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared', artifactName: 'resource' });
|
|
50608
|
+
}
|
|
50298
50609
|
if (!device.isBootloader() && features) {
|
|
50299
50610
|
const serialNo = device.getCurrentSerialNo();
|
|
50300
50611
|
if (this.isEnteredManuallyBoot()) {
|
|
50301
50612
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateManuallyEnterBoot);
|
|
50302
50613
|
}
|
|
50303
50614
|
yield acquireFirmwareSource();
|
|
50304
|
-
if (
|
|
50615
|
+
if (preparedResourceRequested) {
|
|
50616
|
+
if (!this.isSupportResourceUpdate(params.updateType)) {
|
|
50617
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Prepared firmware resources are not supported by this device', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared', artifactName: 'resource' });
|
|
50618
|
+
}
|
|
50619
|
+
this.postTipMessage('CheckLatestUiResource');
|
|
50620
|
+
this.postTipMessage('DownloadLatestUiResource');
|
|
50621
|
+
const verifiedEntries = yield readVerifiedPreparedResourceArchive({
|
|
50622
|
+
preparedPlan: params.preparedPlan,
|
|
50623
|
+
reader: params.artifactReader,
|
|
50624
|
+
});
|
|
50625
|
+
const sources = [];
|
|
50626
|
+
try {
|
|
50627
|
+
for (const entry of verifiedEntries) {
|
|
50628
|
+
const source = yield openFirmwareByteSource({ binary: entry.binary });
|
|
50629
|
+
if (!source) {
|
|
50630
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Firmware resource entry ${entry.entryName} is empty`, {
|
|
50631
|
+
firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch',
|
|
50632
|
+
artifactName: 'resource',
|
|
50633
|
+
});
|
|
50634
|
+
}
|
|
50635
|
+
sources.push({ entryName: entry.entryName, source });
|
|
50636
|
+
}
|
|
50637
|
+
yield updateResourcesFromSources(this.device.getCommands().typedCall.bind(this.device.getCommands()), this.postMessage, device, sources);
|
|
50638
|
+
}
|
|
50639
|
+
finally {
|
|
50640
|
+
yield Promise.all(sources.map(entry => entry.source.close().catch(() => undefined)));
|
|
50641
|
+
}
|
|
50642
|
+
this.postTipMessage('DownloadLatestUiResourceSuccess');
|
|
50643
|
+
}
|
|
50644
|
+
else if (this.isSupportResourceUpdate(params.updateType)) {
|
|
50305
50645
|
this.postTipMessage('CheckLatestUiResource');
|
|
50306
50646
|
const resourceUrl = DataManager.getSysResourcesLatestRelease({
|
|
50307
50647
|
features,
|
|
@@ -50310,46 +50650,20 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50310
50650
|
});
|
|
50311
50651
|
if (resourceUrl) {
|
|
50312
50652
|
this.postTipMessage('DownloadLatestUiResource');
|
|
50313
|
-
if (
|
|
50314
|
-
|
|
50315
|
-
|
|
50316
|
-
|
|
50317
|
-
|
|
50318
|
-
|
|
50319
|
-
artifact: entry.artifact,
|
|
50320
|
-
reader: params.artifactReader,
|
|
50321
|
-
});
|
|
50322
|
-
if (!source) {
|
|
50323
|
-
throw new Error('Firmware resource entry is not prepared');
|
|
50324
|
-
}
|
|
50325
|
-
sources.push({ entryName: resourceName, source });
|
|
50326
|
-
}
|
|
50327
|
-
yield updateResourcesFromSources(this.device.getCommands().typedCall.bind(this.device.getCommands()), this.postMessage, device, sources.map(entry => ({
|
|
50328
|
-
entryName: entry.entryName,
|
|
50329
|
-
source: entry.source,
|
|
50330
|
-
})));
|
|
50331
|
-
}
|
|
50332
|
-
finally {
|
|
50333
|
-
yield Promise.all(sources.map(entry => entry.source.close().catch(() => undefined)));
|
|
50334
|
-
}
|
|
50335
|
-
this.postTipMessage('DownloadLatestUiResourceSuccess');
|
|
50336
|
-
}
|
|
50337
|
-
else {
|
|
50338
|
-
if (params.artifactReader ||
|
|
50339
|
-
DataManager.getSettings('firmwareManifestMode') === 'external-only') {
|
|
50340
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware resource must be prepared by the external firmware host', {
|
|
50341
|
-
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
50342
|
-
artifactName: 'resource',
|
|
50343
|
-
});
|
|
50344
|
-
}
|
|
50345
|
-
const resourceBinary = (yield getSysResourceBinary(resourceUrl))
|
|
50346
|
-
.binary;
|
|
50347
|
-
this.postTipMessage('DownloadLatestUiResourceSuccess');
|
|
50348
|
-
yield updateResources(this.device.getCommands().typedCall.bind(this.device.getCommands()), this.postMessage, device, resourceBinary);
|
|
50653
|
+
if (params.artifactReader ||
|
|
50654
|
+
DataManager.getSettings('firmwareManifestMode') === 'external-only') {
|
|
50655
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware resource must be prepared by the external firmware host', {
|
|
50656
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
50657
|
+
artifactName: 'resource',
|
|
50658
|
+
});
|
|
50349
50659
|
}
|
|
50660
|
+
const resourceBinary = (yield getSysResourceBinary(resourceUrl))
|
|
50661
|
+
.binary;
|
|
50662
|
+
this.postTipMessage('DownloadLatestUiResourceSuccess');
|
|
50663
|
+
yield updateResources(this.device.getCommands().typedCall.bind(this.device.getCommands()), this.postMessage, device, resourceBinary);
|
|
50350
50664
|
}
|
|
50351
50665
|
}
|
|
50352
|
-
(
|
|
50666
|
+
(_e = (_d = this.device) === null || _d === void 0 ? void 0 : _d.commands) === null || _e === void 0 ? void 0 : _e.checkDisposed();
|
|
50353
50667
|
try {
|
|
50354
50668
|
this.postTipMessage('AutoRebootToBootloader');
|
|
50355
50669
|
const bootRes = yield commands.typedCall('DeviceBackToBoot', 'Success');
|
|
@@ -50362,9 +50676,9 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50362
50676
|
DevicePool.clearDeviceCache(serialNo);
|
|
50363
50677
|
}
|
|
50364
50678
|
delete DevicePool.devicesCache[''];
|
|
50365
|
-
yield ((
|
|
50679
|
+
yield ((_f = this.checkPromise) === null || _f === void 0 ? void 0 : _f.promise);
|
|
50366
50680
|
this.checkPromise = null;
|
|
50367
|
-
(
|
|
50681
|
+
(_h = (_g = this.device) === null || _g === void 0 ? void 0 : _g.commands) === null || _h === void 0 ? void 0 : _h.checkDisposed();
|
|
50368
50682
|
const isTouch = DeviceModelToTypes.model_touch.includes(deviceType);
|
|
50369
50683
|
yield wait(isTouch ? 3000 : 1500);
|
|
50370
50684
|
}
|
|
@@ -50377,7 +50691,7 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50377
50691
|
}
|
|
50378
50692
|
}
|
|
50379
50693
|
const source = yield acquireFirmwareSource();
|
|
50380
|
-
(
|
|
50694
|
+
(_k = (_j = this.device) === null || _j === void 0 ? void 0 : _j.commands) === null || _k === void 0 ? void 0 : _k.checkDisposed();
|
|
50381
50695
|
yield this.device.acquire();
|
|
50382
50696
|
const response = yield uploadFirmwareFromSource(params.updateType, this.device.getCommands().typedCall.bind(this.device.getCommands()), this.postMessage, device, source, true, params.isUpdateBootloader);
|
|
50383
50697
|
if (this.connectId) {
|
|
@@ -50402,7 +50716,7 @@ class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod {
|
|
|
50402
50716
|
this.artifactSources = [];
|
|
50403
50717
|
}
|
|
50404
50718
|
init() {
|
|
50405
|
-
var _a, _b, _c
|
|
50719
|
+
var _a, _b, _c;
|
|
50406
50720
|
this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
|
|
50407
50721
|
this.requireDeviceMode = [];
|
|
50408
50722
|
this.useDevicePassphraseState = false;
|
|
@@ -50420,50 +50734,80 @@ class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod {
|
|
|
50420
50734
|
{ name: 'firmwareType', type: 'string' },
|
|
50421
50735
|
{ name: 'platform', type: 'string' },
|
|
50422
50736
|
]);
|
|
50423
|
-
const
|
|
50424
|
-
|
|
50737
|
+
const hasPreparedPlan = payload.preparedPlan !== undefined;
|
|
50738
|
+
if (!hasPreparedPlan && payload.artifacts !== undefined) {
|
|
50739
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Firmware artifacts require a prepared plan');
|
|
50740
|
+
}
|
|
50741
|
+
const preparedPlan = hasPreparedPlan
|
|
50742
|
+
? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
|
|
50425
50743
|
: undefined;
|
|
50426
|
-
|
|
50744
|
+
const hasLegacyInputs = [
|
|
50745
|
+
payload.bleVersion,
|
|
50746
|
+
payload.bleBinary,
|
|
50747
|
+
payload.firmwareVersion,
|
|
50748
|
+
payload.firmwareBinary,
|
|
50749
|
+
payload.resourceBinary,
|
|
50750
|
+
payload.bootloaderVersion,
|
|
50751
|
+
payload.bootloaderBinary,
|
|
50752
|
+
].some(input => input !== undefined);
|
|
50753
|
+
if (preparedPlan && hasLegacyInputs) {
|
|
50754
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Prepared firmware plans cannot be combined with legacy firmware inputs');
|
|
50755
|
+
}
|
|
50756
|
+
const artifactReader = preparedPlan
|
|
50757
|
+
? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration, preparedPlan.preparedPlanDigest).artifactReader
|
|
50758
|
+
: payload.artifactReader;
|
|
50759
|
+
const preparedArtifacts = {};
|
|
50760
|
+
if (preparedPlan) {
|
|
50761
|
+
const componentTargets = ['bootloader', 'firmware', 'ble'];
|
|
50762
|
+
const supportedTargets = new Set([...componentTargets, 'resource']);
|
|
50763
|
+
const unsupportedTarget = preparedPlan.targetsToUpdate.find(target => !supportedTargets.has(target));
|
|
50764
|
+
if (unsupportedTarget) {
|
|
50765
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Firmware prepared plan target ${unsupportedTarget} is not supported by V3`, { firmwareUpdateCode: 'FirmwarePreparedPlanInvalid' });
|
|
50766
|
+
}
|
|
50767
|
+
for (const target of componentTargets) {
|
|
50768
|
+
if (preparedPlan.targetsToUpdate.includes(target)) {
|
|
50769
|
+
preparedArtifacts[target] = getFirmwareUpdatePreparedRawArtifact({
|
|
50770
|
+
preparedPlan,
|
|
50771
|
+
target,
|
|
50772
|
+
role: target,
|
|
50773
|
+
}).artifact;
|
|
50774
|
+
}
|
|
50775
|
+
}
|
|
50776
|
+
const resourceBindings = ((_b = (_a = payload.artifacts) === null || _a === void 0 ? void 0 : _a.resourceEntries) !== null && _b !== void 0 ? _b : []).map((entry) => ({
|
|
50777
|
+
target: 'resource',
|
|
50778
|
+
entryName: entry.entryName,
|
|
50779
|
+
artifact: entry.artifact,
|
|
50780
|
+
}));
|
|
50427
50781
|
assertFirmwareUpdatePreparedPlanBinding({
|
|
50428
|
-
preparedPlan
|
|
50782
|
+
preparedPlan,
|
|
50429
50783
|
executor: 'v3',
|
|
50430
50784
|
platform: payload.platform,
|
|
50431
|
-
scopeTargets: [
|
|
50785
|
+
scopeTargets: [
|
|
50786
|
+
'bootloader',
|
|
50787
|
+
'firmware',
|
|
50788
|
+
'ble',
|
|
50789
|
+
...(resourceBindings.length ? ['resource'] : []),
|
|
50790
|
+
],
|
|
50432
50791
|
bindings: [
|
|
50433
|
-
...(
|
|
50434
|
-
|
|
50435
|
-
|
|
50436
|
-
|
|
50437
|
-
|
|
50438
|
-
|
|
50439
|
-
|
|
50440
|
-
|
|
50441
|
-
|
|
50442
|
-
|
|
50443
|
-
|
|
50444
|
-
|
|
50445
|
-
|
|
50446
|
-
|
|
50447
|
-
]
|
|
50448
|
-
: []),
|
|
50449
|
-
...(((_c = payload.artifacts) === null || _c === void 0 ? void 0 : _c.ble)
|
|
50450
|
-
? [
|
|
50451
|
-
{
|
|
50452
|
-
target: 'ble',
|
|
50453
|
-
artifact: payload.artifacts.ble,
|
|
50454
|
-
},
|
|
50455
|
-
]
|
|
50456
|
-
: []),
|
|
50457
|
-
...((_e = (_d = payload.artifacts) === null || _d === void 0 ? void 0 : _d.resourceEntries) !== null && _e !== void 0 ? _e : []).map((entry) => ({
|
|
50458
|
-
target: 'resource',
|
|
50459
|
-
entryName: entry.entryName,
|
|
50460
|
-
artifact: entry.artifact,
|
|
50461
|
-
})),
|
|
50792
|
+
...componentTargets.flatMap(target => {
|
|
50793
|
+
var _a;
|
|
50794
|
+
const plannedArtifact = preparedArtifacts[target];
|
|
50795
|
+
const suppliedArtifact = (_a = payload.artifacts) === null || _a === void 0 ? void 0 : _a[target];
|
|
50796
|
+
return plannedArtifact || suppliedArtifact
|
|
50797
|
+
? [
|
|
50798
|
+
{
|
|
50799
|
+
target,
|
|
50800
|
+
artifact: suppliedArtifact !== null && suppliedArtifact !== void 0 ? suppliedArtifact : plannedArtifact,
|
|
50801
|
+
},
|
|
50802
|
+
]
|
|
50803
|
+
: [];
|
|
50804
|
+
}),
|
|
50805
|
+
...resourceBindings,
|
|
50462
50806
|
],
|
|
50463
50807
|
});
|
|
50464
50808
|
}
|
|
50465
50809
|
this.params = {
|
|
50466
|
-
preparedPlan
|
|
50810
|
+
preparedPlan,
|
|
50467
50811
|
bleBinary: payload.bleBinary,
|
|
50468
50812
|
firmwareBinary: payload.firmwareBinary,
|
|
50469
50813
|
forcedUpdateRes: payload.forcedUpdateRes,
|
|
@@ -50472,10 +50816,10 @@ class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod {
|
|
|
50472
50816
|
bootloaderBinary: payload.bootloaderBinary,
|
|
50473
50817
|
firmwareVersion: payload.firmwareVersion,
|
|
50474
50818
|
resourceBinary: payload.resourceBinary,
|
|
50475
|
-
firmwareType: payload.firmwareType,
|
|
50819
|
+
firmwareType: (_c = preparedPlan === null || preparedPlan === void 0 ? void 0 : preparedPlan.firmwareType) !== null && _c !== void 0 ? _c : payload.firmwareType,
|
|
50476
50820
|
platform: payload.platform,
|
|
50477
|
-
artifactReader
|
|
50478
|
-
artifacts:
|
|
50821
|
+
artifactReader,
|
|
50822
|
+
artifacts: preparedPlan ? preparedArtifacts : undefined,
|
|
50479
50823
|
};
|
|
50480
50824
|
}
|
|
50481
50825
|
run() {
|
|
@@ -50581,19 +50925,21 @@ class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod {
|
|
|
50581
50925
|
prepareResourceInput(firmwareType) {
|
|
50582
50926
|
var _a;
|
|
50583
50927
|
return __awaiter(this, void 0, void 0, function* () {
|
|
50584
|
-
|
|
50585
|
-
|
|
50586
|
-
|
|
50587
|
-
|
|
50588
|
-
|
|
50928
|
+
if ((_a = this.params.preparedPlan) === null || _a === void 0 ? void 0 : _a.targetsToUpdate.includes('resource')) {
|
|
50929
|
+
const verifiedEntries = yield readVerifiedPreparedResourceArchive({
|
|
50930
|
+
preparedPlan: this.params.preparedPlan,
|
|
50931
|
+
reader: this.params.artifactReader,
|
|
50932
|
+
});
|
|
50589
50933
|
const resourceEntries = [];
|
|
50590
|
-
for (const entry of
|
|
50591
|
-
const
|
|
50592
|
-
const source = yield this.openArtifactSource(undefined, entry.artifact);
|
|
50934
|
+
for (const entry of verifiedEntries) {
|
|
50935
|
+
const source = yield this.openArtifactSource(entry.binary, undefined);
|
|
50593
50936
|
if (!source) {
|
|
50594
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Firmware resource entry ${entry.entryName} is
|
|
50937
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Firmware resource entry ${entry.entryName} is empty`, {
|
|
50938
|
+
firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch',
|
|
50939
|
+
artifactName: 'resource',
|
|
50940
|
+
});
|
|
50595
50941
|
}
|
|
50596
|
-
resourceEntries.push({ entryName:
|
|
50942
|
+
resourceEntries.push({ entryName: entry.entryName, source });
|
|
50597
50943
|
}
|
|
50598
50944
|
return {
|
|
50599
50945
|
resourceBinary: null,
|
|
@@ -51090,6 +51436,88 @@ const INSTALLABLE_FIRMWARE_TARGET_IDS = new Set([
|
|
|
51090
51436
|
]);
|
|
51091
51437
|
new Map(Object.entries(ProtocolV2FirmwareTargetType).flatMap(([key, value]) => INSTALLABLE_FIRMWARE_TARGET_IDS.has(value) ? [[key, value]] : []));
|
|
51092
51438
|
|
|
51439
|
+
let memoryHostSequence = 0;
|
|
51440
|
+
const createReference = (binary, prefix) => {
|
|
51441
|
+
const digest = utils.bytesToHex(sha256.sha256(new Uint8Array(binary)));
|
|
51442
|
+
return {
|
|
51443
|
+
artifactRef: `fwmem:${prefix}:${digest.slice(0, 32)}`,
|
|
51444
|
+
size: binary.byteLength,
|
|
51445
|
+
sha256: digest,
|
|
51446
|
+
};
|
|
51447
|
+
};
|
|
51448
|
+
function prepareFirmwareUpdateV4MemoryHost({ sdk, plan, artifacts, }) {
|
|
51449
|
+
if (plan.executor !== 'v4') {
|
|
51450
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware memory host only supports V4 plans');
|
|
51451
|
+
}
|
|
51452
|
+
memoryHostSequence += 1;
|
|
51453
|
+
const hostId = `${Date.now()}:${memoryHostSequence}`;
|
|
51454
|
+
const binaries = new Map();
|
|
51455
|
+
const inputs = artifacts.map((input, artifactIndex) => {
|
|
51456
|
+
var _a;
|
|
51457
|
+
const artifactBinary = new Uint8Array(input.binary).slice();
|
|
51458
|
+
const artifact = createReference(artifactBinary.buffer, `${hostId}:artifact:${artifactIndex}`);
|
|
51459
|
+
binaries.set(artifact.artifactRef, artifactBinary);
|
|
51460
|
+
const materializedEntries = (_a = input.materializedEntries) === null || _a === void 0 ? void 0 : _a.map((entry, entryIndex) => {
|
|
51461
|
+
const entryBinary = new Uint8Array(entry.binary).slice();
|
|
51462
|
+
const entryArtifact = createReference(entryBinary.buffer, `${hostId}:entry:${artifactIndex}:${entryIndex}`);
|
|
51463
|
+
binaries.set(entryArtifact.artifactRef, entryBinary);
|
|
51464
|
+
return {
|
|
51465
|
+
entryName: entry.entryName,
|
|
51466
|
+
artifact: entryArtifact,
|
|
51467
|
+
};
|
|
51468
|
+
});
|
|
51469
|
+
return Object.assign({ artifactId: input.artifactId, artifact }, ((materializedEntries === null || materializedEntries === void 0 ? void 0 : materializedEntries.length) ? { materializedEntries } : {}));
|
|
51470
|
+
});
|
|
51471
|
+
const preparedPlan = sdk.prepareFirmwareUpdatePlan({
|
|
51472
|
+
plan,
|
|
51473
|
+
leaseRef: `fwmemlease:${hostId}`,
|
|
51474
|
+
artifacts: inputs,
|
|
51475
|
+
});
|
|
51476
|
+
const readers = new Map();
|
|
51477
|
+
let readerSequence = 0;
|
|
51478
|
+
const artifactReader = {
|
|
51479
|
+
open({ artifactRef }) {
|
|
51480
|
+
const binary = binaries.get(artifactRef);
|
|
51481
|
+
if (!binary) {
|
|
51482
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware memory artifact is unavailable');
|
|
51483
|
+
}
|
|
51484
|
+
readerSequence += 1;
|
|
51485
|
+
const readerId = `fwmemreader:${hostId}:${readerSequence}`;
|
|
51486
|
+
readers.set(readerId, binary);
|
|
51487
|
+
return Promise.resolve({ readerId, size: binary.byteLength });
|
|
51488
|
+
},
|
|
51489
|
+
read({ readerId, offset, length }) {
|
|
51490
|
+
const binary = readers.get(readerId);
|
|
51491
|
+
if (!binary || offset < 0 || length <= 0 || offset + length > binary.byteLength) {
|
|
51492
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware memory artifact read is invalid');
|
|
51493
|
+
}
|
|
51494
|
+
const data = binary.slice(offset, offset + length).buffer;
|
|
51495
|
+
return Promise.resolve({
|
|
51496
|
+
data,
|
|
51497
|
+
bytesRead: data.byteLength,
|
|
51498
|
+
eof: offset + length === binary.byteLength,
|
|
51499
|
+
});
|
|
51500
|
+
},
|
|
51501
|
+
close({ readerId }) {
|
|
51502
|
+
readers.delete(readerId);
|
|
51503
|
+
return Promise.resolve();
|
|
51504
|
+
},
|
|
51505
|
+
};
|
|
51506
|
+
const hostBindingGeneration = sdk.registerFirmwareUpdateHostBinding({
|
|
51507
|
+
artifactReader,
|
|
51508
|
+
preparedPlanDigest: preparedPlan.preparedPlanDigest,
|
|
51509
|
+
});
|
|
51510
|
+
return {
|
|
51511
|
+
preparedPlan,
|
|
51512
|
+
hostBindingGeneration,
|
|
51513
|
+
release: () => {
|
|
51514
|
+
sdk.unregisterFirmwareUpdateHostBinding(hostBindingGeneration);
|
|
51515
|
+
readers.clear();
|
|
51516
|
+
binaries.clear();
|
|
51517
|
+
},
|
|
51518
|
+
};
|
|
51519
|
+
}
|
|
51520
|
+
|
|
51093
51521
|
const Log$6 = getLogger(exports.LoggerNames.Method);
|
|
51094
51522
|
const SESSION_ERROR$1 = 'session not found';
|
|
51095
51523
|
const PROTOCOL_V2_BOOTLOADER_RECONNECT_TIMEOUT = 90 * 1000;
|
|
@@ -51116,7 +51544,24 @@ const PROTOCOL_V2_OKPP_HEADER_SIZE = 0x52a0;
|
|
|
51116
51544
|
const PROTOCOL_V2_OKPP_PAYLOAD_HASH_OFFSET = 0x200;
|
|
51117
51545
|
const PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET = 0x240;
|
|
51118
51546
|
const PROTOCOL_V2_OKPP_HASH_SIZE = 64;
|
|
51547
|
+
const PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES = 1024 * 1024;
|
|
51548
|
+
const PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT = 512;
|
|
51549
|
+
const PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES = 256 * 1024 * 1024;
|
|
51119
51550
|
const PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS = new Set(['se03', 'se04']);
|
|
51551
|
+
const getProtocolV2ZipEntrySizes = (entry) => {
|
|
51552
|
+
var _a;
|
|
51553
|
+
const { compressedSize, uncompressedSize } = (_a = entry._data) !== null && _a !== void 0 ? _a : {};
|
|
51554
|
+
if (!Number.isSafeInteger(compressedSize) ||
|
|
51555
|
+
Number(compressedSize) < 0 ||
|
|
51556
|
+
!Number.isSafeInteger(uncompressedSize) ||
|
|
51557
|
+
Number(uncompressedSize) <= 0) {
|
|
51558
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local resource ZIP entry size is invalid: ${entry.name}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
51559
|
+
}
|
|
51560
|
+
return {
|
|
51561
|
+
compressedSize: Number(compressedSize),
|
|
51562
|
+
uncompressedSize: Number(uncompressedSize),
|
|
51563
|
+
};
|
|
51564
|
+
};
|
|
51120
51565
|
function assertProtocolV2FirmwareTargetsSupported(deviceType, params) {
|
|
51121
51566
|
var _a;
|
|
51122
51567
|
const unsupportedTargets = new Set(((_a = params.targetsToUpdate) !== null && _a !== void 0 ? _a : []).filter(target => PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS.has(target)));
|
|
@@ -51187,6 +51632,14 @@ const PROTOCOL_V2_REMOTE_COMPONENT_TARGETS = {
|
|
|
51187
51632
|
},
|
|
51188
51633
|
};
|
|
51189
51634
|
const PROTOCOL_V2_FIRMWARE_STAGING_PATHS = new Set(Object.values(PROTOCOL_V2_REMOTE_COMPONENT_TARGETS).map(target => `${PROTOCOL_V2_FIRMWARE_STAGING_VOLUME}${target.fileName}`));
|
|
51635
|
+
const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH = 'vol0:/loaders/bootloader/boot_resource.okpkg';
|
|
51636
|
+
const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_STAGING_PATH = `${PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH}.staging`;
|
|
51637
|
+
const isProtocolV2BootResourcePackagePath = (devicePath) => typeof devicePath === 'string' &&
|
|
51638
|
+
devicePath.replace(/^vol0:(?!\/)/i, 'vol0:/').toLowerCase() ===
|
|
51639
|
+
PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH;
|
|
51640
|
+
const resolveProtocolV2ResourceWritePath = (devicePath) => isProtocolV2BootResourcePackagePath(devicePath)
|
|
51641
|
+
? PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_STAGING_PATH
|
|
51642
|
+
: devicePath;
|
|
51190
51643
|
const PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID = new Map([
|
|
51191
51644
|
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER, 'boot'],
|
|
51192
51645
|
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P1, 'app_v1'],
|
|
@@ -51197,6 +51650,10 @@ const PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID = new Map([
|
|
|
51197
51650
|
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE03, 'se03'],
|
|
51198
51651
|
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE04, 'se04'],
|
|
51199
51652
|
]);
|
|
51653
|
+
const PROTOCOL_V2_INSTALL_TARGET_BY_UPDATE_TARGET = new Map(Object.values(PROTOCOL_V2_REMOTE_COMPONENT_TARGETS).map(target => [
|
|
51654
|
+
PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(target.targetId),
|
|
51655
|
+
target,
|
|
51656
|
+
]));
|
|
51200
51657
|
const PROTOCOL_V2_ROMLOADER_UNSUPPORTED_MESSAGE = 'FW_MGMT_TARGET_ROMLOADER is not accepted by the current Pro2 bootloader update request. Flash romloader with the loader-specific flow instead of firmwareUpdateV4.';
|
|
51201
51658
|
const PROTOCOL_V2_TARGET_ID_BY_DECODED_NAME = new Map(Object.entries(ProtocolV2FirmwareTargetType).map(([key, value]) => [key, value]));
|
|
51202
51659
|
const PROTOCOL_V2_TARGET_STATUS_BY_DECODED_NAME = new Map([
|
|
@@ -51354,6 +51811,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51354
51811
|
super(...arguments);
|
|
51355
51812
|
this.protocolV2PreparedSources = [];
|
|
51356
51813
|
this.protocolV2ExecutionInLoader = false;
|
|
51814
|
+
this.protocolV2BootResourceStagingSafe = false;
|
|
51357
51815
|
this.protocolV2CompletedTargetVersions = new Map();
|
|
51358
51816
|
this.protocolV2FinalStatusVerified = false;
|
|
51359
51817
|
}
|
|
@@ -51361,7 +51819,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51361
51819
|
return ['V2'];
|
|
51362
51820
|
}
|
|
51363
51821
|
init() {
|
|
51364
|
-
var _a, _b
|
|
51822
|
+
var _a, _b;
|
|
51365
51823
|
this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
|
|
51366
51824
|
this.requireDeviceMode = [];
|
|
51367
51825
|
this.unlockPolicy = 'unlock-before-run';
|
|
@@ -51392,54 +51850,85 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51392
51850
|
{ name: 'se02Binary', type: 'buffer' },
|
|
51393
51851
|
{ name: 'se03Binary', type: 'buffer' },
|
|
51394
51852
|
{ name: 'se04Binary', type: 'buffer' },
|
|
51853
|
+
{ name: 'resourceArchiveBinary', type: 'buffer' },
|
|
51395
51854
|
{ name: 'firmwareType', type: 'string' },
|
|
51396
51855
|
{ name: 'targetsToUpdate', type: 'array', allowEmpty: true },
|
|
51397
51856
|
{ name: 'platform', type: 'string' },
|
|
51398
51857
|
{ name: 'expectedDeviceId', type: 'string' },
|
|
51399
|
-
{ name: 'resourceFiles', type: 'array', allowEmpty: true },
|
|
51400
51858
|
]);
|
|
51401
51859
|
if (payload.expectedDeviceId !== undefined &&
|
|
51402
51860
|
(payload.expectedDeviceId.length === 0 || payload.expectedDeviceId.length > 160)) {
|
|
51403
51861
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Protocol V2 expected device identity is invalid');
|
|
51404
51862
|
}
|
|
51405
|
-
const
|
|
51406
|
-
?
|
|
51863
|
+
const preparedPlan = payload.preparedPlan
|
|
51864
|
+
? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
|
|
51407
51865
|
: undefined;
|
|
51408
|
-
|
|
51866
|
+
const hasLocalArtifacts = [
|
|
51867
|
+
payload.bootloaderBinary,
|
|
51868
|
+
payload.romloaderBinary,
|
|
51869
|
+
payload.applicationP1Binary,
|
|
51870
|
+
payload.applicationP2Binary,
|
|
51871
|
+
payload.coprocessorBinary,
|
|
51872
|
+
payload.se01Binary,
|
|
51873
|
+
payload.se02Binary,
|
|
51874
|
+
payload.se03Binary,
|
|
51875
|
+
payload.se04Binary,
|
|
51876
|
+
payload.resourceArchiveBinary,
|
|
51877
|
+
].some(Boolean);
|
|
51878
|
+
if (preparedPlan && hasLocalArtifacts) {
|
|
51879
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Prepared firmware plans cannot be combined with legacy or local firmware inputs');
|
|
51880
|
+
}
|
|
51881
|
+
let { artifactReader } = payload;
|
|
51882
|
+
if (preparedPlan) {
|
|
51883
|
+
artifactReader = resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration, preparedPlan.preparedPlanDigest).artifactReader;
|
|
51884
|
+
}
|
|
51885
|
+
else if (payload.hostBindingGeneration !== undefined) {
|
|
51886
|
+
artifactReader = resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration).artifactReader;
|
|
51887
|
+
}
|
|
51888
|
+
if (preparedPlan) {
|
|
51409
51889
|
assertFirmwareUpdatePreparedPlanBinding({
|
|
51410
|
-
preparedPlan
|
|
51890
|
+
preparedPlan,
|
|
51411
51891
|
executor: 'v4',
|
|
51412
51892
|
platform: payload.platform,
|
|
51413
|
-
scopeTargets: [
|
|
51414
|
-
|
|
51415
|
-
'app_v1',
|
|
51416
|
-
'app_v2',
|
|
51417
|
-
'coprocessor',
|
|
51418
|
-
'resource',
|
|
51419
|
-
'se01',
|
|
51420
|
-
'se02',
|
|
51421
|
-
'se03',
|
|
51422
|
-
'se04',
|
|
51423
|
-
],
|
|
51424
|
-
bindings: [
|
|
51425
|
-
...Object.entries((_a = payload.componentArtifacts) !== null && _a !== void 0 ? _a : {}).flatMap(([target, artifact]) => artifact
|
|
51426
|
-
? [
|
|
51427
|
-
{
|
|
51428
|
-
target: target,
|
|
51429
|
-
artifact,
|
|
51430
|
-
},
|
|
51431
|
-
]
|
|
51432
|
-
: []),
|
|
51433
|
-
...((_b = payload.resourceBundleArtifacts) !== null && _b !== void 0 ? _b : []).map((entry) => ({
|
|
51434
|
-
target: 'resource',
|
|
51435
|
-
logicalName: entry.name,
|
|
51436
|
-
artifact: entry.artifact,
|
|
51437
|
-
})),
|
|
51438
|
-
],
|
|
51893
|
+
scopeTargets: [],
|
|
51894
|
+
bindings: [],
|
|
51439
51895
|
});
|
|
51896
|
+
if (payload.componentArtifacts) {
|
|
51897
|
+
const componentBindings = Object.entries(payload.componentArtifacts).flatMap(([target, artifact]) => artifact
|
|
51898
|
+
? [
|
|
51899
|
+
{
|
|
51900
|
+
target: target,
|
|
51901
|
+
artifact: artifact,
|
|
51902
|
+
},
|
|
51903
|
+
]
|
|
51904
|
+
: []);
|
|
51905
|
+
assertFirmwareUpdatePreparedPlanBinding({
|
|
51906
|
+
preparedPlan,
|
|
51907
|
+
executor: 'v4',
|
|
51908
|
+
platform: payload.platform,
|
|
51909
|
+
scopeTargets: componentBindings.map(binding => binding.target),
|
|
51910
|
+
bindings: componentBindings,
|
|
51911
|
+
});
|
|
51912
|
+
}
|
|
51440
51913
|
}
|
|
51914
|
+
const preparedExpectedTargetVersions = preparedPlan === null || preparedPlan === void 0 ? void 0 : preparedPlan.artifacts.reduce((result, artifact) => {
|
|
51915
|
+
if (artifact.role === 'component' &&
|
|
51916
|
+
artifact.target !== 'resource' &&
|
|
51917
|
+
artifact.targetVersion &&
|
|
51918
|
+
PROTOCOL_V2_INSTALL_TARGET_BY_UPDATE_TARGET.has(artifact.target)) {
|
|
51919
|
+
result[artifact.target] = artifact.targetVersion;
|
|
51920
|
+
}
|
|
51921
|
+
return result;
|
|
51922
|
+
}, {});
|
|
51923
|
+
const localTargetsToUpdate = (_a = payload.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.map((target) => target === 'boot_resources' ? 'resource' : target);
|
|
51924
|
+
if (payload.resourceArchiveBinary &&
|
|
51925
|
+
localTargetsToUpdate &&
|
|
51926
|
+
!localTargetsToUpdate.includes('resource')) {
|
|
51927
|
+
localTargetsToUpdate.push('resource');
|
|
51928
|
+
}
|
|
51929
|
+
const resolvedLocalTargetsToUpdate = localTargetsToUpdate !== null && localTargetsToUpdate !== void 0 ? localTargetsToUpdate : (payload.resourceArchiveBinary ? ['resource'] : undefined);
|
|
51441
51930
|
this.params = {
|
|
51442
|
-
preparedPlan
|
|
51931
|
+
preparedPlan,
|
|
51443
51932
|
chunkSize: payload.chunkSize,
|
|
51444
51933
|
forcedUpdateRes: payload.forcedUpdateRes,
|
|
51445
51934
|
bootloaderBinary: payload.bootloaderBinary,
|
|
@@ -51451,15 +51940,18 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51451
51940
|
se02Binary: payload.se02Binary,
|
|
51452
51941
|
se03Binary: payload.se03Binary,
|
|
51453
51942
|
se04Binary: payload.se04Binary,
|
|
51454
|
-
|
|
51455
|
-
firmwareType: payload.firmwareType,
|
|
51456
|
-
targetsToUpdate:
|
|
51457
|
-
|
|
51943
|
+
resourceArchiveBinary: payload.resourceArchiveBinary,
|
|
51944
|
+
firmwareType: (_b = preparedPlan === null || preparedPlan === void 0 ? void 0 : preparedPlan.firmwareType) !== null && _b !== void 0 ? _b : payload.firmwareType,
|
|
51945
|
+
targetsToUpdate: preparedPlan
|
|
51946
|
+
? [...preparedPlan.targetsToUpdate]
|
|
51947
|
+
: resolvedLocalTargetsToUpdate,
|
|
51948
|
+
expectedTargetVersions: preparedPlan
|
|
51949
|
+
? preparedExpectedTargetVersions
|
|
51950
|
+
: payload.expectedTargetVersions,
|
|
51458
51951
|
platform: payload.platform,
|
|
51459
51952
|
expectedDeviceId: payload.expectedDeviceId,
|
|
51460
|
-
artifactReader
|
|
51461
|
-
componentArtifacts: payload.componentArtifacts,
|
|
51462
|
-
resourceBundleArtifacts: payload.resourceBundleArtifacts,
|
|
51953
|
+
artifactReader,
|
|
51954
|
+
componentArtifacts: preparedPlan ? undefined : payload.componentArtifacts,
|
|
51463
51955
|
};
|
|
51464
51956
|
}
|
|
51465
51957
|
getProtocolV2FirmwareChunkSize(direction, filePath) {
|
|
@@ -51490,7 +51982,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51490
51982
|
});
|
|
51491
51983
|
}
|
|
51492
51984
|
runProtocolV2() {
|
|
51493
|
-
var _a, _b, _c, _d, _e;
|
|
51985
|
+
var _a, _b, _c, _d, _e, _f;
|
|
51494
51986
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51495
51987
|
yield this.captureProtocolV2PhysicalIdentity();
|
|
51496
51988
|
const deviceFeatures = yield this.getProtocolV2DeviceFeatures();
|
|
@@ -51502,85 +51994,80 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51502
51994
|
const deviceFirmwareType = getFirmwareType(deviceFeatures);
|
|
51503
51995
|
const firmwareType = (_a = this.params.firmwareType) !== null && _a !== void 0 ? _a : deviceFirmwareType;
|
|
51504
51996
|
this.validateExpectedTargetVersions();
|
|
51505
|
-
if (
|
|
51506
|
-
|
|
51997
|
+
if (!this.params.preparedPlan &&
|
|
51998
|
+
this.params.resourceArchiveBinary &&
|
|
51999
|
+
((_b = this.params.targetsToUpdate) === null || _b === void 0 ? void 0 : _b.includes('resource'))) {
|
|
52000
|
+
const localMemoryHost = yield this.prepareProtocolV2LocalMemoryHost({
|
|
52001
|
+
features: deviceFeatures,
|
|
52002
|
+
firmwareType,
|
|
52003
|
+
});
|
|
52004
|
+
try {
|
|
52005
|
+
return yield this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType);
|
|
52006
|
+
}
|
|
52007
|
+
finally {
|
|
52008
|
+
localMemoryHost.release();
|
|
52009
|
+
}
|
|
52010
|
+
}
|
|
52011
|
+
const hasPreparedComponentArtifacts = Object.values((_c = this.params.componentArtifacts) !== null && _c !== void 0 ? _c : {}).some(Boolean);
|
|
52012
|
+
if (this.params.preparedPlan || hasPreparedComponentArtifacts) {
|
|
51507
52013
|
return this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType);
|
|
51508
52014
|
}
|
|
51509
|
-
const
|
|
51510
|
-
const wantsStableResources = !!((_d = this.params.targetsToUpdate) === null || _d === void 0 ? void 0 : _d.includes('resource'));
|
|
51511
|
-
const wantsBootResources = !!((_e = this.params.targetsToUpdate) === null || _e === void 0 ? void 0 : _e.includes('boot_resources'));
|
|
51512
|
-
const needsRemoteResources = !hasExplicitResourceFiles && wantsStableResources;
|
|
51513
|
-
const needsRemoteBootResources = !hasExplicitResourceFiles && (wantsBootResources || wantsStableResources);
|
|
52015
|
+
const wantsResources = !!((_d = this.params.targetsToUpdate) === null || _d === void 0 ? void 0 : _d.includes('resource'));
|
|
51514
52016
|
let fwBinaryMap = [];
|
|
51515
52017
|
let bootloaderBinary = null;
|
|
51516
52018
|
let installItems;
|
|
51517
|
-
let resourceBundles;
|
|
51518
52019
|
try {
|
|
51519
52020
|
this.postTipMessage(exports.FirmwareUpdateTipMessage.StartDownloadFirmware);
|
|
51520
|
-
resourceBundles = this.prepareExplicitProtocolV2ResourceFiles();
|
|
51521
52021
|
fwBinaryMap = this.collectExplicitTargetBinaries();
|
|
51522
52022
|
bootloaderBinary = this.prepareBootloaderBinary();
|
|
51523
|
-
const
|
|
51524
|
-
|
|
52023
|
+
const explicitInstallItems = this.buildProtocolV2InstallItems({
|
|
52024
|
+
bootloaderBinary,
|
|
52025
|
+
fwBinaryMap,
|
|
52026
|
+
});
|
|
52027
|
+
const missingFirmwareTargets = this.getMissingProtocolV2FirmwareTargets(explicitInstallItems);
|
|
52028
|
+
const needsRemoteFirmware = ((_e = this.params.targetsToUpdate) === null || _e === void 0 ? void 0 : _e.length)
|
|
52029
|
+
? missingFirmwareTargets.length > 0
|
|
52030
|
+
: explicitInstallItems.length === 0;
|
|
52031
|
+
if (wantsResources) {
|
|
52032
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource archive must be provided through a local or external PreparedPlan', {
|
|
52033
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
52034
|
+
});
|
|
52035
|
+
}
|
|
52036
|
+
if (needsRemoteFirmware &&
|
|
51525
52037
|
(this.params.artifactReader ||
|
|
51526
52038
|
DataManager.getSettings('firmwareManifestMode') === 'external-only')) {
|
|
51527
52039
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 firmware artifacts must be prepared by the external firmware host', {
|
|
51528
52040
|
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
51529
52041
|
});
|
|
51530
52042
|
}
|
|
51531
|
-
if (needsRemoteFirmware
|
|
51532
|
-
yield DataManager.forceReloadData(
|
|
51533
|
-
requireResources: needsRemoteResources || needsRemoteBootResources,
|
|
51534
|
-
});
|
|
52043
|
+
if (needsRemoteFirmware) {
|
|
52044
|
+
yield DataManager.forceReloadData();
|
|
51535
52045
|
}
|
|
51536
52046
|
if (needsRemoteFirmware) {
|
|
51537
|
-
const remoteBinaries = yield this.prepareRemoteProtocolV2Binaries(firmwareType, deviceFeatures);
|
|
52047
|
+
const remoteBinaries = yield this.prepareRemoteProtocolV2Binaries(firmwareType, deviceFeatures, explicitInstallItems);
|
|
51538
52048
|
bootloaderBinary = remoteBinaries.bootloaderBinary;
|
|
51539
52049
|
fwBinaryMap = remoteBinaries.fwBinaryMap;
|
|
51540
52050
|
installItems = remoteBinaries.installItems;
|
|
51541
52051
|
}
|
|
51542
|
-
|
|
51543
|
-
if (bootResourceFiles === null || bootResourceFiles === void 0 ? void 0 : bootResourceFiles.length) {
|
|
51544
|
-
resourceBundles = this.mergeProtocolV2ResourceBundles(resourceBundles, bootResourceFiles);
|
|
51545
|
-
}
|
|
51546
|
-
if (!needsRemoteResources) {
|
|
51547
|
-
this.postTipMessage(exports.FirmwareUpdateTipMessage.FinishDownloadFirmware);
|
|
51548
|
-
}
|
|
52052
|
+
this.postTipMessage(exports.FirmwareUpdateTipMessage.FinishDownloadFirmware);
|
|
51549
52053
|
}
|
|
51550
52054
|
catch (err) {
|
|
52055
|
+
if (typeof err === 'object' &&
|
|
52056
|
+
err !== null &&
|
|
52057
|
+
'params' in err &&
|
|
52058
|
+
((_f = err.params) === null || _f === void 0 ? void 0 : _f.firmwareUpdateCode) === 'FirmwareArtifactsNotPrepared') {
|
|
52059
|
+
throw err;
|
|
52060
|
+
}
|
|
51551
52061
|
if (err instanceof hdShared.HardwareError && err.errorCode === hdShared.HardwareErrorCode.NetworkError) {
|
|
51552
52062
|
throw err;
|
|
51553
52063
|
}
|
|
51554
52064
|
throw normalizeFirmwarePreparationError(err);
|
|
51555
52065
|
}
|
|
51556
|
-
if (!bootloaderBinary &&
|
|
51557
|
-
fwBinaryMap.length === 0 &&
|
|
51558
|
-
!(installItems === null || installItems === void 0 ? void 0 : installItems.length) &&
|
|
51559
|
-
!(resourceBundles === null || resourceBundles === void 0 ? void 0 : resourceBundles.length) &&
|
|
51560
|
-
!needsRemoteResources) {
|
|
52066
|
+
if (!bootloaderBinary && fwBinaryMap.length === 0 && !(installItems === null || installItems === void 0 ? void 0 : installItems.length)) {
|
|
51561
52067
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, 'No firmware to update');
|
|
51562
52068
|
}
|
|
51563
|
-
|
|
51564
|
-
|
|
51565
|
-
try {
|
|
51566
|
-
const stableResources = yield this.prepareProtocolV2ResourceBundles();
|
|
51567
|
-
resourceBundles = this.mergeProtocolV2ResourceBundles(resourceBundles, stableResources);
|
|
51568
|
-
this.postTipMessage(exports.FirmwareUpdateTipMessage.FinishDownloadFirmware);
|
|
51569
|
-
}
|
|
51570
|
-
catch (err) {
|
|
51571
|
-
if (enteredBootloader) {
|
|
51572
|
-
try {
|
|
51573
|
-
yield this.exitProtocolV2BootloaderToNormal();
|
|
51574
|
-
}
|
|
51575
|
-
catch (restoreError) {
|
|
51576
|
-
Log$6.warn('[FirmwareUpdateV4] failed to restore App mode after resource preparation error:', restoreError);
|
|
51577
|
-
}
|
|
51578
|
-
}
|
|
51579
|
-
throw normalizeFirmwarePreparationError(err);
|
|
51580
|
-
}
|
|
51581
|
-
}
|
|
51582
|
-
return this.executeProtocolV2Update(Object.assign(Object.assign({ fwBinaryMap,
|
|
51583
|
-
bootloaderBinary }, (installItems ? { installItems } : undefined)), ((resourceBundles === null || resourceBundles === void 0 ? void 0 : resourceBundles.length) ? { resourceBundles } : undefined)));
|
|
52069
|
+
return this.executeProtocolV2Update(Object.assign({ fwBinaryMap,
|
|
52070
|
+
bootloaderBinary }, (installItems ? { installItems } : undefined)));
|
|
51584
52071
|
});
|
|
51585
52072
|
}
|
|
51586
52073
|
openProtocolV2PreparedSource(artifact) {
|
|
@@ -51617,6 +52104,34 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51617
52104
|
prepareProtocolV2InstallSources(firmwareType, features) {
|
|
51618
52105
|
var _a, _b;
|
|
51619
52106
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52107
|
+
if (this.params.preparedPlan) {
|
|
52108
|
+
const requestedTargets = new Set(this.params.preparedPlan.targetsToUpdate.filter((target) => target !== 'resource'));
|
|
52109
|
+
const installSources = [];
|
|
52110
|
+
const preparedTargets = new Set();
|
|
52111
|
+
for (const artifact of this.params.preparedPlan.artifacts) {
|
|
52112
|
+
if (artifact.target !== 'resource') {
|
|
52113
|
+
const target = artifact.target;
|
|
52114
|
+
const installTarget = PROTOCOL_V2_INSTALL_TARGET_BY_UPDATE_TARGET.get(target);
|
|
52115
|
+
if (!requestedTargets.has(target) ||
|
|
52116
|
+
artifact.role !== 'component' ||
|
|
52117
|
+
artifact.container !== 'raw' ||
|
|
52118
|
+
!installTarget ||
|
|
52119
|
+
preparedTargets.has(target)) {
|
|
52120
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 prepared component artifact is invalid: ${artifact.artifactId}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52121
|
+
}
|
|
52122
|
+
installSources.push(Object.assign(Object.assign({}, installTarget), { source: yield this.openProtocolV2PreparedSource(artifact.artifact) }));
|
|
52123
|
+
preparedTargets.add(target);
|
|
52124
|
+
}
|
|
52125
|
+
}
|
|
52126
|
+
const missingTarget = Array.from(requestedTargets).find(target => !preparedTargets.has(target));
|
|
52127
|
+
if (missingTarget) {
|
|
52128
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 ${missingTarget} artifact is not prepared`, {
|
|
52129
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
52130
|
+
artifactName: missingTarget,
|
|
52131
|
+
});
|
|
52132
|
+
}
|
|
52133
|
+
return installSources;
|
|
52134
|
+
}
|
|
51620
52135
|
const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
|
|
51621
52136
|
if (!release) {
|
|
51622
52137
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 firmware release is unavailable');
|
|
@@ -51647,39 +52162,278 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51647
52162
|
return installSources;
|
|
51648
52163
|
});
|
|
51649
52164
|
}
|
|
51650
|
-
|
|
51651
|
-
var _a, _b
|
|
52165
|
+
prepareProtocolV2LocalMemoryHost({ features, firmwareType, }) {
|
|
52166
|
+
var _a, _b;
|
|
51652
52167
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51653
|
-
const
|
|
51654
|
-
|
|
52168
|
+
const installItems = this.buildProtocolV2InstallItems({
|
|
52169
|
+
bootloaderBinary: this.prepareBootloaderBinary(),
|
|
52170
|
+
fwBinaryMap: this.collectExplicitTargetBinaries(),
|
|
52171
|
+
});
|
|
52172
|
+
const requestedComponentTargets = new Set(((_a = this.params.targetsToUpdate) !== null && _a !== void 0 ? _a : []).filter((target) => target !== 'resource' && target !== 'boot_resources'));
|
|
52173
|
+
const localComponentTargets = new Set(installItems.flatMap(item => {
|
|
52174
|
+
const target = PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(item.targetId);
|
|
52175
|
+
return target ? [target] : [];
|
|
52176
|
+
}));
|
|
52177
|
+
const missingTarget = Array.from(requestedComponentTargets).find(target => !localComponentTargets.has(target));
|
|
52178
|
+
if (missingTarget) {
|
|
52179
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local update has no binary for requested target ${missingTarget}`, {
|
|
52180
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
52181
|
+
artifactName: missingTarget,
|
|
52182
|
+
});
|
|
52183
|
+
}
|
|
52184
|
+
const planArtifacts = [];
|
|
52185
|
+
const memoryArtifacts = [];
|
|
52186
|
+
for (const item of installItems) {
|
|
52187
|
+
const target = PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(item.targetId);
|
|
52188
|
+
if (!target || item.binary.byteLength <= 0) {
|
|
52189
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local firmware artifact is invalid: ${item.fileName}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52190
|
+
}
|
|
52191
|
+
const artifactId = `component:${target}`;
|
|
52192
|
+
planArtifacts.push(Object.assign({ artifactId,
|
|
52193
|
+
target, container: 'raw', logicalName: item.fileName, expectedSize: item.binary.byteLength, expectedSha256: bytesToHex(sha256.sha256(new Uint8Array(item.binary))) }, (((_b = this.params.expectedTargetVersions) === null || _b === void 0 ? void 0 : _b[target])
|
|
52194
|
+
? { targetVersion: this.params.expectedTargetVersions[target] }
|
|
52195
|
+
: {})));
|
|
52196
|
+
memoryArtifacts.push({ artifactId, binary: item.binary });
|
|
52197
|
+
}
|
|
52198
|
+
const resourceArchive = yield this.prepareProtocolV2LocalResourceArchive(this.params.resourceArchiveBinary);
|
|
52199
|
+
const resourceArtifactId = 'resource:archive';
|
|
52200
|
+
planArtifacts.push({
|
|
52201
|
+
artifactId: resourceArtifactId,
|
|
52202
|
+
target: 'resource',
|
|
52203
|
+
container: 'zip',
|
|
52204
|
+
logicalName: 'protocol-v2-local-resource-archive',
|
|
52205
|
+
expectedSize: resourceArchive.binary.byteLength,
|
|
52206
|
+
expectedSha256: bytesToHex(sha256.sha256(new Uint8Array(resourceArchive.binary))),
|
|
52207
|
+
});
|
|
52208
|
+
memoryArtifacts.push({
|
|
52209
|
+
artifactId: resourceArtifactId,
|
|
52210
|
+
binary: resourceArchive.binary,
|
|
52211
|
+
materializedEntries: resourceArchive.materializedEntries,
|
|
52212
|
+
});
|
|
52213
|
+
const plan = buildProtocolV2LocalFirmwareUpdatePlan({
|
|
52214
|
+
features,
|
|
52215
|
+
firmwareType,
|
|
52216
|
+
platform: this.params.platform,
|
|
52217
|
+
artifacts: planArtifacts,
|
|
52218
|
+
});
|
|
52219
|
+
let memoryHost;
|
|
52220
|
+
try {
|
|
52221
|
+
memoryHost = prepareFirmwareUpdateV4MemoryHost({
|
|
52222
|
+
sdk: {
|
|
52223
|
+
prepareFirmwareUpdatePlan,
|
|
52224
|
+
registerFirmwareUpdateHostBinding,
|
|
52225
|
+
unregisterFirmwareUpdateHostBinding,
|
|
52226
|
+
},
|
|
52227
|
+
plan,
|
|
52228
|
+
artifacts: memoryArtifacts,
|
|
52229
|
+
});
|
|
52230
|
+
const preparedPlan = validateFirmwareUpdatePreparedPlan(memoryHost.preparedPlan);
|
|
52231
|
+
assertFirmwareUpdatePreparedPlanBinding({
|
|
52232
|
+
preparedPlan,
|
|
52233
|
+
executor: 'v4',
|
|
52234
|
+
platform: this.params.platform,
|
|
52235
|
+
scopeTargets: [],
|
|
52236
|
+
bindings: [],
|
|
52237
|
+
});
|
|
52238
|
+
assertFirmwareUpdatePreparedPlanDeviceIdentity({
|
|
52239
|
+
preparedPlan,
|
|
52240
|
+
deviceIdentity: this.protocolV2ExpectedSerialNumber,
|
|
52241
|
+
deviceModel: this.getProtocolV2PreparedPlanDeviceModel(features),
|
|
52242
|
+
});
|
|
52243
|
+
const hostBinding = resolveFirmwareUpdateHostBinding(memoryHost.hostBindingGeneration, preparedPlan.preparedPlanDigest);
|
|
52244
|
+
this.params.preparedPlan = preparedPlan;
|
|
52245
|
+
this.params.targetsToUpdate = [...preparedPlan.targetsToUpdate];
|
|
52246
|
+
this.params.artifactReader = hostBinding.artifactReader;
|
|
52247
|
+
this.params.componentArtifacts = undefined;
|
|
52248
|
+
return memoryHost;
|
|
52249
|
+
}
|
|
52250
|
+
catch (error) {
|
|
52251
|
+
memoryHost === null || memoryHost === void 0 ? void 0 : memoryHost.release();
|
|
52252
|
+
throw error;
|
|
52253
|
+
}
|
|
52254
|
+
});
|
|
52255
|
+
}
|
|
52256
|
+
prepareProtocolV2LocalResourceArchive(binary) {
|
|
52257
|
+
var _a;
|
|
52258
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
52259
|
+
if (binary.byteLength <= 0 || binary.byteLength > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
|
|
52260
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP archive size is invalid', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52261
|
+
}
|
|
52262
|
+
const zip = yield JSZip__default["default"].loadAsync(binary);
|
|
52263
|
+
const zipEntries = Object.values(zip.files);
|
|
52264
|
+
if (zipEntries.some(entry => entry.unsafeOriginalName && entry.unsafeOriginalName !== entry.name)) {
|
|
52265
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP contains an unsafe entry path', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52266
|
+
}
|
|
52267
|
+
const entries = zipEntries.filter(entry => !entry.dir);
|
|
52268
|
+
if (entries.length === 0 || entries.length > PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT + 1) {
|
|
52269
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP entry set is invalid', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52270
|
+
}
|
|
52271
|
+
let declaredUncompressedSize = 0;
|
|
52272
|
+
let declaredCompressedSize = 0;
|
|
52273
|
+
for (const entry of entries) {
|
|
52274
|
+
const sizes = getProtocolV2ZipEntrySizes(entry);
|
|
52275
|
+
declaredCompressedSize += sizes.compressedSize;
|
|
52276
|
+
declaredUncompressedSize += sizes.uncompressedSize;
|
|
52277
|
+
const entryLimit = entry.name === 'manifest.json'
|
|
52278
|
+
? PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES
|
|
52279
|
+
: PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES;
|
|
52280
|
+
if (sizes.uncompressedSize > entryLimit ||
|
|
52281
|
+
declaredCompressedSize > binary.byteLength ||
|
|
52282
|
+
declaredUncompressedSize >
|
|
52283
|
+
PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES + PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES) {
|
|
52284
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP declared size exceeds the allowed limit', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52285
|
+
}
|
|
52286
|
+
}
|
|
52287
|
+
const manifestEntry = zip.file('manifest.json');
|
|
52288
|
+
if (!manifestEntry) {
|
|
52289
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP has no manifest.json', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52290
|
+
}
|
|
52291
|
+
const manifestBinary = yield manifestEntry.async('arraybuffer');
|
|
52292
|
+
if (manifestBinary.byteLength <= 0 ||
|
|
52293
|
+
manifestBinary.byteLength > PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES) {
|
|
52294
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource manifest size is invalid', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52295
|
+
}
|
|
52296
|
+
let manifestValue;
|
|
52297
|
+
try {
|
|
52298
|
+
manifestValue = JSON.parse(new TextDecoder().decode(manifestBinary));
|
|
52299
|
+
}
|
|
52300
|
+
catch (error) {
|
|
52301
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local resource manifest is invalid: ${String(error)}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52302
|
+
}
|
|
52303
|
+
const manifest = parseProtocolV2ResourceManifest(manifestValue);
|
|
52304
|
+
const selectedFiles = selectProtocolV2ResourceManifestFiles({
|
|
52305
|
+
manifest,
|
|
52306
|
+
targetsToUpdate: (_a = this.params.targetsToUpdate) !== null && _a !== void 0 ? _a : [],
|
|
52307
|
+
});
|
|
52308
|
+
const expectedEntryNames = new Set([
|
|
52309
|
+
'manifest.json',
|
|
52310
|
+
...selectedFiles.map(file => file.archive_path),
|
|
52311
|
+
]);
|
|
52312
|
+
if (entries.length !== expectedEntryNames.size ||
|
|
52313
|
+
entries.some(entry => !expectedEntryNames.has(entry.name))) {
|
|
52314
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP contains an unexpected entry', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52315
|
+
}
|
|
52316
|
+
let totalSize = 0;
|
|
52317
|
+
const materializedEntries = [
|
|
52318
|
+
{ entryName: 'manifest.json', binary: manifestBinary },
|
|
52319
|
+
];
|
|
52320
|
+
for (const file of selectedFiles) {
|
|
52321
|
+
const entry = zip.file(file.archive_path);
|
|
52322
|
+
if (!entry) {
|
|
52323
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local resource ZIP is missing ${file.archive_path}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52324
|
+
}
|
|
52325
|
+
const { uncompressedSize } = getProtocolV2ZipEntrySizes(entry);
|
|
52326
|
+
totalSize += uncompressedSize;
|
|
52327
|
+
if (uncompressedSize !== file.size || totalSize > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
|
|
52328
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local resource file declared size is invalid: ${file.archive_path}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52329
|
+
}
|
|
52330
|
+
const fileBinary = yield entry.async('arraybuffer');
|
|
52331
|
+
const digest = bytesToHex(sha256.sha256(new Uint8Array(fileBinary)));
|
|
52332
|
+
if (fileBinary.byteLength !== file.size || digest !== file.sha256.toLowerCase()) {
|
|
52333
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local resource file does not match manifest: ${file.archive_path}`, { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
|
|
52334
|
+
}
|
|
52335
|
+
materializedEntries.push({ entryName: file.archive_path, binary: fileBinary });
|
|
52336
|
+
}
|
|
52337
|
+
return { binary, materializedEntries };
|
|
52338
|
+
});
|
|
52339
|
+
}
|
|
52340
|
+
prepareProtocolV2ResourceSources() {
|
|
52341
|
+
var _a, _b;
|
|
52342
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
52343
|
+
const resourceRequested = (_b = (_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.includes('resource')) !== null && _b !== void 0 ? _b : false;
|
|
51655
52344
|
if (!resourceRequested) {
|
|
51656
52345
|
return [];
|
|
51657
52346
|
}
|
|
51658
|
-
const
|
|
51659
|
-
|
|
51660
|
-
|
|
52347
|
+
const archiveSources = yield this.prepareProtocolV2ResourceArchiveSources();
|
|
52348
|
+
if (archiveSources) {
|
|
52349
|
+
return archiveSources;
|
|
52350
|
+
}
|
|
52351
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource archive is not prepared', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52352
|
+
});
|
|
52353
|
+
}
|
|
52354
|
+
prepareProtocolV2ResourceArchiveSources() {
|
|
52355
|
+
var _a, _b, _c, _d;
|
|
52356
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
52357
|
+
const archiveArtifacts = (_b = (_a = this.params.preparedPlan) === null || _a === void 0 ? void 0 : _a.artifacts.filter(artifact => artifact.role === 'resourceBundle' &&
|
|
52358
|
+
artifact.target === 'resource' &&
|
|
52359
|
+
artifact.container === 'zip')) !== null && _b !== void 0 ? _b : [];
|
|
52360
|
+
if (archiveArtifacts.length === 0) {
|
|
52361
|
+
return undefined;
|
|
52362
|
+
}
|
|
52363
|
+
if (archiveArtifacts.length !== 1) {
|
|
52364
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared plan must contain exactly one resource archive', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52365
|
+
}
|
|
52366
|
+
const archiveArtifact = archiveArtifacts[0];
|
|
52367
|
+
const archiveSource = yield this.openProtocolV2PreparedSource(archiveArtifact.artifact);
|
|
52368
|
+
if (archiveSource.size > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
|
|
52369
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive exceeds the total size limit', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52370
|
+
}
|
|
52371
|
+
let archiveBinary;
|
|
52372
|
+
try {
|
|
52373
|
+
archiveBinary = yield readFirmwareByteSourceFully(archiveSource);
|
|
52374
|
+
}
|
|
52375
|
+
finally {
|
|
52376
|
+
yield archiveSource.close();
|
|
52377
|
+
}
|
|
52378
|
+
const archiveDigest = bytesToHex(sha256.sha256(new Uint8Array(archiveBinary)));
|
|
52379
|
+
if (archiveDigest !== archiveArtifact.artifact.sha256.toLowerCase()) {
|
|
52380
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive does not match its approved receipt', { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
|
|
52381
|
+
}
|
|
52382
|
+
const verifiedArchive = yield this.prepareProtocolV2LocalResourceArchive(archiveBinary);
|
|
52383
|
+
const entries = (_c = archiveArtifact.materializedEntries) !== null && _c !== void 0 ? _c : [];
|
|
52384
|
+
const entriesByName = new Map(entries.map(entry => [entry.entryName, entry]));
|
|
52385
|
+
if (entries.length !== verifiedArchive.materializedEntries.length ||
|
|
52386
|
+
verifiedArchive.materializedEntries.some(entry => {
|
|
52387
|
+
const preparedEntry = entriesByName.get(entry.entryName);
|
|
52388
|
+
const digest = bytesToHex(sha256.sha256(new Uint8Array(entry.binary)));
|
|
52389
|
+
return (!preparedEntry ||
|
|
52390
|
+
preparedEntry.artifact.size !== entry.binary.byteLength ||
|
|
52391
|
+
preparedEntry.artifact.sha256.toLowerCase() !== digest);
|
|
52392
|
+
})) {
|
|
52393
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource entries do not match the approved archive', { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
|
|
52394
|
+
}
|
|
52395
|
+
const verifiedEntriesByName = new Map(verifiedArchive.materializedEntries.map(entry => [entry.entryName, entry.binary]));
|
|
52396
|
+
const manifestBinary = verifiedEntriesByName.get('manifest.json');
|
|
52397
|
+
if (!manifestBinary) {
|
|
52398
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive has no valid manifest.json', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52399
|
+
}
|
|
52400
|
+
let manifestValue;
|
|
52401
|
+
try {
|
|
52402
|
+
manifestValue = JSON.parse(new TextDecoder().decode(manifestBinary));
|
|
52403
|
+
}
|
|
52404
|
+
catch (error) {
|
|
52405
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 prepared resource manifest is invalid: ${String(error)}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52406
|
+
}
|
|
52407
|
+
const manifest = parseProtocolV2ResourceManifest(manifestValue);
|
|
52408
|
+
const selectedFiles = selectProtocolV2ResourceManifestFiles({
|
|
52409
|
+
manifest,
|
|
52410
|
+
targetsToUpdate: (_d = this.params.targetsToUpdate) !== null && _d !== void 0 ? _d : [],
|
|
52411
|
+
});
|
|
52412
|
+
if (selectedFiles.length > PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT) {
|
|
52413
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive contains too many files', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52414
|
+
}
|
|
52415
|
+
let totalSize = 0;
|
|
51661
52416
|
const sources = [];
|
|
51662
|
-
for (const
|
|
51663
|
-
const
|
|
51664
|
-
if (!
|
|
51665
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 resource
|
|
51666
|
-
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
51667
|
-
artifactName: descriptor.name,
|
|
51668
|
-
});
|
|
52417
|
+
for (const [index, file] of selectedFiles.entries()) {
|
|
52418
|
+
const binary = verifiedEntriesByName.get(file.archive_path);
|
|
52419
|
+
if (!binary || binary.byteLength !== file.size) {
|
|
52420
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 prepared resource file does not match manifest: ${file.archive_path}`, { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
|
|
51669
52421
|
}
|
|
51670
|
-
|
|
51671
|
-
|
|
51672
|
-
|
|
51673
|
-
|
|
51674
|
-
|
|
51675
|
-
|
|
51676
|
-
|
|
51677
|
-
|
|
51678
|
-
}
|
|
51679
|
-
|
|
51680
|
-
|
|
51681
|
-
|
|
51682
|
-
|
|
52422
|
+
totalSize += binary.byteLength;
|
|
52423
|
+
if (totalSize > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
|
|
52424
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive exceeds the total size limit', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52425
|
+
}
|
|
52426
|
+
const source = yield this.openProtocolV2MemorySource(binary);
|
|
52427
|
+
const header = source.size >= PROTOCOL_V2_OKPP_HEADER_SIZE
|
|
52428
|
+
? parseProtocolV2OkppHeader(new Uint8Array(yield source.readAt(0, PROTOCOL_V2_OKPP_HEADER_SIZE)))
|
|
52429
|
+
: null;
|
|
52430
|
+
sources.push(Object.assign({ name: file.original_name || `resource-${index}`, source, devicePath: file.device_path }, (header
|
|
52431
|
+
? {
|
|
52432
|
+
version: header.version,
|
|
52433
|
+
payloadHash: header.payloadHash,
|
|
52434
|
+
headerHash: header.headerHash,
|
|
52435
|
+
}
|
|
52436
|
+
: {})));
|
|
51683
52437
|
}
|
|
51684
52438
|
return sources;
|
|
51685
52439
|
});
|
|
@@ -51689,7 +52443,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51689
52443
|
try {
|
|
51690
52444
|
this.postTipMessage(exports.FirmwareUpdateTipMessage.StartDownloadFirmware);
|
|
51691
52445
|
const installSources = yield this.prepareProtocolV2InstallSources(firmwareType, features);
|
|
51692
|
-
const resourceSources = yield this.prepareProtocolV2ResourceSources(
|
|
52446
|
+
const resourceSources = yield this.prepareProtocolV2ResourceSources();
|
|
51693
52447
|
if (installSources.length === 0 && resourceSources.length === 0) {
|
|
51694
52448
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, 'No firmware to update');
|
|
51695
52449
|
}
|
|
@@ -51773,15 +52527,15 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51773
52527
|
}
|
|
51774
52528
|
}
|
|
51775
52529
|
getProtocolV2RequestedTargets() {
|
|
51776
|
-
var _a, _b, _c
|
|
52530
|
+
var _a, _b, _c;
|
|
51777
52531
|
if ((_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.length) {
|
|
51778
52532
|
return [...new Set(this.params.targetsToUpdate)];
|
|
51779
52533
|
}
|
|
51780
|
-
|
|
51781
|
-
|
|
51782
|
-
if (((_c = this.params.resourceBundleArtifacts) === null || _c === void 0 ? void 0 : _c.length) || ((_d = this.params.resourceFiles) === null || _d === void 0 ? void 0 : _d.length)) {
|
|
51783
|
-
targets.add('resource');
|
|
52534
|
+
if ((_b = this.params.preparedPlan) === null || _b === void 0 ? void 0 : _b.targetsToUpdate.length) {
|
|
52535
|
+
return [...new Set(this.params.preparedPlan.targetsToUpdate)];
|
|
51784
52536
|
}
|
|
52537
|
+
const targets = new Set();
|
|
52538
|
+
Object.keys((_c = this.params.componentArtifacts) !== null && _c !== void 0 ? _c : {}).forEach(target => targets.add(target));
|
|
51785
52539
|
if (this.params.bootloaderBinary)
|
|
51786
52540
|
targets.add('boot');
|
|
51787
52541
|
if (this.params.applicationP1Binary)
|
|
@@ -51818,8 +52572,26 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51818
52572
|
const serialNumber = (_b = (_a = deviceInfo.hw) === null || _a === void 0 ? void 0 : _a.serial_no) === null || _b === void 0 ? void 0 : _b.trim();
|
|
51819
52573
|
return serialNumber || undefined;
|
|
51820
52574
|
}
|
|
52575
|
+
getProtocolV2PreparedPlanDeviceModel(features) {
|
|
52576
|
+
const currentDeviceType = this.device.getCurrentDeviceType();
|
|
52577
|
+
const featureDeviceType = features ? getDeviceType(features) : undefined;
|
|
52578
|
+
const deviceType = currentDeviceType === hdShared.EDeviceType.Pro2 || currentDeviceType === hdShared.EDeviceType.Neo
|
|
52579
|
+
? currentDeviceType
|
|
52580
|
+
: featureDeviceType;
|
|
52581
|
+
return deviceType === hdShared.EDeviceType.Pro2 || deviceType === hdShared.EDeviceType.Neo
|
|
52582
|
+
? String(deviceType)
|
|
52583
|
+
: undefined;
|
|
52584
|
+
}
|
|
52585
|
+
getProtocolV2ConnectionRoute() {
|
|
52586
|
+
var _a, _b, _c, _d, _e;
|
|
52587
|
+
const descriptor = this.device.originalDescriptor;
|
|
52588
|
+
return (((_a = descriptor === null || descriptor === void 0 ? void 0 : descriptor.path) === null || _a === void 0 ? void 0 : _a.trim()) ||
|
|
52589
|
+
((_d = (_c = (_b = this.device).getConnectId) === null || _c === void 0 ? void 0 : _c.call(_b)) === null || _d === void 0 ? void 0 : _d.trim()) ||
|
|
52590
|
+
((_e = descriptor === null || descriptor === void 0 ? void 0 : descriptor.id) === null || _e === void 0 ? void 0 : _e.trim()) ||
|
|
52591
|
+
undefined);
|
|
52592
|
+
}
|
|
51821
52593
|
assertProtocolV2DeviceInfoIdentity(deviceInfo) {
|
|
51822
|
-
assertProtocolV2ReconnectIdentity(this.protocolV2ExpectedSerialNumber, this.getProtocolV2SerialNumber(deviceInfo), this.protocolV2ExpectedPath, this.
|
|
52594
|
+
assertProtocolV2ReconnectIdentity(this.protocolV2ExpectedSerialNumber, this.getProtocolV2SerialNumber(deviceInfo), this.protocolV2ExpectedPath, this.getProtocolV2ConnectionRoute());
|
|
51823
52595
|
}
|
|
51824
52596
|
getProtocolV2DeviceInfoTimeout() {
|
|
51825
52597
|
var _a;
|
|
@@ -51836,19 +52608,20 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51836
52608
|
});
|
|
51837
52609
|
}
|
|
51838
52610
|
captureProtocolV2PhysicalIdentity() {
|
|
51839
|
-
var _a, _b, _c
|
|
52611
|
+
var _a, _b, _c;
|
|
51840
52612
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51841
52613
|
const deviceInfo = yield this.requestProtocolV2PhysicalIdentity();
|
|
51842
52614
|
const serialNumber = this.getProtocolV2SerialNumber(deviceInfo);
|
|
51843
|
-
const path =
|
|
51844
|
-
if ((
|
|
52615
|
+
const path = this.getProtocolV2ConnectionRoute();
|
|
52616
|
+
if ((_a = this.params) === null || _a === void 0 ? void 0 : _a.preparedPlan) {
|
|
51845
52617
|
assertFirmwareUpdatePreparedPlanDeviceIdentity({
|
|
51846
52618
|
preparedPlan: this.params.preparedPlan,
|
|
51847
52619
|
deviceIdentity: serialNumber,
|
|
52620
|
+
deviceModel: this.getProtocolV2PreparedPlanDeviceModel(this.device.features),
|
|
51848
52621
|
});
|
|
51849
52622
|
}
|
|
51850
|
-
else if ((
|
|
51851
|
-
assertProtocolV2ReconnectIdentity((
|
|
52623
|
+
else if ((_b = this.params) === null || _b === void 0 ? void 0 : _b.expectedDeviceId) {
|
|
52624
|
+
assertProtocolV2ReconnectIdentity((_c = this.params) === null || _c === void 0 ? void 0 : _c.expectedDeviceId, serialNumber);
|
|
51852
52625
|
}
|
|
51853
52626
|
else {
|
|
51854
52627
|
assertProtocolV2ReconnectIdentity(serialNumber, serialNumber, path, path);
|
|
@@ -51868,11 +52641,15 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51868
52641
|
var _a;
|
|
51869
52642
|
return (_a = this.params.bootloaderBinary) !== null && _a !== void 0 ? _a : null;
|
|
51870
52643
|
}
|
|
51871
|
-
|
|
52644
|
+
getMissingProtocolV2FirmwareTargets(installItems) {
|
|
51872
52645
|
var _a;
|
|
51873
|
-
|
|
51874
|
-
|
|
51875
|
-
|
|
52646
|
+
const preparedTargets = new Set(installItems.flatMap(item => {
|
|
52647
|
+
const target = PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(item.targetId);
|
|
52648
|
+
return target ? [target] : [];
|
|
52649
|
+
}));
|
|
52650
|
+
return ((_a = this.params.targetsToUpdate) !== null && _a !== void 0 ? _a : [])
|
|
52651
|
+
.filter((target) => target !== 'resource' && target !== 'boot_resources')
|
|
52652
|
+
.filter(target => !preparedTargets.has(target));
|
|
51876
52653
|
}
|
|
51877
52654
|
buildProtocolV2InstallItems({ bootloaderBinary, fwBinaryMap, }) {
|
|
51878
52655
|
const installItems = [];
|
|
@@ -51921,7 +52698,17 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51921
52698
|
if (!component.url) {
|
|
51922
52699
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Missing Protocol V2 firmware component url: ${key}/${component.target}`);
|
|
51923
52700
|
}
|
|
52701
|
+
const expectedFingerprint = normalizeProtocolV2Hex(component.fingerprint);
|
|
52702
|
+
if (!Number.isSafeInteger(component.expectedSize) ||
|
|
52703
|
+
Number(component.expectedSize) <= 0 ||
|
|
52704
|
+
!expectedFingerprint ||
|
|
52705
|
+
!/^[0-9a-f]{64}$/u.test(expectedFingerprint)) {
|
|
52706
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 firmware component integrity metadata is invalid: ${key}/${component.target}`, { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
52707
|
+
}
|
|
51924
52708
|
const { binary } = yield getSysResourceBinary(component.url);
|
|
52709
|
+
if (binary.byteLength !== component.expectedSize) {
|
|
52710
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 firmware size mismatch: ${key}/${component.target}`, { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
|
|
52711
|
+
}
|
|
51925
52712
|
if (!isProtocolV2FirmwareFingerprintValid(binary, component.fingerprint)) {
|
|
51926
52713
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 firmware fingerprint mismatch: ${key}/${component.target}`);
|
|
51927
52714
|
}
|
|
@@ -51935,7 +52722,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51935
52722
|
return Object.assign(Object.assign({}, target), { binary });
|
|
51936
52723
|
});
|
|
51937
52724
|
}
|
|
51938
|
-
prepareRemoteProtocolV2Binaries(firmwareType, features) {
|
|
52725
|
+
prepareRemoteProtocolV2Binaries(firmwareType, features, explicitInstallItems = []) {
|
|
51939
52726
|
var _a, _b;
|
|
51940
52727
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51941
52728
|
const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
|
|
@@ -51943,6 +52730,10 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51943
52730
|
const fwBinaryMap = [];
|
|
51944
52731
|
const installItems = [];
|
|
51945
52732
|
if (!release) {
|
|
52733
|
+
const missingFirmwareTargets = this.getMissingProtocolV2FirmwareTargets(explicitInstallItems);
|
|
52734
|
+
if (missingFirmwareTargets.length > 0) {
|
|
52735
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 firmware release is unavailable for requested targets: ${missingFirmwareTargets.join(', ')}`);
|
|
52736
|
+
}
|
|
51946
52737
|
return {
|
|
51947
52738
|
bootloaderBinary,
|
|
51948
52739
|
fwBinaryMap,
|
|
@@ -51951,6 +52742,8 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51951
52742
|
}
|
|
51952
52743
|
const entries = this.getRemoteComponentEntries(release);
|
|
51953
52744
|
const targetsToUpdate = new Set((_a = this.params.targetsToUpdate) !== null && _a !== void 0 ? _a : []);
|
|
52745
|
+
const explicitInstallItemByTargetId = new Map(explicitInstallItems.map(item => [item.targetId, item]));
|
|
52746
|
+
const preparedTargets = new Set();
|
|
51954
52747
|
for (const [key, component] of entries) {
|
|
51955
52748
|
const targetName = (_b = component.target) === null || _b === void 0 ? void 0 : _b.toUpperCase();
|
|
51956
52749
|
const target = PROTOCOL_V2_REMOTE_COMPONENT_TARGETS[targetName];
|
|
@@ -51958,27 +52751,27 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51958
52751
|
? PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(target.targetId)
|
|
51959
52752
|
: undefined;
|
|
51960
52753
|
if (updateTarget && targetsToUpdate.has(updateTarget)) {
|
|
51961
|
-
const
|
|
51962
|
-
|
|
51963
|
-
|
|
51964
|
-
|
|
51965
|
-
fileName: remoteBinary.fileName,
|
|
51966
|
-
binary: remoteBinary.binary,
|
|
51967
|
-
targetId: remoteBinary.targetId,
|
|
51968
|
-
kind: remoteBinary.kind,
|
|
51969
|
-
});
|
|
52754
|
+
const explicitInstallItem = explicitInstallItemByTargetId.get(target.targetId);
|
|
52755
|
+
const installItem = explicitInstallItem !== null && explicitInstallItem !== void 0 ? explicitInstallItem : (yield this.downloadRemoteProtocolV2Component(key, component));
|
|
52756
|
+
if (installItem.kind === 'bootloader') {
|
|
52757
|
+
bootloaderBinary = installItem.binary;
|
|
51970
52758
|
}
|
|
51971
52759
|
else {
|
|
51972
52760
|
const binaryEntry = {
|
|
51973
|
-
fileName:
|
|
51974
|
-
binary:
|
|
51975
|
-
targetId:
|
|
52761
|
+
fileName: installItem.fileName,
|
|
52762
|
+
binary: installItem.binary,
|
|
52763
|
+
targetId: installItem.targetId,
|
|
51976
52764
|
};
|
|
51977
52765
|
fwBinaryMap.push(binaryEntry);
|
|
51978
|
-
installItems.push(Object.assign(Object.assign({}, binaryEntry), { kind: remoteBinary.kind }));
|
|
51979
52766
|
}
|
|
52767
|
+
installItems.push(Object.assign({}, installItem));
|
|
52768
|
+
preparedTargets.add(updateTarget);
|
|
51980
52769
|
}
|
|
51981
52770
|
}
|
|
52771
|
+
const missingTarget = Array.from(targetsToUpdate).find(target => target !== 'resource' && !preparedTargets.has(target));
|
|
52772
|
+
if (missingTarget) {
|
|
52773
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 release does not contain requested target ${missingTarget}`);
|
|
52774
|
+
}
|
|
51982
52775
|
return {
|
|
51983
52776
|
bootloaderBinary,
|
|
51984
52777
|
fwBinaryMap,
|
|
@@ -51986,178 +52779,6 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51986
52779
|
};
|
|
51987
52780
|
});
|
|
51988
52781
|
}
|
|
51989
|
-
getProtocolV2DeviceType() {
|
|
51990
|
-
const deviceType = this.device.getCurrentDeviceType();
|
|
51991
|
-
if (deviceType === hdShared.EDeviceType.Pro2 || deviceType === hdShared.EDeviceType.Neo)
|
|
51992
|
-
return deviceType;
|
|
51993
|
-
throw new Error(`Unsupported Protocol V2 device type: ${deviceType}`);
|
|
51994
|
-
}
|
|
51995
|
-
prepareProtocolV2BootResources() {
|
|
51996
|
-
var _a, _b, _c, _d, _e;
|
|
51997
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
51998
|
-
const wantsStableResources = !!((_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.includes('resource'));
|
|
51999
|
-
const wantsBootResources = !!((_b = this.params.targetsToUpdate) === null || _b === void 0 ? void 0 : _b.includes('boot_resources'));
|
|
52000
|
-
if (!wantsStableResources && !wantsBootResources) {
|
|
52001
|
-
return undefined;
|
|
52002
|
-
}
|
|
52003
|
-
if ((_c = this.params.resourceFiles) === null || _c === void 0 ? void 0 : _c.length) {
|
|
52004
|
-
return undefined;
|
|
52005
|
-
}
|
|
52006
|
-
const resource = DataManager.getProtocolV2BootResources(this.getProtocolV2DeviceType());
|
|
52007
|
-
if (!resource) {
|
|
52008
|
-
if (wantsBootResources) {
|
|
52009
|
-
throw new Error('Missing Protocol V2 boot resources configuration');
|
|
52010
|
-
}
|
|
52011
|
-
Log$6.debug('[FirmwareUpdateV4] no boot resources configured; continue with stable resources');
|
|
52012
|
-
return undefined;
|
|
52013
|
-
}
|
|
52014
|
-
const files = [];
|
|
52015
|
-
for (const file of resource.files) {
|
|
52016
|
-
const isCurrent = !this.params.forcedUpdateRes && (yield this.isProtocolV2BootResourceCurrent(file));
|
|
52017
|
-
if (isCurrent) {
|
|
52018
|
-
Log$6.log(`[FirmwareUpdateV4] boot resource unchanged, skipping ${file.devicePath}`);
|
|
52019
|
-
}
|
|
52020
|
-
else {
|
|
52021
|
-
Log$6.log(`[FirmwareUpdateV4] downloading boot resource ${file.devicePath}`);
|
|
52022
|
-
const { binary } = yield getSysResourceBinary(file.url);
|
|
52023
|
-
if (!isProtocolV2ResourceFileValid(binary, file)) {
|
|
52024
|
-
throw new Error(`Boot resource file verification failed: ${file.devicePath}`);
|
|
52025
|
-
}
|
|
52026
|
-
files.push({
|
|
52027
|
-
name: (_e = (_d = file.name) !== null && _d !== void 0 ? _d : file.devicePath.split('/').pop()) !== null && _e !== void 0 ? _e : file.devicePath,
|
|
52028
|
-
binary,
|
|
52029
|
-
devicePath: file.devicePath,
|
|
52030
|
-
});
|
|
52031
|
-
}
|
|
52032
|
-
}
|
|
52033
|
-
return files;
|
|
52034
|
-
});
|
|
52035
|
-
}
|
|
52036
|
-
isProtocolV2BootResourceCurrent(file) {
|
|
52037
|
-
var _a, _b, _c, _d;
|
|
52038
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
52039
|
-
try {
|
|
52040
|
-
const commands = this.device.getCommands();
|
|
52041
|
-
const pathInfo = yield commands.typedCall('FilesystemPathInfoQuery', 'FilesystemPathInfo', { path: file.devicePath }, { timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT });
|
|
52042
|
-
const size = toProtocolV2FiniteNumber((_a = pathInfo.message) === null || _a === void 0 ? void 0 : _a.size);
|
|
52043
|
-
if (!((_b = pathInfo.message) === null || _b === void 0 ? void 0 : _b.exist) ||
|
|
52044
|
-
((_c = pathInfo.message) === null || _c === void 0 ? void 0 : _c.directory) ||
|
|
52045
|
-
!Number.isSafeInteger(size) ||
|
|
52046
|
-
size !== file.size) {
|
|
52047
|
-
return false;
|
|
52048
|
-
}
|
|
52049
|
-
const digest = sha256.sha256.create();
|
|
52050
|
-
const chunkSize = this.getProtocolV2FirmwareChunkSize('write');
|
|
52051
|
-
let offset = 0;
|
|
52052
|
-
while (offset < file.size) {
|
|
52053
|
-
const response = yield commands.typedCall('FilesystemFileRead', 'FilesystemFile', {
|
|
52054
|
-
file: { path: file.devicePath, offset, total_size: 0 },
|
|
52055
|
-
chunk_len: Math.min(chunkSize, file.size - offset),
|
|
52056
|
-
}, { timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT });
|
|
52057
|
-
const data = toProtocolV2Bytes((_d = response.message) === null || _d === void 0 ? void 0 : _d.data);
|
|
52058
|
-
if (data.byteLength === 0)
|
|
52059
|
-
return false;
|
|
52060
|
-
const consumed = data.subarray(0, Math.min(data.byteLength, file.size - offset));
|
|
52061
|
-
digest.update(consumed);
|
|
52062
|
-
offset += consumed.byteLength;
|
|
52063
|
-
}
|
|
52064
|
-
return bytesToHex(digest.digest()) === normalizeProtocolV2Hex(file.fileHash);
|
|
52065
|
-
}
|
|
52066
|
-
catch (error) {
|
|
52067
|
-
Log$6.debug(`[FirmwareUpdateV4] unable to compare boot resource ${file.devicePath}; scheduling rewrite`, error);
|
|
52068
|
-
return false;
|
|
52069
|
-
}
|
|
52070
|
-
});
|
|
52071
|
-
}
|
|
52072
|
-
mergeProtocolV2ResourceBundles(...groups) {
|
|
52073
|
-
const merged = groups.flatMap(group => group !== null && group !== void 0 ? group : []);
|
|
52074
|
-
if (!merged.length)
|
|
52075
|
-
return undefined;
|
|
52076
|
-
const seenPaths = new Set();
|
|
52077
|
-
for (const bundle of merged) {
|
|
52078
|
-
if (seenPaths.has(bundle.devicePath)) {
|
|
52079
|
-
throw new Error(`Duplicate Protocol V2 resource devicePath: ${bundle.devicePath}`);
|
|
52080
|
-
}
|
|
52081
|
-
seenPaths.add(bundle.devicePath);
|
|
52082
|
-
}
|
|
52083
|
-
return merged;
|
|
52084
|
-
}
|
|
52085
|
-
prepareExplicitProtocolV2ResourceFiles() {
|
|
52086
|
-
var _a;
|
|
52087
|
-
const files = (_a = this.params.resourceFiles) !== null && _a !== void 0 ? _a : [];
|
|
52088
|
-
if (!(files === null || files === void 0 ? void 0 : files.length))
|
|
52089
|
-
return undefined;
|
|
52090
|
-
const prepared = files.map((file, index) => {
|
|
52091
|
-
var _a;
|
|
52092
|
-
const devicePath = validateProtocolV2FilesystemPath(file.devicePath, `resourceFiles[${index}].devicePath`);
|
|
52093
|
-
const descriptor = file;
|
|
52094
|
-
if (descriptor.size !== undefined && descriptor.size !== file.binary.byteLength) {
|
|
52095
|
-
throw new Error(`resourceFiles[${index}] size mismatch`);
|
|
52096
|
-
}
|
|
52097
|
-
if (descriptor.fileHash &&
|
|
52098
|
-
!isProtocolV2ResourceFileValid(file.binary, {
|
|
52099
|
-
size: file.binary.byteLength,
|
|
52100
|
-
fileHash: descriptor.fileHash,
|
|
52101
|
-
})) {
|
|
52102
|
-
throw new Error(`resourceFiles[${index}] SHA-256 mismatch`);
|
|
52103
|
-
}
|
|
52104
|
-
return {
|
|
52105
|
-
name: (_a = devicePath.split('/').pop()) !== null && _a !== void 0 ? _a : devicePath,
|
|
52106
|
-
binary: file.binary,
|
|
52107
|
-
devicePath,
|
|
52108
|
-
};
|
|
52109
|
-
});
|
|
52110
|
-
if (new Set(prepared.map(file => file.devicePath)).size !== prepared.length) {
|
|
52111
|
-
throw new Error('resourceFiles contain duplicate devicePath values');
|
|
52112
|
-
}
|
|
52113
|
-
return prepared;
|
|
52114
|
-
}
|
|
52115
|
-
prepareProtocolV2ResourceBundles() {
|
|
52116
|
-
var _a;
|
|
52117
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
52118
|
-
if (!((_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.includes('resource'))) {
|
|
52119
|
-
return undefined;
|
|
52120
|
-
}
|
|
52121
|
-
const resources = DataManager.getProtocolV2Resources(this.getProtocolV2DeviceType());
|
|
52122
|
-
if (!(resources === null || resources === void 0 ? void 0 : resources.length)) {
|
|
52123
|
-
throw new Error('Missing Pro2 stable resource configuration');
|
|
52124
|
-
}
|
|
52125
|
-
const inventory = this.params.forcedUpdateRes
|
|
52126
|
-
? undefined
|
|
52127
|
-
: yield readProtocolV2ResourceInventory({
|
|
52128
|
-
commands: this.device.getCommands(),
|
|
52129
|
-
resources,
|
|
52130
|
-
chunkSize: this.getProtocolV2FirmwareChunkSize('write'),
|
|
52131
|
-
timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT,
|
|
52132
|
-
});
|
|
52133
|
-
const plan = buildProtocolV2ResourceUpdatePlan({
|
|
52134
|
-
resources,
|
|
52135
|
-
inventory,
|
|
52136
|
-
mode: 'bootloader-recovery',
|
|
52137
|
-
forced: this.params.forcedUpdateRes,
|
|
52138
|
-
});
|
|
52139
|
-
Log$6.log(`[FirmwareUpdateV4] Protocol V2 resource plan mode=bootloader-recovery status=${plan.status} count=${plan.resources.length}`);
|
|
52140
|
-
const bundles = [];
|
|
52141
|
-
for (const resource of plan.resources) {
|
|
52142
|
-
bundles.push(yield this.downloadProtocolV2Resource(resource));
|
|
52143
|
-
}
|
|
52144
|
-
return bundles;
|
|
52145
|
-
});
|
|
52146
|
-
}
|
|
52147
|
-
downloadProtocolV2Resource(resource) {
|
|
52148
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
52149
|
-
Log$6.log(`[FirmwareUpdateV4] downloading Pro2 resource ${resource.type}`);
|
|
52150
|
-
const { binary } = yield getSysResourceBinary(resource.url);
|
|
52151
|
-
if (!isProtocolV2ResourceFileValid(binary, resource)) {
|
|
52152
|
-
throw new Error(`Pro2 resource file verification failed: ${resource.type}`);
|
|
52153
|
-
}
|
|
52154
|
-
return {
|
|
52155
|
-
name: `${resource.type}.okpkg`,
|
|
52156
|
-
binary,
|
|
52157
|
-
devicePath: PROTOCOL_V2_RESOURCE_DEVICE_PATHS[resource.type],
|
|
52158
|
-
};
|
|
52159
|
-
});
|
|
52160
|
-
}
|
|
52161
52782
|
getProtocolV2ResourceFilePath(path) {
|
|
52162
52783
|
if (path.startsWith('vol'))
|
|
52163
52784
|
return path;
|
|
@@ -52165,7 +52786,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52165
52786
|
return `vol0:${path}`;
|
|
52166
52787
|
return `vol0:/${path}`;
|
|
52167
52788
|
}
|
|
52168
|
-
readProtocolV2DeviceFileHeader(path) {
|
|
52789
|
+
readProtocolV2DeviceFileHeader(path, expectedSize) {
|
|
52169
52790
|
var _a, _b, _c, _d;
|
|
52170
52791
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52171
52792
|
const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
|
|
@@ -52177,7 +52798,8 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52177
52798
|
if (!((_b = pathInfoRes.message) === null || _b === void 0 ? void 0 : _b.exist) ||
|
|
52178
52799
|
((_c = pathInfoRes.message) === null || _c === void 0 ? void 0 : _c.directory) ||
|
|
52179
52800
|
fileSize === undefined ||
|
|
52180
|
-
fileSize < PROTOCOL_V2_OKPP_HEADER_SIZE
|
|
52801
|
+
fileSize < PROTOCOL_V2_OKPP_HEADER_SIZE ||
|
|
52802
|
+
(expectedSize !== undefined && fileSize !== expectedSize)) {
|
|
52181
52803
|
return null;
|
|
52182
52804
|
}
|
|
52183
52805
|
const chunkSize = this.getProtocolV2FirmwareChunkSize('read');
|
|
@@ -52214,10 +52836,10 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52214
52836
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52215
52837
|
if ((_a = this.params) === null || _a === void 0 ? void 0 : _a.forcedUpdateRes)
|
|
52216
52838
|
return false;
|
|
52217
|
-
if (!bundle.
|
|
52839
|
+
if (!bundle.payloadHash || !bundle.headerHash)
|
|
52218
52840
|
return false;
|
|
52219
52841
|
try {
|
|
52220
|
-
const header = yield this.readProtocolV2DeviceFileHeader(bundle.devicePath);
|
|
52842
|
+
const header = yield this.readProtocolV2DeviceFileHeader(bundle.devicePath, bundle.source.size);
|
|
52221
52843
|
if (!header)
|
|
52222
52844
|
return false;
|
|
52223
52845
|
if (bundle.version) {
|
|
@@ -52225,16 +52847,12 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52225
52847
|
if (cmp === undefined || cmp !== 0)
|
|
52226
52848
|
return false;
|
|
52227
52849
|
}
|
|
52228
|
-
|
|
52229
|
-
|
|
52230
|
-
|
|
52231
|
-
|
|
52232
|
-
|
|
52233
|
-
|
|
52234
|
-
const expected = normalizeProtocolV2Hex(bundle.headerHash);
|
|
52235
|
-
if (expected && header.headerHash !== expected)
|
|
52236
|
-
return false;
|
|
52237
|
-
}
|
|
52850
|
+
const expectedPayloadHash = normalizeProtocolV2Hex(bundle.payloadHash);
|
|
52851
|
+
const expectedHeaderHash = normalizeProtocolV2Hex(bundle.headerHash);
|
|
52852
|
+
if (!expectedPayloadHash || header.payloadHash !== expectedPayloadHash)
|
|
52853
|
+
return false;
|
|
52854
|
+
if (!expectedHeaderHash || header.headerHash !== expectedHeaderHash)
|
|
52855
|
+
return false;
|
|
52238
52856
|
return true;
|
|
52239
52857
|
}
|
|
52240
52858
|
catch (error) {
|
|
@@ -52349,11 +52967,13 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52349
52967
|
}
|
|
52350
52968
|
buildProtocolV2ExecutionPhases({ installSources, resourceSources, }) {
|
|
52351
52969
|
const phases = [];
|
|
52352
|
-
|
|
52970
|
+
const bootResourceSources = resourceSources.filter(source => isProtocolV2BootResourcePackagePath(source.devicePath));
|
|
52971
|
+
const remainingResourceSources = resourceSources.filter(source => !isProtocolV2BootResourcePackagePath(source.devicePath));
|
|
52972
|
+
if (bootResourceSources.length > 0) {
|
|
52353
52973
|
phases.push({
|
|
52354
52974
|
kind: 'resource-sync',
|
|
52355
52975
|
installSources: [],
|
|
52356
|
-
resourceSources,
|
|
52976
|
+
resourceSources: bootResourceSources,
|
|
52357
52977
|
});
|
|
52358
52978
|
}
|
|
52359
52979
|
const bootloaderSources = installSources.filter(source => source.kind === 'bootloader');
|
|
@@ -52368,6 +52988,13 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52368
52988
|
resourceSources: [],
|
|
52369
52989
|
});
|
|
52370
52990
|
}
|
|
52991
|
+
if (remainingResourceSources.length > 0) {
|
|
52992
|
+
phases.push({
|
|
52993
|
+
kind: 'resource-sync',
|
|
52994
|
+
installSources: [],
|
|
52995
|
+
resourceSources: remainingResourceSources,
|
|
52996
|
+
});
|
|
52997
|
+
}
|
|
52371
52998
|
const componentSources = installSources.filter(source => source.kind !== 'bootloader');
|
|
52372
52999
|
if (componentSources.length > 0) {
|
|
52373
53000
|
phases.push({
|
|
@@ -52385,6 +53012,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52385
53012
|
}
|
|
52386
53013
|
executeProtocolV2Phases({ installSources, resourceSources, }) {
|
|
52387
53014
|
return __awaiter(this, void 0, void 0, function* () {
|
|
53015
|
+
this.protocolV2BootResourceStagingSafe = false;
|
|
52388
53016
|
const phases = this.buildProtocolV2ExecutionPhases({
|
|
52389
53017
|
installSources,
|
|
52390
53018
|
resourceSources,
|
|
@@ -52395,10 +53023,14 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52395
53023
|
}
|
|
52396
53024
|
if (phase.kind === 'resource-sync') {
|
|
52397
53025
|
yield this.enterProtocolV2BootloaderMode();
|
|
53026
|
+
if (!phase.resourceSources.some(source => isProtocolV2BootResourcePackagePath(source.devicePath))) {
|
|
53027
|
+
yield this.ensureProtocolV2BootResourceStagingIsEmpty();
|
|
53028
|
+
}
|
|
52398
53029
|
yield this.executeProtocolV2TransferPhase(phase);
|
|
52399
53030
|
}
|
|
52400
53031
|
else if (phase.kind === 'bootloader-install' || phase.kind === 'component-install') {
|
|
52401
53032
|
yield this.enterProtocolV2BootloaderMode();
|
|
53033
|
+
yield this.ensureProtocolV2BootResourceStagingIsEmpty();
|
|
52402
53034
|
yield this.executeProtocolV2TransferPhase(phase);
|
|
52403
53035
|
yield this.exitProtocolV2BootloaderToNormal();
|
|
52404
53036
|
}
|
|
@@ -52410,6 +53042,31 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52410
53042
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 execution has no final verification phase');
|
|
52411
53043
|
});
|
|
52412
53044
|
}
|
|
53045
|
+
ensureProtocolV2BootResourceStagingIsEmpty() {
|
|
53046
|
+
var _a, _b;
|
|
53047
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
53048
|
+
if (this.protocolV2BootResourceStagingSafe)
|
|
53049
|
+
return;
|
|
53050
|
+
const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
|
|
53051
|
+
const query = () => typedCall('FilesystemPathInfoQuery', 'FilesystemPathInfo', {
|
|
53052
|
+
path: PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_STAGING_PATH,
|
|
53053
|
+
});
|
|
53054
|
+
const current = yield query();
|
|
53055
|
+
if ((_a = current.message) === null || _a === void 0 ? void 0 : _a.exist) {
|
|
53056
|
+
if (current.message.directory) {
|
|
53057
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.EmmcFileWriteFirmwareError, 'Protocol V2 boot resource staging path is not a file');
|
|
53058
|
+
}
|
|
53059
|
+
yield typedCall('FilesystemFileDelete', 'Success', {
|
|
53060
|
+
path: PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_STAGING_PATH,
|
|
53061
|
+
});
|
|
53062
|
+
const remaining = yield query();
|
|
53063
|
+
if ((_b = remaining.message) === null || _b === void 0 ? void 0 : _b.exist) {
|
|
53064
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.EmmcFileWriteFirmwareError, 'Protocol V2 stale boot resource staging file could not be removed');
|
|
53065
|
+
}
|
|
53066
|
+
}
|
|
53067
|
+
this.protocolV2BootResourceStagingSafe = true;
|
|
53068
|
+
});
|
|
53069
|
+
}
|
|
52413
53070
|
executeProtocolV2SourceUpdate({ installSources, resourceSources, }) {
|
|
52414
53071
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52415
53072
|
return this.executeProtocolV2Phases({
|
|
@@ -52418,7 +53075,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52418
53075
|
});
|
|
52419
53076
|
});
|
|
52420
53077
|
}
|
|
52421
|
-
executeProtocolV2Update({ fwBinaryMap, bootloaderBinary, installItems,
|
|
53078
|
+
executeProtocolV2Update({ fwBinaryMap, bootloaderBinary, installItems, }) {
|
|
52422
53079
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52423
53080
|
const memoryInstallItems = installItems !== null && installItems !== void 0 ? installItems : this.buildProtocolV2InstallItems({
|
|
52424
53081
|
fwBinaryMap: fwBinaryMap !== null && fwBinaryMap !== void 0 ? fwBinaryMap : [],
|
|
@@ -52433,16 +53090,9 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52433
53090
|
kind: item.kind,
|
|
52434
53091
|
});
|
|
52435
53092
|
})));
|
|
52436
|
-
const resourceSources = yield Promise.all((resourceBundles !== null && resourceBundles !== void 0 ? resourceBundles : []).map((bundle) => __awaiter(this, void 0, void 0, function* () {
|
|
52437
|
-
return ({
|
|
52438
|
-
name: bundle.name,
|
|
52439
|
-
source: yield this.openProtocolV2MemorySource(bundle.binary),
|
|
52440
|
-
devicePath: bundle.devicePath,
|
|
52441
|
-
});
|
|
52442
|
-
})));
|
|
52443
53093
|
return yield this.executeProtocolV2Phases({
|
|
52444
53094
|
installSources,
|
|
52445
|
-
resourceSources,
|
|
53095
|
+
resourceSources: [],
|
|
52446
53096
|
});
|
|
52447
53097
|
}
|
|
52448
53098
|
finally {
|
|
@@ -52455,7 +53105,8 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52455
53105
|
let totalSize = installSources.reduce((total, item) => total + item.source.size, 0);
|
|
52456
53106
|
const resourcesToSync = [];
|
|
52457
53107
|
for (const resource of resourceSources) {
|
|
52458
|
-
|
|
53108
|
+
const requiresFreshStaging = isProtocolV2BootResourcePackagePath(resource.devicePath);
|
|
53109
|
+
if (!requiresFreshStaging && (yield this.isProtocolV2ResourceBundleUpToDate(resource))) {
|
|
52459
53110
|
Log$6.log(`[FirmwareUpdateV4] skip RESC bundle ${resource.name}; already up to date`);
|
|
52460
53111
|
}
|
|
52461
53112
|
else {
|
|
@@ -52466,13 +53117,17 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52466
53117
|
this.postTipMessage(exports.FirmwareUpdateTipMessage.StartTransferData);
|
|
52467
53118
|
let processedSize = 0;
|
|
52468
53119
|
for (const resource of resourcesToSync) {
|
|
53120
|
+
const writePath = resolveProtocolV2ResourceWritePath(resource.devicePath);
|
|
52469
53121
|
processedSize = yield this.protocolV2SourceUpdateProcess({
|
|
52470
53122
|
source: resource.source,
|
|
52471
|
-
filePath:
|
|
53123
|
+
filePath: writePath,
|
|
52472
53124
|
processedSize,
|
|
52473
53125
|
totalSize,
|
|
52474
53126
|
});
|
|
52475
|
-
yield this.verifyProtocolV2StagedFile(
|
|
53127
|
+
yield this.verifyProtocolV2StagedFile(writePath, resource.source.size);
|
|
53128
|
+
if (isProtocolV2BootResourcePackagePath(resource.devicePath)) {
|
|
53129
|
+
this.protocolV2BootResourceStagingSafe = true;
|
|
53130
|
+
}
|
|
52476
53131
|
}
|
|
52477
53132
|
const stagedInstallTargets = [];
|
|
52478
53133
|
for (const item of installSources) {
|
|
@@ -53462,7 +54117,7 @@ class DeviceUploadWallpaper extends BaseMethod {
|
|
|
53462
54117
|
}
|
|
53463
54118
|
|
|
53464
54119
|
const FILESYSTEM_PATH_INFO_QUERY_MESSAGE_TYPE = 60802;
|
|
53465
|
-
const FILESYSTEM_FILE_WRITE_MESSAGE_TYPE = 60805;
|
|
54120
|
+
const FILESYSTEM_FILE_WRITE_MESSAGE_TYPE$1 = 60805;
|
|
53466
54121
|
const FILESYSTEM_DIR_LIST_MESSAGE_TYPE = 60808;
|
|
53467
54122
|
const NFT_UPDATE_MESSAGE_TYPE = 61500;
|
|
53468
54123
|
class DeviceUploadNft extends BaseMethod {
|
|
@@ -53491,7 +54146,7 @@ class DeviceUploadNft extends BaseMethod {
|
|
|
53491
54146
|
assertCapabilities() {
|
|
53492
54147
|
return __awaiter(this, void 0, void 0, function* () {
|
|
53493
54148
|
const protocolInfo = yield this.device.ensureProtocolV2RuntimeContext();
|
|
53494
|
-
const hasFileWrite = supportsProtocolV2Message(protocolInfo, FILESYSTEM_FILE_WRITE_MESSAGE_TYPE);
|
|
54149
|
+
const hasFileWrite = supportsProtocolV2Message(protocolInfo, FILESYSTEM_FILE_WRITE_MESSAGE_TYPE$1);
|
|
53495
54150
|
const hasPathInfo = supportsProtocolV2Message(protocolInfo, FILESYSTEM_PATH_INFO_QUERY_MESSAGE_TYPE);
|
|
53496
54151
|
const hasDirList = supportsProtocolV2Message(protocolInfo, FILESYSTEM_DIR_LIST_MESSAGE_TYPE);
|
|
53497
54152
|
const hasNftUpdate = supportsProtocolV2Message(protocolInfo, NFT_UPDATE_MESSAGE_TYPE);
|
|
@@ -53626,6 +54281,8 @@ class FileWrite extends BaseMethod {
|
|
|
53626
54281
|
|
|
53627
54282
|
const PORTFOLIO_PENDING_PATH = 'vol1:/portfolio/portfolio.okpkg.pending';
|
|
53628
54283
|
const PORTFOLIO_CHUNK_SIZE = 2048;
|
|
54284
|
+
const FILESYSTEM_FILE_WRITE_MESSAGE_TYPE = 60805;
|
|
54285
|
+
const PORTFOLIO_UPDATE_MESSAGE_TYPE = 61400;
|
|
53629
54286
|
class UploadPortfolio extends FileWrite {
|
|
53630
54287
|
init() {
|
|
53631
54288
|
const { packageBytes, timeoutMs } = this.payload;
|
|
@@ -53639,6 +54296,12 @@ class UploadPortfolio extends FileWrite {
|
|
|
53639
54296
|
run: { get: () => super.run }
|
|
53640
54297
|
});
|
|
53641
54298
|
return __awaiter(this, void 0, void 0, function* () {
|
|
54299
|
+
const protocolInfo = yield this.device.ensureProtocolV2RuntimeContext();
|
|
54300
|
+
const hasFileWrite = supportsProtocolV2Message(protocolInfo, FILESYSTEM_FILE_WRITE_MESSAGE_TYPE);
|
|
54301
|
+
const hasPortfolioUpdate = supportsProtocolV2Message(protocolInfo, PORTFOLIO_UPDATE_MESSAGE_TYPE);
|
|
54302
|
+
if (!hasFileWrite || !hasPortfolioUpdate) {
|
|
54303
|
+
throw hdShared.createDeviceNotSupportMethodError(this.name, this.device.getCurrentFirmwareType());
|
|
54304
|
+
}
|
|
53642
54305
|
const stagedFile = yield _super.run.call(this);
|
|
53643
54306
|
this.throwIfAborted();
|
|
53644
54307
|
yield this.device.commands.typedCall('PortfolioUpdate', 'Success', {});
|
|
@@ -65180,11 +65843,14 @@ exports.normalizeSafetyCheckLevel = normalizeSafetyCheckLevel;
|
|
|
65180
65843
|
exports.normalizeVersionArray = normalizeVersionArray;
|
|
65181
65844
|
exports.parseConnectSettings = parseConnectSettings;
|
|
65182
65845
|
exports.parseMessage = parseMessage;
|
|
65846
|
+
exports.parseProtocolV2ResourceManifest = parseProtocolV2ResourceManifest;
|
|
65183
65847
|
exports.patchFeatures = patchFeatures;
|
|
65184
65848
|
exports.preloadSessionCache = preloadSessionCache;
|
|
65849
|
+
exports.prepareFirmwareUpdateV4MemoryHost = prepareFirmwareUpdateV4MemoryHost;
|
|
65185
65850
|
exports.projectDeviceStateFeatures = projectFeatures;
|
|
65186
65851
|
exports.registerFirmwareUpdateHostBinding = registerFirmwareUpdateHostBinding;
|
|
65187
65852
|
exports.safeThrowError = safeThrowError;
|
|
65853
|
+
exports.selectProtocolV2ResourceManifestFiles = selectProtocolV2ResourceManifestFiles;
|
|
65188
65854
|
exports.setLoggerPostMessage = setLoggerPostMessage;
|
|
65189
65855
|
exports.supportInputPinOnSoftware = supportInputPinOnSoftware;
|
|
65190
65856
|
exports.switchTransport = switchTransport;
|