@onekeyfe/hd-core 1.2.0-alpha.96 → 1.2.0-alpha.98
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__tests__/firmware-update/device-update-bootloader.test.ts +8 -1
- package/__tests__/firmware-update/firmware-prepared-host-digest.test.ts +106 -2
- package/__tests__/firmware-update/firmware-prepared-resource-archive.test.ts +150 -0
- package/__tests__/firmware-update/firmware-update-bootloader-poll.test.ts +112 -0
- package/__tests__/firmware-update/firmware-update-plan.test.ts +101 -0
- 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.test.ts +131 -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 +2 -0
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
- 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.map +1 -1
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +6 -1
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.js +359 -157
- package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdate.d.ts +1 -1
- 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/package.json +4 -4
- package/src/api/FirmwareUpdateV2.ts +95 -72
- package/src/api/FirmwareUpdateV3.ts +74 -51
- package/src/api/FirmwareUpdateV4.ts +72 -7
- package/src/api/device/DeviceUpdateBootloader.ts +17 -12
- package/src/api/firmware/FirmwarePreparedResourceArchive.ts +207 -0
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +2 -0
- package/src/api/firmware/FirmwareUpdatePlan.ts +70 -48
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +17 -0
- package/src/types/api/deviceUpdateBootloader.ts +1 -0
- package/src/types/api/firmwareUpdate.ts +2 -1
- package/src/types/api/firmwareUpdatePlan.ts +2 -2
package/dist/index.js
CHANGED
|
@@ -595,6 +595,16 @@ const planError = (message) => {
|
|
|
595
595
|
firmwareUpdateCode: 'FirmwarePlanInvalid',
|
|
596
596
|
});
|
|
597
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
|
+
};
|
|
598
608
|
const FIRMWARE_UPDATE_PLAN_FORCE_TARGETS = new Set([
|
|
599
609
|
'firmware',
|
|
600
610
|
'ble',
|
|
@@ -705,7 +715,7 @@ const assertFirmwareUpdatePlan = (value) => {
|
|
|
705
715
|
if (!artifact) {
|
|
706
716
|
return planError('Firmware update plan artifact is invalid');
|
|
707
717
|
}
|
|
708
|
-
assertExactKeys(artifact, ['artifactId', 'role', 'target', 'url', 'container'
|
|
718
|
+
assertExactKeys(artifact, ['artifactId', 'role', 'target', 'url', 'container', 'expectedSize', 'expectedSha256'], ['logicalName', 'targetVersion']);
|
|
709
719
|
const artifactId = assertBoundedString(artifact.artifactId, 'artifact id', 160);
|
|
710
720
|
if (artifactIds.has(artifactId)) {
|
|
711
721
|
return planError('Firmware update plan contains duplicate artifact ids');
|
|
@@ -721,13 +731,11 @@ const assertFirmwareUpdatePlan = (value) => {
|
|
|
721
731
|
if (artifact.logicalName !== undefined) {
|
|
722
732
|
assertBoundedString(artifact.logicalName, 'logical name', 256);
|
|
723
733
|
}
|
|
724
|
-
if (artifact.expectedSize
|
|
725
|
-
(!Number.isSafeInteger(artifact.expectedSize) || artifact.expectedSize <= 0)) {
|
|
734
|
+
if (!Number.isSafeInteger(artifact.expectedSize) || artifact.expectedSize <= 0) {
|
|
726
735
|
return planError('Firmware update plan artifact size is invalid');
|
|
727
736
|
}
|
|
728
|
-
if (artifact.expectedSha256 !==
|
|
729
|
-
(
|
|
730
|
-
!/^[a-f0-9]{64}$/u.test(artifact.expectedSha256))) {
|
|
737
|
+
if (typeof artifact.expectedSha256 !== 'string' ||
|
|
738
|
+
!/^[a-f0-9]{64}$/u.test(artifact.expectedSha256)) {
|
|
731
739
|
return planError('Firmware update plan artifact digest is invalid');
|
|
732
740
|
}
|
|
733
741
|
if (artifact.targetVersion !== undefined) {
|
|
@@ -836,13 +844,7 @@ const buildProtocolV2Artifacts = (release, { includeComponents = true, component
|
|
|
836
844
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 component ${key} duplicates target ${target}`, { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
837
845
|
}
|
|
838
846
|
componentTargetSet.add(target);
|
|
839
|
-
const integrity =
|
|
840
|
-
size: component.expectedSize,
|
|
841
|
-
sha256: component.fingerprint,
|
|
842
|
-
});
|
|
843
|
-
if (integrity.expectedSize === undefined || integrity.expectedSha256 === undefined) {
|
|
844
|
-
planError(`Protocol V2 component ${key} integrity metadata is invalid`);
|
|
845
|
-
}
|
|
847
|
+
const integrity = requireArtifactIntegrity({ size: component.expectedSize, sha256: component.fingerprint }, `Protocol V2 component ${key}`);
|
|
846
848
|
artifacts.push(Object.assign(Object.assign({ artifactId: `component:${target}`, role: 'component', target, url: assertArtifactUrl(component.url, `Protocol V2 component ${key}`), container: 'raw', logicalName: key }, integrity), (asVersion(component.version) ? { targetVersion: asVersion(component.version) } : {})));
|
|
847
849
|
targets.push(target);
|
|
848
850
|
}
|
|
@@ -934,13 +936,7 @@ const buildProtocolV2FirmwareUpdatePlan = ({ features, firmwareType, platform, r
|
|
|
934
936
|
if (!archive) {
|
|
935
937
|
return planError('Protocol V2 resource target has no resource archive');
|
|
936
938
|
}
|
|
937
|
-
const integrity =
|
|
938
|
-
size: archive.archiveSize,
|
|
939
|
-
sha256: archive.archiveSha256,
|
|
940
|
-
});
|
|
941
|
-
if (integrity.expectedSize === undefined || integrity.expectedSha256 === undefined) {
|
|
942
|
-
planError('Protocol V2 resource archive integrity metadata is invalid');
|
|
943
|
-
}
|
|
939
|
+
const integrity = requireArtifactIntegrity({ size: archive.archiveSize, sha256: archive.archiveSha256 }, 'Protocol V2 resource archive');
|
|
944
940
|
protocolV2.artifacts.push(Object.assign({ artifactId: 'resource:archive', role: 'resourceBundle', target: 'resource', url: assertArtifactUrl(archive.archiveUrl, 'Protocol V2 resource archive'), container: 'zip', logicalName: 'protocol-v2-resource-archive' }, integrity));
|
|
945
941
|
protocolV2.targets.push('resource');
|
|
946
942
|
}
|
|
@@ -964,7 +960,7 @@ const buildProtocolV2FirmwareUpdatePlan = ({ features, firmwareType, platform, r
|
|
|
964
960
|
});
|
|
965
961
|
};
|
|
966
962
|
const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, ble, bootloader, forceUpdateTargets, }) => {
|
|
967
|
-
var _a, _b
|
|
963
|
+
var _a, _b;
|
|
968
964
|
const executor = getExecutor(features);
|
|
969
965
|
let artifacts = [];
|
|
970
966
|
let targetsToUpdate = [];
|
|
@@ -976,7 +972,8 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
|
|
|
976
972
|
((release === null || release === void 0 ? void 0 : release.status) === 'none' || (release === null || release === void 0 ? void 0 : release.status) === 'unknown') &&
|
|
977
973
|
!!asRelease(release);
|
|
978
974
|
const shouldUpdateFirmware = isUpgrade(firmware) || isRecoveryInstall(firmware) || forcedTargets.has('firmware');
|
|
979
|
-
const shouldUpdateResource =
|
|
975
|
+
const shouldUpdateResource = !(executor === 'v2' && bootloaderMode) &&
|
|
976
|
+
(isUpgrade(firmware) || forcedTargets.has('resource'));
|
|
980
977
|
if (executor === 'v4' &&
|
|
981
978
|
validatedForceTargets.some(target => target === 'ble' || target === 'bootloader')) {
|
|
982
979
|
planError('Protocol V2 does not support forced BLE or legacy bootloader targets');
|
|
@@ -990,12 +987,14 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
|
|
|
990
987
|
}
|
|
991
988
|
else {
|
|
992
989
|
if (isUpgrade(bootloader) || forcedTargets.has('bootloader')) {
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
990
|
+
const bootloaderRelease = asRelease(bootloader);
|
|
991
|
+
const integrity = requireArtifactIntegrity({
|
|
992
|
+
size: bootloaderRelease === null || bootloaderRelease === void 0 ? void 0 : bootloaderRelease.bootloaderExpectedSize,
|
|
993
|
+
sha256: bootloaderRelease === null || bootloaderRelease === void 0 ? void 0 : bootloaderRelease.bootloaderFingerprint,
|
|
994
|
+
}, 'Bootloader release');
|
|
995
|
+
artifacts.push(Object.assign(Object.assign({ artifactId: 'bootloader', role: 'bootloader', target: 'bootloader', url: assertArtifactUrl(bootloaderRelease === null || bootloaderRelease === void 0 ? void 0 : bootloaderRelease.bootloaderResource, 'Bootloader release'), container: 'raw' }, integrity), (asVersion(bootloaderRelease === null || bootloaderRelease === void 0 ? void 0 : bootloaderRelease.bootloaderVersion)
|
|
997
996
|
? {
|
|
998
|
-
targetVersion: asVersion(
|
|
997
|
+
targetVersion: asVersion(bootloaderRelease === null || bootloaderRelease === void 0 ? void 0 : bootloaderRelease.bootloaderVersion),
|
|
999
998
|
}
|
|
1000
999
|
: {})));
|
|
1001
1000
|
}
|
|
@@ -1006,10 +1005,8 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
|
|
|
1006
1005
|
});
|
|
1007
1006
|
}
|
|
1008
1007
|
if (shouldUpdateFirmware) {
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
sha256: firmwareRelease.fingerprint,
|
|
1012
|
-
})), (asVersion(firmwareRelease.version)
|
|
1008
|
+
const integrity = requireArtifactIntegrity({ size: firmwareRelease.expectedSize, sha256: firmwareRelease.fingerprint }, 'Firmware release');
|
|
1009
|
+
artifacts.push(Object.assign(Object.assign({ artifactId: 'firmware', role: 'firmware', target: 'firmware', url: assertArtifactUrl(firmwareRelease.url, 'Firmware release'), container: 'raw' }, integrity), (asVersion(firmwareRelease.version)
|
|
1013
1010
|
? { targetVersion: asVersion(firmwareRelease.version) }
|
|
1014
1011
|
: {})));
|
|
1015
1012
|
}
|
|
@@ -1020,23 +1017,25 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
|
|
|
1020
1017
|
platform,
|
|
1021
1018
|
});
|
|
1022
1019
|
if (resourceUrl) {
|
|
1023
|
-
|
|
1020
|
+
const integrity = requireArtifactIntegrity({
|
|
1024
1021
|
size: resourceUrl === asString(firmwareRelease.fullResource)
|
|
1025
1022
|
? firmwareRelease.fullResourceExpectedSize
|
|
1026
1023
|
: firmwareRelease.resourceExpectedSize,
|
|
1027
1024
|
sha256: resourceUrl === asString(firmwareRelease.fullResource)
|
|
1028
1025
|
? firmwareRelease.fullResourceFingerprint
|
|
1029
1026
|
: firmwareRelease.resourceFingerprint,
|
|
1030
|
-
})
|
|
1027
|
+
}, 'Legacy resource archive');
|
|
1028
|
+
artifacts.push(Object.assign({ artifactId: 'resource', role: 'resource', target: 'resource', url: assertArtifactUrl(resourceUrl, 'Firmware resource release'), container: 'zip' }, integrity));
|
|
1031
1029
|
}
|
|
1032
1030
|
}
|
|
1033
1031
|
}
|
|
1034
1032
|
if (isUpgrade(ble) || isRecoveryInstall(ble) || forcedTargets.has('ble')) {
|
|
1035
1033
|
const bleRelease = asRelease(ble);
|
|
1036
|
-
|
|
1034
|
+
const integrity = requireArtifactIntegrity({
|
|
1037
1035
|
size: bleRelease === null || bleRelease === void 0 ? void 0 : bleRelease.expectedSize,
|
|
1038
|
-
sha256: (
|
|
1039
|
-
}
|
|
1036
|
+
sha256: (_a = bleRelease === null || bleRelease === void 0 ? void 0 : bleRelease.fingerprintWeb) !== null && _a !== void 0 ? _a : bleRelease === null || bleRelease === void 0 ? void 0 : bleRelease.fingerprint,
|
|
1037
|
+
}, 'BLE release');
|
|
1038
|
+
artifacts.push(Object.assign(Object.assign({ artifactId: 'ble', role: 'ble', target: 'ble', url: assertArtifactUrl((_b = bleRelease === null || bleRelease === void 0 ? void 0 : bleRelease.webUpdate) !== null && _b !== void 0 ? _b : bleRelease === null || bleRelease === void 0 ? void 0 : bleRelease.url, 'BLE release'), container: 'raw' }, integrity), (asVersion(bleRelease === null || bleRelease === void 0 ? void 0 : bleRelease.version)
|
|
1040
1039
|
? { targetVersion: asVersion(bleRelease === null || bleRelease === void 0 ? void 0 : bleRelease.version) }
|
|
1041
1040
|
: {})));
|
|
1042
1041
|
}
|
|
@@ -1275,6 +1274,14 @@ const validateFirmwareUpdatePreparedPlan = (value) => {
|
|
|
1275
1274
|
}
|
|
1276
1275
|
return preparedPlan;
|
|
1277
1276
|
};
|
|
1277
|
+
const getFirmwareUpdatePreparedRawArtifact = ({ preparedPlan: value, target, role, }) => {
|
|
1278
|
+
const preparedPlan = validateFirmwareUpdatePreparedPlan(value);
|
|
1279
|
+
const artifacts = preparedPlan.artifacts.filter(artifact => artifact.target === target);
|
|
1280
|
+
if (artifacts.length !== 1 || artifacts[0].role !== role || artifacts[0].container !== 'raw') {
|
|
1281
|
+
return preparedPlanError(`Firmware prepared plan ${target} artifact is invalid`);
|
|
1282
|
+
}
|
|
1283
|
+
return artifacts[0];
|
|
1284
|
+
};
|
|
1278
1285
|
const degradedPlanIdentityPins = new Map();
|
|
1279
1286
|
const DEGRADED_PLAN_IDENTITY_PIN_LIMIT = 32;
|
|
1280
1287
|
const pinDegradedPlanIdentity = (leaseRef, deviceIdentity) => {
|
|
@@ -49404,6 +49411,8 @@ class FirmwareUpdateBaseMethod extends BaseMethod {
|
|
|
49404
49411
|
!this.payload.skipWebDevicePrompt &&
|
|
49405
49412
|
!hasPromptedWebDevice &&
|
|
49406
49413
|
!isPromptingWebDevice) {
|
|
49414
|
+
clearInterval(intervalTimer);
|
|
49415
|
+
clearTimeout(timeoutTimer);
|
|
49407
49416
|
isPromptingWebDevice = true;
|
|
49408
49417
|
try {
|
|
49409
49418
|
this.postTipMessage(exports.FirmwareUpdateTipMessage.SelectDeviceInBootloaderForWebDevice);
|
|
@@ -49783,21 +49792,27 @@ class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod {
|
|
|
49783
49792
|
const { features } = device;
|
|
49784
49793
|
const payload = this.payload;
|
|
49785
49794
|
const hasPreparedPlan = payload.preparedPlan !== undefined;
|
|
49786
|
-
|
|
49787
|
-
|
|
49788
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Prepared bootloader plans require exactly one prepared artifact');
|
|
49795
|
+
if (hasPreparedPlan && payload.binary !== undefined) {
|
|
49796
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Prepared bootloader plans cannot be combined with a legacy binary');
|
|
49789
49797
|
}
|
|
49790
|
-
if (payload.
|
|
49791
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Bootloader
|
|
49798
|
+
if (!hasPreparedPlan && payload.artifact !== undefined) {
|
|
49799
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Bootloader artifacts require a prepared plan');
|
|
49792
49800
|
}
|
|
49793
|
-
const preparedPlan =
|
|
49801
|
+
const preparedPlan = hasPreparedPlan
|
|
49794
49802
|
? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
|
|
49795
49803
|
: undefined;
|
|
49804
|
+
const plannedArtifact = preparedPlan
|
|
49805
|
+
? getFirmwareUpdatePreparedRawArtifact({
|
|
49806
|
+
preparedPlan,
|
|
49807
|
+
target: 'bootloader',
|
|
49808
|
+
role: 'bootloader',
|
|
49809
|
+
}).artifact
|
|
49810
|
+
: undefined;
|
|
49796
49811
|
const artifactReader = preparedPlan
|
|
49797
49812
|
? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration, preparedPlan.preparedPlanDigest).artifactReader
|
|
49798
49813
|
: payload.artifactReader;
|
|
49799
49814
|
const executionParams = Object.assign(Object.assign({}, payload), { artifactReader });
|
|
49800
|
-
if (
|
|
49815
|
+
if (preparedPlan && plannedArtifact) {
|
|
49801
49816
|
assertFirmwareUpdatePreparedPlanDeviceIdentity({
|
|
49802
49817
|
preparedPlan,
|
|
49803
49818
|
deviceIdentity: getDeviceUUID(features) || undefined,
|
|
@@ -49811,12 +49826,12 @@ class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod {
|
|
|
49811
49826
|
bindings: [
|
|
49812
49827
|
{
|
|
49813
49828
|
target: 'bootloader',
|
|
49814
|
-
artifact: payload.artifact,
|
|
49829
|
+
artifact: (_a = payload.artifact) !== null && _a !== void 0 ? _a : plannedArtifact,
|
|
49815
49830
|
},
|
|
49816
49831
|
],
|
|
49817
49832
|
});
|
|
49818
49833
|
const source = yield openFirmwareByteSource({
|
|
49819
|
-
artifact:
|
|
49834
|
+
artifact: plannedArtifact,
|
|
49820
49835
|
reader: executionParams.artifactReader,
|
|
49821
49836
|
});
|
|
49822
49837
|
if (!source) {
|
|
@@ -49824,13 +49839,11 @@ class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod {
|
|
|
49824
49839
|
}
|
|
49825
49840
|
try {
|
|
49826
49841
|
const deviceType = device.getCurrentDeviceType();
|
|
49827
|
-
const deviceFirmwareType = device.getCurrentFirmwareType();
|
|
49828
|
-
const firmwareType = (_a = payload.firmwareType) !== null && _a !== void 0 ? _a : deviceFirmwareType;
|
|
49829
49842
|
if (DeviceModelToTypes.model_touch.includes(deviceType)) {
|
|
49830
49843
|
return yield this.updateTouchBootloader({
|
|
49831
49844
|
device,
|
|
49832
49845
|
features,
|
|
49833
|
-
firmwareType,
|
|
49846
|
+
firmwareType: preparedPlan.firmwareType,
|
|
49834
49847
|
source,
|
|
49835
49848
|
});
|
|
49836
49849
|
}
|
|
@@ -50104,6 +50117,119 @@ const normalizeFirmwarePreparationError = (error) => {
|
|
|
50104
50117
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, error instanceof Error ? error.message : String(error));
|
|
50105
50118
|
};
|
|
50106
50119
|
|
|
50120
|
+
const PREPARED_RESOURCE_ARCHIVE_MAX_BYTES = 256 * 1024 * 1024;
|
|
50121
|
+
const PREPARED_RESOURCE_ENTRY_MAX_COUNT = 512;
|
|
50122
|
+
const resourceArchiveError = (message, firmwareUpdateCode) => {
|
|
50123
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, message, { firmwareUpdateCode });
|
|
50124
|
+
};
|
|
50125
|
+
const getZipEntrySizes = (entry) => {
|
|
50126
|
+
var _a;
|
|
50127
|
+
const { compressedSize, uncompressedSize } = (_a = entry._data) !== null && _a !== void 0 ? _a : {};
|
|
50128
|
+
if (!Number.isSafeInteger(compressedSize) ||
|
|
50129
|
+
Number(compressedSize) < 0 ||
|
|
50130
|
+
!Number.isSafeInteger(uncompressedSize) ||
|
|
50131
|
+
Number(uncompressedSize) <= 0) {
|
|
50132
|
+
return resourceArchiveError(`Firmware prepared resource ZIP entry size is invalid: ${entry.name}`, 'FirmwareArtifactsNotPrepared');
|
|
50133
|
+
}
|
|
50134
|
+
return {
|
|
50135
|
+
compressedSize: Number(compressedSize),
|
|
50136
|
+
uncompressedSize: Number(uncompressedSize),
|
|
50137
|
+
};
|
|
50138
|
+
};
|
|
50139
|
+
const readVerifiedPreparedResourceArchive = ({ preparedPlan, reader, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
50140
|
+
const resourceArtifacts = preparedPlan.artifacts.filter(artifact => artifact.target === 'resource');
|
|
50141
|
+
if (!preparedPlan.targetsToUpdate.includes('resource')) {
|
|
50142
|
+
if (resourceArtifacts.length > 0) {
|
|
50143
|
+
return resourceArchiveError('Firmware prepared resource artifact is outside the approved targets', 'FirmwareArtifactsNotPrepared');
|
|
50144
|
+
}
|
|
50145
|
+
return [];
|
|
50146
|
+
}
|
|
50147
|
+
if (resourceArtifacts.length !== 1) {
|
|
50148
|
+
return resourceArchiveError('Firmware prepared plan must contain exactly one materialized resource ZIP', 'FirmwareArtifactsNotPrepared');
|
|
50149
|
+
}
|
|
50150
|
+
const archiveArtifact = resourceArtifacts[0];
|
|
50151
|
+
const preparedEntries = archiveArtifact.materializedEntries;
|
|
50152
|
+
if (archiveArtifact.role !== 'resource' ||
|
|
50153
|
+
archiveArtifact.container !== 'zip' ||
|
|
50154
|
+
!(preparedEntries === null || preparedEntries === void 0 ? void 0 : preparedEntries.length)) {
|
|
50155
|
+
return resourceArchiveError('Firmware prepared plan must contain exactly one materialized resource ZIP', 'FirmwareArtifactsNotPrepared');
|
|
50156
|
+
}
|
|
50157
|
+
const archiveSource = yield openFirmwareByteSource({
|
|
50158
|
+
artifact: archiveArtifact.artifact,
|
|
50159
|
+
reader,
|
|
50160
|
+
});
|
|
50161
|
+
if (!archiveSource) {
|
|
50162
|
+
return resourceArchiveError('Firmware prepared resource ZIP is unavailable', 'FirmwareArtifactsNotPrepared');
|
|
50163
|
+
}
|
|
50164
|
+
if (archiveSource.size > PREPARED_RESOURCE_ARCHIVE_MAX_BYTES) {
|
|
50165
|
+
yield archiveSource.close().catch(() => undefined);
|
|
50166
|
+
return resourceArchiveError('Firmware prepared resource ZIP exceeds the archive size limit', 'FirmwareArtifactsNotPrepared');
|
|
50167
|
+
}
|
|
50168
|
+
let archiveBinary;
|
|
50169
|
+
try {
|
|
50170
|
+
archiveBinary = yield readFirmwareByteSourceFully(archiveSource);
|
|
50171
|
+
}
|
|
50172
|
+
finally {
|
|
50173
|
+
yield archiveSource.close().catch(() => undefined);
|
|
50174
|
+
}
|
|
50175
|
+
const archiveDigest = utils.bytesToHex(sha256.sha256(new Uint8Array(archiveBinary)));
|
|
50176
|
+
if (archiveDigest !== archiveArtifact.artifact.sha256.toLowerCase()) {
|
|
50177
|
+
return resourceArchiveError('Firmware prepared resource ZIP does not match its approved receipt', 'FirmwareArtifactReceiptMismatch');
|
|
50178
|
+
}
|
|
50179
|
+
let zip;
|
|
50180
|
+
try {
|
|
50181
|
+
zip = yield JSZip__default["default"].loadAsync(archiveBinary);
|
|
50182
|
+
}
|
|
50183
|
+
catch (_a) {
|
|
50184
|
+
return resourceArchiveError('Firmware prepared resource ZIP cannot be parsed', 'FirmwareArtifactsNotPrepared');
|
|
50185
|
+
}
|
|
50186
|
+
const zipEntries = Object.values(zip.files);
|
|
50187
|
+
if (zipEntries.some(entry => entry.unsafeOriginalName && entry.unsafeOriginalName !== entry.name)) {
|
|
50188
|
+
return resourceArchiveError('Firmware prepared resource ZIP contains an unsafe entry path', 'FirmwareArtifactsNotPrepared');
|
|
50189
|
+
}
|
|
50190
|
+
const files = zipEntries.filter(entry => !entry.dir);
|
|
50191
|
+
if (files.length === 0 || files.length > PREPARED_RESOURCE_ENTRY_MAX_COUNT) {
|
|
50192
|
+
return resourceArchiveError('Firmware prepared resource ZIP entry set is invalid', 'FirmwareArtifactsNotPrepared');
|
|
50193
|
+
}
|
|
50194
|
+
let totalSize = 0;
|
|
50195
|
+
const canonicalNames = new Set();
|
|
50196
|
+
for (const entry of files) {
|
|
50197
|
+
const { compressedSize, uncompressedSize } = getZipEntrySizes(entry);
|
|
50198
|
+
const resourceName = getFirmwareUpdateResourceName(entry.name);
|
|
50199
|
+
const canonicalName = resourceName.toLowerCase();
|
|
50200
|
+
totalSize += uncompressedSize;
|
|
50201
|
+
if (compressedSize > archiveBinary.byteLength ||
|
|
50202
|
+
uncompressedSize > PREPARED_RESOURCE_ARCHIVE_MAX_BYTES ||
|
|
50203
|
+
totalSize > PREPARED_RESOURCE_ARCHIVE_MAX_BYTES ||
|
|
50204
|
+
canonicalNames.has(canonicalName)) {
|
|
50205
|
+
return resourceArchiveError(`Firmware prepared resource ZIP entry bounds are invalid: ${entry.name}`, 'FirmwareArtifactsNotPrepared');
|
|
50206
|
+
}
|
|
50207
|
+
canonicalNames.add(canonicalName);
|
|
50208
|
+
}
|
|
50209
|
+
const preparedEntriesByName = new Map(preparedEntries.map(entry => [entry.entryName, entry]));
|
|
50210
|
+
if (preparedEntriesByName.size !== files.length || preparedEntries.length !== files.length) {
|
|
50211
|
+
return resourceArchiveError('Firmware prepared resource entries do not match the approved ZIP', 'FirmwareArtifactReceiptMismatch');
|
|
50212
|
+
}
|
|
50213
|
+
const verifiedEntries = [];
|
|
50214
|
+
for (const entry of files) {
|
|
50215
|
+
const { uncompressedSize } = getZipEntrySizes(entry);
|
|
50216
|
+
const binary = yield entry.async('arraybuffer');
|
|
50217
|
+
const preparedEntry = preparedEntriesByName.get(entry.name);
|
|
50218
|
+
const digest = utils.bytesToHex(sha256.sha256(new Uint8Array(binary)));
|
|
50219
|
+
if (binary.byteLength !== uncompressedSize ||
|
|
50220
|
+
!preparedEntry ||
|
|
50221
|
+
preparedEntry.artifact.size !== binary.byteLength ||
|
|
50222
|
+
preparedEntry.artifact.sha256.toLowerCase() !== digest) {
|
|
50223
|
+
return resourceArchiveError(`Firmware prepared resource entry does not match the approved ZIP: ${entry.name}`, 'FirmwareArtifactReceiptMismatch');
|
|
50224
|
+
}
|
|
50225
|
+
verifiedEntries.push({
|
|
50226
|
+
entryName: getFirmwareUpdateResourceName(entry.name),
|
|
50227
|
+
binary,
|
|
50228
|
+
});
|
|
50229
|
+
}
|
|
50230
|
+
return verifiedEntries;
|
|
50231
|
+
});
|
|
50232
|
+
|
|
50107
50233
|
const Log$8 = getLogger(exports.LoggerNames.Method);
|
|
50108
50234
|
const FIRMWARE_DOWNLOAD_REQUEST_OPTIONS = {
|
|
50109
50235
|
connectTimeoutMs: 60000,
|
|
@@ -50178,7 +50304,7 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50178
50304
|
};
|
|
50179
50305
|
}
|
|
50180
50306
|
init() {
|
|
50181
|
-
var _a;
|
|
50307
|
+
var _a, _b;
|
|
50182
50308
|
this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
|
|
50183
50309
|
this.requireDeviceMode = [];
|
|
50184
50310
|
this.useDevicePassphraseState = false;
|
|
@@ -50191,14 +50317,12 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50191
50317
|
{ name: 'platform', type: 'string', required: true },
|
|
50192
50318
|
{ name: 'firmwareType', type: 'string' },
|
|
50193
50319
|
]);
|
|
50194
|
-
|
|
50195
|
-
|
|
50196
|
-
'
|
|
50197
|
-
payload.artifact !== undefined) {
|
|
50198
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Firmware update binary and artifact are mutually exclusive');
|
|
50320
|
+
const hasPreparedPlan = payload.preparedPlan !== undefined;
|
|
50321
|
+
if (hasPreparedPlan && (payload.binary !== undefined || payload.version !== undefined)) {
|
|
50322
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Prepared firmware plans cannot be combined with legacy firmware inputs');
|
|
50199
50323
|
}
|
|
50200
|
-
if (
|
|
50201
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, '
|
|
50324
|
+
if (!hasPreparedPlan && payload.artifact !== undefined) {
|
|
50325
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Firmware artifacts require a prepared plan');
|
|
50202
50326
|
}
|
|
50203
50327
|
if (!payload.updateType) {
|
|
50204
50328
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'updateType is required');
|
|
@@ -50208,16 +50332,21 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50208
50332
|
forcedUpdateRes: payload.forcedUpdateRes,
|
|
50209
50333
|
isUpdateBootloader: payload.isUpdateBootloader,
|
|
50210
50334
|
};
|
|
50211
|
-
if ('version' in payload) {
|
|
50335
|
+
if (!hasPreparedPlan && 'version' in payload) {
|
|
50212
50336
|
this.params = Object.assign(Object.assign({}, this.params), { version: payload.version, firmwareType: payload.firmwareType });
|
|
50213
50337
|
}
|
|
50214
|
-
if ('binary' in payload) {
|
|
50338
|
+
if (!hasPreparedPlan && 'binary' in payload) {
|
|
50215
50339
|
this.params = Object.assign(Object.assign({}, this.params), { binary: payload.binary });
|
|
50216
50340
|
}
|
|
50217
|
-
if (
|
|
50341
|
+
if (hasPreparedPlan) {
|
|
50218
50342
|
const preparedPlan = validateFirmwareUpdatePreparedPlan(payload.preparedPlan);
|
|
50219
50343
|
const hostBinding = resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration, preparedPlan.preparedPlanDigest);
|
|
50220
50344
|
const target = payload.isUpdateBootloader ? 'bootloader' : payload.updateType;
|
|
50345
|
+
const plannedArtifact = getFirmwareUpdatePreparedRawArtifact({
|
|
50346
|
+
preparedPlan,
|
|
50347
|
+
target,
|
|
50348
|
+
role: target,
|
|
50349
|
+
}).artifact;
|
|
50221
50350
|
const resourceBindings = ((_a = payload.resourceEntries) !== null && _a !== void 0 ? _a : []).map((entry) => ({
|
|
50222
50351
|
target: 'resource',
|
|
50223
50352
|
entryName: entry.entryName,
|
|
@@ -50227,10 +50356,13 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50227
50356
|
preparedPlan,
|
|
50228
50357
|
executor: 'v2',
|
|
50229
50358
|
platform: payload.platform,
|
|
50230
|
-
scopeTargets: [
|
|
50231
|
-
|
|
50359
|
+
scopeTargets: [
|
|
50360
|
+
target,
|
|
50361
|
+
...(target === 'firmware' && resourceBindings.length ? ['resource'] : []),
|
|
50362
|
+
],
|
|
50363
|
+
bindings: [{ target, artifact: (_b = payload.artifact) !== null && _b !== void 0 ? _b : plannedArtifact }, ...resourceBindings],
|
|
50232
50364
|
});
|
|
50233
|
-
this.params = Object.assign(Object.assign({}, this.params), { preparedPlan, artifact:
|
|
50365
|
+
this.params = Object.assign(Object.assign({}, this.params), { preparedPlan, artifact: plannedArtifact, artifactReader: hostBinding.artifactReader, firmwareType: preparedPlan.firmwareType });
|
|
50234
50366
|
}
|
|
50235
50367
|
}
|
|
50236
50368
|
_promptDeviceInBootloaderForWebDevice() {
|
|
@@ -50380,7 +50512,7 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50380
50512
|
}
|
|
50381
50513
|
}
|
|
50382
50514
|
run() {
|
|
50383
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
50515
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
50384
50516
|
return __awaiter(this, void 0, void 0, function* () {
|
|
50385
50517
|
const { device, params } = this;
|
|
50386
50518
|
const { features, commands } = device;
|
|
@@ -50468,13 +50600,48 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50468
50600
|
throw normalizeFirmwarePreparationError(err);
|
|
50469
50601
|
}
|
|
50470
50602
|
});
|
|
50603
|
+
const preparedResourceRequested = !params.isUpdateBootloader &&
|
|
50604
|
+
params.updateType === 'firmware' &&
|
|
50605
|
+
((_c = (_b = params.preparedPlan) === null || _b === void 0 ? void 0 : _b.targetsToUpdate.includes('resource')) !== null && _c !== void 0 ? _c : false);
|
|
50606
|
+
if (preparedResourceRequested && device.isBootloader()) {
|
|
50607
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Prepared firmware resources require the device application mode', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared', artifactName: 'resource' });
|
|
50608
|
+
}
|
|
50471
50609
|
if (!device.isBootloader() && features) {
|
|
50472
50610
|
const serialNo = device.getCurrentSerialNo();
|
|
50473
50611
|
if (this.isEnteredManuallyBoot()) {
|
|
50474
50612
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateManuallyEnterBoot);
|
|
50475
50613
|
}
|
|
50476
50614
|
yield acquireFirmwareSource();
|
|
50477
|
-
if (
|
|
50615
|
+
if (preparedResourceRequested) {
|
|
50616
|
+
if (!this.isSupportResourceUpdate(params.updateType)) {
|
|
50617
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Prepared firmware resources are not supported by this device', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared', artifactName: 'resource' });
|
|
50618
|
+
}
|
|
50619
|
+
this.postTipMessage('CheckLatestUiResource');
|
|
50620
|
+
this.postTipMessage('DownloadLatestUiResource');
|
|
50621
|
+
const verifiedEntries = yield readVerifiedPreparedResourceArchive({
|
|
50622
|
+
preparedPlan: params.preparedPlan,
|
|
50623
|
+
reader: params.artifactReader,
|
|
50624
|
+
});
|
|
50625
|
+
const sources = [];
|
|
50626
|
+
try {
|
|
50627
|
+
for (const entry of verifiedEntries) {
|
|
50628
|
+
const source = yield openFirmwareByteSource({ binary: entry.binary });
|
|
50629
|
+
if (!source) {
|
|
50630
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Firmware resource entry ${entry.entryName} is empty`, {
|
|
50631
|
+
firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch',
|
|
50632
|
+
artifactName: 'resource',
|
|
50633
|
+
});
|
|
50634
|
+
}
|
|
50635
|
+
sources.push({ entryName: entry.entryName, source });
|
|
50636
|
+
}
|
|
50637
|
+
yield updateResourcesFromSources(this.device.getCommands().typedCall.bind(this.device.getCommands()), this.postMessage, device, sources);
|
|
50638
|
+
}
|
|
50639
|
+
finally {
|
|
50640
|
+
yield Promise.all(sources.map(entry => entry.source.close().catch(() => undefined)));
|
|
50641
|
+
}
|
|
50642
|
+
this.postTipMessage('DownloadLatestUiResourceSuccess');
|
|
50643
|
+
}
|
|
50644
|
+
else if (this.isSupportResourceUpdate(params.updateType)) {
|
|
50478
50645
|
this.postTipMessage('CheckLatestUiResource');
|
|
50479
50646
|
const resourceUrl = DataManager.getSysResourcesLatestRelease({
|
|
50480
50647
|
features,
|
|
@@ -50483,46 +50650,20 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50483
50650
|
});
|
|
50484
50651
|
if (resourceUrl) {
|
|
50485
50652
|
this.postTipMessage('DownloadLatestUiResource');
|
|
50486
|
-
if (
|
|
50487
|
-
|
|
50488
|
-
|
|
50489
|
-
|
|
50490
|
-
|
|
50491
|
-
|
|
50492
|
-
artifact: entry.artifact,
|
|
50493
|
-
reader: params.artifactReader,
|
|
50494
|
-
});
|
|
50495
|
-
if (!source) {
|
|
50496
|
-
throw new Error('Firmware resource entry is not prepared');
|
|
50497
|
-
}
|
|
50498
|
-
sources.push({ entryName: resourceName, source });
|
|
50499
|
-
}
|
|
50500
|
-
yield updateResourcesFromSources(this.device.getCommands().typedCall.bind(this.device.getCommands()), this.postMessage, device, sources.map(entry => ({
|
|
50501
|
-
entryName: entry.entryName,
|
|
50502
|
-
source: entry.source,
|
|
50503
|
-
})));
|
|
50504
|
-
}
|
|
50505
|
-
finally {
|
|
50506
|
-
yield Promise.all(sources.map(entry => entry.source.close().catch(() => undefined)));
|
|
50507
|
-
}
|
|
50508
|
-
this.postTipMessage('DownloadLatestUiResourceSuccess');
|
|
50509
|
-
}
|
|
50510
|
-
else {
|
|
50511
|
-
if (params.artifactReader ||
|
|
50512
|
-
DataManager.getSettings('firmwareManifestMode') === 'external-only') {
|
|
50513
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware resource must be prepared by the external firmware host', {
|
|
50514
|
-
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
50515
|
-
artifactName: 'resource',
|
|
50516
|
-
});
|
|
50517
|
-
}
|
|
50518
|
-
const resourceBinary = (yield getSysResourceBinary(resourceUrl))
|
|
50519
|
-
.binary;
|
|
50520
|
-
this.postTipMessage('DownloadLatestUiResourceSuccess');
|
|
50521
|
-
yield updateResources(this.device.getCommands().typedCall.bind(this.device.getCommands()), this.postMessage, device, resourceBinary);
|
|
50653
|
+
if (params.artifactReader ||
|
|
50654
|
+
DataManager.getSettings('firmwareManifestMode') === 'external-only') {
|
|
50655
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware resource must be prepared by the external firmware host', {
|
|
50656
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
50657
|
+
artifactName: 'resource',
|
|
50658
|
+
});
|
|
50522
50659
|
}
|
|
50660
|
+
const resourceBinary = (yield getSysResourceBinary(resourceUrl))
|
|
50661
|
+
.binary;
|
|
50662
|
+
this.postTipMessage('DownloadLatestUiResourceSuccess');
|
|
50663
|
+
yield updateResources(this.device.getCommands().typedCall.bind(this.device.getCommands()), this.postMessage, device, resourceBinary);
|
|
50523
50664
|
}
|
|
50524
50665
|
}
|
|
50525
|
-
(
|
|
50666
|
+
(_e = (_d = this.device) === null || _d === void 0 ? void 0 : _d.commands) === null || _e === void 0 ? void 0 : _e.checkDisposed();
|
|
50526
50667
|
try {
|
|
50527
50668
|
this.postTipMessage('AutoRebootToBootloader');
|
|
50528
50669
|
const bootRes = yield commands.typedCall('DeviceBackToBoot', 'Success');
|
|
@@ -50535,9 +50676,9 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50535
50676
|
DevicePool.clearDeviceCache(serialNo);
|
|
50536
50677
|
}
|
|
50537
50678
|
delete DevicePool.devicesCache[''];
|
|
50538
|
-
yield ((
|
|
50679
|
+
yield ((_f = this.checkPromise) === null || _f === void 0 ? void 0 : _f.promise);
|
|
50539
50680
|
this.checkPromise = null;
|
|
50540
|
-
(
|
|
50681
|
+
(_h = (_g = this.device) === null || _g === void 0 ? void 0 : _g.commands) === null || _h === void 0 ? void 0 : _h.checkDisposed();
|
|
50541
50682
|
const isTouch = DeviceModelToTypes.model_touch.includes(deviceType);
|
|
50542
50683
|
yield wait(isTouch ? 3000 : 1500);
|
|
50543
50684
|
}
|
|
@@ -50550,7 +50691,7 @@ class FirmwareUpdateV2 extends BaseMethod {
|
|
|
50550
50691
|
}
|
|
50551
50692
|
}
|
|
50552
50693
|
const source = yield acquireFirmwareSource();
|
|
50553
|
-
(
|
|
50694
|
+
(_k = (_j = this.device) === null || _j === void 0 ? void 0 : _j.commands) === null || _k === void 0 ? void 0 : _k.checkDisposed();
|
|
50554
50695
|
yield this.device.acquire();
|
|
50555
50696
|
const response = yield uploadFirmwareFromSource(params.updateType, this.device.getCommands().typedCall.bind(this.device.getCommands()), this.postMessage, device, source, true, params.isUpdateBootloader);
|
|
50556
50697
|
if (this.connectId) {
|
|
@@ -50575,7 +50716,7 @@ class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod {
|
|
|
50575
50716
|
this.artifactSources = [];
|
|
50576
50717
|
}
|
|
50577
50718
|
init() {
|
|
50578
|
-
var _a, _b, _c
|
|
50719
|
+
var _a, _b, _c;
|
|
50579
50720
|
this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
|
|
50580
50721
|
this.requireDeviceMode = [];
|
|
50581
50722
|
this.useDevicePassphraseState = false;
|
|
@@ -50593,7 +50734,11 @@ class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod {
|
|
|
50593
50734
|
{ name: 'firmwareType', type: 'string' },
|
|
50594
50735
|
{ name: 'platform', type: 'string' },
|
|
50595
50736
|
]);
|
|
50596
|
-
const
|
|
50737
|
+
const hasPreparedPlan = payload.preparedPlan !== undefined;
|
|
50738
|
+
if (!hasPreparedPlan && payload.artifacts !== undefined) {
|
|
50739
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Firmware artifacts require a prepared plan');
|
|
50740
|
+
}
|
|
50741
|
+
const preparedPlan = hasPreparedPlan
|
|
50597
50742
|
? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
|
|
50598
50743
|
: undefined;
|
|
50599
50744
|
const hasLegacyInputs = [
|
|
@@ -50611,42 +50756,53 @@ class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod {
|
|
|
50611
50756
|
const artifactReader = preparedPlan
|
|
50612
50757
|
? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration, preparedPlan.preparedPlanDigest).artifactReader
|
|
50613
50758
|
: payload.artifactReader;
|
|
50759
|
+
const preparedArtifacts = {};
|
|
50614
50760
|
if (preparedPlan) {
|
|
50761
|
+
const componentTargets = ['bootloader', 'firmware', 'ble'];
|
|
50762
|
+
const supportedTargets = new Set([...componentTargets, 'resource']);
|
|
50763
|
+
const unsupportedTarget = preparedPlan.targetsToUpdate.find(target => !supportedTargets.has(target));
|
|
50764
|
+
if (unsupportedTarget) {
|
|
50765
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Firmware prepared plan target ${unsupportedTarget} is not supported by V3`, { firmwareUpdateCode: 'FirmwarePreparedPlanInvalid' });
|
|
50766
|
+
}
|
|
50767
|
+
for (const target of componentTargets) {
|
|
50768
|
+
if (preparedPlan.targetsToUpdate.includes(target)) {
|
|
50769
|
+
preparedArtifacts[target] = getFirmwareUpdatePreparedRawArtifact({
|
|
50770
|
+
preparedPlan,
|
|
50771
|
+
target,
|
|
50772
|
+
role: target,
|
|
50773
|
+
}).artifact;
|
|
50774
|
+
}
|
|
50775
|
+
}
|
|
50776
|
+
const resourceBindings = ((_b = (_a = payload.artifacts) === null || _a === void 0 ? void 0 : _a.resourceEntries) !== null && _b !== void 0 ? _b : []).map((entry) => ({
|
|
50777
|
+
target: 'resource',
|
|
50778
|
+
entryName: entry.entryName,
|
|
50779
|
+
artifact: entry.artifact,
|
|
50780
|
+
}));
|
|
50615
50781
|
assertFirmwareUpdatePreparedPlanBinding({
|
|
50616
50782
|
preparedPlan,
|
|
50617
50783
|
executor: 'v3',
|
|
50618
50784
|
platform: payload.platform,
|
|
50619
|
-
scopeTargets: [
|
|
50785
|
+
scopeTargets: [
|
|
50786
|
+
'bootloader',
|
|
50787
|
+
'firmware',
|
|
50788
|
+
'ble',
|
|
50789
|
+
...(resourceBindings.length ? ['resource'] : []),
|
|
50790
|
+
],
|
|
50620
50791
|
bindings: [
|
|
50621
|
-
...(
|
|
50622
|
-
|
|
50623
|
-
|
|
50624
|
-
|
|
50625
|
-
|
|
50626
|
-
|
|
50627
|
-
|
|
50628
|
-
|
|
50629
|
-
|
|
50630
|
-
|
|
50631
|
-
|
|
50632
|
-
|
|
50633
|
-
|
|
50634
|
-
|
|
50635
|
-
]
|
|
50636
|
-
: []),
|
|
50637
|
-
...(((_c = payload.artifacts) === null || _c === void 0 ? void 0 : _c.ble)
|
|
50638
|
-
? [
|
|
50639
|
-
{
|
|
50640
|
-
target: 'ble',
|
|
50641
|
-
artifact: payload.artifacts.ble,
|
|
50642
|
-
},
|
|
50643
|
-
]
|
|
50644
|
-
: []),
|
|
50645
|
-
...((_e = (_d = payload.artifacts) === null || _d === void 0 ? void 0 : _d.resourceEntries) !== null && _e !== void 0 ? _e : []).map((entry) => ({
|
|
50646
|
-
target: 'resource',
|
|
50647
|
-
entryName: entry.entryName,
|
|
50648
|
-
artifact: entry.artifact,
|
|
50649
|
-
})),
|
|
50792
|
+
...componentTargets.flatMap(target => {
|
|
50793
|
+
var _a;
|
|
50794
|
+
const plannedArtifact = preparedArtifacts[target];
|
|
50795
|
+
const suppliedArtifact = (_a = payload.artifacts) === null || _a === void 0 ? void 0 : _a[target];
|
|
50796
|
+
return plannedArtifact || suppliedArtifact
|
|
50797
|
+
? [
|
|
50798
|
+
{
|
|
50799
|
+
target,
|
|
50800
|
+
artifact: suppliedArtifact !== null && suppliedArtifact !== void 0 ? suppliedArtifact : plannedArtifact,
|
|
50801
|
+
},
|
|
50802
|
+
]
|
|
50803
|
+
: [];
|
|
50804
|
+
}),
|
|
50805
|
+
...resourceBindings,
|
|
50650
50806
|
],
|
|
50651
50807
|
});
|
|
50652
50808
|
}
|
|
@@ -50660,10 +50816,10 @@ class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod {
|
|
|
50660
50816
|
bootloaderBinary: payload.bootloaderBinary,
|
|
50661
50817
|
firmwareVersion: payload.firmwareVersion,
|
|
50662
50818
|
resourceBinary: payload.resourceBinary,
|
|
50663
|
-
firmwareType: (
|
|
50819
|
+
firmwareType: (_c = preparedPlan === null || preparedPlan === void 0 ? void 0 : preparedPlan.firmwareType) !== null && _c !== void 0 ? _c : payload.firmwareType,
|
|
50664
50820
|
platform: payload.platform,
|
|
50665
50821
|
artifactReader,
|
|
50666
|
-
artifacts:
|
|
50822
|
+
artifacts: preparedPlan ? preparedArtifacts : undefined,
|
|
50667
50823
|
};
|
|
50668
50824
|
}
|
|
50669
50825
|
run() {
|
|
@@ -50769,19 +50925,21 @@ class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod {
|
|
|
50769
50925
|
prepareResourceInput(firmwareType) {
|
|
50770
50926
|
var _a;
|
|
50771
50927
|
return __awaiter(this, void 0, void 0, function* () {
|
|
50772
|
-
|
|
50773
|
-
|
|
50774
|
-
|
|
50775
|
-
|
|
50776
|
-
|
|
50928
|
+
if ((_a = this.params.preparedPlan) === null || _a === void 0 ? void 0 : _a.targetsToUpdate.includes('resource')) {
|
|
50929
|
+
const verifiedEntries = yield readVerifiedPreparedResourceArchive({
|
|
50930
|
+
preparedPlan: this.params.preparedPlan,
|
|
50931
|
+
reader: this.params.artifactReader,
|
|
50932
|
+
});
|
|
50777
50933
|
const resourceEntries = [];
|
|
50778
|
-
for (const entry of
|
|
50779
|
-
const
|
|
50780
|
-
const source = yield this.openArtifactSource(undefined, entry.artifact);
|
|
50934
|
+
for (const entry of verifiedEntries) {
|
|
50935
|
+
const source = yield this.openArtifactSource(entry.binary, undefined);
|
|
50781
50936
|
if (!source) {
|
|
50782
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Firmware resource entry ${entry.entryName} is
|
|
50937
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Firmware resource entry ${entry.entryName} is empty`, {
|
|
50938
|
+
firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch',
|
|
50939
|
+
artifactName: 'resource',
|
|
50940
|
+
});
|
|
50783
50941
|
}
|
|
50784
|
-
resourceEntries.push({ entryName:
|
|
50942
|
+
resourceEntries.push({ entryName: entry.entryName, source });
|
|
50785
50943
|
}
|
|
50786
50944
|
return {
|
|
50787
50945
|
resourceBinary: null,
|
|
@@ -51476,12 +51634,12 @@ const PROTOCOL_V2_REMOTE_COMPONENT_TARGETS = {
|
|
|
51476
51634
|
const PROTOCOL_V2_FIRMWARE_STAGING_PATHS = new Set(Object.values(PROTOCOL_V2_REMOTE_COMPONENT_TARGETS).map(target => `${PROTOCOL_V2_FIRMWARE_STAGING_VOLUME}${target.fileName}`));
|
|
51477
51635
|
const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH = 'vol0:/loaders/bootloader/boot_resource.okpkg';
|
|
51478
51636
|
const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_STAGING_PATH = `${PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH}.staging`;
|
|
51479
|
-
const
|
|
51480
|
-
|
|
51481
|
-
|
|
51482
|
-
|
|
51483
|
-
|
|
51484
|
-
|
|
51637
|
+
const isProtocolV2BootResourcePackagePath = (devicePath) => typeof devicePath === 'string' &&
|
|
51638
|
+
devicePath.replace(/^vol0:(?!\/)/i, 'vol0:/').toLowerCase() ===
|
|
51639
|
+
PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH;
|
|
51640
|
+
const resolveProtocolV2ResourceWritePath = (devicePath) => isProtocolV2BootResourcePackagePath(devicePath)
|
|
51641
|
+
? PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_STAGING_PATH
|
|
51642
|
+
: devicePath;
|
|
51485
51643
|
const PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID = new Map([
|
|
51486
51644
|
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER, 'boot'],
|
|
51487
51645
|
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P1, 'app_v1'],
|
|
@@ -51653,6 +51811,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51653
51811
|
super(...arguments);
|
|
51654
51812
|
this.protocolV2PreparedSources = [];
|
|
51655
51813
|
this.protocolV2ExecutionInLoader = false;
|
|
51814
|
+
this.protocolV2BootResourceStagingSafe = false;
|
|
51656
51815
|
this.protocolV2CompletedTargetVersions = new Map();
|
|
51657
51816
|
this.protocolV2FinalStatusVerified = false;
|
|
51658
51817
|
}
|
|
@@ -52808,6 +52967,15 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52808
52967
|
}
|
|
52809
52968
|
buildProtocolV2ExecutionPhases({ installSources, resourceSources, }) {
|
|
52810
52969
|
const phases = [];
|
|
52970
|
+
const bootResourceSources = resourceSources.filter(source => isProtocolV2BootResourcePackagePath(source.devicePath));
|
|
52971
|
+
const remainingResourceSources = resourceSources.filter(source => !isProtocolV2BootResourcePackagePath(source.devicePath));
|
|
52972
|
+
if (bootResourceSources.length > 0) {
|
|
52973
|
+
phases.push({
|
|
52974
|
+
kind: 'resource-sync',
|
|
52975
|
+
installSources: [],
|
|
52976
|
+
resourceSources: bootResourceSources,
|
|
52977
|
+
});
|
|
52978
|
+
}
|
|
52811
52979
|
const bootloaderSources = installSources.filter(source => source.kind === 'bootloader');
|
|
52812
52980
|
if (bootloaderSources.length > 0) {
|
|
52813
52981
|
phases.push({
|
|
@@ -52820,11 +52988,11 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52820
52988
|
resourceSources: [],
|
|
52821
52989
|
});
|
|
52822
52990
|
}
|
|
52823
|
-
if (
|
|
52991
|
+
if (remainingResourceSources.length > 0) {
|
|
52824
52992
|
phases.push({
|
|
52825
52993
|
kind: 'resource-sync',
|
|
52826
52994
|
installSources: [],
|
|
52827
|
-
resourceSources,
|
|
52995
|
+
resourceSources: remainingResourceSources,
|
|
52828
52996
|
});
|
|
52829
52997
|
}
|
|
52830
52998
|
const componentSources = installSources.filter(source => source.kind !== 'bootloader');
|
|
@@ -52844,6 +53012,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52844
53012
|
}
|
|
52845
53013
|
executeProtocolV2Phases({ installSources, resourceSources, }) {
|
|
52846
53014
|
return __awaiter(this, void 0, void 0, function* () {
|
|
53015
|
+
this.protocolV2BootResourceStagingSafe = false;
|
|
52847
53016
|
const phases = this.buildProtocolV2ExecutionPhases({
|
|
52848
53017
|
installSources,
|
|
52849
53018
|
resourceSources,
|
|
@@ -52854,10 +53023,14 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52854
53023
|
}
|
|
52855
53024
|
if (phase.kind === 'resource-sync') {
|
|
52856
53025
|
yield this.enterProtocolV2BootloaderMode();
|
|
53026
|
+
if (!phase.resourceSources.some(source => isProtocolV2BootResourcePackagePath(source.devicePath))) {
|
|
53027
|
+
yield this.ensureProtocolV2BootResourceStagingIsEmpty();
|
|
53028
|
+
}
|
|
52857
53029
|
yield this.executeProtocolV2TransferPhase(phase);
|
|
52858
53030
|
}
|
|
52859
53031
|
else if (phase.kind === 'bootloader-install' || phase.kind === 'component-install') {
|
|
52860
53032
|
yield this.enterProtocolV2BootloaderMode();
|
|
53033
|
+
yield this.ensureProtocolV2BootResourceStagingIsEmpty();
|
|
52861
53034
|
yield this.executeProtocolV2TransferPhase(phase);
|
|
52862
53035
|
yield this.exitProtocolV2BootloaderToNormal();
|
|
52863
53036
|
}
|
|
@@ -52869,6 +53042,31 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52869
53042
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 execution has no final verification phase');
|
|
52870
53043
|
});
|
|
52871
53044
|
}
|
|
53045
|
+
ensureProtocolV2BootResourceStagingIsEmpty() {
|
|
53046
|
+
var _a, _b;
|
|
53047
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
53048
|
+
if (this.protocolV2BootResourceStagingSafe)
|
|
53049
|
+
return;
|
|
53050
|
+
const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
|
|
53051
|
+
const query = () => typedCall('FilesystemPathInfoQuery', 'FilesystemPathInfo', {
|
|
53052
|
+
path: PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_STAGING_PATH,
|
|
53053
|
+
});
|
|
53054
|
+
const current = yield query();
|
|
53055
|
+
if ((_a = current.message) === null || _a === void 0 ? void 0 : _a.exist) {
|
|
53056
|
+
if (current.message.directory) {
|
|
53057
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.EmmcFileWriteFirmwareError, 'Protocol V2 boot resource staging path is not a file');
|
|
53058
|
+
}
|
|
53059
|
+
yield typedCall('FilesystemFileDelete', 'Success', {
|
|
53060
|
+
path: PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_STAGING_PATH,
|
|
53061
|
+
});
|
|
53062
|
+
const remaining = yield query();
|
|
53063
|
+
if ((_b = remaining.message) === null || _b === void 0 ? void 0 : _b.exist) {
|
|
53064
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.EmmcFileWriteFirmwareError, 'Protocol V2 stale boot resource staging file could not be removed');
|
|
53065
|
+
}
|
|
53066
|
+
}
|
|
53067
|
+
this.protocolV2BootResourceStagingSafe = true;
|
|
53068
|
+
});
|
|
53069
|
+
}
|
|
52872
53070
|
executeProtocolV2SourceUpdate({ installSources, resourceSources, }) {
|
|
52873
53071
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52874
53072
|
return this.executeProtocolV2Phases({
|
|
@@ -52907,7 +53105,8 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52907
53105
|
let totalSize = installSources.reduce((total, item) => total + item.source.size, 0);
|
|
52908
53106
|
const resourcesToSync = [];
|
|
52909
53107
|
for (const resource of resourceSources) {
|
|
52910
|
-
|
|
53108
|
+
const requiresFreshStaging = isProtocolV2BootResourcePackagePath(resource.devicePath);
|
|
53109
|
+
if (!requiresFreshStaging && (yield this.isProtocolV2ResourceBundleUpToDate(resource))) {
|
|
52911
53110
|
Log$6.log(`[FirmwareUpdateV4] skip RESC bundle ${resource.name}; already up to date`);
|
|
52912
53111
|
}
|
|
52913
53112
|
else {
|
|
@@ -52926,6 +53125,9 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52926
53125
|
totalSize,
|
|
52927
53126
|
});
|
|
52928
53127
|
yield this.verifyProtocolV2StagedFile(writePath, resource.source.size);
|
|
53128
|
+
if (isProtocolV2BootResourcePackagePath(resource.devicePath)) {
|
|
53129
|
+
this.protocolV2BootResourceStagingSafe = true;
|
|
53130
|
+
}
|
|
52929
53131
|
}
|
|
52930
53132
|
const stagedInstallTargets = [];
|
|
52931
53133
|
for (const item of installSources) {
|