@onekeyfe/hd-core 1.2.0-alpha.97 → 1.2.0-alpha.99
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 +411 -86
- package/__tests__/check-firmware-release-protocol-v2.test.ts +199 -0
- package/__tests__/firmware-memory-host.test.ts +126 -0
- package/__tests__/firmware-update/device-update-bootloader.test.ts +14 -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-bootloader-poll.test.ts +65 -2
- package/__tests__/firmware-update/firmware-update-plan-bootloader-identity.test.ts +80 -0
- package/__tests__/firmware-update/firmware-update-plan.test.ts +293 -71
- 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-firmware-targets.test.ts +16 -0
- package/__tests__/protocol-v2-resources.test.ts +148 -232
- package/__tests__/protocol-v2.test.ts +1326 -510
- 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 +11 -9
- 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/FirmwareUpdateBaseMethod.d.ts.map +1 -1
- 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 +7 -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 +1825 -1006
- 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 +113 -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 +231 -138
- package/src/api/FirmwareUpdateV3.ts +101 -56
- package/src/api/FirmwareUpdateV4.ts +936 -408
- package/src/api/UploadPortfolio.ts +18 -0
- package/src/api/device/DeviceUpdateBootloader.ts +37 -11
- package/src/api/firmware/FirmwareHostBinding.ts +26 -3
- package/src/api/firmware/FirmwareMemoryHost.ts +143 -0
- package/src/api/firmware/FirmwarePreparedResourceArchive.ts +207 -0
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +122 -73
- package/src/api/firmware/FirmwareUpdatePlan.ts +295 -122
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +49 -12
- 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,21 @@ 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
|
+
return planError('Protocol V2 firmware update targets are invalid');
|
|
632
|
+
}
|
|
633
|
+
const normalizedTargets = value.map(target => target === 'boot_resources' ? 'resource' : target);
|
|
634
|
+
if (normalizedTargets.length > PROTOCOL_V2_FIRMWARE_UPDATE_TARGETS.size ||
|
|
635
|
+
normalizedTargets.some(target => !PROTOCOL_V2_FIRMWARE_UPDATE_TARGETS.has(target)) ||
|
|
636
|
+
new Set(normalizedTargets).size !== normalizedTargets.length) {
|
|
637
|
+
return planError('Protocol V2 firmware update targets are invalid');
|
|
638
|
+
}
|
|
639
|
+
return normalizedTargets;
|
|
640
|
+
};
|
|
612
641
|
const assertExactKeys = (value, required, optional = []) => {
|
|
613
642
|
const allowed = new Set([...required, ...optional]);
|
|
614
643
|
if (required.some(key => !Object.prototype.hasOwnProperty.call(value, key)) ||
|
|
@@ -689,7 +718,7 @@ const assertFirmwareUpdatePlan = (value) => {
|
|
|
689
718
|
if (!artifact) {
|
|
690
719
|
return planError('Firmware update plan artifact is invalid');
|
|
691
720
|
}
|
|
692
|
-
assertExactKeys(artifact, ['artifactId', 'role', 'target', 'url', 'container'
|
|
721
|
+
assertExactKeys(artifact, ['artifactId', 'role', 'target', 'url', 'container', 'expectedSize', 'expectedSha256'], ['logicalName', 'targetVersion']);
|
|
693
722
|
const artifactId = assertBoundedString(artifact.artifactId, 'artifact id', 160);
|
|
694
723
|
if (artifactIds.has(artifactId)) {
|
|
695
724
|
return planError('Firmware update plan contains duplicate artifact ids');
|
|
@@ -705,13 +734,11 @@ const assertFirmwareUpdatePlan = (value) => {
|
|
|
705
734
|
if (artifact.logicalName !== undefined) {
|
|
706
735
|
assertBoundedString(artifact.logicalName, 'logical name', 256);
|
|
707
736
|
}
|
|
708
|
-
if (artifact.expectedSize
|
|
709
|
-
(!Number.isSafeInteger(artifact.expectedSize) || artifact.expectedSize <= 0)) {
|
|
737
|
+
if (!Number.isSafeInteger(artifact.expectedSize) || artifact.expectedSize <= 0) {
|
|
710
738
|
return planError('Firmware update plan artifact size is invalid');
|
|
711
739
|
}
|
|
712
|
-
if (artifact.expectedSha256 !==
|
|
713
|
-
(
|
|
714
|
-
!/^[a-f0-9]{64}$/u.test(artifact.expectedSha256))) {
|
|
740
|
+
if (typeof artifact.expectedSha256 !== 'string' ||
|
|
741
|
+
!/^[a-f0-9]{64}$/u.test(artifact.expectedSha256)) {
|
|
715
742
|
return planError('Firmware update plan artifact digest is invalid');
|
|
716
743
|
}
|
|
717
744
|
if (artifact.targetVersion !== undefined) {
|
|
@@ -738,7 +765,7 @@ const assertFirmwareUpdatePlan = (value) => {
|
|
|
738
765
|
plan.targetsToUpdate.some(target => legacyOnlyTargets.has(target))) ||
|
|
739
766
|
(plan.artifacts.length > 0 &&
|
|
740
767
|
(plan.platform === 'native' || plan.platform === 'desktop') &&
|
|
741
|
-
plan.executor
|
|
768
|
+
plan.executor === 'v3' &&
|
|
742
769
|
plan.deviceIdentity === 'unavailable')) {
|
|
743
770
|
return planError('Firmware update plan executor contract is invalid');
|
|
744
771
|
}
|
|
@@ -773,7 +800,7 @@ const selectResourceUrl = ({ release, features, platform, }) => {
|
|
|
773
800
|
};
|
|
774
801
|
const getExecutor = (features) => {
|
|
775
802
|
const deviceType = getDeviceType(features);
|
|
776
|
-
if (deviceType === hdShared.EDeviceType.Pro2) {
|
|
803
|
+
if (deviceType === hdShared.EDeviceType.Pro2 || deviceType === hdShared.EDeviceType.Neo) {
|
|
777
804
|
return 'v4';
|
|
778
805
|
}
|
|
779
806
|
if (deviceType === hdShared.EDeviceType.Pro &&
|
|
@@ -782,7 +809,7 @@ const getExecutor = (features) => {
|
|
|
782
809
|
}
|
|
783
810
|
return 'v2';
|
|
784
811
|
};
|
|
785
|
-
const buildProtocolV2Artifacts = (release, { includeComponents = true,
|
|
812
|
+
const buildProtocolV2Artifacts = (release, { includeComponents = true, componentTargets: selectedComponentTargets, } = {}) => {
|
|
786
813
|
var _a;
|
|
787
814
|
const components = asRecord(release.components);
|
|
788
815
|
if (includeComponents && !components) {
|
|
@@ -794,49 +821,36 @@ const buildProtocolV2Artifacts = (release, { includeComponents = true, includeRe
|
|
|
794
821
|
const componentKeys = includeComponents && components
|
|
795
822
|
? [...installOrder, ...Object.keys(components).filter(key => !installOrder.includes(key))]
|
|
796
823
|
: [];
|
|
824
|
+
const selectedComponentKeys = selectedComponentTargets
|
|
825
|
+
? componentKeys.filter(key => {
|
|
826
|
+
var _a;
|
|
827
|
+
const component = asRecord(components === null || components === void 0 ? void 0 : components[key]);
|
|
828
|
+
const targetName = (_a = asString(component === null || component === void 0 ? void 0 : component.target)) === null || _a === void 0 ? void 0 : _a.toUpperCase();
|
|
829
|
+
const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
|
|
830
|
+
return !!target && selectedComponentTargets.has(target);
|
|
831
|
+
})
|
|
832
|
+
: componentKeys;
|
|
797
833
|
const artifacts = [];
|
|
798
834
|
const targets = [];
|
|
799
|
-
const
|
|
800
|
-
for (const key of
|
|
835
|
+
const componentTargetSet = new Set();
|
|
836
|
+
for (const key of selectedComponentKeys) {
|
|
801
837
|
const component = asRecord(components === null || components === void 0 ? void 0 : components[key]);
|
|
802
838
|
const targetName = (_a = asString(component === null || component === void 0 ? void 0 : component.target)) === null || _a === void 0 ? void 0 : _a.toUpperCase();
|
|
839
|
+
const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
|
|
803
840
|
if (targetName === 'ROMLOADER') {
|
|
804
841
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 ROMLOADER requires its dedicated loader flow', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
805
842
|
}
|
|
806
|
-
const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
|
|
807
843
|
if (!component || !target) {
|
|
808
844
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 component ${key} has an unsupported target`, { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
809
845
|
}
|
|
810
|
-
if (
|
|
846
|
+
if (componentTargetSet.has(target)) {
|
|
811
847
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 component ${key} duplicates target ${target}`, { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
812
848
|
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
sha256: component.fingerprint,
|
|
817
|
-
})), (asVersion(component.version) ? { targetVersion: asVersion(component.version) } : {})));
|
|
849
|
+
componentTargetSet.add(target);
|
|
850
|
+
const integrity = requireArtifactIntegrity({ size: component.expectedSize, sha256: component.fingerprint }, `Protocol V2 component ${key}`);
|
|
851
|
+
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
852
|
targets.push(target);
|
|
819
853
|
}
|
|
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
854
|
return { artifacts, targets: [...new Set(targets)] };
|
|
841
855
|
};
|
|
842
856
|
const isForcedTargetRepresented = ({ executor, forcedTarget, artifacts, targetsToUpdate, }) => {
|
|
@@ -865,8 +879,91 @@ const assertForcedTargetsRepresented = ({ executor, forcedTargets, artifacts, ta
|
|
|
865
879
|
}
|
|
866
880
|
}
|
|
867
881
|
};
|
|
882
|
+
const finalizeFirmwareUpdatePlan = ({ features, firmwareType, platform, artifacts, targetsToUpdate, }) => {
|
|
883
|
+
const executor = getExecutor(features);
|
|
884
|
+
const bootloaderMode = resolveDeviceBootloaderMode(features);
|
|
885
|
+
const reportedIdentity = getDeviceUUID(features);
|
|
886
|
+
const deviceIdentity = reportedIdentity === 'unavailable' ? '' : reportedIdentity;
|
|
887
|
+
const allowsUnavailableIdentity = (bootloaderMode && executor === 'v2') || executor === 'v4';
|
|
888
|
+
if (artifacts.length > 0 &&
|
|
889
|
+
(platform === 'native' || platform === 'desktop') &&
|
|
890
|
+
!deviceIdentity &&
|
|
891
|
+
!allowsUnavailableIdentity) {
|
|
892
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Prepared firmware update requires a stable device identity', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
893
|
+
}
|
|
894
|
+
const planWithoutDigest = {
|
|
895
|
+
schemaVersion: 2,
|
|
896
|
+
executor,
|
|
897
|
+
deviceIdentity: deviceIdentity || 'unavailable',
|
|
898
|
+
deviceModel: String(getDeviceType(features)),
|
|
899
|
+
firmwareType,
|
|
900
|
+
platform,
|
|
901
|
+
artifacts,
|
|
902
|
+
targetsToUpdate,
|
|
903
|
+
};
|
|
904
|
+
return assertFirmwareUpdatePlan(Object.assign(Object.assign({}, planWithoutDigest), { planDigest: digestFirmwareUpdatePlan(planWithoutDigest) }));
|
|
905
|
+
};
|
|
906
|
+
const buildProtocolV2LocalFirmwareUpdatePlan = ({ features, firmwareType, platform, artifacts, }) => {
|
|
907
|
+
if (artifacts.length === 0) {
|
|
908
|
+
return planError('Protocol V2 local firmware plan has no artifacts');
|
|
909
|
+
}
|
|
910
|
+
const plan = finalizeFirmwareUpdatePlan({
|
|
911
|
+
features,
|
|
912
|
+
firmwareType,
|
|
913
|
+
platform,
|
|
914
|
+
artifacts: artifacts.map(artifact => (Object.assign(Object.assign({}, artifact), { role: artifact.target === 'resource' ? 'resourceBundle' : 'component', url: `https://local-firmware.invalid/${encodeURIComponent(artifact.artifactId)}` }))),
|
|
915
|
+
targetsToUpdate: artifacts.map(artifact => artifact.target),
|
|
916
|
+
});
|
|
917
|
+
if (plan.executor !== 'v4') {
|
|
918
|
+
return planError('Protocol V2 local firmware plan requires executor v4');
|
|
919
|
+
}
|
|
920
|
+
return plan;
|
|
921
|
+
};
|
|
922
|
+
const buildProtocolV2FirmwareUpdatePlan = ({ features, firmwareType, platform, release, targetsToUpdate, forceUpdateTargets, resourceArchive, }) => {
|
|
923
|
+
const validatedForceTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
|
|
924
|
+
if (validatedForceTargets.some(target => target === 'ble' || target === 'bootloader')) {
|
|
925
|
+
planError('Protocol V2 does not support forced BLE or legacy bootloader targets');
|
|
926
|
+
}
|
|
927
|
+
const requestedComponentTargets = new Set(targetsToUpdate.filter(target => target !== 'resource'));
|
|
928
|
+
if (getDeviceType(features) === hdShared.EDeviceType.Neo &&
|
|
929
|
+
(requestedComponentTargets.has('se03') || requestedComponentTargets.has('se04'))) {
|
|
930
|
+
planError('Neo does not support Protocol V2 targets se03 or se04');
|
|
931
|
+
}
|
|
932
|
+
const protocolV2 = buildProtocolV2Artifacts(release !== null && release !== void 0 ? release : {}, {
|
|
933
|
+
includeComponents: requestedComponentTargets.size > 0,
|
|
934
|
+
componentTargets: requestedComponentTargets,
|
|
935
|
+
});
|
|
936
|
+
const resourceRequested = targetsToUpdate.includes('resource');
|
|
937
|
+
if (resourceRequested) {
|
|
938
|
+
const archive = resourceArchive;
|
|
939
|
+
if (!archive) {
|
|
940
|
+
return planError('Protocol V2 resource target has no resource archive');
|
|
941
|
+
}
|
|
942
|
+
const integrity = requireArtifactIntegrity({ size: archive.archiveSize, sha256: archive.archiveSha256 }, 'Protocol V2 resource archive');
|
|
943
|
+
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));
|
|
944
|
+
protocolV2.targets.push('resource');
|
|
945
|
+
}
|
|
946
|
+
const representedTargets = new Set(protocolV2.targets);
|
|
947
|
+
const missingTarget = Array.from(requestedComponentTargets).find(target => !representedTargets.has(target));
|
|
948
|
+
if (missingTarget) {
|
|
949
|
+
planError(`Protocol V2 release does not contain requested target ${missingTarget}`);
|
|
950
|
+
}
|
|
951
|
+
if (validatedForceTargets.includes('firmware') && protocolV2.targets.length === 0) {
|
|
952
|
+
planError('Forced firmware update target firmware is not represented by the plan');
|
|
953
|
+
}
|
|
954
|
+
if (validatedForceTargets.includes('resource') && !resourceArchive) {
|
|
955
|
+
planError('Forced firmware update target resource has no Protocol V2 resource archive');
|
|
956
|
+
}
|
|
957
|
+
return finalizeFirmwareUpdatePlan({
|
|
958
|
+
features,
|
|
959
|
+
firmwareType,
|
|
960
|
+
platform,
|
|
961
|
+
artifacts: protocolV2.artifacts,
|
|
962
|
+
targetsToUpdate: protocolV2.targets,
|
|
963
|
+
});
|
|
964
|
+
};
|
|
868
965
|
const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, ble, bootloader, forceUpdateTargets, }) => {
|
|
869
|
-
var _a, _b
|
|
966
|
+
var _a, _b;
|
|
870
967
|
const executor = getExecutor(features);
|
|
871
968
|
let artifacts = [];
|
|
872
969
|
let targetsToUpdate = [];
|
|
@@ -878,7 +975,8 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
|
|
|
878
975
|
((release === null || release === void 0 ? void 0 : release.status) === 'none' || (release === null || release === void 0 ? void 0 : release.status) === 'unknown') &&
|
|
879
976
|
!!asRelease(release);
|
|
880
977
|
const shouldUpdateFirmware = isUpgrade(firmware) || isRecoveryInstall(firmware) || forcedTargets.has('firmware');
|
|
881
|
-
const shouldUpdateResource =
|
|
978
|
+
const shouldUpdateResource = !(executor === 'v2' && bootloaderMode) &&
|
|
979
|
+
(isUpgrade(firmware) || forcedTargets.has('resource'));
|
|
882
980
|
if (executor === 'v4' &&
|
|
883
981
|
validatedForceTargets.some(target => target === 'ble' || target === 'bootloader')) {
|
|
884
982
|
planError('Protocol V2 does not support forced BLE or legacy bootloader targets');
|
|
@@ -886,19 +984,20 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
|
|
|
886
984
|
if (executor === 'v4' && (shouldUpdateFirmware || shouldUpdateResource)) {
|
|
887
985
|
const protocolV2 = buildProtocolV2Artifacts(firmwareRelease !== null && firmwareRelease !== void 0 ? firmwareRelease : {}, {
|
|
888
986
|
includeComponents: shouldUpdateFirmware,
|
|
889
|
-
includeResources: shouldUpdateResource,
|
|
890
987
|
});
|
|
891
988
|
artifacts = protocolV2.artifacts;
|
|
892
989
|
targetsToUpdate = protocolV2.targets;
|
|
893
990
|
}
|
|
894
991
|
else {
|
|
895
992
|
if (isUpgrade(bootloader) || forcedTargets.has('bootloader')) {
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
993
|
+
const bootloaderRelease = asRelease(bootloader);
|
|
994
|
+
const integrity = requireArtifactIntegrity({
|
|
995
|
+
size: bootloaderRelease === null || bootloaderRelease === void 0 ? void 0 : bootloaderRelease.bootloaderExpectedSize,
|
|
996
|
+
sha256: bootloaderRelease === null || bootloaderRelease === void 0 ? void 0 : bootloaderRelease.bootloaderFingerprint,
|
|
997
|
+
}, 'Bootloader release');
|
|
998
|
+
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
999
|
? {
|
|
901
|
-
targetVersion: asVersion(
|
|
1000
|
+
targetVersion: asVersion(bootloaderRelease === null || bootloaderRelease === void 0 ? void 0 : bootloaderRelease.bootloaderVersion),
|
|
902
1001
|
}
|
|
903
1002
|
: {})));
|
|
904
1003
|
}
|
|
@@ -909,10 +1008,8 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
|
|
|
909
1008
|
});
|
|
910
1009
|
}
|
|
911
1010
|
if (shouldUpdateFirmware) {
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
sha256: firmwareRelease.fingerprint,
|
|
915
|
-
})), (asVersion(firmwareRelease.version)
|
|
1011
|
+
const integrity = requireArtifactIntegrity({ size: firmwareRelease.expectedSize, sha256: firmwareRelease.fingerprint }, 'Firmware release');
|
|
1012
|
+
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
1013
|
? { targetVersion: asVersion(firmwareRelease.version) }
|
|
917
1014
|
: {})));
|
|
918
1015
|
}
|
|
@@ -923,53 +1020,48 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
|
|
|
923
1020
|
platform,
|
|
924
1021
|
});
|
|
925
1022
|
if (resourceUrl) {
|
|
926
|
-
|
|
1023
|
+
const integrity = requireArtifactIntegrity({
|
|
927
1024
|
size: resourceUrl === asString(firmwareRelease.fullResource)
|
|
928
1025
|
? firmwareRelease.fullResourceExpectedSize
|
|
929
1026
|
: firmwareRelease.resourceExpectedSize,
|
|
930
1027
|
sha256: resourceUrl === asString(firmwareRelease.fullResource)
|
|
931
1028
|
? firmwareRelease.fullResourceFingerprint
|
|
932
1029
|
: firmwareRelease.resourceFingerprint,
|
|
933
|
-
})
|
|
1030
|
+
}, 'Legacy resource archive');
|
|
1031
|
+
artifacts.push(Object.assign({ artifactId: 'resource', role: 'resource', target: 'resource', url: assertArtifactUrl(resourceUrl, 'Firmware resource release'), container: 'zip' }, integrity));
|
|
934
1032
|
}
|
|
935
1033
|
}
|
|
936
1034
|
}
|
|
937
1035
|
if (isUpgrade(ble) || isRecoveryInstall(ble) || forcedTargets.has('ble')) {
|
|
938
1036
|
const bleRelease = asRelease(ble);
|
|
939
|
-
|
|
1037
|
+
const integrity = requireArtifactIntegrity({
|
|
940
1038
|
size: bleRelease === null || bleRelease === void 0 ? void 0 : bleRelease.expectedSize,
|
|
941
|
-
sha256: (
|
|
942
|
-
}
|
|
1039
|
+
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,
|
|
1040
|
+
}, 'BLE release');
|
|
1041
|
+
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
1042
|
? { targetVersion: asVersion(bleRelease === null || bleRelease === void 0 ? void 0 : bleRelease.version) }
|
|
944
1043
|
: {})));
|
|
945
1044
|
}
|
|
946
1045
|
targetsToUpdate = [...new Set(artifacts.map(artifact => artifact.target))];
|
|
947
1046
|
}
|
|
1047
|
+
if (executor !== 'v4' &&
|
|
1048
|
+
targetsToUpdate.includes('resource') &&
|
|
1049
|
+
!targetsToUpdate.includes('firmware')) {
|
|
1050
|
+
planError('Legacy resource updates require a firmware target');
|
|
1051
|
+
}
|
|
948
1052
|
assertForcedTargetsRepresented({
|
|
949
1053
|
executor,
|
|
950
1054
|
forcedTargets: validatedForceTargets,
|
|
951
1055
|
artifacts,
|
|
952
1056
|
targetsToUpdate,
|
|
953
1057
|
});
|
|
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)),
|
|
1058
|
+
return finalizeFirmwareUpdatePlan({
|
|
1059
|
+
features,
|
|
967
1060
|
firmwareType,
|
|
968
1061
|
platform,
|
|
969
1062
|
artifacts,
|
|
970
1063
|
targetsToUpdate,
|
|
971
|
-
};
|
|
972
|
-
return assertFirmwareUpdatePlan(Object.assign(Object.assign({}, planWithoutDigest), { planDigest: digestFirmwareUpdatePlan(planWithoutDigest) }));
|
|
1064
|
+
});
|
|
973
1065
|
};
|
|
974
1066
|
|
|
975
1067
|
const preparedPlanError = (message) => {
|
|
@@ -1090,7 +1182,7 @@ const prepareFirmwareUpdatePlan = ({ plan: value, leaseRef, artifacts, }) => {
|
|
|
1090
1182
|
return Object.assign(Object.assign({}, planWithoutDigest), { preparedPlanDigest: digestPreparedPlan(planWithoutDigest) });
|
|
1091
1183
|
};
|
|
1092
1184
|
const validateFirmwareUpdatePreparedPlan = (value) => {
|
|
1093
|
-
var _a, _b, _c;
|
|
1185
|
+
var _a, _b, _c, _d;
|
|
1094
1186
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
1095
1187
|
return preparedPlanError('Firmware prepared plan must be an object');
|
|
1096
1188
|
}
|
|
@@ -1170,7 +1262,13 @@ const validateFirmwareUpdatePreparedPlan = (value) => {
|
|
|
1170
1262
|
artifactIds.add(artifact.artifactId);
|
|
1171
1263
|
artifactTargets.add(artifact.target);
|
|
1172
1264
|
assertFirmwareArtifactReference(artifact.artifact);
|
|
1173
|
-
(_c = artifact.materializedEntries) === null || _c === void 0 ? void 0 : _c.
|
|
1265
|
+
const materializedEntryNames = (_d = (_c = artifact.materializedEntries) === null || _c === void 0 ? void 0 : _c.map(entry => {
|
|
1266
|
+
assertPreparedEntry(entry);
|
|
1267
|
+
return getFirmwareUpdateResourceName(entry.entryName).toLowerCase();
|
|
1268
|
+
})) !== null && _d !== void 0 ? _d : [];
|
|
1269
|
+
if (new Set(materializedEntryNames).size !== materializedEntryNames.length) {
|
|
1270
|
+
return preparedPlanError('Firmware prepared plan contains duplicate entry names');
|
|
1271
|
+
}
|
|
1174
1272
|
}
|
|
1175
1273
|
if (preparedPlan.targetsToUpdate.some(target => !FIRMWARE_UPDATE_PLAN_TARGETS.has(target)) ||
|
|
1176
1274
|
new Set(preparedPlan.targetsToUpdate).size !== preparedPlan.targetsToUpdate.length ||
|
|
@@ -1184,16 +1282,29 @@ const validateFirmwareUpdatePreparedPlan = (value) => {
|
|
|
1184
1282
|
}
|
|
1185
1283
|
return preparedPlan;
|
|
1186
1284
|
};
|
|
1285
|
+
const getFirmwareUpdatePreparedRawArtifact = ({ preparedPlan: value, target, role, }) => {
|
|
1286
|
+
const preparedPlan = validateFirmwareUpdatePreparedPlan(value);
|
|
1287
|
+
const artifacts = preparedPlan.artifacts.filter(artifact => artifact.target === target);
|
|
1288
|
+
if (artifacts.length !== 1 || artifacts[0].role !== role || artifacts[0].container !== 'raw') {
|
|
1289
|
+
return preparedPlanError(`Firmware prepared plan ${target} artifact is invalid`);
|
|
1290
|
+
}
|
|
1291
|
+
return artifacts[0];
|
|
1292
|
+
};
|
|
1187
1293
|
const degradedPlanIdentityPins = new Map();
|
|
1188
1294
|
const DEGRADED_PLAN_IDENTITY_PIN_LIMIT = 32;
|
|
1189
|
-
const pinDegradedPlanIdentity = (
|
|
1190
|
-
|
|
1295
|
+
const pinDegradedPlanIdentity = (preparedPlanDigest, deviceIdentity) => {
|
|
1296
|
+
const key = preparedPlanDigest.toLowerCase();
|
|
1297
|
+
if (!degradedPlanIdentityPins.has(key) &&
|
|
1298
|
+
degradedPlanIdentityPins.size >= DEGRADED_PLAN_IDENTITY_PIN_LIMIT) {
|
|
1191
1299
|
const oldest = degradedPlanIdentityPins.keys().next();
|
|
1192
1300
|
if (!oldest.done) {
|
|
1193
1301
|
degradedPlanIdentityPins.delete(oldest.value);
|
|
1194
1302
|
}
|
|
1195
1303
|
}
|
|
1196
|
-
degradedPlanIdentityPins.set(
|
|
1304
|
+
degradedPlanIdentityPins.set(key, deviceIdentity);
|
|
1305
|
+
};
|
|
1306
|
+
const clearFirmwareUpdatePreparedPlanDeviceIdentityPin = (preparedPlanDigest) => {
|
|
1307
|
+
degradedPlanIdentityPins.delete(preparedPlanDigest.toLowerCase());
|
|
1197
1308
|
};
|
|
1198
1309
|
const assertFirmwareUpdatePreparedPlanDeviceIdentity = ({ preparedPlan: value, deviceIdentity: reportedIdentity, bootloaderMode, deviceModel, }) => {
|
|
1199
1310
|
const preparedPlan = validateFirmwareUpdatePreparedPlan(value);
|
|
@@ -1202,15 +1313,15 @@ const assertFirmwareUpdatePreparedPlanDeviceIdentity = ({ preparedPlan: value, d
|
|
|
1202
1313
|
if (deviceModel === undefined || preparedPlan.deviceModel !== deviceModel) {
|
|
1203
1314
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckDeviceIdError);
|
|
1204
1315
|
}
|
|
1205
|
-
const pinnedIdentity = degradedPlanIdentityPins.get(preparedPlan.
|
|
1316
|
+
const pinnedIdentity = degradedPlanIdentityPins.get(preparedPlan.preparedPlanDigest.toLowerCase());
|
|
1206
1317
|
if (!deviceIdentity) {
|
|
1207
|
-
if (bootloaderMode !== true) {
|
|
1318
|
+
if (preparedPlan.executor !== 'v4' && bootloaderMode !== true) {
|
|
1208
1319
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckDeviceIdError);
|
|
1209
1320
|
}
|
|
1210
1321
|
return preparedPlan;
|
|
1211
1322
|
}
|
|
1212
1323
|
if (!pinnedIdentity) {
|
|
1213
|
-
pinDegradedPlanIdentity(preparedPlan.
|
|
1324
|
+
pinDegradedPlanIdentity(preparedPlan.preparedPlanDigest, deviceIdentity);
|
|
1214
1325
|
return preparedPlan;
|
|
1215
1326
|
}
|
|
1216
1327
|
if (pinnedIdentity !== deviceIdentity) {
|
|
@@ -1275,29 +1386,40 @@ class FirmwareHostBindingRegistry {
|
|
|
1275
1386
|
this.generation = 0;
|
|
1276
1387
|
}
|
|
1277
1388
|
register(binding) {
|
|
1278
|
-
var _a;
|
|
1389
|
+
var _a, _b;
|
|
1279
1390
|
if (!binding ||
|
|
1391
|
+
typeof binding.preparedPlanDigest !== 'string' ||
|
|
1392
|
+
!/^[0-9a-f]{64}$/i.test(binding.preparedPlanDigest) ||
|
|
1280
1393
|
typeof ((_a = binding.artifactReader) === null || _a === void 0 ? void 0 : _a.open) !== 'function' ||
|
|
1281
1394
|
typeof binding.artifactReader.read !== 'function' ||
|
|
1282
1395
|
typeof binding.artifactReader.close !== 'function') {
|
|
1283
1396
|
return bindingError('Firmware host binding is invalid');
|
|
1284
1397
|
}
|
|
1398
|
+
const replacedPreparedPlanDigest = (_b = this.binding) === null || _b === void 0 ? void 0 : _b.preparedPlanDigest;
|
|
1285
1399
|
this.generation += 1;
|
|
1286
1400
|
this.binding = binding;
|
|
1401
|
+
if (replacedPreparedPlanDigest) {
|
|
1402
|
+
clearFirmwareUpdatePreparedPlanDeviceIdentityPin(replacedPreparedPlanDigest);
|
|
1403
|
+
}
|
|
1287
1404
|
return this.generation;
|
|
1288
1405
|
}
|
|
1289
1406
|
unregister(generation) {
|
|
1407
|
+
var _a;
|
|
1290
1408
|
if (generation !== undefined && generation !== this.generation) {
|
|
1291
1409
|
return false;
|
|
1292
1410
|
}
|
|
1411
|
+
const releasedPreparedPlanDigest = (_a = this.binding) === null || _a === void 0 ? void 0 : _a.preparedPlanDigest;
|
|
1293
1412
|
this.generation += 1;
|
|
1294
1413
|
this.binding = undefined;
|
|
1414
|
+
if (releasedPreparedPlanDigest) {
|
|
1415
|
+
clearFirmwareUpdatePreparedPlanDeviceIdentityPin(releasedPreparedPlanDigest);
|
|
1416
|
+
}
|
|
1295
1417
|
return true;
|
|
1296
1418
|
}
|
|
1297
1419
|
getGeneration() {
|
|
1298
1420
|
return this.generation;
|
|
1299
1421
|
}
|
|
1300
|
-
resolve(generation) {
|
|
1422
|
+
resolve(generation, preparedPlanDigest) {
|
|
1301
1423
|
if (!Number.isSafeInteger(generation) ||
|
|
1302
1424
|
generation <= 0 ||
|
|
1303
1425
|
generation !== this.generation ||
|
|
@@ -1305,12 +1427,17 @@ class FirmwareHostBindingRegistry {
|
|
|
1305
1427
|
return bindingError(`Firmware host binding generation ${generation} is stale`);
|
|
1306
1428
|
}
|
|
1307
1429
|
const { binding } = this;
|
|
1430
|
+
if (preparedPlanDigest !== undefined &&
|
|
1431
|
+
binding.preparedPlanDigest.toLowerCase() !== preparedPlanDigest.toLowerCase()) {
|
|
1432
|
+
return bindingError(`Firmware host binding generation ${generation} does not match the prepared plan`);
|
|
1433
|
+
}
|
|
1308
1434
|
const assertCurrent = () => {
|
|
1309
1435
|
if (generation !== this.generation || binding !== this.binding) {
|
|
1310
1436
|
bindingError(`Firmware host binding generation ${generation} is stale`);
|
|
1311
1437
|
}
|
|
1312
1438
|
};
|
|
1313
1439
|
return {
|
|
1440
|
+
preparedPlanDigest: binding.preparedPlanDigest,
|
|
1314
1441
|
artifactReader: {
|
|
1315
1442
|
open: (input) => __awaiter(this, void 0, void 0, function* () {
|
|
1316
1443
|
assertCurrent();
|
|
@@ -1343,7 +1470,7 @@ const firmwareHostBindingRegistry = new FirmwareHostBindingRegistry();
|
|
|
1343
1470
|
const registerFirmwareUpdateHostBinding = (binding) => firmwareHostBindingRegistry.register(binding);
|
|
1344
1471
|
const unregisterFirmwareUpdateHostBinding = (generation) => firmwareHostBindingRegistry.unregister(generation);
|
|
1345
1472
|
const getFirmwareUpdateHostBindingGeneration = () => firmwareHostBindingRegistry.getGeneration();
|
|
1346
|
-
const resolveFirmwareUpdateHostBinding = (generation) => firmwareHostBindingRegistry.resolve(generation !== null && generation !== void 0 ? generation : Number.NaN);
|
|
1473
|
+
const resolveFirmwareUpdateHostBinding = (generation, preparedPlanDigest) => firmwareHostBindingRegistry.resolve(generation !== null && generation !== void 0 ? generation : Number.NaN, preparedPlanDigest);
|
|
1347
1474
|
|
|
1348
1475
|
const callbackManager = new Map();
|
|
1349
1476
|
const generateCallbackId = () => `callback_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
|
|
@@ -40504,143 +40631,8 @@ const findLatestRelease = (releases) => {
|
|
|
40504
40631
|
return leastRelease;
|
|
40505
40632
|
};
|
|
40506
40633
|
|
|
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);
|
|
40634
|
+
const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1 = 'vol0:/loaders/bootloader/boot_resource.okpkg';
|
|
40526
40635
|
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
40636
|
function normalizeHex$1(value, expectedLength, field) {
|
|
40645
40637
|
if (typeof value !== 'string') {
|
|
40646
40638
|
throw new Error(`Invalid Pro2 resource ${field}: expected a hexadecimal string`);
|
|
@@ -40651,132 +40643,158 @@ function normalizeHex$1(value, expectedLength, field) {
|
|
|
40651
40643
|
}
|
|
40652
40644
|
return normalized;
|
|
40653
40645
|
}
|
|
40654
|
-
function
|
|
40646
|
+
function parseProtocolV2Resources(value) {
|
|
40647
|
+
if (value === undefined)
|
|
40648
|
+
return undefined;
|
|
40655
40649
|
if (!value || typeof value !== 'object') {
|
|
40656
|
-
throw new Error(
|
|
40650
|
+
throw new Error('Invalid Pro2 resources config');
|
|
40651
|
+
}
|
|
40652
|
+
const { source } = value;
|
|
40653
|
+
if (!source || typeof source !== 'object') {
|
|
40654
|
+
throw new Error('Invalid Pro2 resources config: source is required');
|
|
40657
40655
|
}
|
|
40658
|
-
const
|
|
40659
|
-
if (typeof
|
|
40660
|
-
throw new Error(
|
|
40656
|
+
const { archiveUrl, archiveSha256, archiveSize } = source;
|
|
40657
|
+
if (typeof archiveUrl !== 'string' || !archiveUrl.startsWith('https://')) {
|
|
40658
|
+
throw new Error('Invalid Pro2 resources config: source.archiveUrl must use HTTPS');
|
|
40661
40659
|
}
|
|
40662
|
-
if (typeof
|
|
40663
|
-
throw new Error(
|
|
40660
|
+
if (typeof archiveSha256 !== 'string' || !/^[0-9a-fA-F]{64}$/.test(archiveSha256)) {
|
|
40661
|
+
throw new Error('Invalid Pro2 resources config: source.archiveSha256 must be a SHA-256 digest');
|
|
40664
40662
|
}
|
|
40665
|
-
if (!Number.isSafeInteger(
|
|
40666
|
-
throw new Error(
|
|
40663
|
+
if (!Number.isSafeInteger(archiveSize) || archiveSize <= 0) {
|
|
40664
|
+
throw new Error('Invalid Pro2 resources config: source.archiveSize must be a positive integer');
|
|
40667
40665
|
}
|
|
40668
40666
|
return {
|
|
40669
|
-
|
|
40670
|
-
|
|
40671
|
-
|
|
40672
|
-
|
|
40673
|
-
|
|
40667
|
+
source: {
|
|
40668
|
+
archiveUrl,
|
|
40669
|
+
archiveSha256: archiveSha256.toLowerCase(),
|
|
40670
|
+
archiveSize: archiveSize,
|
|
40671
|
+
},
|
|
40674
40672
|
};
|
|
40675
40673
|
}
|
|
40676
|
-
|
|
40677
|
-
|
|
40678
|
-
|
|
40674
|
+
const PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS = [
|
|
40675
|
+
'vol0:/bundles/',
|
|
40676
|
+
'vol0:/loaders/rom/',
|
|
40677
|
+
];
|
|
40678
|
+
function isAllowedManifestDevicePath(path) {
|
|
40679
|
+
if (!path.endsWith('.okpkg') ||
|
|
40680
|
+
path.includes('\\') ||
|
|
40681
|
+
path.includes('//') ||
|
|
40682
|
+
path.split('/').some(part => part === '.' || part === '..')) {
|
|
40683
|
+
return false;
|
|
40679
40684
|
}
|
|
40680
|
-
|
|
40681
|
-
|
|
40682
|
-
throw new Error('Invalid Pro2 boot resources required flag: expected false');
|
|
40685
|
+
if (path === PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) {
|
|
40686
|
+
return true;
|
|
40683
40687
|
}
|
|
40684
|
-
|
|
40685
|
-
|
|
40688
|
+
return PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS.some(root => path.startsWith(root));
|
|
40689
|
+
}
|
|
40690
|
+
function assertManifestString(value, field) {
|
|
40691
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
40692
|
+
throw new Error(`Invalid Pro2 resource manifest ${field}`);
|
|
40686
40693
|
}
|
|
40687
|
-
|
|
40688
|
-
|
|
40689
|
-
|
|
40694
|
+
return value;
|
|
40695
|
+
}
|
|
40696
|
+
function assertManifestRelativePath(value, field) {
|
|
40697
|
+
const path = assertManifestString(value, field);
|
|
40698
|
+
if (path.startsWith('/') ||
|
|
40699
|
+
path.includes('\\') ||
|
|
40700
|
+
path.includes(':') ||
|
|
40701
|
+
path.split('/').some(part => !part || part === '.' || part === '..')) {
|
|
40702
|
+
throw new Error(`Invalid Pro2 resource manifest ${field}`);
|
|
40703
|
+
}
|
|
40704
|
+
return path;
|
|
40705
|
+
}
|
|
40706
|
+
function parseProtocolV2ResourceManifestFile(value, index) {
|
|
40707
|
+
var _a;
|
|
40708
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
40709
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}]`);
|
|
40690
40710
|
}
|
|
40691
|
-
|
|
40692
|
-
|
|
40711
|
+
const file = value;
|
|
40712
|
+
const archivePath = assertManifestRelativePath(file.archive_path, `files[${index}].archive_path`);
|
|
40713
|
+
const originalName = assertManifestRelativePath(file.original_name, `files[${index}].original_name`);
|
|
40714
|
+
if (originalName.includes('/')) {
|
|
40715
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].original_name`);
|
|
40693
40716
|
}
|
|
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');
|
|
40717
|
+
const devicePath = assertManifestString(file.device_path, `files[${index}].device_path`);
|
|
40718
|
+
if (!isAllowedManifestDevicePath(devicePath)) {
|
|
40719
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].device_path`);
|
|
40715
40720
|
}
|
|
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');
|
|
40721
|
+
if (!Number.isSafeInteger(file.size) || Number(file.size) <= 0) {
|
|
40722
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].size`);
|
|
40725
40723
|
}
|
|
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`);
|
|
40724
|
+
const digest = normalizeHex$1(file.sha256, SHA256_HEX_LENGTH, `files[${index}].sha256`);
|
|
40725
|
+
if (file.signed !== true) {
|
|
40726
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].signed`);
|
|
40731
40727
|
}
|
|
40732
|
-
|
|
40733
|
-
|
|
40734
|
-
throw new Error(`Invalid Pro2 resources config: stable is missing ${type}`);
|
|
40735
|
-
}
|
|
40728
|
+
if (file.sig_algo !== 'ed25519' && file.sig_algo !== 'mldsa65') {
|
|
40729
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].sig_algo`);
|
|
40736
40730
|
}
|
|
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
|
-
};
|
|
40731
|
+
if (file.payload_version !== null && typeof file.payload_version !== 'string') {
|
|
40732
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].payload_version`);
|
|
40752
40733
|
}
|
|
40753
|
-
if (!
|
|
40754
|
-
|
|
40755
|
-
? {
|
|
40756
|
-
status: resources.length > 0 ? 'outdated' : 'valid',
|
|
40757
|
-
resources: [...resources],
|
|
40758
|
-
}
|
|
40759
|
-
: { status: 'unknown', resources: [] };
|
|
40734
|
+
if (!archivePath.endsWith('.okpkg') || !originalName.endsWith('.okpkg')) {
|
|
40735
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}] package extension`);
|
|
40760
40736
|
}
|
|
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
40737
|
return {
|
|
40769
|
-
|
|
40770
|
-
|
|
40738
|
+
archive_path: archivePath,
|
|
40739
|
+
original_name: originalName,
|
|
40740
|
+
device_path: devicePath,
|
|
40741
|
+
size: Number(file.size),
|
|
40742
|
+
sha256: digest,
|
|
40743
|
+
signed: true,
|
|
40744
|
+
sig_algo: file.sig_algo,
|
|
40745
|
+
payload_version: (_a = file.payload_version) !== null && _a !== void 0 ? _a : null,
|
|
40771
40746
|
};
|
|
40772
40747
|
}
|
|
40773
|
-
function
|
|
40774
|
-
|
|
40748
|
+
function parseProtocolV2ResourceManifest(value) {
|
|
40749
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
40750
|
+
throw new Error('Invalid Pro2 resource manifest');
|
|
40751
|
+
}
|
|
40752
|
+
const manifest = value;
|
|
40753
|
+
if (manifest.schema !== 1 ||
|
|
40754
|
+
manifest.variant !== 'resource' ||
|
|
40755
|
+
manifest.device_root !== 'vol0:' ||
|
|
40756
|
+
manifest.restore_mode !== 'bootloader_update' ||
|
|
40757
|
+
!Array.isArray(manifest.trees) ||
|
|
40758
|
+
!Array.isArray(manifest.files)) {
|
|
40759
|
+
throw new Error('Invalid Pro2 resource manifest contract');
|
|
40760
|
+
}
|
|
40761
|
+
const files = manifest.files.map(parseProtocolV2ResourceManifestFile);
|
|
40762
|
+
const devicePaths = new Set(files.map(file => file.device_path));
|
|
40763
|
+
const archivePaths = new Set(files.map(file => file.archive_path));
|
|
40764
|
+
if (files.length === 0 ||
|
|
40765
|
+
devicePaths.size !== files.length ||
|
|
40766
|
+
archivePaths.size !== files.length ||
|
|
40767
|
+
!devicePaths.has(PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) ||
|
|
40768
|
+
!files.some(file => file.device_path.startsWith('vol0:/bundles/'))) {
|
|
40769
|
+
throw new Error('Invalid Pro2 resource manifest file set');
|
|
40770
|
+
}
|
|
40771
|
+
return {
|
|
40772
|
+
schema: 1,
|
|
40773
|
+
artifact_name: assertManifestString(manifest.artifact_name, 'artifact_name'),
|
|
40774
|
+
release_name: assertManifestString(manifest.release_name, 'release_name'),
|
|
40775
|
+
variant: 'resource',
|
|
40776
|
+
commit: assertManifestString(manifest.commit, 'commit'),
|
|
40777
|
+
short_sha: assertManifestString(manifest.short_sha, 'short_sha'),
|
|
40778
|
+
timestamp_utc: assertManifestString(manifest.timestamp_utc, 'timestamp_utc'),
|
|
40779
|
+
core_version: assertManifestString(manifest.core_version, 'core_version'),
|
|
40780
|
+
key_set: assertManifestString(manifest.key_set, 'key_set'),
|
|
40781
|
+
device_root: 'vol0:',
|
|
40782
|
+
restore_mode: 'bootloader_update',
|
|
40783
|
+
trees: manifest.trees.map((tree, index) => {
|
|
40784
|
+
if (!tree || typeof tree !== 'object') {
|
|
40785
|
+
throw new Error(`Invalid Pro2 resource manifest trees[${index}]`);
|
|
40786
|
+
}
|
|
40787
|
+
const item = tree;
|
|
40788
|
+
return {
|
|
40789
|
+
path: assertManifestRelativePath(item.path, `trees[${index}].path`),
|
|
40790
|
+
device: assertManifestString(item.device, `trees[${index}].device`),
|
|
40791
|
+
};
|
|
40792
|
+
}),
|
|
40793
|
+
files,
|
|
40794
|
+
};
|
|
40775
40795
|
}
|
|
40776
|
-
function
|
|
40777
|
-
|
|
40778
|
-
return false;
|
|
40779
|
-
return bytesToHex$3(sha256.sha256(new Uint8Array(binary))) === resource.fileHash.toLowerCase();
|
|
40796
|
+
function selectProtocolV2ResourceManifestFiles({ manifest, targetsToUpdate, }) {
|
|
40797
|
+
return targetsToUpdate.includes('resource') ? [...manifest.files] : [];
|
|
40780
40798
|
}
|
|
40781
40799
|
|
|
40782
40800
|
var _a$1;
|
|
@@ -40837,6 +40855,7 @@ class DataManager {
|
|
|
40837
40855
|
return __awaiter(this, void 0, void 0, function* () {
|
|
40838
40856
|
this.settings = settings;
|
|
40839
40857
|
this.protocolV2ResourcesConfigError = undefined;
|
|
40858
|
+
this.protocolV2NeoResourcesConfigError = undefined;
|
|
40840
40859
|
const manifestMode = (_b = settings.firmwareManifestMode) !== null && _b !== void 0 ? _b : (settings.fetchConfig ? 'sdk-managed' : undefined);
|
|
40841
40860
|
if (settings.preloadedConfig) {
|
|
40842
40861
|
this.applyRemoteConfig(settings.preloadedConfig);
|
|
@@ -40897,12 +40916,19 @@ class DataManager {
|
|
|
40897
40916
|
let neoResources;
|
|
40898
40917
|
try {
|
|
40899
40918
|
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
40919
|
}
|
|
40902
40920
|
catch (error) {
|
|
40903
40921
|
this.protocolV2ResourcesConfigError =
|
|
40904
40922
|
error instanceof Error ? error : new Error(String(error));
|
|
40905
|
-
Log$k.warn('[DataConfig] Ignoring invalid
|
|
40923
|
+
Log$k.warn('[DataConfig] Ignoring invalid Pro2 resources config:', error);
|
|
40924
|
+
}
|
|
40925
|
+
try {
|
|
40926
|
+
neoResources = parseProtocolV2Resources((_c = data.neo) === null || _c === void 0 ? void 0 : _c.resources);
|
|
40927
|
+
}
|
|
40928
|
+
catch (error) {
|
|
40929
|
+
this.protocolV2NeoResourcesConfigError =
|
|
40930
|
+
error instanceof Error ? error : new Error(String(error));
|
|
40931
|
+
Log$k.warn('[DataConfig] Ignoring invalid Neo resources config:', error);
|
|
40906
40932
|
}
|
|
40907
40933
|
const enrichedPro2Config = this.enrichFirmwareReleaseInfo(data.pro2);
|
|
40908
40934
|
const enrichedNeoConfig = this.enrichFirmwareReleaseInfo(data.neo);
|
|
@@ -40940,16 +40966,20 @@ class DataManager {
|
|
|
40940
40966
|
}
|
|
40941
40967
|
});
|
|
40942
40968
|
}
|
|
40943
|
-
static forceReloadData({ requireResources = false, } = {}) {
|
|
40969
|
+
static forceReloadData({ requireResources = false, resourceDeviceType = hdShared.EDeviceType.Pro2, } = {}) {
|
|
40944
40970
|
return __awaiter(this, void 0, void 0, function* () {
|
|
40971
|
+
const resourceDeviceName = resourceDeviceType === hdShared.EDeviceType.Pro2 ? 'Pro2' : 'Neo';
|
|
40945
40972
|
if (!this.settings) {
|
|
40946
40973
|
throw new Error('Remote config settings are not initialized');
|
|
40947
40974
|
}
|
|
40948
40975
|
const hasFreshConfig = this.lastCheckTimestamp > 0 &&
|
|
40949
40976
|
getTimeStamp() - this.lastCheckTimestamp <= FIRMWARE_UPDATE_CONFIG_FRESHNESS_MS;
|
|
40950
40977
|
if (hasFreshConfig) {
|
|
40951
|
-
|
|
40952
|
-
|
|
40978
|
+
const resourcesConfigError = resourceDeviceType === hdShared.EDeviceType.Pro2
|
|
40979
|
+
? this.protocolV2ResourcesConfigError
|
|
40980
|
+
: this.protocolV2NeoResourcesConfigError;
|
|
40981
|
+
if (requireResources && resourcesConfigError) {
|
|
40982
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, `Invalid ${resourceDeviceName} resources config: ${resourcesConfigError.message}`);
|
|
40953
40983
|
}
|
|
40954
40984
|
return;
|
|
40955
40985
|
}
|
|
@@ -40957,19 +40987,18 @@ class DataManager {
|
|
|
40957
40987
|
if (!loaded) {
|
|
40958
40988
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.NetworkError, 'Unable to refresh the latest remote config');
|
|
40959
40989
|
}
|
|
40960
|
-
|
|
40961
|
-
|
|
40990
|
+
const resourcesConfigError = resourceDeviceType === hdShared.EDeviceType.Pro2
|
|
40991
|
+
? this.protocolV2ResourcesConfigError
|
|
40992
|
+
: this.protocolV2NeoResourcesConfigError;
|
|
40993
|
+
if (requireResources && resourcesConfigError) {
|
|
40994
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, `Invalid ${resourceDeviceName} resources config: ${resourcesConfigError.message}`);
|
|
40962
40995
|
}
|
|
40963
40996
|
this.lastCheckTimestamp = getTimeStamp();
|
|
40964
40997
|
});
|
|
40965
40998
|
}
|
|
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) {
|
|
40999
|
+
static getProtocolV2ResourceSource(deviceType = hdShared.EDeviceType.Pro2) {
|
|
40971
41000
|
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.
|
|
41001
|
+
return (_c = (_b = this.deviceMap[deviceType]) === null || _b === void 0 ? void 0 : _b.resources) === null || _c === void 0 ? void 0 : _c.source;
|
|
40973
41002
|
}
|
|
40974
41003
|
static getProtobufMessages(schema = 'v1CurrentSchema') {
|
|
40975
41004
|
return this.messages[schema];
|
|
@@ -41006,12 +41035,10 @@ DataManager.deviceMap = {
|
|
|
41006
41035
|
ble: [],
|
|
41007
41036
|
},
|
|
41008
41037
|
[hdShared.EDeviceType.Pro2]: {
|
|
41009
|
-
firmware: [],
|
|
41010
|
-
ble: [],
|
|
41038
|
+
'firmware-v1': [],
|
|
41011
41039
|
},
|
|
41012
41040
|
[hdShared.EDeviceType.Neo]: {
|
|
41013
|
-
firmware: [],
|
|
41014
|
-
ble: [],
|
|
41041
|
+
'firmware-v1': [],
|
|
41015
41042
|
},
|
|
41016
41043
|
[hdShared.EDeviceType.ClassicPure]: {
|
|
41017
41044
|
firmware: [],
|
|
@@ -42008,7 +42035,7 @@ const getFirmwareUpdateField = ({ features, updateType, targetVersion, firmwareT
|
|
|
42008
42035
|
if (deviceType === hdShared.EDeviceType.Pro) {
|
|
42009
42036
|
return latestFirmwareField;
|
|
42010
42037
|
}
|
|
42011
|
-
if (deviceType === hdShared.EDeviceType.Pro2) {
|
|
42038
|
+
if (deviceType === hdShared.EDeviceType.Pro2 || deviceType === hdShared.EDeviceType.Neo) {
|
|
42012
42039
|
return 'firmware-v1';
|
|
42013
42040
|
}
|
|
42014
42041
|
return 'firmware';
|
|
@@ -42040,7 +42067,7 @@ const getFirmwareUpdateFieldArray = (features, updateType) => {
|
|
|
42040
42067
|
if (deviceType === 'pro') {
|
|
42041
42068
|
return ['firmware-v8'];
|
|
42042
42069
|
}
|
|
42043
|
-
if (deviceType === 'pro2') {
|
|
42070
|
+
if (deviceType === 'pro2' || deviceType === 'neo') {
|
|
42044
42071
|
return ['firmware-v1'];
|
|
42045
42072
|
}
|
|
42046
42073
|
return ['firmware'];
|
|
@@ -47383,76 +47410,93 @@ class ClearSessionCache extends BaseMethod {
|
|
|
47383
47410
|
}
|
|
47384
47411
|
}
|
|
47385
47412
|
|
|
47386
|
-
|
|
47387
|
-
|
|
47388
|
-
|
|
47389
|
-
|
|
47390
|
-
|
|
47391
|
-
|
|
47392
|
-
|
|
47393
|
-
|
|
47394
|
-
|
|
47395
|
-
|
|
47396
|
-
|
|
47397
|
-
|
|
47398
|
-
|
|
47399
|
-
|
|
47400
|
-
|
|
47401
|
-
|
|
47402
|
-
|
|
47403
|
-
|
|
47413
|
+
const PROTOCOL_V2_MAIN_FIRMWARE_TARGETS = [
|
|
47414
|
+
'APPLICATION_P1',
|
|
47415
|
+
'APPLICATION_P2',
|
|
47416
|
+
'SE01',
|
|
47417
|
+
'SE02',
|
|
47418
|
+
'SE03',
|
|
47419
|
+
'SE04',
|
|
47420
|
+
];
|
|
47421
|
+
const PROTOCOL_V2_BLE_TARGETS = [
|
|
47422
|
+
'COPROCESSOR',
|
|
47423
|
+
];
|
|
47424
|
+
const PROTOCOL_V2_BOOTLOADER_TARGETS = [
|
|
47425
|
+
'BOOTLOADER',
|
|
47426
|
+
];
|
|
47427
|
+
function loadProtocolV2FirmwareReleaseContext({ device, firmwareType: firmwareTypeParam, checkFirmwareHash = false, methodName, }) {
|
|
47428
|
+
var _a;
|
|
47429
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
47430
|
+
const state = yield device.getDeviceState({
|
|
47431
|
+
refreshSections: checkFirmwareHash
|
|
47432
|
+
? ['identity', 'versions', 'verification']
|
|
47433
|
+
: ['identity', 'versions'],
|
|
47434
|
+
});
|
|
47435
|
+
if (state.identity.deviceType !== 'pro2' && state.identity.deviceType !== 'neo') {
|
|
47436
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotSupportMethod, `${methodName} requires a Pro2 or Neo device for Protocol V2`);
|
|
47404
47437
|
}
|
|
47405
|
-
|
|
47406
|
-
|
|
47438
|
+
const { features } = device;
|
|
47439
|
+
if (!features) {
|
|
47440
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `${methodName} requires initialized device features`);
|
|
47441
|
+
}
|
|
47442
|
+
const firmwareType = (_a = firmwareTypeParam !== null && firmwareTypeParam !== void 0 ? firmwareTypeParam : state.identity.firmwareType) !== null && _a !== void 0 ? _a : hdShared.EFirmwareType.Universal;
|
|
47443
|
+
return {
|
|
47444
|
+
state: state,
|
|
47445
|
+
features,
|
|
47446
|
+
firmwareType,
|
|
47447
|
+
release: DataManager.getFirmwareLatestRelease(features, firmwareType),
|
|
47448
|
+
};
|
|
47449
|
+
});
|
|
47407
47450
|
}
|
|
47408
|
-
|
|
47409
|
-
|
|
47410
|
-
|
|
47411
|
-
|
|
47412
|
-
|
|
47413
|
-
|
|
47414
|
-
|
|
47415
|
-
|
|
47416
|
-
|
|
47417
|
-
|
|
47451
|
+
function summarizeProtocolV2FirmwareRelease(plan, componentTargets) {
|
|
47452
|
+
var _a;
|
|
47453
|
+
const targetSet = new Set(componentTargets);
|
|
47454
|
+
const components = plan.components.filter(component => targetSet.has(component.componentTarget));
|
|
47455
|
+
const targetsToUpdate = Array.from(new Set(components.flatMap(component => component.status === 'outdated' && component.updateTarget ? [component.updateTarget] : [])));
|
|
47456
|
+
const hasUpgrade = targetsToUpdate.length > 0;
|
|
47457
|
+
const required = !!((_a = plan.release) === null || _a === void 0 ? void 0 : _a.required) && hasUpgrade;
|
|
47458
|
+
let status = 'valid';
|
|
47459
|
+
if (!plan.release || components.length === 0) {
|
|
47460
|
+
status = 'unavailable';
|
|
47418
47461
|
}
|
|
47419
|
-
|
|
47420
|
-
|
|
47421
|
-
|
|
47422
|
-
|
|
47423
|
-
|
|
47424
|
-
|
|
47462
|
+
else if (required) {
|
|
47463
|
+
status = 'required';
|
|
47464
|
+
}
|
|
47465
|
+
else if (hasUpgrade) {
|
|
47466
|
+
status = 'outdated';
|
|
47467
|
+
}
|
|
47468
|
+
else if (components.some(component => component.status === 'unknown')) {
|
|
47469
|
+
status = 'unknown';
|
|
47470
|
+
}
|
|
47471
|
+
else if (components.every(component => component.status === 'unsupported')) {
|
|
47472
|
+
status = 'unavailable';
|
|
47425
47473
|
}
|
|
47474
|
+
return Object.assign(Object.assign({}, plan), { status,
|
|
47475
|
+
hasUpgrade,
|
|
47476
|
+
required,
|
|
47477
|
+
components,
|
|
47478
|
+
targetsToUpdate });
|
|
47426
47479
|
}
|
|
47427
|
-
|
|
47428
|
-
|
|
47429
|
-
|
|
47430
|
-
|
|
47431
|
-
|
|
47432
|
-
|
|
47480
|
+
function toProtocolV2FirmwareReleaseInfo({ plan, state, release, }) {
|
|
47481
|
+
return {
|
|
47482
|
+
shouldUpdate: plan.hasUpgrade,
|
|
47483
|
+
status: plan.status === 'unavailable' ? 'unknown' : plan.status,
|
|
47484
|
+
changelog: plan.release ? [plan.release.changelog] : [],
|
|
47485
|
+
release,
|
|
47486
|
+
bootloaderMode: state.status.mode === 'bootloader' || state.status.mode === 'romloader',
|
|
47487
|
+
};
|
|
47488
|
+
}
|
|
47489
|
+
function getProtocolV2ComponentReleaseInfo(plan, componentTarget) {
|
|
47490
|
+
var _a;
|
|
47491
|
+
const componentRelease = plan.components.find(component => component.componentTarget === componentTarget);
|
|
47492
|
+
if (!componentRelease || !plan.release) {
|
|
47493
|
+
return undefined;
|
|
47433
47494
|
}
|
|
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
|
-
});
|
|
47495
|
+
const component = (_a = plan.release.components) === null || _a === void 0 ? void 0 : _a[componentRelease.configKey];
|
|
47496
|
+
if (!component) {
|
|
47497
|
+
return undefined;
|
|
47455
47498
|
}
|
|
47499
|
+
return Object.assign(Object.assign({}, component), { protocol: 'V2', configKey: componentRelease.configKey, componentTarget, required: plan.release.required, changelog: plan.release.changelog });
|
|
47456
47500
|
}
|
|
47457
47501
|
|
|
47458
47502
|
const REQUIRED_BRIDGE_VERSION = '2.2.0';
|
|
@@ -47509,56 +47553,6 @@ function getBridgeReleaseInfo({ deviceType, currentFirmwareVersion, willUpdateFi
|
|
|
47509
47553
|
});
|
|
47510
47554
|
}
|
|
47511
47555
|
|
|
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
47556
|
const UPDATE_TARGET_BY_COMPONENT_TARGET = {
|
|
47563
47557
|
BOOTLOADER: 'boot',
|
|
47564
47558
|
APPLICATION_P1: 'app_v1',
|
|
@@ -47806,22 +47800,15 @@ class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
47806
47800
|
runProtocolV2() {
|
|
47807
47801
|
var _a;
|
|
47808
47802
|
return __awaiter(this, void 0, void 0, function* () {
|
|
47809
|
-
const { checkFirmwareHash = false, firmwareType: firmwareTypeParam } = this
|
|
47810
|
-
|
|
47811
|
-
const
|
|
47812
|
-
|
|
47813
|
-
|
|
47814
|
-
|
|
47803
|
+
const { checkFirmwareHash = false, firmwareType: firmwareTypeParam, platform, forceUpdateTargets, protocolV2ForceUpdateTargets, } = this.payload;
|
|
47804
|
+
const validatedForceUpdateTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
|
|
47805
|
+
const validatedProtocolV2ForceUpdateTargets = validateProtocolV2FirmwareUpdateTargets(protocolV2ForceUpdateTargets);
|
|
47806
|
+
const { state, features, firmwareType, release } = yield loadProtocolV2FirmwareReleaseContext({
|
|
47807
|
+
device: this.device,
|
|
47808
|
+
firmwareType: firmwareTypeParam,
|
|
47809
|
+
checkFirmwareHash,
|
|
47810
|
+
methodName: 'checkAllFirmwareRelease',
|
|
47815
47811
|
});
|
|
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
47812
|
const plan = buildProtocolV2FirmwareRelease({
|
|
47826
47813
|
currentVersions: state.versions,
|
|
47827
47814
|
currentVerification: checkFirmwareHash ? state.verification : undefined,
|
|
@@ -47831,48 +47818,251 @@ class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
47831
47818
|
deviceType: state.identity.deviceType,
|
|
47832
47819
|
});
|
|
47833
47820
|
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
|
-
|
|
47821
|
+
const resourceSource = DataManager.getProtocolV2ResourceSource(resourceDeviceType);
|
|
47822
|
+
const resourceStatus = 'unknown';
|
|
47823
|
+
const detectedComponentTargets = validatedForceUpdateTargets.includes('firmware')
|
|
47824
|
+
? plan.components.flatMap(component => component.updateTarget ? [component.updateTarget] : [])
|
|
47825
|
+
: plan.targetsToUpdate;
|
|
47826
|
+
const componentTargetsToUpdate = Array.from(new Set([
|
|
47827
|
+
...detectedComponentTargets,
|
|
47828
|
+
...validatedProtocolV2ForceUpdateTargets.filter(target => target !== 'resource'),
|
|
47829
|
+
]));
|
|
47830
|
+
const forceResourceUpdate = validatedForceUpdateTargets.includes('resource') ||
|
|
47831
|
+
validatedProtocolV2ForceUpdateTargets.includes('resource');
|
|
47832
|
+
const includeResourceUpdate = forceResourceUpdate || (resourceSource !== undefined && detectedComponentTargets.length > 0);
|
|
47833
|
+
const targetsToUpdate = Array.from(new Set([
|
|
47834
|
+
...componentTargetsToUpdate,
|
|
47835
|
+
...(includeResourceUpdate ? ['resource'] : []),
|
|
47836
|
+
]));
|
|
47837
|
+
let firmwareUpdatePlan;
|
|
47838
|
+
const shouldBuildFirmwareUpdatePlan = targetsToUpdate.length > 0;
|
|
47839
|
+
const requestedPlatform = platform !== null && platform !== void 0 ? platform : 'web';
|
|
47840
|
+
const requiresPreparedPlan = shouldBuildFirmwareUpdatePlan &&
|
|
47841
|
+
(requestedPlatform === 'native' || requestedPlatform === 'desktop');
|
|
47842
|
+
try {
|
|
47843
|
+
if (shouldBuildFirmwareUpdatePlan) {
|
|
47844
|
+
const validatedPlan = buildProtocolV2FirmwareUpdatePlan({
|
|
47845
|
+
features,
|
|
47846
|
+
firmwareType,
|
|
47847
|
+
platform: requestedPlatform,
|
|
47848
|
+
release,
|
|
47849
|
+
targetsToUpdate,
|
|
47850
|
+
forceUpdateTargets: validatedForceUpdateTargets,
|
|
47851
|
+
resourceArchive: resourceSource,
|
|
47852
|
+
});
|
|
47853
|
+
firmwareUpdatePlan = validatedPlan;
|
|
47854
|
+
}
|
|
47855
|
+
else {
|
|
47856
|
+
firmwareUpdatePlan = undefined;
|
|
47857
|
+
}
|
|
47858
|
+
}
|
|
47859
|
+
catch (error) {
|
|
47860
|
+
if (requiresPreparedPlan ||
|
|
47861
|
+
validatedForceUpdateTargets.length > 0 ||
|
|
47862
|
+
validatedProtocolV2ForceUpdateTargets.length > 0 ||
|
|
47863
|
+
!(error instanceof hdShared.HardwareError) ||
|
|
47864
|
+
((_a = error.params) === null || _a === void 0 ? void 0 : _a.firmwareUpdateCode) !== 'FirmwarePlanInvalid') {
|
|
47865
|
+
throw error;
|
|
47866
|
+
}
|
|
47867
|
+
Log$c.warn('[CheckAllFirmwareRelease] Optional Protocol V2 firmware Plan is unavailable; using the release result');
|
|
47868
|
+
firmwareUpdatePlan = undefined;
|
|
47869
|
+
}
|
|
47870
|
+
const firmwarePlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_MAIN_FIRMWARE_TARGETS);
|
|
47871
|
+
const blePlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_BLE_TARGETS);
|
|
47872
|
+
const bootloaderPlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_BOOTLOADER_TARGETS);
|
|
47873
|
+
const { status } = plan;
|
|
47874
|
+
return Object.assign(Object.assign({ firmware: toProtocolV2FirmwareReleaseInfo({ plan: firmwarePlan, state, release }), ble: toProtocolV2FirmwareReleaseInfo({
|
|
47875
|
+
plan: blePlan,
|
|
47876
|
+
state,
|
|
47877
|
+
release: getProtocolV2ComponentReleaseInfo(plan, 'COPROCESSOR'),
|
|
47878
|
+
}), bootloader: toProtocolV2FirmwareReleaseInfo({
|
|
47879
|
+
plan: bootloaderPlan,
|
|
47880
|
+
state,
|
|
47881
|
+
release: getProtocolV2ComponentReleaseInfo(plan, 'BOOTLOADER'),
|
|
47882
|
+
}), features, protocol: 'V2', deviceType: state.identity.deviceType }, plan), { status,
|
|
47883
|
+
resourceStatus, resourceArchive: resourceSource, hasUpgrade: targetsToUpdate.length > 0, targetsToUpdate,
|
|
47884
|
+
firmwareUpdatePlan });
|
|
47885
|
+
});
|
|
47886
|
+
}
|
|
47887
|
+
}
|
|
47888
|
+
|
|
47889
|
+
class CheckFirmwareRelease extends BaseMethod {
|
|
47890
|
+
getSupportedProtocols() {
|
|
47891
|
+
return ['V1', 'V2'];
|
|
47892
|
+
}
|
|
47893
|
+
init() {
|
|
47894
|
+
this.allowDeviceMode = [
|
|
47895
|
+
...this.allowDeviceMode,
|
|
47896
|
+
UI_REQUEST.NOT_INITIALIZE,
|
|
47897
|
+
UI_REQUEST.BOOTLOADER,
|
|
47898
|
+
];
|
|
47899
|
+
this.useDevicePassphraseState = false;
|
|
47900
|
+
this.skipForceUpdateCheck = true;
|
|
47901
|
+
}
|
|
47902
|
+
run() {
|
|
47903
|
+
var _a;
|
|
47904
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
47905
|
+
const payload = this.payload;
|
|
47906
|
+
if (!this.device.features)
|
|
47907
|
+
return null;
|
|
47908
|
+
if (this.device.isProtocolV2()) {
|
|
47909
|
+
const { state, firmwareType, release } = yield loadProtocolV2FirmwareReleaseContext({
|
|
47910
|
+
device: this.device,
|
|
47911
|
+
firmwareType: payload.firmwareType,
|
|
47912
|
+
methodName: 'checkFirmwareRelease',
|
|
47913
|
+
});
|
|
47914
|
+
const plan = summarizeProtocolV2FirmwareRelease(buildProtocolV2FirmwareRelease({
|
|
47915
|
+
currentVersions: state.versions,
|
|
47916
|
+
firmwareType,
|
|
47917
|
+
release,
|
|
47918
|
+
deviceType: state.identity.deviceType,
|
|
47919
|
+
}), PROTOCOL_V2_MAIN_FIRMWARE_TARGETS);
|
|
47920
|
+
return toProtocolV2FirmwareReleaseInfo({ plan, state, release });
|
|
47921
|
+
}
|
|
47922
|
+
const deviceFirmwareType = this.device.getCurrentFirmwareType();
|
|
47923
|
+
const firmwareType = (_a = payload.firmwareType) !== null && _a !== void 0 ? _a : deviceFirmwareType;
|
|
47924
|
+
const releaseInfo = getFirmwareReleaseInfo(this.device.features, firmwareType);
|
|
47925
|
+
return releaseInfo;
|
|
47926
|
+
});
|
|
47927
|
+
}
|
|
47928
|
+
}
|
|
47929
|
+
|
|
47930
|
+
class CheckBLEFirmwareRelease extends BaseMethod {
|
|
47931
|
+
getSupportedProtocols() {
|
|
47932
|
+
return ['V1', 'V2'];
|
|
47933
|
+
}
|
|
47934
|
+
init() {
|
|
47935
|
+
this.allowDeviceMode = [
|
|
47936
|
+
...this.allowDeviceMode,
|
|
47937
|
+
UI_REQUEST.NOT_INITIALIZE,
|
|
47938
|
+
UI_REQUEST.BOOTLOADER,
|
|
47939
|
+
];
|
|
47940
|
+
this.useDevicePassphraseState = false;
|
|
47941
|
+
this.skipForceUpdateCheck = true;
|
|
47942
|
+
}
|
|
47943
|
+
run() {
|
|
47944
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
47945
|
+
if (!this.device.features)
|
|
47946
|
+
return null;
|
|
47947
|
+
if (this.device.isProtocolV2()) {
|
|
47948
|
+
const { state, firmwareType, release } = yield loadProtocolV2FirmwareReleaseContext({
|
|
47949
|
+
device: this.device,
|
|
47950
|
+
methodName: 'checkBLEFirmwareRelease',
|
|
47951
|
+
});
|
|
47952
|
+
const plan = summarizeProtocolV2FirmwareRelease(buildProtocolV2FirmwareRelease({
|
|
47953
|
+
currentVersions: state.versions,
|
|
47954
|
+
firmwareType,
|
|
47955
|
+
release,
|
|
47956
|
+
deviceType: state.identity.deviceType,
|
|
47957
|
+
}), PROTOCOL_V2_BLE_TARGETS);
|
|
47958
|
+
return toProtocolV2FirmwareReleaseInfo({
|
|
47959
|
+
plan,
|
|
47960
|
+
state,
|
|
47961
|
+
release: getProtocolV2ComponentReleaseInfo(plan, 'COPROCESSOR'),
|
|
47962
|
+
});
|
|
47963
|
+
}
|
|
47964
|
+
const releaseInfo = getBleFirmwareReleaseInfo(this.device.features);
|
|
47965
|
+
return releaseInfo;
|
|
47966
|
+
});
|
|
47967
|
+
}
|
|
47968
|
+
}
|
|
47969
|
+
|
|
47970
|
+
class CheckBridgeStatus extends BaseMethod {
|
|
47971
|
+
init() {
|
|
47972
|
+
this.useDevice = false;
|
|
47973
|
+
this.useDevicePassphraseState = false;
|
|
47974
|
+
this.skipForceUpdateCheck = true;
|
|
47975
|
+
}
|
|
47976
|
+
run() {
|
|
47977
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
47978
|
+
return new Promise((resolve, reject) => {
|
|
47979
|
+
axios__default["default"]
|
|
47980
|
+
.request({
|
|
47981
|
+
url: 'http://localhost:21320',
|
|
47982
|
+
method: 'POST',
|
|
47983
|
+
withCredentials: false,
|
|
47984
|
+
timeout: 3000,
|
|
47985
|
+
})
|
|
47986
|
+
.then(() => resolve(true))
|
|
47987
|
+
.catch(e => {
|
|
47988
|
+
if (e.code === 'ECONNABORTED') {
|
|
47989
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BridgeTimeoutError));
|
|
47849
47990
|
}
|
|
47850
|
-
|
|
47851
|
-
|
|
47852
|
-
resources,
|
|
47853
|
-
mode: 'bootloader-recovery',
|
|
47854
|
-
}).status;
|
|
47991
|
+
else {
|
|
47992
|
+
resolve(false);
|
|
47855
47993
|
}
|
|
47856
|
-
}
|
|
47994
|
+
});
|
|
47995
|
+
});
|
|
47996
|
+
});
|
|
47997
|
+
}
|
|
47998
|
+
}
|
|
47999
|
+
|
|
48000
|
+
class CheckBridgeRelease extends BaseMethod {
|
|
48001
|
+
init() {
|
|
48002
|
+
this.allowDeviceMode = [...this.allowDeviceMode, UI_REQUEST.BOOTLOADER];
|
|
48003
|
+
this.useDevicePassphraseState = false;
|
|
48004
|
+
this.skipForceUpdateCheck = true;
|
|
48005
|
+
}
|
|
48006
|
+
run() {
|
|
48007
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
48008
|
+
if (!this.device.features) {
|
|
48009
|
+
return null;
|
|
47857
48010
|
}
|
|
47858
|
-
const
|
|
47859
|
-
|
|
47860
|
-
|
|
47861
|
-
|
|
47862
|
-
|
|
47863
|
-
|
|
47864
|
-
|
|
47865
|
-
|
|
47866
|
-
|
|
47867
|
-
|
|
47868
|
-
|
|
47869
|
-
|
|
47870
|
-
|
|
47871
|
-
|
|
47872
|
-
|
|
47873
|
-
|
|
47874
|
-
|
|
47875
|
-
|
|
48011
|
+
const { willUpdateFirmwareVersion } = this.payload;
|
|
48012
|
+
const { features } = this.device;
|
|
48013
|
+
const deviceType = getDeviceType(features);
|
|
48014
|
+
const currentFirmwareVersion = getDeviceFirmwareVersion(features).join('.');
|
|
48015
|
+
return getBridgeReleaseInfo({
|
|
48016
|
+
deviceType,
|
|
48017
|
+
currentFirmwareVersion,
|
|
48018
|
+
willUpdateFirmwareVersion,
|
|
48019
|
+
});
|
|
48020
|
+
});
|
|
48021
|
+
}
|
|
48022
|
+
}
|
|
48023
|
+
|
|
48024
|
+
class CheckBootloaderRelease extends BaseMethod {
|
|
48025
|
+
getSupportedProtocols() {
|
|
48026
|
+
return ['V1', 'V2'];
|
|
48027
|
+
}
|
|
48028
|
+
init() {
|
|
48029
|
+
this.allowDeviceMode = [...this.allowDeviceMode, UI_REQUEST.BOOTLOADER];
|
|
48030
|
+
this.useDevicePassphraseState = false;
|
|
48031
|
+
this.skipForceUpdateCheck = true;
|
|
48032
|
+
}
|
|
48033
|
+
run() {
|
|
48034
|
+
var _a;
|
|
48035
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
48036
|
+
if (!this.device.features)
|
|
48037
|
+
return null;
|
|
48038
|
+
const { features } = this.device;
|
|
48039
|
+
const payload = this.payload;
|
|
48040
|
+
if (this.device.isProtocolV2()) {
|
|
48041
|
+
const { state, firmwareType, release } = yield loadProtocolV2FirmwareReleaseContext({
|
|
48042
|
+
device: this.device,
|
|
48043
|
+
firmwareType: payload.firmwareType,
|
|
48044
|
+
methodName: 'checkBootloaderRelease',
|
|
48045
|
+
});
|
|
48046
|
+
const plan = summarizeProtocolV2FirmwareRelease(buildProtocolV2FirmwareRelease({
|
|
48047
|
+
currentVersions: state.versions,
|
|
48048
|
+
firmwareType,
|
|
48049
|
+
release,
|
|
48050
|
+
deviceType: state.identity.deviceType,
|
|
48051
|
+
}), PROTOCOL_V2_BOOTLOADER_TARGETS);
|
|
48052
|
+
return toProtocolV2FirmwareReleaseInfo({
|
|
48053
|
+
plan,
|
|
48054
|
+
state,
|
|
48055
|
+
release: getProtocolV2ComponentReleaseInfo(plan, 'BOOTLOADER'),
|
|
48056
|
+
});
|
|
48057
|
+
}
|
|
48058
|
+
const deviceFirmwareType = this.device.getCurrentFirmwareType();
|
|
48059
|
+
const firmwareType = (_a = payload.firmwareType) !== null && _a !== void 0 ? _a : deviceFirmwareType;
|
|
48060
|
+
const releaseInfo = getBootloaderReleaseInfo({
|
|
48061
|
+
features,
|
|
48062
|
+
willUpdateFirmwareVersion: payload.willUpdateFirmwareVersion,
|
|
48063
|
+
firmwareType,
|
|
48064
|
+
});
|
|
48065
|
+
return Promise.resolve(releaseInfo);
|
|
47876
48066
|
});
|
|
47877
48067
|
}
|
|
47878
48068
|
}
|
|
@@ -49227,11 +49417,34 @@ class FirmwareUpdateBaseMethod extends BaseMethod {
|
|
|
49227
49417
|
let checkCount = 0;
|
|
49228
49418
|
let hasPromptedWebDevice = false;
|
|
49229
49419
|
let isPromptingWebDevice = false;
|
|
49420
|
+
let isFinished = false;
|
|
49421
|
+
let intervalTimer;
|
|
49230
49422
|
let timeoutTimer;
|
|
49231
49423
|
const isTouchOrProDevice = ((_a = this === null || this === void 0 ? void 0 : this.device) === null || _a === void 0 ? void 0 : _a.getCurrentDeviceType()) === hdShared.EDeviceType.Touch ||
|
|
49232
49424
|
((_b = this === null || this === void 0 ? void 0 : this.device) === null || _b === void 0 ? void 0 : _b.getCurrentDeviceType()) === hdShared.EDeviceType.Pro;
|
|
49233
|
-
const
|
|
49425
|
+
const clearPollingTimers = () => {
|
|
49426
|
+
if (intervalTimer !== undefined) {
|
|
49427
|
+
clearInterval(intervalTimer);
|
|
49428
|
+
intervalTimer = undefined;
|
|
49429
|
+
}
|
|
49430
|
+
if (timeoutTimer !== undefined) {
|
|
49431
|
+
clearTimeout(timeoutTimer);
|
|
49432
|
+
timeoutTimer = undefined;
|
|
49433
|
+
}
|
|
49434
|
+
};
|
|
49435
|
+
const checkForBootloader = (clearActiveTimers) => __awaiter(this, void 0, void 0, function* () {
|
|
49436
|
+
const found = yield this._checkDeviceInBootloaderMode(connectId, clearActiveTimers ? intervalTimer : undefined, clearActiveTimers ? timeoutTimer : undefined);
|
|
49437
|
+
if (found) {
|
|
49438
|
+
isFinished = true;
|
|
49439
|
+
clearPollingTimers();
|
|
49440
|
+
}
|
|
49441
|
+
return found;
|
|
49442
|
+
});
|
|
49443
|
+
let startPolling = () => undefined;
|
|
49444
|
+
const pollForBootloader = () => __awaiter(this, void 0, void 0, function* () {
|
|
49234
49445
|
var _c, _d, _e, _f;
|
|
49446
|
+
if (isFinished || isPromptingWebDevice)
|
|
49447
|
+
return;
|
|
49235
49448
|
checkCount += 1;
|
|
49236
49449
|
Log$a.log('FirmwareUpdateBaseMethod [checkDeviceToBootloader] isFirstCheck: ', isFirstCheck);
|
|
49237
49450
|
if (isTouchOrProDevice && isFirstCheck) {
|
|
@@ -49244,20 +49457,22 @@ class FirmwareUpdateBaseMethod extends BaseMethod {
|
|
|
49244
49457
|
!this.payload.skipWebDevicePrompt &&
|
|
49245
49458
|
!hasPromptedWebDevice &&
|
|
49246
49459
|
!isPromptingWebDevice) {
|
|
49247
|
-
|
|
49248
|
-
clearTimeout(timeoutTimer);
|
|
49460
|
+
clearPollingTimers();
|
|
49249
49461
|
isPromptingWebDevice = true;
|
|
49250
49462
|
try {
|
|
49251
49463
|
this.postTipMessage(exports.FirmwareUpdateTipMessage.SelectDeviceInBootloaderForWebDevice);
|
|
49252
49464
|
const confirmed = yield this._promptDeviceInBootloaderForWebDevice();
|
|
49253
49465
|
hasPromptedWebDevice = true;
|
|
49254
49466
|
if (confirmed) {
|
|
49255
|
-
yield
|
|
49467
|
+
yield checkForBootloader(false);
|
|
49468
|
+
}
|
|
49469
|
+
if (!isFinished) {
|
|
49470
|
+
startPolling();
|
|
49256
49471
|
}
|
|
49257
49472
|
}
|
|
49258
49473
|
catch (e) {
|
|
49259
|
-
|
|
49260
|
-
|
|
49474
|
+
isFinished = true;
|
|
49475
|
+
clearPollingTimers();
|
|
49261
49476
|
Log$a.log('FirmwareUpdateBaseMethod [checkDeviceToBootloader] _promptDeviceInBootloaderForWebDevice failed: ', e);
|
|
49262
49477
|
(_c = this.checkPromise) === null || _c === void 0 ? void 0 : _c.reject(e);
|
|
49263
49478
|
}
|
|
@@ -49274,7 +49489,8 @@ class FirmwareUpdateBaseMethod extends BaseMethod {
|
|
|
49274
49489
|
yield ((_d = this.device.deviceConnector) === null || _d === void 0 ? void 0 : _d.acquire(this.device.originalDescriptor.id, null, true, (_e = this.payload.connectProtocol) !== null && _e !== void 0 ? _e : this.device.originalDescriptor.protocolType));
|
|
49275
49490
|
yield this.device.initialize({ timeoutMs: BOOTLOADER_POLL_INITIALIZE_TIMEOUT_MS });
|
|
49276
49491
|
if (this.device.isBootloader()) {
|
|
49277
|
-
|
|
49492
|
+
isFinished = true;
|
|
49493
|
+
clearPollingTimers();
|
|
49278
49494
|
(_f = this.checkPromise) === null || _f === void 0 ? void 0 : _f.resolve(true);
|
|
49279
49495
|
}
|
|
49280
49496
|
}
|
|
@@ -49286,15 +49502,32 @@ class FirmwareUpdateBaseMethod extends BaseMethod {
|
|
|
49286
49502
|
}
|
|
49287
49503
|
}
|
|
49288
49504
|
else {
|
|
49289
|
-
yield
|
|
49505
|
+
yield checkForBootloader(true);
|
|
49290
49506
|
}
|
|
49291
|
-
})
|
|
49292
|
-
|
|
49293
|
-
if (
|
|
49294
|
-
|
|
49295
|
-
|
|
49296
|
-
|
|
49297
|
-
|
|
49507
|
+
});
|
|
49508
|
+
startPolling = () => {
|
|
49509
|
+
if (isFinished)
|
|
49510
|
+
return;
|
|
49511
|
+
clearPollingTimers();
|
|
49512
|
+
intervalTimer = setInterval(() => {
|
|
49513
|
+
pollForBootloader().catch(error => {
|
|
49514
|
+
var _a;
|
|
49515
|
+
if (isFinished)
|
|
49516
|
+
return;
|
|
49517
|
+
isFinished = true;
|
|
49518
|
+
clearPollingTimers();
|
|
49519
|
+
(_a = this.checkPromise) === null || _a === void 0 ? void 0 : _a.reject(error);
|
|
49520
|
+
});
|
|
49521
|
+
}, isBleReconnect ? 3000 : 2000);
|
|
49522
|
+
timeoutTimer = setTimeout(() => {
|
|
49523
|
+
if (!isFinished && this.checkPromise) {
|
|
49524
|
+
isFinished = true;
|
|
49525
|
+
clearPollingTimers();
|
|
49526
|
+
this.checkPromise.reject(new Error());
|
|
49527
|
+
}
|
|
49528
|
+
}, 30000);
|
|
49529
|
+
};
|
|
49530
|
+
startPolling();
|
|
49298
49531
|
}
|
|
49299
49532
|
_checkDeviceInBootloaderMode(connectId, intervalTimer, timeoutTimer) {
|
|
49300
49533
|
var _a, _b, _c, _d, _e;
|
|
@@ -49619,35 +49852,52 @@ class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod {
|
|
|
49619
49852
|
});
|
|
49620
49853
|
}
|
|
49621
49854
|
run() {
|
|
49622
|
-
var _a, _b
|
|
49855
|
+
var _a, _b;
|
|
49623
49856
|
return __awaiter(this, void 0, void 0, function* () {
|
|
49624
49857
|
const { device } = this;
|
|
49625
49858
|
const { features } = device;
|
|
49626
49859
|
const payload = this.payload;
|
|
49627
|
-
const
|
|
49628
|
-
|
|
49860
|
+
const hasPreparedPlan = payload.preparedPlan !== undefined;
|
|
49861
|
+
if (hasPreparedPlan && payload.binary !== undefined) {
|
|
49862
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Prepared bootloader plans cannot be combined with a legacy binary');
|
|
49863
|
+
}
|
|
49864
|
+
if (!hasPreparedPlan && payload.artifact !== undefined) {
|
|
49865
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Bootloader artifacts require a prepared plan');
|
|
49866
|
+
}
|
|
49867
|
+
const preparedPlan = hasPreparedPlan
|
|
49868
|
+
? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
|
|
49629
49869
|
: undefined;
|
|
49630
|
-
const
|
|
49631
|
-
|
|
49870
|
+
const plannedArtifact = preparedPlan
|
|
49871
|
+
? getFirmwareUpdatePreparedRawArtifact({
|
|
49872
|
+
preparedPlan,
|
|
49873
|
+
target: 'bootloader',
|
|
49874
|
+
role: 'bootloader',
|
|
49875
|
+
}).artifact
|
|
49876
|
+
: undefined;
|
|
49877
|
+
const artifactReader = preparedPlan
|
|
49878
|
+
? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration, preparedPlan.preparedPlanDigest).artifactReader
|
|
49879
|
+
: payload.artifactReader;
|
|
49880
|
+
const executionParams = Object.assign(Object.assign({}, payload), { artifactReader });
|
|
49881
|
+
if (preparedPlan && plannedArtifact) {
|
|
49632
49882
|
assertFirmwareUpdatePreparedPlanDeviceIdentity({
|
|
49633
|
-
preparedPlan
|
|
49883
|
+
preparedPlan,
|
|
49634
49884
|
deviceIdentity: getDeviceUUID(features) || undefined,
|
|
49635
49885
|
bootloaderMode: resolveDeviceBootloaderMode(features),
|
|
49636
49886
|
deviceModel: String(getDeviceType(features)),
|
|
49637
49887
|
});
|
|
49638
49888
|
assertFirmwareUpdatePreparedPlanBinding({
|
|
49639
|
-
preparedPlan
|
|
49889
|
+
preparedPlan,
|
|
49640
49890
|
executor: 'v2',
|
|
49641
49891
|
scopeTargets: ['bootloader'],
|
|
49642
49892
|
bindings: [
|
|
49643
49893
|
{
|
|
49644
49894
|
target: 'bootloader',
|
|
49645
|
-
artifact: payload.artifact,
|
|
49895
|
+
artifact: (_a = payload.artifact) !== null && _a !== void 0 ? _a : plannedArtifact,
|
|
49646
49896
|
},
|
|
49647
49897
|
],
|
|
49648
49898
|
});
|
|
49649
49899
|
const source = yield openFirmwareByteSource({
|
|
49650
|
-
artifact:
|
|
49900
|
+
artifact: plannedArtifact,
|
|
49651
49901
|
reader: executionParams.artifactReader,
|
|
49652
49902
|
});
|
|
49653
49903
|
if (!source) {
|
|
@@ -49655,13 +49905,11 @@ class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod {
|
|
|
49655
49905
|
}
|
|
49656
49906
|
try {
|
|
49657
49907
|
const deviceType = device.getCurrentDeviceType();
|
|
49658
|
-
const deviceFirmwareType = device.getCurrentFirmwareType();
|
|
49659
|
-
const firmwareType = (_b = payload.firmwareType) !== null && _b !== void 0 ? _b : deviceFirmwareType;
|
|
49660
49908
|
if (DeviceModelToTypes.model_touch.includes(deviceType)) {
|
|
49661
49909
|
return yield this.updateTouchBootloader({
|
|
49662
49910
|
device,
|
|
49663
49911
|
features,
|
|
49664
|
-
firmwareType,
|
|
49912
|
+
firmwareType: preparedPlan.firmwareType,
|
|
49665
49913
|
source,
|
|
49666
49914
|
});
|
|
49667
49915
|
}
|
|
@@ -49674,7 +49922,7 @@ class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod {
|
|
|
49674
49922
|
const { binary } = payload;
|
|
49675
49923
|
const deviceType = device.getCurrentDeviceType();
|
|
49676
49924
|
const deviceFirmwareType = device.getCurrentFirmwareType();
|
|
49677
|
-
const firmwareType = (
|
|
49925
|
+
const firmwareType = (_b = payload.firmwareType) !== null && _b !== void 0 ? _b : deviceFirmwareType;
|
|
49678
49926
|
if (DeviceModelToTypes.model_touch.includes(deviceType)) {
|
|
49679
49927
|
return this.updateTouchBootloader({
|
|
49680
49928
|
device,
|
|
@@ -49935,6 +50183,119 @@ const normalizeFirmwarePreparationError = (error) => {
|
|
|
49935
50183
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, error instanceof Error ? error.message : String(error));
|
|
49936
50184
|
};
|
|
49937
50185
|
|
|
50186
|
+
const PREPARED_RESOURCE_ARCHIVE_MAX_BYTES = 256 * 1024 * 1024;
|
|
50187
|
+
const PREPARED_RESOURCE_ENTRY_MAX_COUNT = 512;
|
|
50188
|
+
const resourceArchiveError = (message, firmwareUpdateCode) => {
|
|
50189
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, message, { firmwareUpdateCode });
|
|
50190
|
+
};
|
|
50191
|
+
const getZipEntrySizes = (entry) => {
|
|
50192
|
+
var _a;
|
|
50193
|
+
const { compressedSize, uncompressedSize } = (_a = entry._data) !== null && _a !== void 0 ? _a : {};
|
|
50194
|
+
if (!Number.isSafeInteger(compressedSize) ||
|
|
50195
|
+
Number(compressedSize) < 0 ||
|
|
50196
|
+
!Number.isSafeInteger(uncompressedSize) ||
|
|
50197
|
+
Number(uncompressedSize) <= 0) {
|
|
50198
|
+
return resourceArchiveError(`Firmware prepared resource ZIP entry size is invalid: ${entry.name}`, 'FirmwareArtifactsNotPrepared');
|
|
50199
|
+
}
|
|
50200
|
+
return {
|
|
50201
|
+
compressedSize: Number(compressedSize),
|
|
50202
|
+
uncompressedSize: Number(uncompressedSize),
|
|
50203
|
+
};
|
|
50204
|
+
};
|
|
50205
|
+
const readVerifiedPreparedResourceArchive = ({ preparedPlan, reader, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
50206
|
+
const resourceArtifacts = preparedPlan.artifacts.filter(artifact => artifact.target === 'resource');
|
|
50207
|
+
if (!preparedPlan.targetsToUpdate.includes('resource')) {
|
|
50208
|
+
if (resourceArtifacts.length > 0) {
|
|
50209
|
+
return resourceArchiveError('Firmware prepared resource artifact is outside the approved targets', 'FirmwareArtifactsNotPrepared');
|
|
50210
|
+
}
|
|
50211
|
+
return [];
|
|
50212
|
+
}
|
|
50213
|
+
if (resourceArtifacts.length !== 1) {
|
|
50214
|
+
return resourceArchiveError('Firmware prepared plan must contain exactly one materialized resource ZIP', 'FirmwareArtifactsNotPrepared');
|
|
50215
|
+
}
|
|
50216
|
+
const archiveArtifact = resourceArtifacts[0];
|
|
50217
|
+
const preparedEntries = archiveArtifact.materializedEntries;
|
|
50218
|
+
if (archiveArtifact.role !== 'resource' ||
|
|
50219
|
+
archiveArtifact.container !== 'zip' ||
|
|
50220
|
+
!(preparedEntries === null || preparedEntries === void 0 ? void 0 : preparedEntries.length)) {
|
|
50221
|
+
return resourceArchiveError('Firmware prepared plan must contain exactly one materialized resource ZIP', 'FirmwareArtifactsNotPrepared');
|
|
50222
|
+
}
|
|
50223
|
+
const archiveSource = yield openFirmwareByteSource({
|
|
50224
|
+
artifact: archiveArtifact.artifact,
|
|
50225
|
+
reader,
|
|
50226
|
+
});
|
|
50227
|
+
if (!archiveSource) {
|
|
50228
|
+
return resourceArchiveError('Firmware prepared resource ZIP is unavailable', 'FirmwareArtifactsNotPrepared');
|
|
50229
|
+
}
|
|
50230
|
+
if (archiveSource.size > PREPARED_RESOURCE_ARCHIVE_MAX_BYTES) {
|
|
50231
|
+
yield archiveSource.close().catch(() => undefined);
|
|
50232
|
+
return resourceArchiveError('Firmware prepared resource ZIP exceeds the archive size limit', 'FirmwareArtifactsNotPrepared');
|
|
50233
|
+
}
|
|
50234
|
+
let archiveBinary;
|
|
50235
|
+
try {
|
|
50236
|
+
archiveBinary = yield readFirmwareByteSourceFully(archiveSource);
|
|
50237
|
+
}
|
|
50238
|
+
finally {
|
|
50239
|
+
yield archiveSource.close().catch(() => undefined);
|
|
50240
|
+
}
|
|
50241
|
+
const archiveDigest = utils.bytesToHex(sha256.sha256(new Uint8Array(archiveBinary)));
|
|
50242
|
+
if (archiveDigest !== archiveArtifact.artifact.sha256.toLowerCase()) {
|
|
50243
|
+
return resourceArchiveError('Firmware prepared resource ZIP does not match its approved receipt', 'FirmwareArtifactReceiptMismatch');
|
|
50244
|
+
}
|
|
50245
|
+
let zip;
|
|
50246
|
+
try {
|
|
50247
|
+
zip = yield JSZip__default["default"].loadAsync(archiveBinary);
|
|
50248
|
+
}
|
|
50249
|
+
catch (_a) {
|
|
50250
|
+
return resourceArchiveError('Firmware prepared resource ZIP cannot be parsed', 'FirmwareArtifactsNotPrepared');
|
|
50251
|
+
}
|
|
50252
|
+
const zipEntries = Object.values(zip.files);
|
|
50253
|
+
if (zipEntries.some(entry => entry.unsafeOriginalName && entry.unsafeOriginalName !== entry.name)) {
|
|
50254
|
+
return resourceArchiveError('Firmware prepared resource ZIP contains an unsafe entry path', 'FirmwareArtifactsNotPrepared');
|
|
50255
|
+
}
|
|
50256
|
+
const files = zipEntries.filter(entry => !entry.dir);
|
|
50257
|
+
if (files.length === 0 || files.length > PREPARED_RESOURCE_ENTRY_MAX_COUNT) {
|
|
50258
|
+
return resourceArchiveError('Firmware prepared resource ZIP entry set is invalid', 'FirmwareArtifactsNotPrepared');
|
|
50259
|
+
}
|
|
50260
|
+
let totalSize = 0;
|
|
50261
|
+
const canonicalNames = new Set();
|
|
50262
|
+
for (const entry of files) {
|
|
50263
|
+
const { compressedSize, uncompressedSize } = getZipEntrySizes(entry);
|
|
50264
|
+
const resourceName = getFirmwareUpdateResourceName(entry.name);
|
|
50265
|
+
const canonicalName = resourceName.toLowerCase();
|
|
50266
|
+
totalSize += uncompressedSize;
|
|
50267
|
+
if (compressedSize > archiveBinary.byteLength ||
|
|
50268
|
+
uncompressedSize > PREPARED_RESOURCE_ARCHIVE_MAX_BYTES ||
|
|
50269
|
+
totalSize > PREPARED_RESOURCE_ARCHIVE_MAX_BYTES ||
|
|
50270
|
+
canonicalNames.has(canonicalName)) {
|
|
50271
|
+
return resourceArchiveError(`Firmware prepared resource ZIP entry bounds are invalid: ${entry.name}`, 'FirmwareArtifactsNotPrepared');
|
|
50272
|
+
}
|
|
50273
|
+
canonicalNames.add(canonicalName);
|
|
50274
|
+
}
|
|
50275
|
+
const preparedEntriesByName = new Map(preparedEntries.map(entry => [entry.entryName, entry]));
|
|
50276
|
+
if (preparedEntriesByName.size !== files.length || preparedEntries.length !== files.length) {
|
|
50277
|
+
return resourceArchiveError('Firmware prepared resource entries do not match the approved ZIP', 'FirmwareArtifactReceiptMismatch');
|
|
50278
|
+
}
|
|
50279
|
+
const verifiedEntries = [];
|
|
50280
|
+
for (const entry of files) {
|
|
50281
|
+
const { uncompressedSize } = getZipEntrySizes(entry);
|
|
50282
|
+
const binary = yield entry.async('arraybuffer');
|
|
50283
|
+
const preparedEntry = preparedEntriesByName.get(entry.name);
|
|
50284
|
+
const digest = utils.bytesToHex(sha256.sha256(new Uint8Array(binary)));
|
|
50285
|
+
if (binary.byteLength !== uncompressedSize ||
|
|
50286
|
+
!preparedEntry ||
|
|
50287
|
+
preparedEntry.artifact.size !== binary.byteLength ||
|
|
50288
|
+
preparedEntry.artifact.sha256.toLowerCase() !== digest) {
|
|
50289
|
+
return resourceArchiveError(`Firmware prepared resource entry does not match the approved ZIP: ${entry.name}`, 'FirmwareArtifactReceiptMismatch');
|
|
50290
|
+
}
|
|
50291
|
+
verifiedEntries.push({
|
|
50292
|
+
entryName: getFirmwareUpdateResourceName(entry.name),
|
|
50293
|
+
binary,
|
|
50294
|
+
});
|
|
50295
|
+
}
|
|
50296
|
+
return verifiedEntries;
|
|
50297
|
+
});
|
|
50298
|
+
|
|
49938
50299
|
const Log$8 = getLogger(exports.LoggerNames.Method);
|
|
49939
50300
|
const FIRMWARE_DOWNLOAD_REQUEST_OPTIONS = {
|
|
49940
50301
|
connectTimeoutMs: 60000,
|
|
@@ -50009,7 +50370,7 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50009
50370
|
};
|
|
50010
50371
|
}
|
|
50011
50372
|
init() {
|
|
50012
|
-
var _a;
|
|
50373
|
+
var _a, _b;
|
|
50013
50374
|
this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
|
|
50014
50375
|
this.requireDeviceMode = [];
|
|
50015
50376
|
this.useDevicePassphraseState = false;
|
|
@@ -50022,11 +50383,12 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50022
50383
|
{ name: 'platform', type: 'string', required: true },
|
|
50023
50384
|
{ name: 'firmwareType', type: 'string' },
|
|
50024
50385
|
]);
|
|
50025
|
-
|
|
50026
|
-
|
|
50027
|
-
'
|
|
50028
|
-
|
|
50029
|
-
|
|
50386
|
+
const hasPreparedPlan = payload.preparedPlan !== undefined;
|
|
50387
|
+
if (hasPreparedPlan && (payload.binary !== undefined || payload.version !== undefined)) {
|
|
50388
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Prepared firmware plans cannot be combined with legacy firmware inputs');
|
|
50389
|
+
}
|
|
50390
|
+
if (!hasPreparedPlan && payload.artifact !== undefined) {
|
|
50391
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Firmware artifacts require a prepared plan');
|
|
50030
50392
|
}
|
|
50031
50393
|
if (!payload.updateType) {
|
|
50032
50394
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'updateType is required');
|
|
@@ -50036,28 +50398,37 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50036
50398
|
forcedUpdateRes: payload.forcedUpdateRes,
|
|
50037
50399
|
isUpdateBootloader: payload.isUpdateBootloader,
|
|
50038
50400
|
};
|
|
50039
|
-
if ('version' in payload) {
|
|
50401
|
+
if (!hasPreparedPlan && 'version' in payload) {
|
|
50040
50402
|
this.params = Object.assign(Object.assign({}, this.params), { version: payload.version, firmwareType: payload.firmwareType });
|
|
50041
50403
|
}
|
|
50042
|
-
if ('binary' in payload) {
|
|
50404
|
+
if (!hasPreparedPlan && 'binary' in payload) {
|
|
50043
50405
|
this.params = Object.assign(Object.assign({}, this.params), { binary: payload.binary });
|
|
50044
50406
|
}
|
|
50045
|
-
if (
|
|
50046
|
-
const
|
|
50407
|
+
if (hasPreparedPlan) {
|
|
50408
|
+
const preparedPlan = validateFirmwareUpdatePreparedPlan(payload.preparedPlan);
|
|
50409
|
+
const hostBinding = resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration, preparedPlan.preparedPlanDigest);
|
|
50047
50410
|
const target = payload.isUpdateBootloader ? 'bootloader' : payload.updateType;
|
|
50411
|
+
const plannedArtifact = getFirmwareUpdatePreparedRawArtifact({
|
|
50412
|
+
preparedPlan,
|
|
50413
|
+
target,
|
|
50414
|
+
role: target,
|
|
50415
|
+
}).artifact;
|
|
50048
50416
|
const resourceBindings = ((_a = payload.resourceEntries) !== null && _a !== void 0 ? _a : []).map((entry) => ({
|
|
50049
50417
|
target: 'resource',
|
|
50050
50418
|
entryName: entry.entryName,
|
|
50051
50419
|
artifact: entry.artifact,
|
|
50052
50420
|
}));
|
|
50053
50421
|
assertFirmwareUpdatePreparedPlanBinding({
|
|
50054
|
-
preparedPlan
|
|
50422
|
+
preparedPlan,
|
|
50055
50423
|
executor: 'v2',
|
|
50056
50424
|
platform: payload.platform,
|
|
50057
|
-
scopeTargets: [
|
|
50058
|
-
|
|
50425
|
+
scopeTargets: [
|
|
50426
|
+
target,
|
|
50427
|
+
...(target === 'firmware' && resourceBindings.length ? ['resource'] : []),
|
|
50428
|
+
],
|
|
50429
|
+
bindings: [{ target, artifact: (_b = payload.artifact) !== null && _b !== void 0 ? _b : plannedArtifact }, ...resourceBindings],
|
|
50059
50430
|
});
|
|
50060
|
-
this.params = Object.assign(Object.assign({}, this.params), { preparedPlan
|
|
50431
|
+
this.params = Object.assign(Object.assign({}, this.params), { preparedPlan, artifact: plannedArtifact, artifactReader: hostBinding.artifactReader, firmwareType: preparedPlan.firmwareType });
|
|
50061
50432
|
}
|
|
50062
50433
|
}
|
|
50063
50434
|
_promptDeviceInBootloaderForWebDevice() {
|
|
@@ -50085,11 +50456,36 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50085
50456
|
Log$8.log('FirmwareUpdateV2 [checkDeviceToBootloader] isBleReconnect: ', isBleReconnect);
|
|
50086
50457
|
let isFirstCheck = true;
|
|
50087
50458
|
let checkCount = 0;
|
|
50459
|
+
let hasPromptedWebDevice = false;
|
|
50460
|
+
let isPromptingWebDevice = false;
|
|
50461
|
+
let isFinished = false;
|
|
50462
|
+
let intervalTimer;
|
|
50088
50463
|
let timeoutTimer;
|
|
50089
50464
|
const deviceType = (_a = this.device) === null || _a === void 0 ? void 0 : _a.getCurrentDeviceType();
|
|
50090
50465
|
const isTouchOrProDevice = deviceType === hdShared.EDeviceType.Touch || deviceType === hdShared.EDeviceType.Pro;
|
|
50091
|
-
const
|
|
50466
|
+
const clearPollingTimers = () => {
|
|
50467
|
+
if (intervalTimer !== undefined) {
|
|
50468
|
+
clearInterval(intervalTimer);
|
|
50469
|
+
intervalTimer = undefined;
|
|
50470
|
+
}
|
|
50471
|
+
if (timeoutTimer !== undefined) {
|
|
50472
|
+
clearTimeout(timeoutTimer);
|
|
50473
|
+
timeoutTimer = undefined;
|
|
50474
|
+
}
|
|
50475
|
+
};
|
|
50476
|
+
const checkForBootloader = (clearActiveTimers) => __awaiter(this, void 0, void 0, function* () {
|
|
50477
|
+
const found = yield this._checkDeviceInBootloaderMode(connectId, clearActiveTimers ? intervalTimer : undefined, clearActiveTimers ? timeoutTimer : undefined);
|
|
50478
|
+
if (found) {
|
|
50479
|
+
isFinished = true;
|
|
50480
|
+
clearPollingTimers();
|
|
50481
|
+
}
|
|
50482
|
+
return found;
|
|
50483
|
+
});
|
|
50484
|
+
let startPolling = () => undefined;
|
|
50485
|
+
const pollForBootloader = () => __awaiter(this, void 0, void 0, function* () {
|
|
50092
50486
|
var _b, _c, _d, _e;
|
|
50487
|
+
if (isFinished || isPromptingWebDevice)
|
|
50488
|
+
return;
|
|
50093
50489
|
checkCount += 1;
|
|
50094
50490
|
Log$8.log('FirmwareUpdateV2 [checkDeviceToBootloader] isFirstCheck: ', isFirstCheck);
|
|
50095
50491
|
if (isTouchOrProDevice && isFirstCheck) {
|
|
@@ -50099,20 +50495,31 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50099
50495
|
}
|
|
50100
50496
|
if (checkCount > 4 &&
|
|
50101
50497
|
DataManager.isBrowserWebUsb(DataManager.getSettings('env')) &&
|
|
50102
|
-
!this.payload.skipWebDevicePrompt
|
|
50103
|
-
|
|
50104
|
-
|
|
50498
|
+
!this.payload.skipWebDevicePrompt &&
|
|
50499
|
+
!hasPromptedWebDevice &&
|
|
50500
|
+
!isPromptingWebDevice) {
|
|
50501
|
+
clearPollingTimers();
|
|
50502
|
+
isPromptingWebDevice = true;
|
|
50105
50503
|
try {
|
|
50106
50504
|
this.postTipMessage(exports.FirmwareUpdateTipMessage.SelectDeviceInBootloaderForWebDevice);
|
|
50107
50505
|
const confirmed = yield this._promptDeviceInBootloaderForWebDevice();
|
|
50506
|
+
hasPromptedWebDevice = true;
|
|
50108
50507
|
if (confirmed) {
|
|
50109
|
-
yield
|
|
50508
|
+
yield checkForBootloader(false);
|
|
50509
|
+
}
|
|
50510
|
+
if (!isFinished) {
|
|
50511
|
+
startPolling();
|
|
50110
50512
|
}
|
|
50111
50513
|
}
|
|
50112
50514
|
catch (e) {
|
|
50515
|
+
isFinished = true;
|
|
50516
|
+
clearPollingTimers();
|
|
50113
50517
|
Log$8.log('FirmwareUpdateV2 [checkDeviceToBootloader] promptDeviceInBootloaderForWebDevice failed: ', e);
|
|
50114
50518
|
(_b = this.checkPromise) === null || _b === void 0 ? void 0 : _b.reject(e);
|
|
50115
50519
|
}
|
|
50520
|
+
finally {
|
|
50521
|
+
isPromptingWebDevice = false;
|
|
50522
|
+
}
|
|
50116
50523
|
return;
|
|
50117
50524
|
}
|
|
50118
50525
|
if (isBleReconnect) {
|
|
@@ -50123,7 +50530,8 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50123
50530
|
yield ((_c = this.device.deviceConnector) === null || _c === void 0 ? void 0 : _c.acquire(this.device.originalDescriptor.id, null, true, (_d = this.payload.connectProtocol) !== null && _d !== void 0 ? _d : this.device.originalDescriptor.protocolType));
|
|
50124
50531
|
yield this.device.initialize({ timeoutMs: BOOTLOADER_POLL_INITIALIZE_TIMEOUT_MS });
|
|
50125
50532
|
if (this.device.isBootloader()) {
|
|
50126
|
-
|
|
50533
|
+
isFinished = true;
|
|
50534
|
+
clearPollingTimers();
|
|
50127
50535
|
(_e = this.checkPromise) === null || _e === void 0 ? void 0 : _e.resolve(true);
|
|
50128
50536
|
}
|
|
50129
50537
|
}
|
|
@@ -50135,15 +50543,32 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50135
50543
|
}
|
|
50136
50544
|
}
|
|
50137
50545
|
else {
|
|
50138
|
-
yield
|
|
50546
|
+
yield checkForBootloader(true);
|
|
50139
50547
|
}
|
|
50140
|
-
})
|
|
50141
|
-
|
|
50142
|
-
if (
|
|
50143
|
-
|
|
50144
|
-
|
|
50145
|
-
|
|
50146
|
-
|
|
50548
|
+
});
|
|
50549
|
+
startPolling = () => {
|
|
50550
|
+
if (isFinished)
|
|
50551
|
+
return;
|
|
50552
|
+
clearPollingTimers();
|
|
50553
|
+
intervalTimer = setInterval(() => {
|
|
50554
|
+
pollForBootloader().catch(error => {
|
|
50555
|
+
var _a;
|
|
50556
|
+
if (isFinished)
|
|
50557
|
+
return;
|
|
50558
|
+
isFinished = true;
|
|
50559
|
+
clearPollingTimers();
|
|
50560
|
+
(_a = this.checkPromise) === null || _a === void 0 ? void 0 : _a.reject(error);
|
|
50561
|
+
});
|
|
50562
|
+
}, isBleReconnect ? 3000 : 2000);
|
|
50563
|
+
timeoutTimer = setTimeout(() => {
|
|
50564
|
+
if (!isFinished && this.checkPromise) {
|
|
50565
|
+
isFinished = true;
|
|
50566
|
+
clearPollingTimers();
|
|
50567
|
+
this.checkPromise.reject(new Error());
|
|
50568
|
+
}
|
|
50569
|
+
}, 30000);
|
|
50570
|
+
};
|
|
50571
|
+
startPolling();
|
|
50147
50572
|
}
|
|
50148
50573
|
_checkDeviceInBootloaderMode(connectId, intervalTimer, timeoutTimer) {
|
|
50149
50574
|
var _a, _b, _c, _d, _e;
|
|
@@ -50207,7 +50632,7 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50207
50632
|
}
|
|
50208
50633
|
}
|
|
50209
50634
|
run() {
|
|
50210
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
50635
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
50211
50636
|
return __awaiter(this, void 0, void 0, function* () {
|
|
50212
50637
|
const { device, params } = this;
|
|
50213
50638
|
const { features, commands } = device;
|
|
@@ -50295,13 +50720,48 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50295
50720
|
throw normalizeFirmwarePreparationError(err);
|
|
50296
50721
|
}
|
|
50297
50722
|
});
|
|
50723
|
+
const preparedResourceRequested = !params.isUpdateBootloader &&
|
|
50724
|
+
params.updateType === 'firmware' &&
|
|
50725
|
+
((_c = (_b = params.preparedPlan) === null || _b === void 0 ? void 0 : _b.targetsToUpdate.includes('resource')) !== null && _c !== void 0 ? _c : false);
|
|
50726
|
+
if (preparedResourceRequested && device.isBootloader()) {
|
|
50727
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Prepared firmware resources require the device application mode', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared', artifactName: 'resource' });
|
|
50728
|
+
}
|
|
50298
50729
|
if (!device.isBootloader() && features) {
|
|
50299
50730
|
const serialNo = device.getCurrentSerialNo();
|
|
50300
50731
|
if (this.isEnteredManuallyBoot()) {
|
|
50301
50732
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateManuallyEnterBoot);
|
|
50302
50733
|
}
|
|
50303
50734
|
yield acquireFirmwareSource();
|
|
50304
|
-
if (
|
|
50735
|
+
if (preparedResourceRequested) {
|
|
50736
|
+
if (!this.isSupportResourceUpdate(params.updateType)) {
|
|
50737
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Prepared firmware resources are not supported by this device', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared', artifactName: 'resource' });
|
|
50738
|
+
}
|
|
50739
|
+
this.postTipMessage('CheckLatestUiResource');
|
|
50740
|
+
this.postTipMessage('DownloadLatestUiResource');
|
|
50741
|
+
const verifiedEntries = yield readVerifiedPreparedResourceArchive({
|
|
50742
|
+
preparedPlan: params.preparedPlan,
|
|
50743
|
+
reader: params.artifactReader,
|
|
50744
|
+
});
|
|
50745
|
+
const sources = [];
|
|
50746
|
+
try {
|
|
50747
|
+
for (const entry of verifiedEntries) {
|
|
50748
|
+
const source = yield openFirmwareByteSource({ binary: entry.binary });
|
|
50749
|
+
if (!source) {
|
|
50750
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Firmware resource entry ${entry.entryName} is empty`, {
|
|
50751
|
+
firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch',
|
|
50752
|
+
artifactName: 'resource',
|
|
50753
|
+
});
|
|
50754
|
+
}
|
|
50755
|
+
sources.push({ entryName: entry.entryName, source });
|
|
50756
|
+
}
|
|
50757
|
+
yield updateResourcesFromSources(this.device.getCommands().typedCall.bind(this.device.getCommands()), this.postMessage, device, sources);
|
|
50758
|
+
}
|
|
50759
|
+
finally {
|
|
50760
|
+
yield Promise.all(sources.map(entry => entry.source.close().catch(() => undefined)));
|
|
50761
|
+
}
|
|
50762
|
+
this.postTipMessage('DownloadLatestUiResourceSuccess');
|
|
50763
|
+
}
|
|
50764
|
+
else if (this.isSupportResourceUpdate(params.updateType)) {
|
|
50305
50765
|
this.postTipMessage('CheckLatestUiResource');
|
|
50306
50766
|
const resourceUrl = DataManager.getSysResourcesLatestRelease({
|
|
50307
50767
|
features,
|
|
@@ -50310,46 +50770,20 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50310
50770
|
});
|
|
50311
50771
|
if (resourceUrl) {
|
|
50312
50772
|
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);
|
|
50773
|
+
if (params.artifactReader ||
|
|
50774
|
+
DataManager.getSettings('firmwareManifestMode') === 'external-only') {
|
|
50775
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware resource must be prepared by the external firmware host', {
|
|
50776
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
50777
|
+
artifactName: 'resource',
|
|
50778
|
+
});
|
|
50349
50779
|
}
|
|
50780
|
+
const resourceBinary = (yield getSysResourceBinary(resourceUrl))
|
|
50781
|
+
.binary;
|
|
50782
|
+
this.postTipMessage('DownloadLatestUiResourceSuccess');
|
|
50783
|
+
yield updateResources(this.device.getCommands().typedCall.bind(this.device.getCommands()), this.postMessage, device, resourceBinary);
|
|
50350
50784
|
}
|
|
50351
50785
|
}
|
|
50352
|
-
(
|
|
50786
|
+
(_e = (_d = this.device) === null || _d === void 0 ? void 0 : _d.commands) === null || _e === void 0 ? void 0 : _e.checkDisposed();
|
|
50353
50787
|
try {
|
|
50354
50788
|
this.postTipMessage('AutoRebootToBootloader');
|
|
50355
50789
|
const bootRes = yield commands.typedCall('DeviceBackToBoot', 'Success');
|
|
@@ -50362,9 +50796,9 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50362
50796
|
DevicePool.clearDeviceCache(serialNo);
|
|
50363
50797
|
}
|
|
50364
50798
|
delete DevicePool.devicesCache[''];
|
|
50365
|
-
yield ((
|
|
50799
|
+
yield ((_f = this.checkPromise) === null || _f === void 0 ? void 0 : _f.promise);
|
|
50366
50800
|
this.checkPromise = null;
|
|
50367
|
-
(
|
|
50801
|
+
(_h = (_g = this.device) === null || _g === void 0 ? void 0 : _g.commands) === null || _h === void 0 ? void 0 : _h.checkDisposed();
|
|
50368
50802
|
const isTouch = DeviceModelToTypes.model_touch.includes(deviceType);
|
|
50369
50803
|
yield wait(isTouch ? 3000 : 1500);
|
|
50370
50804
|
}
|
|
@@ -50377,7 +50811,7 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50377
50811
|
}
|
|
50378
50812
|
}
|
|
50379
50813
|
const source = yield acquireFirmwareSource();
|
|
50380
|
-
(
|
|
50814
|
+
(_k = (_j = this.device) === null || _j === void 0 ? void 0 : _j.commands) === null || _k === void 0 ? void 0 : _k.checkDisposed();
|
|
50381
50815
|
yield this.device.acquire();
|
|
50382
50816
|
const response = yield uploadFirmwareFromSource(params.updateType, this.device.getCommands().typedCall.bind(this.device.getCommands()), this.postMessage, device, source, true, params.isUpdateBootloader);
|
|
50383
50817
|
if (this.connectId) {
|
|
@@ -50402,7 +50836,7 @@ class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod {
|
|
|
50402
50836
|
this.artifactSources = [];
|
|
50403
50837
|
}
|
|
50404
50838
|
init() {
|
|
50405
|
-
var _a, _b, _c
|
|
50839
|
+
var _a, _b, _c;
|
|
50406
50840
|
this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
|
|
50407
50841
|
this.requireDeviceMode = [];
|
|
50408
50842
|
this.useDevicePassphraseState = false;
|
|
@@ -50420,50 +50854,80 @@ class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod {
|
|
|
50420
50854
|
{ name: 'firmwareType', type: 'string' },
|
|
50421
50855
|
{ name: 'platform', type: 'string' },
|
|
50422
50856
|
]);
|
|
50423
|
-
const
|
|
50424
|
-
|
|
50857
|
+
const hasPreparedPlan = payload.preparedPlan !== undefined;
|
|
50858
|
+
if (!hasPreparedPlan && payload.artifacts !== undefined) {
|
|
50859
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Firmware artifacts require a prepared plan');
|
|
50860
|
+
}
|
|
50861
|
+
const preparedPlan = hasPreparedPlan
|
|
50862
|
+
? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
|
|
50425
50863
|
: undefined;
|
|
50426
|
-
|
|
50864
|
+
const hasLegacyInputs = [
|
|
50865
|
+
payload.bleVersion,
|
|
50866
|
+
payload.bleBinary,
|
|
50867
|
+
payload.firmwareVersion,
|
|
50868
|
+
payload.firmwareBinary,
|
|
50869
|
+
payload.resourceBinary,
|
|
50870
|
+
payload.bootloaderVersion,
|
|
50871
|
+
payload.bootloaderBinary,
|
|
50872
|
+
].some(input => input !== undefined);
|
|
50873
|
+
if (preparedPlan && hasLegacyInputs) {
|
|
50874
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Prepared firmware plans cannot be combined with legacy firmware inputs');
|
|
50875
|
+
}
|
|
50876
|
+
const artifactReader = preparedPlan
|
|
50877
|
+
? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration, preparedPlan.preparedPlanDigest).artifactReader
|
|
50878
|
+
: payload.artifactReader;
|
|
50879
|
+
const preparedArtifacts = {};
|
|
50880
|
+
if (preparedPlan) {
|
|
50881
|
+
const componentTargets = ['bootloader', 'firmware', 'ble'];
|
|
50882
|
+
const supportedTargets = new Set([...componentTargets, 'resource']);
|
|
50883
|
+
const unsupportedTarget = preparedPlan.targetsToUpdate.find(target => !supportedTargets.has(target));
|
|
50884
|
+
if (unsupportedTarget) {
|
|
50885
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Firmware prepared plan target ${unsupportedTarget} is not supported by V3`, { firmwareUpdateCode: 'FirmwarePreparedPlanInvalid' });
|
|
50886
|
+
}
|
|
50887
|
+
for (const target of componentTargets) {
|
|
50888
|
+
if (preparedPlan.targetsToUpdate.includes(target)) {
|
|
50889
|
+
preparedArtifacts[target] = getFirmwareUpdatePreparedRawArtifact({
|
|
50890
|
+
preparedPlan,
|
|
50891
|
+
target,
|
|
50892
|
+
role: target,
|
|
50893
|
+
}).artifact;
|
|
50894
|
+
}
|
|
50895
|
+
}
|
|
50896
|
+
const resourceBindings = ((_b = (_a = payload.artifacts) === null || _a === void 0 ? void 0 : _a.resourceEntries) !== null && _b !== void 0 ? _b : []).map((entry) => ({
|
|
50897
|
+
target: 'resource',
|
|
50898
|
+
entryName: entry.entryName,
|
|
50899
|
+
artifact: entry.artifact,
|
|
50900
|
+
}));
|
|
50427
50901
|
assertFirmwareUpdatePreparedPlanBinding({
|
|
50428
|
-
preparedPlan
|
|
50902
|
+
preparedPlan,
|
|
50429
50903
|
executor: 'v3',
|
|
50430
50904
|
platform: payload.platform,
|
|
50431
|
-
scopeTargets: [
|
|
50905
|
+
scopeTargets: [
|
|
50906
|
+
'bootloader',
|
|
50907
|
+
'firmware',
|
|
50908
|
+
'ble',
|
|
50909
|
+
...(resourceBindings.length ? ['resource'] : []),
|
|
50910
|
+
],
|
|
50432
50911
|
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
|
-
})),
|
|
50912
|
+
...componentTargets.flatMap(target => {
|
|
50913
|
+
var _a;
|
|
50914
|
+
const plannedArtifact = preparedArtifacts[target];
|
|
50915
|
+
const suppliedArtifact = (_a = payload.artifacts) === null || _a === void 0 ? void 0 : _a[target];
|
|
50916
|
+
return plannedArtifact || suppliedArtifact
|
|
50917
|
+
? [
|
|
50918
|
+
{
|
|
50919
|
+
target,
|
|
50920
|
+
artifact: suppliedArtifact !== null && suppliedArtifact !== void 0 ? suppliedArtifact : plannedArtifact,
|
|
50921
|
+
},
|
|
50922
|
+
]
|
|
50923
|
+
: [];
|
|
50924
|
+
}),
|
|
50925
|
+
...resourceBindings,
|
|
50462
50926
|
],
|
|
50463
50927
|
});
|
|
50464
50928
|
}
|
|
50465
50929
|
this.params = {
|
|
50466
|
-
preparedPlan
|
|
50930
|
+
preparedPlan,
|
|
50467
50931
|
bleBinary: payload.bleBinary,
|
|
50468
50932
|
firmwareBinary: payload.firmwareBinary,
|
|
50469
50933
|
forcedUpdateRes: payload.forcedUpdateRes,
|
|
@@ -50472,10 +50936,10 @@ class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod {
|
|
|
50472
50936
|
bootloaderBinary: payload.bootloaderBinary,
|
|
50473
50937
|
firmwareVersion: payload.firmwareVersion,
|
|
50474
50938
|
resourceBinary: payload.resourceBinary,
|
|
50475
|
-
firmwareType: payload.firmwareType,
|
|
50939
|
+
firmwareType: (_c = preparedPlan === null || preparedPlan === void 0 ? void 0 : preparedPlan.firmwareType) !== null && _c !== void 0 ? _c : payload.firmwareType,
|
|
50476
50940
|
platform: payload.platform,
|
|
50477
|
-
artifactReader
|
|
50478
|
-
artifacts:
|
|
50941
|
+
artifactReader,
|
|
50942
|
+
artifacts: preparedPlan ? preparedArtifacts : undefined,
|
|
50479
50943
|
};
|
|
50480
50944
|
}
|
|
50481
50945
|
run() {
|
|
@@ -50581,19 +51045,21 @@ class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod {
|
|
|
50581
51045
|
prepareResourceInput(firmwareType) {
|
|
50582
51046
|
var _a;
|
|
50583
51047
|
return __awaiter(this, void 0, void 0, function* () {
|
|
50584
|
-
|
|
50585
|
-
|
|
50586
|
-
|
|
50587
|
-
|
|
50588
|
-
|
|
51048
|
+
if ((_a = this.params.preparedPlan) === null || _a === void 0 ? void 0 : _a.targetsToUpdate.includes('resource')) {
|
|
51049
|
+
const verifiedEntries = yield readVerifiedPreparedResourceArchive({
|
|
51050
|
+
preparedPlan: this.params.preparedPlan,
|
|
51051
|
+
reader: this.params.artifactReader,
|
|
51052
|
+
});
|
|
50589
51053
|
const resourceEntries = [];
|
|
50590
|
-
for (const entry of
|
|
50591
|
-
const
|
|
50592
|
-
const source = yield this.openArtifactSource(undefined, entry.artifact);
|
|
51054
|
+
for (const entry of verifiedEntries) {
|
|
51055
|
+
const source = yield this.openArtifactSource(entry.binary, undefined);
|
|
50593
51056
|
if (!source) {
|
|
50594
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Firmware resource entry ${entry.entryName} is
|
|
51057
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Firmware resource entry ${entry.entryName} is empty`, {
|
|
51058
|
+
firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch',
|
|
51059
|
+
artifactName: 'resource',
|
|
51060
|
+
});
|
|
50595
51061
|
}
|
|
50596
|
-
resourceEntries.push({ entryName:
|
|
51062
|
+
resourceEntries.push({ entryName: entry.entryName, source });
|
|
50597
51063
|
}
|
|
50598
51064
|
return {
|
|
50599
51065
|
resourceBinary: null,
|
|
@@ -51090,6 +51556,86 @@ const INSTALLABLE_FIRMWARE_TARGET_IDS = new Set([
|
|
|
51090
51556
|
]);
|
|
51091
51557
|
new Map(Object.entries(ProtocolV2FirmwareTargetType).flatMap(([key, value]) => INSTALLABLE_FIRMWARE_TARGET_IDS.has(value) ? [[key, value]] : []));
|
|
51092
51558
|
|
|
51559
|
+
let memoryHostSequence = 0;
|
|
51560
|
+
const createReference = (binary, prefix) => {
|
|
51561
|
+
const digest = utils.bytesToHex(sha256.sha256(new Uint8Array(binary)));
|
|
51562
|
+
return {
|
|
51563
|
+
artifactRef: `fwmem:${prefix}:${digest.slice(0, 32)}`,
|
|
51564
|
+
size: binary.byteLength,
|
|
51565
|
+
sha256: digest,
|
|
51566
|
+
};
|
|
51567
|
+
};
|
|
51568
|
+
function prepareFirmwareUpdateV4MemoryHost({ sdk, plan, artifacts, }) {
|
|
51569
|
+
if (plan.executor !== 'v4') {
|
|
51570
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware memory host only supports V4 plans');
|
|
51571
|
+
}
|
|
51572
|
+
memoryHostSequence += 1;
|
|
51573
|
+
const hostId = `${Date.now()}:${memoryHostSequence}`;
|
|
51574
|
+
const binaries = new Map();
|
|
51575
|
+
const inputs = artifacts.map((input, artifactIndex) => {
|
|
51576
|
+
var _a;
|
|
51577
|
+
const artifactBinary = new Uint8Array(input.binary).slice();
|
|
51578
|
+
const artifact = createReference(artifactBinary.buffer, `${hostId}:artifact:${artifactIndex}`);
|
|
51579
|
+
binaries.set(artifact.artifactRef, artifactBinary);
|
|
51580
|
+
const materializedEntries = (_a = input.materializedEntries) === null || _a === void 0 ? void 0 : _a.map((entry, entryIndex) => {
|
|
51581
|
+
const entryArtifact = createReference(entry.binary, `${hostId}:entry:${artifactIndex}:${entryIndex}`);
|
|
51582
|
+
return {
|
|
51583
|
+
entryName: entry.entryName,
|
|
51584
|
+
artifact: entryArtifact,
|
|
51585
|
+
};
|
|
51586
|
+
});
|
|
51587
|
+
return Object.assign({ artifactId: input.artifactId, artifact }, ((materializedEntries === null || materializedEntries === void 0 ? void 0 : materializedEntries.length) ? { materializedEntries } : {}));
|
|
51588
|
+
});
|
|
51589
|
+
const preparedPlan = sdk.prepareFirmwareUpdatePlan({
|
|
51590
|
+
plan,
|
|
51591
|
+
leaseRef: `fwmemlease:${hostId}`,
|
|
51592
|
+
artifacts: inputs,
|
|
51593
|
+
});
|
|
51594
|
+
const readers = new Map();
|
|
51595
|
+
let readerSequence = 0;
|
|
51596
|
+
const artifactReader = {
|
|
51597
|
+
open({ artifactRef }) {
|
|
51598
|
+
const binary = binaries.get(artifactRef);
|
|
51599
|
+
if (!binary) {
|
|
51600
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware memory artifact is unavailable');
|
|
51601
|
+
}
|
|
51602
|
+
readerSequence += 1;
|
|
51603
|
+
const readerId = `fwmemreader:${hostId}:${readerSequence}`;
|
|
51604
|
+
readers.set(readerId, binary);
|
|
51605
|
+
return Promise.resolve({ readerId, size: binary.byteLength });
|
|
51606
|
+
},
|
|
51607
|
+
read({ readerId, offset, length }) {
|
|
51608
|
+
const binary = readers.get(readerId);
|
|
51609
|
+
if (!binary || offset < 0 || length <= 0 || offset + length > binary.byteLength) {
|
|
51610
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware memory artifact read is invalid');
|
|
51611
|
+
}
|
|
51612
|
+
const data = binary.slice(offset, offset + length).buffer;
|
|
51613
|
+
return Promise.resolve({
|
|
51614
|
+
data,
|
|
51615
|
+
bytesRead: data.byteLength,
|
|
51616
|
+
eof: offset + length === binary.byteLength,
|
|
51617
|
+
});
|
|
51618
|
+
},
|
|
51619
|
+
close({ readerId }) {
|
|
51620
|
+
readers.delete(readerId);
|
|
51621
|
+
return Promise.resolve();
|
|
51622
|
+
},
|
|
51623
|
+
};
|
|
51624
|
+
const hostBindingGeneration = sdk.registerFirmwareUpdateHostBinding({
|
|
51625
|
+
artifactReader,
|
|
51626
|
+
preparedPlanDigest: preparedPlan.preparedPlanDigest,
|
|
51627
|
+
});
|
|
51628
|
+
return {
|
|
51629
|
+
preparedPlan,
|
|
51630
|
+
hostBindingGeneration,
|
|
51631
|
+
release: () => {
|
|
51632
|
+
sdk.unregisterFirmwareUpdateHostBinding(hostBindingGeneration);
|
|
51633
|
+
readers.clear();
|
|
51634
|
+
binaries.clear();
|
|
51635
|
+
},
|
|
51636
|
+
};
|
|
51637
|
+
}
|
|
51638
|
+
|
|
51093
51639
|
const Log$6 = getLogger(exports.LoggerNames.Method);
|
|
51094
51640
|
const SESSION_ERROR$1 = 'session not found';
|
|
51095
51641
|
const PROTOCOL_V2_BOOTLOADER_RECONNECT_TIMEOUT = 90 * 1000;
|
|
@@ -51116,14 +51662,34 @@ const PROTOCOL_V2_OKPP_HEADER_SIZE = 0x52a0;
|
|
|
51116
51662
|
const PROTOCOL_V2_OKPP_PAYLOAD_HASH_OFFSET = 0x200;
|
|
51117
51663
|
const PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET = 0x240;
|
|
51118
51664
|
const PROTOCOL_V2_OKPP_HASH_SIZE = 64;
|
|
51665
|
+
const PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES = 1024 * 1024;
|
|
51666
|
+
const PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT = 512;
|
|
51667
|
+
const PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES = 256 * 1024 * 1024;
|
|
51119
51668
|
const PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS = new Set(['se03', 'se04']);
|
|
51120
|
-
|
|
51669
|
+
const getProtocolV2ZipEntrySizes = (entry) => {
|
|
51670
|
+
var _a;
|
|
51671
|
+
const { compressedSize, uncompressedSize } = (_a = entry._data) !== null && _a !== void 0 ? _a : {};
|
|
51672
|
+
if (!Number.isSafeInteger(compressedSize) ||
|
|
51673
|
+
Number(compressedSize) < 0 ||
|
|
51674
|
+
!Number.isSafeInteger(uncompressedSize) ||
|
|
51675
|
+
Number(uncompressedSize) <= 0) {
|
|
51676
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local resource ZIP entry size is invalid: ${entry.name}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
51677
|
+
}
|
|
51678
|
+
return {
|
|
51679
|
+
compressedSize: Number(compressedSize),
|
|
51680
|
+
uncompressedSize: Number(uncompressedSize),
|
|
51681
|
+
};
|
|
51682
|
+
};
|
|
51683
|
+
function assertProtocolV2FirmwareTargetsSupported(deviceType, params, hasExplicitTargetSelection = false) {
|
|
51121
51684
|
var _a;
|
|
51122
|
-
const
|
|
51123
|
-
|
|
51685
|
+
const requestedTargets = new Set((_a = params.targetsToUpdate) !== null && _a !== void 0 ? _a : []);
|
|
51686
|
+
const unsupportedTargets = new Set(Array.from(requestedTargets).filter(target => PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS.has(target)));
|
|
51687
|
+
if (params.se03Binary && (!hasExplicitTargetSelection || requestedTargets.has('se03'))) {
|
|
51124
51688
|
unsupportedTargets.add('se03');
|
|
51125
|
-
|
|
51689
|
+
}
|
|
51690
|
+
if (params.se04Binary && (!hasExplicitTargetSelection || requestedTargets.has('se04'))) {
|
|
51126
51691
|
unsupportedTargets.add('se04');
|
|
51692
|
+
}
|
|
51127
51693
|
if (!unsupportedTargets.size || deviceType === hdShared.EDeviceType.Pro2)
|
|
51128
51694
|
return;
|
|
51129
51695
|
const targetList = Array.from(unsupportedTargets).join(', ');
|
|
@@ -51187,6 +51753,14 @@ const PROTOCOL_V2_REMOTE_COMPONENT_TARGETS = {
|
|
|
51187
51753
|
},
|
|
51188
51754
|
};
|
|
51189
51755
|
const PROTOCOL_V2_FIRMWARE_STAGING_PATHS = new Set(Object.values(PROTOCOL_V2_REMOTE_COMPONENT_TARGETS).map(target => `${PROTOCOL_V2_FIRMWARE_STAGING_VOLUME}${target.fileName}`));
|
|
51756
|
+
const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH = 'vol0:/loaders/bootloader/boot_resource.okpkg';
|
|
51757
|
+
const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_STAGING_PATH = `${PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH}.staging`;
|
|
51758
|
+
const isProtocolV2BootResourcePackagePath = (devicePath) => typeof devicePath === 'string' &&
|
|
51759
|
+
devicePath.replace(/^vol0:(?!\/)/i, 'vol0:/').toLowerCase() ===
|
|
51760
|
+
PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH;
|
|
51761
|
+
const resolveProtocolV2ResourceWritePath = (devicePath) => isProtocolV2BootResourcePackagePath(devicePath)
|
|
51762
|
+
? PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_STAGING_PATH
|
|
51763
|
+
: devicePath;
|
|
51190
51764
|
const PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID = new Map([
|
|
51191
51765
|
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER, 'boot'],
|
|
51192
51766
|
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P1, 'app_v1'],
|
|
@@ -51197,6 +51771,10 @@ const PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID = new Map([
|
|
|
51197
51771
|
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE03, 'se03'],
|
|
51198
51772
|
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE04, 'se04'],
|
|
51199
51773
|
]);
|
|
51774
|
+
const PROTOCOL_V2_INSTALL_TARGET_BY_UPDATE_TARGET = new Map(Object.values(PROTOCOL_V2_REMOTE_COMPONENT_TARGETS).map(target => [
|
|
51775
|
+
PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(target.targetId),
|
|
51776
|
+
target,
|
|
51777
|
+
]));
|
|
51200
51778
|
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
51779
|
const PROTOCOL_V2_TARGET_ID_BY_DECODED_NAME = new Map(Object.entries(ProtocolV2FirmwareTargetType).map(([key, value]) => [key, value]));
|
|
51202
51780
|
const PROTOCOL_V2_TARGET_STATUS_BY_DECODED_NAME = new Map([
|
|
@@ -51352,8 +51930,10 @@ const assertProtocolV2ReconnectIdentity = (expectedSerialNumber, actualSerialNum
|
|
|
51352
51930
|
class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
51353
51931
|
constructor() {
|
|
51354
51932
|
super(...arguments);
|
|
51933
|
+
this.protocolV2HasExplicitTargetSelection = false;
|
|
51355
51934
|
this.protocolV2PreparedSources = [];
|
|
51356
51935
|
this.protocolV2ExecutionInLoader = false;
|
|
51936
|
+
this.protocolV2BootResourceStagingSafe = false;
|
|
51357
51937
|
this.protocolV2CompletedTargetVersions = new Map();
|
|
51358
51938
|
this.protocolV2FinalStatusVerified = false;
|
|
51359
51939
|
}
|
|
@@ -51361,13 +51941,14 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51361
51941
|
return ['V2'];
|
|
51362
51942
|
}
|
|
51363
51943
|
init() {
|
|
51364
|
-
var _a, _b
|
|
51944
|
+
var _a, _b;
|
|
51365
51945
|
this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
|
|
51366
51946
|
this.requireDeviceMode = [];
|
|
51367
51947
|
this.unlockPolicy = 'unlock-before-run';
|
|
51368
51948
|
this.useDevicePassphraseState = false;
|
|
51369
51949
|
this.skipForceUpdateCheck = true;
|
|
51370
51950
|
const { payload } = this;
|
|
51951
|
+
this.protocolV2HasExplicitTargetSelection = payload.targetsToUpdate !== undefined;
|
|
51371
51952
|
if (typeof payload.retryCount !== 'number') {
|
|
51372
51953
|
payload.retryCount = PROTOCOL_V2_CONNECT_RETRY_COUNT;
|
|
51373
51954
|
}
|
|
@@ -51392,54 +51973,85 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51392
51973
|
{ name: 'se02Binary', type: 'buffer' },
|
|
51393
51974
|
{ name: 'se03Binary', type: 'buffer' },
|
|
51394
51975
|
{ name: 'se04Binary', type: 'buffer' },
|
|
51976
|
+
{ name: 'resourceArchiveBinary', type: 'buffer' },
|
|
51395
51977
|
{ name: 'firmwareType', type: 'string' },
|
|
51396
51978
|
{ name: 'targetsToUpdate', type: 'array', allowEmpty: true },
|
|
51397
51979
|
{ name: 'platform', type: 'string' },
|
|
51398
51980
|
{ name: 'expectedDeviceId', type: 'string' },
|
|
51399
|
-
{ name: 'resourceFiles', type: 'array', allowEmpty: true },
|
|
51400
51981
|
]);
|
|
51401
51982
|
if (payload.expectedDeviceId !== undefined &&
|
|
51402
51983
|
(payload.expectedDeviceId.length === 0 || payload.expectedDeviceId.length > 160)) {
|
|
51403
51984
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Protocol V2 expected device identity is invalid');
|
|
51404
51985
|
}
|
|
51405
|
-
const
|
|
51406
|
-
?
|
|
51986
|
+
const preparedPlan = payload.preparedPlan
|
|
51987
|
+
? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
|
|
51407
51988
|
: undefined;
|
|
51408
|
-
|
|
51989
|
+
const hasLocalArtifacts = [
|
|
51990
|
+
payload.bootloaderBinary,
|
|
51991
|
+
payload.romloaderBinary,
|
|
51992
|
+
payload.applicationP1Binary,
|
|
51993
|
+
payload.applicationP2Binary,
|
|
51994
|
+
payload.coprocessorBinary,
|
|
51995
|
+
payload.se01Binary,
|
|
51996
|
+
payload.se02Binary,
|
|
51997
|
+
payload.se03Binary,
|
|
51998
|
+
payload.se04Binary,
|
|
51999
|
+
payload.resourceArchiveBinary,
|
|
52000
|
+
].some(Boolean);
|
|
52001
|
+
if (preparedPlan && hasLocalArtifacts) {
|
|
52002
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Prepared firmware plans cannot be combined with legacy or local firmware inputs');
|
|
52003
|
+
}
|
|
52004
|
+
let { artifactReader } = payload;
|
|
52005
|
+
if (preparedPlan) {
|
|
52006
|
+
artifactReader = resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration, preparedPlan.preparedPlanDigest).artifactReader;
|
|
52007
|
+
}
|
|
52008
|
+
else if (payload.hostBindingGeneration !== undefined) {
|
|
52009
|
+
artifactReader = resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration).artifactReader;
|
|
52010
|
+
}
|
|
52011
|
+
if (preparedPlan) {
|
|
51409
52012
|
assertFirmwareUpdatePreparedPlanBinding({
|
|
51410
|
-
preparedPlan
|
|
52013
|
+
preparedPlan,
|
|
51411
52014
|
executor: 'v4',
|
|
51412
52015
|
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
|
-
],
|
|
52016
|
+
scopeTargets: [],
|
|
52017
|
+
bindings: [],
|
|
51439
52018
|
});
|
|
52019
|
+
if (payload.componentArtifacts) {
|
|
52020
|
+
const componentBindings = Object.entries(payload.componentArtifacts).flatMap(([target, artifact]) => artifact
|
|
52021
|
+
? [
|
|
52022
|
+
{
|
|
52023
|
+
target: target,
|
|
52024
|
+
artifact: artifact,
|
|
52025
|
+
},
|
|
52026
|
+
]
|
|
52027
|
+
: []);
|
|
52028
|
+
assertFirmwareUpdatePreparedPlanBinding({
|
|
52029
|
+
preparedPlan,
|
|
52030
|
+
executor: 'v4',
|
|
52031
|
+
platform: payload.platform,
|
|
52032
|
+
scopeTargets: componentBindings.map(binding => binding.target),
|
|
52033
|
+
bindings: componentBindings,
|
|
52034
|
+
});
|
|
52035
|
+
}
|
|
52036
|
+
}
|
|
52037
|
+
const preparedExpectedTargetVersions = preparedPlan === null || preparedPlan === void 0 ? void 0 : preparedPlan.artifacts.reduce((result, artifact) => {
|
|
52038
|
+
if (artifact.role === 'component' &&
|
|
52039
|
+
artifact.target !== 'resource' &&
|
|
52040
|
+
artifact.targetVersion &&
|
|
52041
|
+
PROTOCOL_V2_INSTALL_TARGET_BY_UPDATE_TARGET.has(artifact.target)) {
|
|
52042
|
+
result[artifact.target] = artifact.targetVersion;
|
|
52043
|
+
}
|
|
52044
|
+
return result;
|
|
52045
|
+
}, {});
|
|
52046
|
+
const localTargetsToUpdate = (_a = payload.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.map((target) => target === 'boot_resources' ? 'resource' : target);
|
|
52047
|
+
if (payload.resourceArchiveBinary &&
|
|
52048
|
+
localTargetsToUpdate &&
|
|
52049
|
+
!localTargetsToUpdate.includes('resource')) {
|
|
52050
|
+
localTargetsToUpdate.push('resource');
|
|
51440
52051
|
}
|
|
52052
|
+
const resolvedLocalTargetsToUpdate = localTargetsToUpdate !== null && localTargetsToUpdate !== void 0 ? localTargetsToUpdate : (payload.resourceArchiveBinary ? ['resource'] : undefined);
|
|
51441
52053
|
this.params = {
|
|
51442
|
-
preparedPlan
|
|
52054
|
+
preparedPlan,
|
|
51443
52055
|
chunkSize: payload.chunkSize,
|
|
51444
52056
|
forcedUpdateRes: payload.forcedUpdateRes,
|
|
51445
52057
|
bootloaderBinary: payload.bootloaderBinary,
|
|
@@ -51451,15 +52063,18 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51451
52063
|
se02Binary: payload.se02Binary,
|
|
51452
52064
|
se03Binary: payload.se03Binary,
|
|
51453
52065
|
se04Binary: payload.se04Binary,
|
|
51454
|
-
|
|
51455
|
-
firmwareType: payload.firmwareType,
|
|
51456
|
-
targetsToUpdate:
|
|
51457
|
-
|
|
52066
|
+
resourceArchiveBinary: payload.resourceArchiveBinary,
|
|
52067
|
+
firmwareType: (_b = preparedPlan === null || preparedPlan === void 0 ? void 0 : preparedPlan.firmwareType) !== null && _b !== void 0 ? _b : payload.firmwareType,
|
|
52068
|
+
targetsToUpdate: preparedPlan
|
|
52069
|
+
? [...preparedPlan.targetsToUpdate]
|
|
52070
|
+
: resolvedLocalTargetsToUpdate,
|
|
52071
|
+
expectedTargetVersions: preparedPlan
|
|
52072
|
+
? preparedExpectedTargetVersions
|
|
52073
|
+
: payload.expectedTargetVersions,
|
|
51458
52074
|
platform: payload.platform,
|
|
51459
52075
|
expectedDeviceId: payload.expectedDeviceId,
|
|
51460
|
-
artifactReader
|
|
51461
|
-
componentArtifacts: payload.componentArtifacts,
|
|
51462
|
-
resourceBundleArtifacts: payload.resourceBundleArtifacts,
|
|
52076
|
+
artifactReader,
|
|
52077
|
+
componentArtifacts: preparedPlan ? undefined : payload.componentArtifacts,
|
|
51463
52078
|
};
|
|
51464
52079
|
}
|
|
51465
52080
|
getProtocolV2FirmwareChunkSize(direction, filePath) {
|
|
@@ -51490,7 +52105,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51490
52105
|
});
|
|
51491
52106
|
}
|
|
51492
52107
|
runProtocolV2() {
|
|
51493
|
-
var _a, _b, _c, _d, _e;
|
|
52108
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
51494
52109
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51495
52110
|
yield this.captureProtocolV2PhysicalIdentity();
|
|
51496
52111
|
const deviceFeatures = yield this.getProtocolV2DeviceFeatures();
|
|
@@ -51498,89 +52113,96 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51498
52113
|
const capabilityDeviceType = currentDeviceType === hdShared.EDeviceType.Pro2 || currentDeviceType === hdShared.EDeviceType.Neo
|
|
51499
52114
|
? currentDeviceType
|
|
51500
52115
|
: getDeviceType(deviceFeatures);
|
|
51501
|
-
assertProtocolV2FirmwareTargetsSupported(capabilityDeviceType, this.params);
|
|
52116
|
+
assertProtocolV2FirmwareTargetsSupported(capabilityDeviceType, this.params, this.protocolV2HasExplicitTargetSelection);
|
|
51502
52117
|
const deviceFirmwareType = getFirmwareType(deviceFeatures);
|
|
51503
52118
|
const firmwareType = (_a = this.params.firmwareType) !== null && _a !== void 0 ? _a : deviceFirmwareType;
|
|
51504
52119
|
this.validateExpectedTargetVersions();
|
|
51505
|
-
if (
|
|
51506
|
-
|
|
52120
|
+
if (!this.params.preparedPlan &&
|
|
52121
|
+
this.params.resourceArchiveBinary &&
|
|
52122
|
+
((_b = this.params.targetsToUpdate) === null || _b === void 0 ? void 0 : _b.includes('resource'))) {
|
|
52123
|
+
const localMemoryHost = yield this.prepareProtocolV2LocalMemoryHost({
|
|
52124
|
+
features: deviceFeatures,
|
|
52125
|
+
firmwareType,
|
|
52126
|
+
});
|
|
52127
|
+
try {
|
|
52128
|
+
return yield this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType);
|
|
52129
|
+
}
|
|
52130
|
+
finally {
|
|
52131
|
+
localMemoryHost.release();
|
|
52132
|
+
}
|
|
52133
|
+
}
|
|
52134
|
+
const hasPreparedComponentArtifacts = Object.values((_c = this.params.componentArtifacts) !== null && _c !== void 0 ? _c : {}).some(Boolean);
|
|
52135
|
+
if (this.params.preparedPlan || hasPreparedComponentArtifacts) {
|
|
51507
52136
|
return this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType);
|
|
51508
52137
|
}
|
|
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);
|
|
52138
|
+
const wantsResources = !!((_d = this.params.targetsToUpdate) === null || _d === void 0 ? void 0 : _d.includes('resource'));
|
|
51514
52139
|
let fwBinaryMap = [];
|
|
51515
52140
|
let bootloaderBinary = null;
|
|
51516
52141
|
let installItems;
|
|
51517
|
-
let resourceBundles;
|
|
51518
52142
|
try {
|
|
51519
52143
|
this.postTipMessage(exports.FirmwareUpdateTipMessage.StartDownloadFirmware);
|
|
51520
|
-
resourceBundles = this.prepareExplicitProtocolV2ResourceFiles();
|
|
51521
52144
|
fwBinaryMap = this.collectExplicitTargetBinaries();
|
|
51522
52145
|
bootloaderBinary = this.prepareBootloaderBinary();
|
|
51523
|
-
const
|
|
51524
|
-
|
|
52146
|
+
const explicitInstallItems = this.buildProtocolV2InstallItems({
|
|
52147
|
+
bootloaderBinary,
|
|
52148
|
+
fwBinaryMap,
|
|
52149
|
+
});
|
|
52150
|
+
const missingFirmwareTargets = this.getMissingProtocolV2FirmwareTargets(explicitInstallItems);
|
|
52151
|
+
const needsRemoteFirmware = ((_e = this.params.targetsToUpdate) === null || _e === void 0 ? void 0 : _e.length)
|
|
52152
|
+
? missingFirmwareTargets.length > 0
|
|
52153
|
+
: explicitInstallItems.length === 0;
|
|
52154
|
+
if (wantsResources) {
|
|
52155
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource archive must be provided through a local or external PreparedPlan', {
|
|
52156
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
52157
|
+
});
|
|
52158
|
+
}
|
|
52159
|
+
if (needsRemoteFirmware &&
|
|
51525
52160
|
(this.params.artifactReader ||
|
|
51526
52161
|
DataManager.getSettings('firmwareManifestMode') === 'external-only')) {
|
|
51527
52162
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 firmware artifacts must be prepared by the external firmware host', {
|
|
51528
52163
|
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
51529
52164
|
});
|
|
51530
52165
|
}
|
|
51531
|
-
if (needsRemoteFirmware
|
|
51532
|
-
yield DataManager.forceReloadData(
|
|
51533
|
-
requireResources: needsRemoteResources || needsRemoteBootResources,
|
|
51534
|
-
});
|
|
52166
|
+
if (needsRemoteFirmware) {
|
|
52167
|
+
yield DataManager.forceReloadData();
|
|
51535
52168
|
}
|
|
51536
52169
|
if (needsRemoteFirmware) {
|
|
51537
|
-
const remoteBinaries = yield this.prepareRemoteProtocolV2Binaries(firmwareType, deviceFeatures);
|
|
52170
|
+
const remoteBinaries = yield this.prepareRemoteProtocolV2Binaries(firmwareType, deviceFeatures, explicitInstallItems);
|
|
51538
52171
|
bootloaderBinary = remoteBinaries.bootloaderBinary;
|
|
51539
52172
|
fwBinaryMap = remoteBinaries.fwBinaryMap;
|
|
51540
52173
|
installItems = remoteBinaries.installItems;
|
|
51541
52174
|
}
|
|
51542
|
-
|
|
51543
|
-
|
|
51544
|
-
|
|
51545
|
-
|
|
51546
|
-
|
|
51547
|
-
|
|
52175
|
+
else {
|
|
52176
|
+
const selectedInstallItems = this.filterProtocolV2LocalInstallItems(explicitInstallItems);
|
|
52177
|
+
bootloaderBinary =
|
|
52178
|
+
(_g = (_f = selectedInstallItems.find(item => item.kind === 'bootloader')) === null || _f === void 0 ? void 0 : _f.binary) !== null && _g !== void 0 ? _g : null;
|
|
52179
|
+
fwBinaryMap = selectedInstallItems
|
|
52180
|
+
.filter(item => item.kind === 'firmware')
|
|
52181
|
+
.map(item => ({
|
|
52182
|
+
fileName: item.fileName,
|
|
52183
|
+
binary: item.binary,
|
|
52184
|
+
targetId: item.targetId,
|
|
52185
|
+
}));
|
|
51548
52186
|
}
|
|
52187
|
+
this.postTipMessage(exports.FirmwareUpdateTipMessage.FinishDownloadFirmware);
|
|
51549
52188
|
}
|
|
51550
52189
|
catch (err) {
|
|
52190
|
+
if (typeof err === 'object' &&
|
|
52191
|
+
err !== null &&
|
|
52192
|
+
'params' in err &&
|
|
52193
|
+
((_h = err.params) === null || _h === void 0 ? void 0 : _h.firmwareUpdateCode) === 'FirmwareArtifactsNotPrepared') {
|
|
52194
|
+
throw err;
|
|
52195
|
+
}
|
|
51551
52196
|
if (err instanceof hdShared.HardwareError && err.errorCode === hdShared.HardwareErrorCode.NetworkError) {
|
|
51552
52197
|
throw err;
|
|
51553
52198
|
}
|
|
51554
52199
|
throw normalizeFirmwarePreparationError(err);
|
|
51555
52200
|
}
|
|
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) {
|
|
52201
|
+
if (!bootloaderBinary && fwBinaryMap.length === 0 && !(installItems === null || installItems === void 0 ? void 0 : installItems.length)) {
|
|
51561
52202
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, 'No firmware to update');
|
|
51562
52203
|
}
|
|
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)));
|
|
52204
|
+
return this.executeProtocolV2Update(Object.assign({ fwBinaryMap,
|
|
52205
|
+
bootloaderBinary }, (installItems ? { installItems } : undefined)));
|
|
51584
52206
|
});
|
|
51585
52207
|
}
|
|
51586
52208
|
openProtocolV2PreparedSource(artifact) {
|
|
@@ -51617,6 +52239,34 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51617
52239
|
prepareProtocolV2InstallSources(firmwareType, features) {
|
|
51618
52240
|
var _a, _b;
|
|
51619
52241
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52242
|
+
if (this.params.preparedPlan) {
|
|
52243
|
+
const requestedTargets = new Set(this.params.preparedPlan.targetsToUpdate.filter((target) => target !== 'resource'));
|
|
52244
|
+
const installSources = [];
|
|
52245
|
+
const preparedTargets = new Set();
|
|
52246
|
+
for (const artifact of this.params.preparedPlan.artifacts) {
|
|
52247
|
+
if (artifact.target !== 'resource') {
|
|
52248
|
+
const target = artifact.target;
|
|
52249
|
+
const installTarget = PROTOCOL_V2_INSTALL_TARGET_BY_UPDATE_TARGET.get(target);
|
|
52250
|
+
if (!requestedTargets.has(target) ||
|
|
52251
|
+
artifact.role !== 'component' ||
|
|
52252
|
+
artifact.container !== 'raw' ||
|
|
52253
|
+
!installTarget ||
|
|
52254
|
+
preparedTargets.has(target)) {
|
|
52255
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 prepared component artifact is invalid: ${artifact.artifactId}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52256
|
+
}
|
|
52257
|
+
installSources.push(Object.assign(Object.assign({}, installTarget), { source: yield this.openProtocolV2PreparedSource(artifact.artifact) }));
|
|
52258
|
+
preparedTargets.add(target);
|
|
52259
|
+
}
|
|
52260
|
+
}
|
|
52261
|
+
const missingTarget = Array.from(requestedTargets).find(target => !preparedTargets.has(target));
|
|
52262
|
+
if (missingTarget) {
|
|
52263
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 ${missingTarget} artifact is not prepared`, {
|
|
52264
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
52265
|
+
artifactName: missingTarget,
|
|
52266
|
+
});
|
|
52267
|
+
}
|
|
52268
|
+
return installSources;
|
|
52269
|
+
}
|
|
51620
52270
|
const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
|
|
51621
52271
|
if (!release) {
|
|
51622
52272
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 firmware release is unavailable');
|
|
@@ -51647,39 +52297,285 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51647
52297
|
return installSources;
|
|
51648
52298
|
});
|
|
51649
52299
|
}
|
|
51650
|
-
|
|
51651
|
-
var _a, _b
|
|
52300
|
+
prepareProtocolV2LocalMemoryHost({ features, firmwareType, }) {
|
|
52301
|
+
var _a, _b;
|
|
51652
52302
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51653
|
-
const
|
|
51654
|
-
|
|
52303
|
+
const availableInstallItems = this.buildProtocolV2InstallItems({
|
|
52304
|
+
bootloaderBinary: this.prepareBootloaderBinary(),
|
|
52305
|
+
fwBinaryMap: this.collectExplicitTargetBinaries(),
|
|
52306
|
+
});
|
|
52307
|
+
const requestedComponentTargets = new Set(((_a = this.params.targetsToUpdate) !== null && _a !== void 0 ? _a : []).filter((target) => target !== 'resource' && target !== 'boot_resources'));
|
|
52308
|
+
const localComponentTargets = new Set(availableInstallItems.flatMap(item => {
|
|
52309
|
+
const target = PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(item.targetId);
|
|
52310
|
+
return target ? [target] : [];
|
|
52311
|
+
}));
|
|
52312
|
+
const missingTarget = Array.from(requestedComponentTargets).find(target => !localComponentTargets.has(target));
|
|
52313
|
+
if (missingTarget) {
|
|
52314
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local update has no binary for requested target ${missingTarget}`, {
|
|
52315
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
52316
|
+
artifactName: missingTarget,
|
|
52317
|
+
});
|
|
52318
|
+
}
|
|
52319
|
+
const installItems = this.filterProtocolV2LocalInstallItems(availableInstallItems);
|
|
52320
|
+
const planArtifacts = [];
|
|
52321
|
+
const memoryArtifacts = [];
|
|
52322
|
+
for (const item of installItems) {
|
|
52323
|
+
const target = PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(item.targetId);
|
|
52324
|
+
if (!target || item.binary.byteLength <= 0) {
|
|
52325
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local firmware artifact is invalid: ${item.fileName}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52326
|
+
}
|
|
52327
|
+
const artifactId = `component:${target}`;
|
|
52328
|
+
planArtifacts.push(Object.assign({ artifactId,
|
|
52329
|
+
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])
|
|
52330
|
+
? { targetVersion: this.params.expectedTargetVersions[target] }
|
|
52331
|
+
: {})));
|
|
52332
|
+
memoryArtifacts.push({ artifactId, binary: item.binary });
|
|
52333
|
+
}
|
|
52334
|
+
const resourceArchive = yield this.prepareProtocolV2LocalResourceArchive(this.params.resourceArchiveBinary);
|
|
52335
|
+
const resourceArtifactId = 'resource:archive';
|
|
52336
|
+
planArtifacts.push({
|
|
52337
|
+
artifactId: resourceArtifactId,
|
|
52338
|
+
target: 'resource',
|
|
52339
|
+
container: 'zip',
|
|
52340
|
+
logicalName: 'protocol-v2-local-resource-archive',
|
|
52341
|
+
expectedSize: resourceArchive.binary.byteLength,
|
|
52342
|
+
expectedSha256: bytesToHex(sha256.sha256(new Uint8Array(resourceArchive.binary))),
|
|
52343
|
+
});
|
|
52344
|
+
memoryArtifacts.push({
|
|
52345
|
+
artifactId: resourceArtifactId,
|
|
52346
|
+
binary: resourceArchive.binary,
|
|
52347
|
+
materializedEntries: resourceArchive.materializedEntries,
|
|
52348
|
+
});
|
|
52349
|
+
const plan = buildProtocolV2LocalFirmwareUpdatePlan({
|
|
52350
|
+
features,
|
|
52351
|
+
firmwareType,
|
|
52352
|
+
platform: this.params.platform,
|
|
52353
|
+
artifacts: planArtifacts,
|
|
52354
|
+
});
|
|
52355
|
+
let memoryHost;
|
|
52356
|
+
try {
|
|
52357
|
+
memoryHost = prepareFirmwareUpdateV4MemoryHost({
|
|
52358
|
+
sdk: {
|
|
52359
|
+
prepareFirmwareUpdatePlan,
|
|
52360
|
+
registerFirmwareUpdateHostBinding,
|
|
52361
|
+
unregisterFirmwareUpdateHostBinding,
|
|
52362
|
+
},
|
|
52363
|
+
plan,
|
|
52364
|
+
artifacts: memoryArtifacts,
|
|
52365
|
+
});
|
|
52366
|
+
const preparedPlan = validateFirmwareUpdatePreparedPlan(memoryHost.preparedPlan);
|
|
52367
|
+
assertFirmwareUpdatePreparedPlanBinding({
|
|
52368
|
+
preparedPlan,
|
|
52369
|
+
executor: 'v4',
|
|
52370
|
+
platform: this.params.platform,
|
|
52371
|
+
scopeTargets: [],
|
|
52372
|
+
bindings: [],
|
|
52373
|
+
});
|
|
52374
|
+
assertFirmwareUpdatePreparedPlanDeviceIdentity({
|
|
52375
|
+
preparedPlan,
|
|
52376
|
+
deviceIdentity: this.protocolV2ExpectedSerialNumber,
|
|
52377
|
+
deviceModel: this.getProtocolV2PreparedPlanDeviceModel(features),
|
|
52378
|
+
});
|
|
52379
|
+
const hostBinding = resolveFirmwareUpdateHostBinding(memoryHost.hostBindingGeneration, preparedPlan.preparedPlanDigest);
|
|
52380
|
+
this.params.preparedPlan = preparedPlan;
|
|
52381
|
+
this.params.targetsToUpdate = [...preparedPlan.targetsToUpdate];
|
|
52382
|
+
this.params.artifactReader = hostBinding.artifactReader;
|
|
52383
|
+
this.params.componentArtifacts = undefined;
|
|
52384
|
+
return memoryHost;
|
|
52385
|
+
}
|
|
52386
|
+
catch (error) {
|
|
52387
|
+
memoryHost === null || memoryHost === void 0 ? void 0 : memoryHost.release();
|
|
52388
|
+
throw error;
|
|
52389
|
+
}
|
|
52390
|
+
});
|
|
52391
|
+
}
|
|
52392
|
+
prepareProtocolV2LocalResourceArchive(binary) {
|
|
52393
|
+
var _a;
|
|
52394
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
52395
|
+
if (binary.byteLength <= 0 || binary.byteLength > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
|
|
52396
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP archive size is invalid', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52397
|
+
}
|
|
52398
|
+
let zip;
|
|
52399
|
+
try {
|
|
52400
|
+
zip = yield JSZip__default["default"].loadAsync(binary);
|
|
52401
|
+
}
|
|
52402
|
+
catch (_b) {
|
|
52403
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource ZIP cannot be parsed', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52404
|
+
}
|
|
52405
|
+
const zipEntries = Object.values(zip.files);
|
|
52406
|
+
if (zipEntries.some(entry => entry.unsafeOriginalName && entry.unsafeOriginalName !== entry.name)) {
|
|
52407
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP contains an unsafe entry path', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52408
|
+
}
|
|
52409
|
+
const entries = zipEntries.filter(entry => !entry.dir);
|
|
52410
|
+
if (entries.length === 0 || entries.length > PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT + 1) {
|
|
52411
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP entry set is invalid', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52412
|
+
}
|
|
52413
|
+
let declaredUncompressedSize = 0;
|
|
52414
|
+
let declaredCompressedSize = 0;
|
|
52415
|
+
for (const entry of entries) {
|
|
52416
|
+
const sizes = getProtocolV2ZipEntrySizes(entry);
|
|
52417
|
+
declaredCompressedSize += sizes.compressedSize;
|
|
52418
|
+
declaredUncompressedSize += sizes.uncompressedSize;
|
|
52419
|
+
const entryLimit = entry.name === 'manifest.json'
|
|
52420
|
+
? PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES
|
|
52421
|
+
: PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES;
|
|
52422
|
+
if (sizes.uncompressedSize > entryLimit ||
|
|
52423
|
+
declaredCompressedSize > binary.byteLength ||
|
|
52424
|
+
declaredUncompressedSize >
|
|
52425
|
+
PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES + PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES) {
|
|
52426
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP declared size exceeds the allowed limit', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52427
|
+
}
|
|
52428
|
+
}
|
|
52429
|
+
const manifestEntry = zip.file('manifest.json');
|
|
52430
|
+
if (!manifestEntry) {
|
|
52431
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP has no manifest.json', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52432
|
+
}
|
|
52433
|
+
const manifestBinary = yield manifestEntry.async('arraybuffer');
|
|
52434
|
+
if (manifestBinary.byteLength <= 0 ||
|
|
52435
|
+
manifestBinary.byteLength > PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES) {
|
|
52436
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource manifest size is invalid', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52437
|
+
}
|
|
52438
|
+
let manifestValue;
|
|
52439
|
+
try {
|
|
52440
|
+
manifestValue = JSON.parse(new TextDecoder().decode(manifestBinary));
|
|
52441
|
+
}
|
|
52442
|
+
catch (error) {
|
|
52443
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local resource manifest is invalid: ${String(error)}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52444
|
+
}
|
|
52445
|
+
const manifest = parseProtocolV2ResourceManifest(manifestValue);
|
|
52446
|
+
const selectedFiles = selectProtocolV2ResourceManifestFiles({
|
|
52447
|
+
manifest,
|
|
52448
|
+
targetsToUpdate: (_a = this.params.targetsToUpdate) !== null && _a !== void 0 ? _a : [],
|
|
52449
|
+
});
|
|
52450
|
+
const expectedEntryNames = new Set([
|
|
52451
|
+
'manifest.json',
|
|
52452
|
+
...selectedFiles.map(file => file.archive_path),
|
|
52453
|
+
]);
|
|
52454
|
+
if (entries.length !== expectedEntryNames.size ||
|
|
52455
|
+
entries.some(entry => !expectedEntryNames.has(entry.name))) {
|
|
52456
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP contains an unexpected entry', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52457
|
+
}
|
|
52458
|
+
let totalSize = 0;
|
|
52459
|
+
const materializedEntries = [
|
|
52460
|
+
{ entryName: 'manifest.json', binary: manifestBinary },
|
|
52461
|
+
];
|
|
52462
|
+
for (const file of selectedFiles) {
|
|
52463
|
+
const entry = zip.file(file.archive_path);
|
|
52464
|
+
if (!entry) {
|
|
52465
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local resource ZIP is missing ${file.archive_path}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52466
|
+
}
|
|
52467
|
+
const { uncompressedSize } = getProtocolV2ZipEntrySizes(entry);
|
|
52468
|
+
totalSize += uncompressedSize;
|
|
52469
|
+
if (uncompressedSize !== file.size || totalSize > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
|
|
52470
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local resource file declared size is invalid: ${file.archive_path}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52471
|
+
}
|
|
52472
|
+
const fileBinary = yield entry.async('arraybuffer');
|
|
52473
|
+
const digest = bytesToHex(sha256.sha256(new Uint8Array(fileBinary)));
|
|
52474
|
+
if (fileBinary.byteLength !== file.size || digest !== file.sha256.toLowerCase()) {
|
|
52475
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local resource file does not match manifest: ${file.archive_path}`, { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
|
|
52476
|
+
}
|
|
52477
|
+
materializedEntries.push({ entryName: file.archive_path, binary: fileBinary });
|
|
52478
|
+
}
|
|
52479
|
+
return { binary, materializedEntries };
|
|
52480
|
+
});
|
|
52481
|
+
}
|
|
52482
|
+
prepareProtocolV2ResourceSources() {
|
|
52483
|
+
var _a, _b;
|
|
52484
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
52485
|
+
const resourceRequested = (_b = (_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.includes('resource')) !== null && _b !== void 0 ? _b : false;
|
|
51655
52486
|
if (!resourceRequested) {
|
|
51656
52487
|
return [];
|
|
51657
52488
|
}
|
|
51658
|
-
const
|
|
51659
|
-
|
|
51660
|
-
|
|
52489
|
+
const archiveSources = yield this.prepareProtocolV2ResourceArchiveSources();
|
|
52490
|
+
if (archiveSources) {
|
|
52491
|
+
return archiveSources;
|
|
52492
|
+
}
|
|
52493
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource archive is not prepared', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52494
|
+
});
|
|
52495
|
+
}
|
|
52496
|
+
prepareProtocolV2ResourceArchiveSources() {
|
|
52497
|
+
var _a, _b, _c, _d;
|
|
52498
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
52499
|
+
const archiveArtifacts = (_b = (_a = this.params.preparedPlan) === null || _a === void 0 ? void 0 : _a.artifacts.filter(artifact => artifact.role === 'resourceBundle' &&
|
|
52500
|
+
artifact.target === 'resource' &&
|
|
52501
|
+
artifact.container === 'zip')) !== null && _b !== void 0 ? _b : [];
|
|
52502
|
+
if (archiveArtifacts.length === 0) {
|
|
52503
|
+
return undefined;
|
|
52504
|
+
}
|
|
52505
|
+
if (archiveArtifacts.length !== 1) {
|
|
52506
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared plan must contain exactly one resource archive', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52507
|
+
}
|
|
52508
|
+
const archiveArtifact = archiveArtifacts[0];
|
|
52509
|
+
const archiveSource = yield this.openProtocolV2PreparedSource(archiveArtifact.artifact);
|
|
52510
|
+
if (archiveSource.size > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
|
|
52511
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive exceeds the total size limit', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52512
|
+
}
|
|
52513
|
+
let archiveBinary;
|
|
52514
|
+
try {
|
|
52515
|
+
archiveBinary = yield readFirmwareByteSourceFully(archiveSource);
|
|
52516
|
+
}
|
|
52517
|
+
finally {
|
|
52518
|
+
yield archiveSource.close();
|
|
52519
|
+
}
|
|
52520
|
+
const archiveDigest = bytesToHex(sha256.sha256(new Uint8Array(archiveBinary)));
|
|
52521
|
+
if (archiveDigest !== archiveArtifact.artifact.sha256.toLowerCase()) {
|
|
52522
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive does not match its approved receipt', { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
|
|
52523
|
+
}
|
|
52524
|
+
const verifiedArchive = yield this.prepareProtocolV2LocalResourceArchive(archiveBinary);
|
|
52525
|
+
const entries = (_c = archiveArtifact.materializedEntries) !== null && _c !== void 0 ? _c : [];
|
|
52526
|
+
const entriesByName = new Map(entries.map(entry => [entry.entryName, entry]));
|
|
52527
|
+
if (entries.length !== verifiedArchive.materializedEntries.length ||
|
|
52528
|
+
verifiedArchive.materializedEntries.some(entry => {
|
|
52529
|
+
const preparedEntry = entriesByName.get(entry.entryName);
|
|
52530
|
+
const digest = bytesToHex(sha256.sha256(new Uint8Array(entry.binary)));
|
|
52531
|
+
return (!preparedEntry ||
|
|
52532
|
+
preparedEntry.artifact.size !== entry.binary.byteLength ||
|
|
52533
|
+
preparedEntry.artifact.sha256.toLowerCase() !== digest);
|
|
52534
|
+
})) {
|
|
52535
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource entries do not match the approved archive', { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
|
|
52536
|
+
}
|
|
52537
|
+
const verifiedEntriesByName = new Map(verifiedArchive.materializedEntries.map(entry => [entry.entryName, entry.binary]));
|
|
52538
|
+
const manifestBinary = verifiedEntriesByName.get('manifest.json');
|
|
52539
|
+
if (!manifestBinary) {
|
|
52540
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive has no valid manifest.json', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52541
|
+
}
|
|
52542
|
+
let manifestValue;
|
|
52543
|
+
try {
|
|
52544
|
+
manifestValue = JSON.parse(new TextDecoder().decode(manifestBinary));
|
|
52545
|
+
}
|
|
52546
|
+
catch (error) {
|
|
52547
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 prepared resource manifest is invalid: ${String(error)}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52548
|
+
}
|
|
52549
|
+
const manifest = parseProtocolV2ResourceManifest(manifestValue);
|
|
52550
|
+
const selectedFiles = selectProtocolV2ResourceManifestFiles({
|
|
52551
|
+
manifest,
|
|
52552
|
+
targetsToUpdate: (_d = this.params.targetsToUpdate) !== null && _d !== void 0 ? _d : [],
|
|
52553
|
+
});
|
|
52554
|
+
if (selectedFiles.length > PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT) {
|
|
52555
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive contains too many files', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52556
|
+
}
|
|
52557
|
+
let totalSize = 0;
|
|
51661
52558
|
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
|
-
});
|
|
52559
|
+
for (const [index, file] of selectedFiles.entries()) {
|
|
52560
|
+
const binary = verifiedEntriesByName.get(file.archive_path);
|
|
52561
|
+
if (!binary || binary.byteLength !== file.size) {
|
|
52562
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 prepared resource file does not match manifest: ${file.archive_path}`, { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
|
|
51669
52563
|
}
|
|
51670
|
-
|
|
51671
|
-
|
|
51672
|
-
|
|
51673
|
-
|
|
51674
|
-
|
|
51675
|
-
|
|
51676
|
-
|
|
51677
|
-
|
|
51678
|
-
}
|
|
51679
|
-
|
|
51680
|
-
|
|
51681
|
-
|
|
51682
|
-
|
|
52564
|
+
totalSize += binary.byteLength;
|
|
52565
|
+
if (totalSize > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
|
|
52566
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive exceeds the total size limit', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
52567
|
+
}
|
|
52568
|
+
const source = yield this.openProtocolV2MemorySource(binary);
|
|
52569
|
+
const header = source.size >= PROTOCOL_V2_OKPP_HEADER_SIZE
|
|
52570
|
+
? parseProtocolV2OkppHeader(new Uint8Array(yield source.readAt(0, PROTOCOL_V2_OKPP_HEADER_SIZE)))
|
|
52571
|
+
: null;
|
|
52572
|
+
sources.push(Object.assign({ name: file.original_name || `resource-${index}`, source, devicePath: file.device_path }, (header
|
|
52573
|
+
? {
|
|
52574
|
+
version: header.version,
|
|
52575
|
+
payloadHash: header.payloadHash,
|
|
52576
|
+
headerHash: header.headerHash,
|
|
52577
|
+
}
|
|
52578
|
+
: {})));
|
|
51683
52579
|
}
|
|
51684
52580
|
return sources;
|
|
51685
52581
|
});
|
|
@@ -51689,7 +52585,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51689
52585
|
try {
|
|
51690
52586
|
this.postTipMessage(exports.FirmwareUpdateTipMessage.StartDownloadFirmware);
|
|
51691
52587
|
const installSources = yield this.prepareProtocolV2InstallSources(firmwareType, features);
|
|
51692
|
-
const resourceSources = yield this.prepareProtocolV2ResourceSources(
|
|
52588
|
+
const resourceSources = yield this.prepareProtocolV2ResourceSources();
|
|
51693
52589
|
if (installSources.length === 0 && resourceSources.length === 0) {
|
|
51694
52590
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, 'No firmware to update');
|
|
51695
52591
|
}
|
|
@@ -51773,15 +52669,15 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51773
52669
|
}
|
|
51774
52670
|
}
|
|
51775
52671
|
getProtocolV2RequestedTargets() {
|
|
51776
|
-
var _a, _b, _c
|
|
52672
|
+
var _a, _b, _c;
|
|
51777
52673
|
if ((_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.length) {
|
|
51778
52674
|
return [...new Set(this.params.targetsToUpdate)];
|
|
51779
52675
|
}
|
|
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');
|
|
52676
|
+
if ((_b = this.params.preparedPlan) === null || _b === void 0 ? void 0 : _b.targetsToUpdate.length) {
|
|
52677
|
+
return [...new Set(this.params.preparedPlan.targetsToUpdate)];
|
|
51784
52678
|
}
|
|
52679
|
+
const targets = new Set();
|
|
52680
|
+
Object.keys((_c = this.params.componentArtifacts) !== null && _c !== void 0 ? _c : {}).forEach(target => targets.add(target));
|
|
51785
52681
|
if (this.params.bootloaderBinary)
|
|
51786
52682
|
targets.add('boot');
|
|
51787
52683
|
if (this.params.applicationP1Binary)
|
|
@@ -51818,8 +52714,26 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51818
52714
|
const serialNumber = (_b = (_a = deviceInfo.hw) === null || _a === void 0 ? void 0 : _a.serial_no) === null || _b === void 0 ? void 0 : _b.trim();
|
|
51819
52715
|
return serialNumber || undefined;
|
|
51820
52716
|
}
|
|
52717
|
+
getProtocolV2PreparedPlanDeviceModel(features) {
|
|
52718
|
+
const currentDeviceType = this.device.getCurrentDeviceType();
|
|
52719
|
+
const featureDeviceType = features ? getDeviceType(features) : undefined;
|
|
52720
|
+
const deviceType = currentDeviceType === hdShared.EDeviceType.Pro2 || currentDeviceType === hdShared.EDeviceType.Neo
|
|
52721
|
+
? currentDeviceType
|
|
52722
|
+
: featureDeviceType;
|
|
52723
|
+
return deviceType === hdShared.EDeviceType.Pro2 || deviceType === hdShared.EDeviceType.Neo
|
|
52724
|
+
? String(deviceType)
|
|
52725
|
+
: undefined;
|
|
52726
|
+
}
|
|
52727
|
+
getProtocolV2ConnectionRoute() {
|
|
52728
|
+
var _a, _b, _c, _d, _e;
|
|
52729
|
+
const descriptor = this.device.originalDescriptor;
|
|
52730
|
+
return (((_a = descriptor === null || descriptor === void 0 ? void 0 : descriptor.path) === null || _a === void 0 ? void 0 : _a.trim()) ||
|
|
52731
|
+
((_d = (_c = (_b = this.device).getConnectId) === null || _c === void 0 ? void 0 : _c.call(_b)) === null || _d === void 0 ? void 0 : _d.trim()) ||
|
|
52732
|
+
((_e = descriptor === null || descriptor === void 0 ? void 0 : descriptor.id) === null || _e === void 0 ? void 0 : _e.trim()) ||
|
|
52733
|
+
undefined);
|
|
52734
|
+
}
|
|
51821
52735
|
assertProtocolV2DeviceInfoIdentity(deviceInfo) {
|
|
51822
|
-
assertProtocolV2ReconnectIdentity(this.protocolV2ExpectedSerialNumber, this.getProtocolV2SerialNumber(deviceInfo), this.protocolV2ExpectedPath, this.
|
|
52736
|
+
assertProtocolV2ReconnectIdentity(this.protocolV2ExpectedSerialNumber, this.getProtocolV2SerialNumber(deviceInfo), this.protocolV2ExpectedPath, this.getProtocolV2ConnectionRoute());
|
|
51823
52737
|
}
|
|
51824
52738
|
getProtocolV2DeviceInfoTimeout() {
|
|
51825
52739
|
var _a;
|
|
@@ -51836,19 +52750,20 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51836
52750
|
});
|
|
51837
52751
|
}
|
|
51838
52752
|
captureProtocolV2PhysicalIdentity() {
|
|
51839
|
-
var _a, _b, _c
|
|
52753
|
+
var _a, _b, _c;
|
|
51840
52754
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51841
52755
|
const deviceInfo = yield this.requestProtocolV2PhysicalIdentity();
|
|
51842
52756
|
const serialNumber = this.getProtocolV2SerialNumber(deviceInfo);
|
|
51843
|
-
const path =
|
|
51844
|
-
if ((
|
|
52757
|
+
const path = this.getProtocolV2ConnectionRoute();
|
|
52758
|
+
if ((_a = this.params) === null || _a === void 0 ? void 0 : _a.preparedPlan) {
|
|
51845
52759
|
assertFirmwareUpdatePreparedPlanDeviceIdentity({
|
|
51846
52760
|
preparedPlan: this.params.preparedPlan,
|
|
51847
52761
|
deviceIdentity: serialNumber,
|
|
52762
|
+
deviceModel: this.getProtocolV2PreparedPlanDeviceModel(this.device.features),
|
|
51848
52763
|
});
|
|
51849
52764
|
}
|
|
51850
|
-
else if ((
|
|
51851
|
-
assertProtocolV2ReconnectIdentity((
|
|
52765
|
+
else if ((_b = this.params) === null || _b === void 0 ? void 0 : _b.expectedDeviceId) {
|
|
52766
|
+
assertProtocolV2ReconnectIdentity((_c = this.params) === null || _c === void 0 ? void 0 : _c.expectedDeviceId, serialNumber);
|
|
51852
52767
|
}
|
|
51853
52768
|
else {
|
|
51854
52769
|
assertProtocolV2ReconnectIdentity(serialNumber, serialNumber, path, path);
|
|
@@ -51868,11 +52783,26 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51868
52783
|
var _a;
|
|
51869
52784
|
return (_a = this.params.bootloaderBinary) !== null && _a !== void 0 ? _a : null;
|
|
51870
52785
|
}
|
|
51871
|
-
|
|
52786
|
+
getMissingProtocolV2FirmwareTargets(installItems) {
|
|
51872
52787
|
var _a;
|
|
51873
|
-
|
|
51874
|
-
|
|
51875
|
-
|
|
52788
|
+
const preparedTargets = new Set(installItems.flatMap(item => {
|
|
52789
|
+
const target = PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(item.targetId);
|
|
52790
|
+
return target ? [target] : [];
|
|
52791
|
+
}));
|
|
52792
|
+
return ((_a = this.params.targetsToUpdate) !== null && _a !== void 0 ? _a : [])
|
|
52793
|
+
.filter((target) => target !== 'resource' && target !== 'boot_resources')
|
|
52794
|
+
.filter(target => !preparedTargets.has(target));
|
|
52795
|
+
}
|
|
52796
|
+
filterProtocolV2LocalInstallItems(installItems) {
|
|
52797
|
+
var _a;
|
|
52798
|
+
if (!this.protocolV2HasExplicitTargetSelection) {
|
|
52799
|
+
return installItems;
|
|
52800
|
+
}
|
|
52801
|
+
const requestedTargets = new Set((_a = this.params.targetsToUpdate) !== null && _a !== void 0 ? _a : []);
|
|
52802
|
+
return installItems.filter(item => {
|
|
52803
|
+
const target = PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(item.targetId);
|
|
52804
|
+
return target !== undefined && requestedTargets.has(target);
|
|
52805
|
+
});
|
|
51876
52806
|
}
|
|
51877
52807
|
buildProtocolV2InstallItems({ bootloaderBinary, fwBinaryMap, }) {
|
|
51878
52808
|
const installItems = [];
|
|
@@ -51921,7 +52851,17 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51921
52851
|
if (!component.url) {
|
|
51922
52852
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Missing Protocol V2 firmware component url: ${key}/${component.target}`);
|
|
51923
52853
|
}
|
|
52854
|
+
const expectedFingerprint = normalizeProtocolV2Hex(component.fingerprint);
|
|
52855
|
+
if (!Number.isSafeInteger(component.expectedSize) ||
|
|
52856
|
+
Number(component.expectedSize) <= 0 ||
|
|
52857
|
+
!expectedFingerprint ||
|
|
52858
|
+
!/^[0-9a-f]{64}$/u.test(expectedFingerprint)) {
|
|
52859
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 firmware component integrity metadata is invalid: ${key}/${component.target}`, { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
52860
|
+
}
|
|
51924
52861
|
const { binary } = yield getSysResourceBinary(component.url);
|
|
52862
|
+
if (binary.byteLength !== component.expectedSize) {
|
|
52863
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 firmware size mismatch: ${key}/${component.target}`, { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
|
|
52864
|
+
}
|
|
51925
52865
|
if (!isProtocolV2FirmwareFingerprintValid(binary, component.fingerprint)) {
|
|
51926
52866
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 firmware fingerprint mismatch: ${key}/${component.target}`);
|
|
51927
52867
|
}
|
|
@@ -51935,7 +52875,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51935
52875
|
return Object.assign(Object.assign({}, target), { binary });
|
|
51936
52876
|
});
|
|
51937
52877
|
}
|
|
51938
|
-
prepareRemoteProtocolV2Binaries(firmwareType, features) {
|
|
52878
|
+
prepareRemoteProtocolV2Binaries(firmwareType, features, explicitInstallItems = []) {
|
|
51939
52879
|
var _a, _b;
|
|
51940
52880
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51941
52881
|
const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
|
|
@@ -51943,6 +52883,10 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51943
52883
|
const fwBinaryMap = [];
|
|
51944
52884
|
const installItems = [];
|
|
51945
52885
|
if (!release) {
|
|
52886
|
+
const missingFirmwareTargets = this.getMissingProtocolV2FirmwareTargets(explicitInstallItems);
|
|
52887
|
+
if (missingFirmwareTargets.length > 0) {
|
|
52888
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 firmware release is unavailable for requested targets: ${missingFirmwareTargets.join(', ')}`);
|
|
52889
|
+
}
|
|
51946
52890
|
return {
|
|
51947
52891
|
bootloaderBinary,
|
|
51948
52892
|
fwBinaryMap,
|
|
@@ -51951,6 +52895,8 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51951
52895
|
}
|
|
51952
52896
|
const entries = this.getRemoteComponentEntries(release);
|
|
51953
52897
|
const targetsToUpdate = new Set((_a = this.params.targetsToUpdate) !== null && _a !== void 0 ? _a : []);
|
|
52898
|
+
const explicitInstallItemByTargetId = new Map(explicitInstallItems.map(item => [item.targetId, item]));
|
|
52899
|
+
const preparedTargets = new Set();
|
|
51954
52900
|
for (const [key, component] of entries) {
|
|
51955
52901
|
const targetName = (_b = component.target) === null || _b === void 0 ? void 0 : _b.toUpperCase();
|
|
51956
52902
|
const target = PROTOCOL_V2_REMOTE_COMPONENT_TARGETS[targetName];
|
|
@@ -51958,27 +52904,27 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51958
52904
|
? PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(target.targetId)
|
|
51959
52905
|
: undefined;
|
|
51960
52906
|
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
|
-
});
|
|
52907
|
+
const explicitInstallItem = explicitInstallItemByTargetId.get(target.targetId);
|
|
52908
|
+
const installItem = explicitInstallItem !== null && explicitInstallItem !== void 0 ? explicitInstallItem : (yield this.downloadRemoteProtocolV2Component(key, component));
|
|
52909
|
+
if (installItem.kind === 'bootloader') {
|
|
52910
|
+
bootloaderBinary = installItem.binary;
|
|
51970
52911
|
}
|
|
51971
52912
|
else {
|
|
51972
52913
|
const binaryEntry = {
|
|
51973
|
-
fileName:
|
|
51974
|
-
binary:
|
|
51975
|
-
targetId:
|
|
52914
|
+
fileName: installItem.fileName,
|
|
52915
|
+
binary: installItem.binary,
|
|
52916
|
+
targetId: installItem.targetId,
|
|
51976
52917
|
};
|
|
51977
52918
|
fwBinaryMap.push(binaryEntry);
|
|
51978
|
-
installItems.push(Object.assign(Object.assign({}, binaryEntry), { kind: remoteBinary.kind }));
|
|
51979
52919
|
}
|
|
52920
|
+
installItems.push(Object.assign({}, installItem));
|
|
52921
|
+
preparedTargets.add(updateTarget);
|
|
51980
52922
|
}
|
|
51981
52923
|
}
|
|
52924
|
+
const missingTarget = Array.from(targetsToUpdate).find(target => target !== 'resource' && !preparedTargets.has(target));
|
|
52925
|
+
if (missingTarget) {
|
|
52926
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 release does not contain requested target ${missingTarget}`);
|
|
52927
|
+
}
|
|
51982
52928
|
return {
|
|
51983
52929
|
bootloaderBinary,
|
|
51984
52930
|
fwBinaryMap,
|
|
@@ -51986,178 +52932,6 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51986
52932
|
};
|
|
51987
52933
|
});
|
|
51988
52934
|
}
|
|
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
52935
|
getProtocolV2ResourceFilePath(path) {
|
|
52162
52936
|
if (path.startsWith('vol'))
|
|
52163
52937
|
return path;
|
|
@@ -52165,7 +52939,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52165
52939
|
return `vol0:${path}`;
|
|
52166
52940
|
return `vol0:/${path}`;
|
|
52167
52941
|
}
|
|
52168
|
-
readProtocolV2DeviceFileHeader(path) {
|
|
52942
|
+
readProtocolV2DeviceFileHeader(path, expectedSize) {
|
|
52169
52943
|
var _a, _b, _c, _d;
|
|
52170
52944
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52171
52945
|
const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
|
|
@@ -52177,7 +52951,8 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52177
52951
|
if (!((_b = pathInfoRes.message) === null || _b === void 0 ? void 0 : _b.exist) ||
|
|
52178
52952
|
((_c = pathInfoRes.message) === null || _c === void 0 ? void 0 : _c.directory) ||
|
|
52179
52953
|
fileSize === undefined ||
|
|
52180
|
-
fileSize < PROTOCOL_V2_OKPP_HEADER_SIZE
|
|
52954
|
+
fileSize < PROTOCOL_V2_OKPP_HEADER_SIZE ||
|
|
52955
|
+
(expectedSize !== undefined && fileSize !== expectedSize)) {
|
|
52181
52956
|
return null;
|
|
52182
52957
|
}
|
|
52183
52958
|
const chunkSize = this.getProtocolV2FirmwareChunkSize('read');
|
|
@@ -52214,10 +52989,10 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52214
52989
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52215
52990
|
if ((_a = this.params) === null || _a === void 0 ? void 0 : _a.forcedUpdateRes)
|
|
52216
52991
|
return false;
|
|
52217
|
-
if (!bundle.
|
|
52992
|
+
if (!bundle.payloadHash || !bundle.headerHash)
|
|
52218
52993
|
return false;
|
|
52219
52994
|
try {
|
|
52220
|
-
const header = yield this.readProtocolV2DeviceFileHeader(bundle.devicePath);
|
|
52995
|
+
const header = yield this.readProtocolV2DeviceFileHeader(bundle.devicePath, bundle.source.size);
|
|
52221
52996
|
if (!header)
|
|
52222
52997
|
return false;
|
|
52223
52998
|
if (bundle.version) {
|
|
@@ -52225,16 +53000,12 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52225
53000
|
if (cmp === undefined || cmp !== 0)
|
|
52226
53001
|
return false;
|
|
52227
53002
|
}
|
|
52228
|
-
|
|
52229
|
-
|
|
52230
|
-
|
|
52231
|
-
|
|
52232
|
-
|
|
52233
|
-
|
|
52234
|
-
const expected = normalizeProtocolV2Hex(bundle.headerHash);
|
|
52235
|
-
if (expected && header.headerHash !== expected)
|
|
52236
|
-
return false;
|
|
52237
|
-
}
|
|
53003
|
+
const expectedPayloadHash = normalizeProtocolV2Hex(bundle.payloadHash);
|
|
53004
|
+
const expectedHeaderHash = normalizeProtocolV2Hex(bundle.headerHash);
|
|
53005
|
+
if (!expectedPayloadHash || header.payloadHash !== expectedPayloadHash)
|
|
53006
|
+
return false;
|
|
53007
|
+
if (!expectedHeaderHash || header.headerHash !== expectedHeaderHash)
|
|
53008
|
+
return false;
|
|
52238
53009
|
return true;
|
|
52239
53010
|
}
|
|
52240
53011
|
catch (error) {
|
|
@@ -52349,11 +53120,13 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52349
53120
|
}
|
|
52350
53121
|
buildProtocolV2ExecutionPhases({ installSources, resourceSources, }) {
|
|
52351
53122
|
const phases = [];
|
|
52352
|
-
|
|
53123
|
+
const bootResourceSources = resourceSources.filter(source => isProtocolV2BootResourcePackagePath(source.devicePath));
|
|
53124
|
+
const remainingResourceSources = resourceSources.filter(source => !isProtocolV2BootResourcePackagePath(source.devicePath));
|
|
53125
|
+
if (bootResourceSources.length > 0) {
|
|
52353
53126
|
phases.push({
|
|
52354
53127
|
kind: 'resource-sync',
|
|
52355
53128
|
installSources: [],
|
|
52356
|
-
resourceSources,
|
|
53129
|
+
resourceSources: bootResourceSources,
|
|
52357
53130
|
});
|
|
52358
53131
|
}
|
|
52359
53132
|
const bootloaderSources = installSources.filter(source => source.kind === 'bootloader');
|
|
@@ -52368,6 +53141,13 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52368
53141
|
resourceSources: [],
|
|
52369
53142
|
});
|
|
52370
53143
|
}
|
|
53144
|
+
if (remainingResourceSources.length > 0) {
|
|
53145
|
+
phases.push({
|
|
53146
|
+
kind: 'resource-sync',
|
|
53147
|
+
installSources: [],
|
|
53148
|
+
resourceSources: remainingResourceSources,
|
|
53149
|
+
});
|
|
53150
|
+
}
|
|
52371
53151
|
const componentSources = installSources.filter(source => source.kind !== 'bootloader');
|
|
52372
53152
|
if (componentSources.length > 0) {
|
|
52373
53153
|
phases.push({
|
|
@@ -52385,6 +53165,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52385
53165
|
}
|
|
52386
53166
|
executeProtocolV2Phases({ installSources, resourceSources, }) {
|
|
52387
53167
|
return __awaiter(this, void 0, void 0, function* () {
|
|
53168
|
+
this.protocolV2BootResourceStagingSafe = false;
|
|
52388
53169
|
const phases = this.buildProtocolV2ExecutionPhases({
|
|
52389
53170
|
installSources,
|
|
52390
53171
|
resourceSources,
|
|
@@ -52395,10 +53176,14 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52395
53176
|
}
|
|
52396
53177
|
if (phase.kind === 'resource-sync') {
|
|
52397
53178
|
yield this.enterProtocolV2BootloaderMode();
|
|
53179
|
+
if (!phase.resourceSources.some(source => isProtocolV2BootResourcePackagePath(source.devicePath))) {
|
|
53180
|
+
yield this.ensureProtocolV2BootResourceStagingIsEmpty();
|
|
53181
|
+
}
|
|
52398
53182
|
yield this.executeProtocolV2TransferPhase(phase);
|
|
52399
53183
|
}
|
|
52400
53184
|
else if (phase.kind === 'bootloader-install' || phase.kind === 'component-install') {
|
|
52401
53185
|
yield this.enterProtocolV2BootloaderMode();
|
|
53186
|
+
yield this.ensureProtocolV2BootResourceStagingIsEmpty();
|
|
52402
53187
|
yield this.executeProtocolV2TransferPhase(phase);
|
|
52403
53188
|
yield this.exitProtocolV2BootloaderToNormal();
|
|
52404
53189
|
}
|
|
@@ -52410,6 +53195,31 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52410
53195
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 execution has no final verification phase');
|
|
52411
53196
|
});
|
|
52412
53197
|
}
|
|
53198
|
+
ensureProtocolV2BootResourceStagingIsEmpty() {
|
|
53199
|
+
var _a, _b;
|
|
53200
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
53201
|
+
if (this.protocolV2BootResourceStagingSafe)
|
|
53202
|
+
return;
|
|
53203
|
+
const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
|
|
53204
|
+
const query = () => typedCall('FilesystemPathInfoQuery', 'FilesystemPathInfo', {
|
|
53205
|
+
path: PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_STAGING_PATH,
|
|
53206
|
+
});
|
|
53207
|
+
const current = yield query();
|
|
53208
|
+
if ((_a = current.message) === null || _a === void 0 ? void 0 : _a.exist) {
|
|
53209
|
+
if (current.message.directory) {
|
|
53210
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.EmmcFileWriteFirmwareError, 'Protocol V2 boot resource staging path is not a file');
|
|
53211
|
+
}
|
|
53212
|
+
yield typedCall('FilesystemFileDelete', 'Success', {
|
|
53213
|
+
path: PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_STAGING_PATH,
|
|
53214
|
+
});
|
|
53215
|
+
const remaining = yield query();
|
|
53216
|
+
if ((_b = remaining.message) === null || _b === void 0 ? void 0 : _b.exist) {
|
|
53217
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.EmmcFileWriteFirmwareError, 'Protocol V2 stale boot resource staging file could not be removed');
|
|
53218
|
+
}
|
|
53219
|
+
}
|
|
53220
|
+
this.protocolV2BootResourceStagingSafe = true;
|
|
53221
|
+
});
|
|
53222
|
+
}
|
|
52413
53223
|
executeProtocolV2SourceUpdate({ installSources, resourceSources, }) {
|
|
52414
53224
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52415
53225
|
return this.executeProtocolV2Phases({
|
|
@@ -52418,7 +53228,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52418
53228
|
});
|
|
52419
53229
|
});
|
|
52420
53230
|
}
|
|
52421
|
-
executeProtocolV2Update({ fwBinaryMap, bootloaderBinary, installItems,
|
|
53231
|
+
executeProtocolV2Update({ fwBinaryMap, bootloaderBinary, installItems, }) {
|
|
52422
53232
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52423
53233
|
const memoryInstallItems = installItems !== null && installItems !== void 0 ? installItems : this.buildProtocolV2InstallItems({
|
|
52424
53234
|
fwBinaryMap: fwBinaryMap !== null && fwBinaryMap !== void 0 ? fwBinaryMap : [],
|
|
@@ -52433,16 +53243,9 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52433
53243
|
kind: item.kind,
|
|
52434
53244
|
});
|
|
52435
53245
|
})));
|
|
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
53246
|
return yield this.executeProtocolV2Phases({
|
|
52444
53247
|
installSources,
|
|
52445
|
-
resourceSources,
|
|
53248
|
+
resourceSources: [],
|
|
52446
53249
|
});
|
|
52447
53250
|
}
|
|
52448
53251
|
finally {
|
|
@@ -52455,7 +53258,8 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52455
53258
|
let totalSize = installSources.reduce((total, item) => total + item.source.size, 0);
|
|
52456
53259
|
const resourcesToSync = [];
|
|
52457
53260
|
for (const resource of resourceSources) {
|
|
52458
|
-
|
|
53261
|
+
const requiresFreshStaging = isProtocolV2BootResourcePackagePath(resource.devicePath);
|
|
53262
|
+
if (!requiresFreshStaging && (yield this.isProtocolV2ResourceBundleUpToDate(resource))) {
|
|
52459
53263
|
Log$6.log(`[FirmwareUpdateV4] skip RESC bundle ${resource.name}; already up to date`);
|
|
52460
53264
|
}
|
|
52461
53265
|
else {
|
|
@@ -52466,13 +53270,17 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52466
53270
|
this.postTipMessage(exports.FirmwareUpdateTipMessage.StartTransferData);
|
|
52467
53271
|
let processedSize = 0;
|
|
52468
53272
|
for (const resource of resourcesToSync) {
|
|
53273
|
+
const writePath = resolveProtocolV2ResourceWritePath(resource.devicePath);
|
|
52469
53274
|
processedSize = yield this.protocolV2SourceUpdateProcess({
|
|
52470
53275
|
source: resource.source,
|
|
52471
|
-
filePath:
|
|
53276
|
+
filePath: writePath,
|
|
52472
53277
|
processedSize,
|
|
52473
53278
|
totalSize,
|
|
52474
53279
|
});
|
|
52475
|
-
yield this.verifyProtocolV2StagedFile(
|
|
53280
|
+
yield this.verifyProtocolV2StagedFile(writePath, resource.source.size);
|
|
53281
|
+
if (isProtocolV2BootResourcePackagePath(resource.devicePath)) {
|
|
53282
|
+
this.protocolV2BootResourceStagingSafe = true;
|
|
53283
|
+
}
|
|
52476
53284
|
}
|
|
52477
53285
|
const stagedInstallTargets = [];
|
|
52478
53286
|
for (const item of installSources) {
|
|
@@ -53462,7 +54270,7 @@ class DeviceUploadWallpaper extends BaseMethod {
|
|
|
53462
54270
|
}
|
|
53463
54271
|
|
|
53464
54272
|
const FILESYSTEM_PATH_INFO_QUERY_MESSAGE_TYPE = 60802;
|
|
53465
|
-
const FILESYSTEM_FILE_WRITE_MESSAGE_TYPE = 60805;
|
|
54273
|
+
const FILESYSTEM_FILE_WRITE_MESSAGE_TYPE$1 = 60805;
|
|
53466
54274
|
const FILESYSTEM_DIR_LIST_MESSAGE_TYPE = 60808;
|
|
53467
54275
|
const NFT_UPDATE_MESSAGE_TYPE = 61500;
|
|
53468
54276
|
class DeviceUploadNft extends BaseMethod {
|
|
@@ -53491,7 +54299,7 @@ class DeviceUploadNft extends BaseMethod {
|
|
|
53491
54299
|
assertCapabilities() {
|
|
53492
54300
|
return __awaiter(this, void 0, void 0, function* () {
|
|
53493
54301
|
const protocolInfo = yield this.device.ensureProtocolV2RuntimeContext();
|
|
53494
|
-
const hasFileWrite = supportsProtocolV2Message(protocolInfo, FILESYSTEM_FILE_WRITE_MESSAGE_TYPE);
|
|
54302
|
+
const hasFileWrite = supportsProtocolV2Message(protocolInfo, FILESYSTEM_FILE_WRITE_MESSAGE_TYPE$1);
|
|
53495
54303
|
const hasPathInfo = supportsProtocolV2Message(protocolInfo, FILESYSTEM_PATH_INFO_QUERY_MESSAGE_TYPE);
|
|
53496
54304
|
const hasDirList = supportsProtocolV2Message(protocolInfo, FILESYSTEM_DIR_LIST_MESSAGE_TYPE);
|
|
53497
54305
|
const hasNftUpdate = supportsProtocolV2Message(protocolInfo, NFT_UPDATE_MESSAGE_TYPE);
|
|
@@ -53626,6 +54434,8 @@ class FileWrite extends BaseMethod {
|
|
|
53626
54434
|
|
|
53627
54435
|
const PORTFOLIO_PENDING_PATH = 'vol1:/portfolio/portfolio.okpkg.pending';
|
|
53628
54436
|
const PORTFOLIO_CHUNK_SIZE = 2048;
|
|
54437
|
+
const FILESYSTEM_FILE_WRITE_MESSAGE_TYPE = 60805;
|
|
54438
|
+
const PORTFOLIO_UPDATE_MESSAGE_TYPE = 61400;
|
|
53629
54439
|
class UploadPortfolio extends FileWrite {
|
|
53630
54440
|
init() {
|
|
53631
54441
|
const { packageBytes, timeoutMs } = this.payload;
|
|
@@ -53639,6 +54449,12 @@ class UploadPortfolio extends FileWrite {
|
|
|
53639
54449
|
run: { get: () => super.run }
|
|
53640
54450
|
});
|
|
53641
54451
|
return __awaiter(this, void 0, void 0, function* () {
|
|
54452
|
+
const protocolInfo = yield this.device.ensureProtocolV2RuntimeContext();
|
|
54453
|
+
const hasFileWrite = supportsProtocolV2Message(protocolInfo, FILESYSTEM_FILE_WRITE_MESSAGE_TYPE);
|
|
54454
|
+
const hasPortfolioUpdate = supportsProtocolV2Message(protocolInfo, PORTFOLIO_UPDATE_MESSAGE_TYPE);
|
|
54455
|
+
if (!hasFileWrite || !hasPortfolioUpdate) {
|
|
54456
|
+
throw hdShared.createDeviceNotSupportMethodError(this.name, this.device.getCurrentFirmwareType());
|
|
54457
|
+
}
|
|
53642
54458
|
const stagedFile = yield _super.run.call(this);
|
|
53643
54459
|
this.throwIfAborted();
|
|
53644
54460
|
yield this.device.commands.typedCall('PortfolioUpdate', 'Success', {});
|
|
@@ -65180,11 +65996,14 @@ exports.normalizeSafetyCheckLevel = normalizeSafetyCheckLevel;
|
|
|
65180
65996
|
exports.normalizeVersionArray = normalizeVersionArray;
|
|
65181
65997
|
exports.parseConnectSettings = parseConnectSettings;
|
|
65182
65998
|
exports.parseMessage = parseMessage;
|
|
65999
|
+
exports.parseProtocolV2ResourceManifest = parseProtocolV2ResourceManifest;
|
|
65183
66000
|
exports.patchFeatures = patchFeatures;
|
|
65184
66001
|
exports.preloadSessionCache = preloadSessionCache;
|
|
66002
|
+
exports.prepareFirmwareUpdateV4MemoryHost = prepareFirmwareUpdateV4MemoryHost;
|
|
65185
66003
|
exports.projectDeviceStateFeatures = projectFeatures;
|
|
65186
66004
|
exports.registerFirmwareUpdateHostBinding = registerFirmwareUpdateHostBinding;
|
|
65187
66005
|
exports.safeThrowError = safeThrowError;
|
|
66006
|
+
exports.selectProtocolV2ResourceManifestFiles = selectProtocolV2ResourceManifestFiles;
|
|
65188
66007
|
exports.setLoggerPostMessage = setLoggerPostMessage;
|
|
65189
66008
|
exports.supportInputPinOnSoftware = supportInputPinOnSoftware;
|
|
65190
66009
|
exports.switchTransport = switchTransport;
|