@onekeyfe/hd-core 1.2.0-alpha.82 → 1.2.0-alpha.85
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 +285 -13
- package/__tests__/check-firmware-release-protocol-v2.test.ts +6 -0
- package/__tests__/firmware-memory-host.test.ts +105 -0
- package/__tests__/firmware-update/firmware-update-plan.test.ts +15 -70
- package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +53 -1
- package/__tests__/protocol-v2-resources.test.ts +0 -38
- package/__tests__/protocol-v2.test.ts +212 -320
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +1 -2
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareMemoryHost.d.ts +27 -0
- package/dist/api/firmware/FirmwareMemoryHost.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +33 -1
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -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.map +1 -1
- package/dist/index.d.ts +25 -64
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +546 -387
- package/dist/inject.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/resources.d.ts +0 -17
- package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
- package/dist/types/api/checkAllFirmwareRelease.d.ts +1 -0
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/export.d.ts +0 -1
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdate.d.ts +0 -10
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +0 -2
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/settings.d.ts +0 -11
- package/dist/types/settings.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/CheckAllFirmwareRelease.ts +72 -5
- package/src/api/FirmwareUpdateV4.ts +154 -165
- package/src/api/firmware/FirmwareMemoryHost.ts +171 -0
- package/src/api/firmware/FirmwareUpdatePlan.ts +176 -79
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +8 -1
- package/src/api/firmware/protocolV2Release.ts +2 -0
- package/src/index.ts +6 -1
- package/src/inject.ts +0 -2
- package/src/protocols/protocol-v2/resources.ts +0 -47
- package/src/types/api/checkAllFirmwareRelease.ts +1 -0
- package/src/types/api/export.ts +0 -4
- package/src/types/api/firmwareUpdate.ts +0 -15
- package/src/types/api/index.ts +0 -2
- package/src/types/settings.ts +0 -20
- package/src/utils/deviceFeaturesUtils.ts +2 -2
- package/dist/types/api/protocolV2ResourceManifest.d.ts +0 -17
- package/dist/types/api/protocolV2ResourceManifest.d.ts.map +0 -1
- package/src/types/api/protocolV2ResourceManifest.ts +0 -19
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;
|
|
@@ -609,6 +613,18 @@ const validateFirmwareUpdatePlanForceTargets = (value) => {
|
|
|
609
613
|
}
|
|
610
614
|
return [...value];
|
|
611
615
|
};
|
|
616
|
+
const validateProtocolV2FirmwareUpdateTargets = (value) => {
|
|
617
|
+
if (value === undefined) {
|
|
618
|
+
return [];
|
|
619
|
+
}
|
|
620
|
+
if (!Array.isArray(value) ||
|
|
621
|
+
value.length > PROTOCOL_V2_FIRMWARE_UPDATE_TARGETS.size ||
|
|
622
|
+
value.some(target => !PROTOCOL_V2_FIRMWARE_UPDATE_TARGETS.has(target)) ||
|
|
623
|
+
new Set(value).size !== value.length) {
|
|
624
|
+
return planError('Protocol V2 firmware update targets are invalid');
|
|
625
|
+
}
|
|
626
|
+
return [...value];
|
|
627
|
+
};
|
|
612
628
|
const assertExactKeys = (value, required, optional = []) => {
|
|
613
629
|
const allowed = new Set([...required, ...optional]);
|
|
614
630
|
if (required.some(key => !Object.prototype.hasOwnProperty.call(value, key)) ||
|
|
@@ -773,7 +789,7 @@ const selectResourceUrl = ({ release, features, platform, }) => {
|
|
|
773
789
|
};
|
|
774
790
|
const getExecutor = (features) => {
|
|
775
791
|
const deviceType = getDeviceType(features);
|
|
776
|
-
if (deviceType === hdShared.EDeviceType.Pro2) {
|
|
792
|
+
if (deviceType === hdShared.EDeviceType.Pro2 || deviceType === hdShared.EDeviceType.Neo) {
|
|
777
793
|
return 'v4';
|
|
778
794
|
}
|
|
779
795
|
if (deviceType === hdShared.EDeviceType.Pro &&
|
|
@@ -782,7 +798,7 @@ const getExecutor = (features) => {
|
|
|
782
798
|
}
|
|
783
799
|
return 'v2';
|
|
784
800
|
};
|
|
785
|
-
const buildProtocolV2Artifacts = (release, { includeComponents = true,
|
|
801
|
+
const buildProtocolV2Artifacts = (release, { includeComponents = true, componentTargets: selectedComponentTargets, } = {}) => {
|
|
786
802
|
var _a;
|
|
787
803
|
const components = asRecord(release.components);
|
|
788
804
|
if (includeComponents && !components) {
|
|
@@ -794,49 +810,38 @@ const buildProtocolV2Artifacts = (release, { includeComponents = true, includeRe
|
|
|
794
810
|
const componentKeys = includeComponents && components
|
|
795
811
|
? [...installOrder, ...Object.keys(components).filter(key => !installOrder.includes(key))]
|
|
796
812
|
: [];
|
|
813
|
+
const selectedComponentKeys = selectedComponentTargets
|
|
814
|
+
? componentKeys.filter(key => {
|
|
815
|
+
var _a;
|
|
816
|
+
const component = asRecord(components === null || components === void 0 ? void 0 : components[key]);
|
|
817
|
+
const targetName = (_a = asString(component === null || component === void 0 ? void 0 : component.target)) === null || _a === void 0 ? void 0 : _a.toUpperCase();
|
|
818
|
+
const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
|
|
819
|
+
return !!target && selectedComponentTargets.has(target);
|
|
820
|
+
})
|
|
821
|
+
: componentKeys;
|
|
797
822
|
const artifacts = [];
|
|
798
823
|
const targets = [];
|
|
799
|
-
const
|
|
800
|
-
for (const key of
|
|
824
|
+
const componentTargetSet = new Set();
|
|
825
|
+
for (const key of selectedComponentKeys) {
|
|
801
826
|
const component = asRecord(components === null || components === void 0 ? void 0 : components[key]);
|
|
802
827
|
const targetName = (_a = asString(component === null || component === void 0 ? void 0 : component.target)) === null || _a === void 0 ? void 0 : _a.toUpperCase();
|
|
828
|
+
const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
|
|
803
829
|
if (targetName === 'ROMLOADER') {
|
|
804
830
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 ROMLOADER requires its dedicated loader flow', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
805
831
|
}
|
|
806
|
-
const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
|
|
807
832
|
if (!component || !target) {
|
|
808
833
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 component ${key} has an unsupported target`, { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
809
834
|
}
|
|
810
|
-
if (
|
|
835
|
+
if (componentTargetSet.has(target)) {
|
|
811
836
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 component ${key} duplicates target ${target}`, { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
812
837
|
}
|
|
813
|
-
|
|
838
|
+
componentTargetSet.add(target);
|
|
814
839
|
artifacts.push(Object.assign(Object.assign({ artifactId: `component:${target}`, role: 'component', target, url: assertArtifactUrl(component.url, `Protocol V2 component ${key}`), container: 'raw', logicalName: key }, asIntegrity({
|
|
815
840
|
size: component.expectedSize,
|
|
816
841
|
sha256: component.fingerprint,
|
|
817
842
|
})), (asVersion(component.version) ? { targetVersion: asVersion(component.version) } : {})));
|
|
818
843
|
targets.push(target);
|
|
819
844
|
}
|
|
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
845
|
return { artifacts, targets: [...new Set(targets)] };
|
|
841
846
|
};
|
|
842
847
|
const isForcedTargetRepresented = ({ executor, forcedTarget, artifacts, targetsToUpdate, }) => {
|
|
@@ -865,6 +870,78 @@ const assertForcedTargetsRepresented = ({ executor, forcedTargets, artifacts, ta
|
|
|
865
870
|
}
|
|
866
871
|
}
|
|
867
872
|
};
|
|
873
|
+
const finalizeFirmwareUpdatePlan = ({ features, firmwareType, platform, artifacts, targetsToUpdate, }) => {
|
|
874
|
+
const executor = getExecutor(features);
|
|
875
|
+
const bootloaderMode = resolveDeviceBootloaderMode(features);
|
|
876
|
+
const reportedIdentity = getDeviceUUID(features);
|
|
877
|
+
const deviceIdentity = reportedIdentity === 'unavailable' ? '' : reportedIdentity;
|
|
878
|
+
if (artifacts.length > 0 &&
|
|
879
|
+
(platform === 'native' || platform === 'desktop') &&
|
|
880
|
+
!deviceIdentity &&
|
|
881
|
+
!(bootloaderMode && executor === 'v2')) {
|
|
882
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Prepared firmware update requires a stable device identity', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
883
|
+
}
|
|
884
|
+
const planWithoutDigest = {
|
|
885
|
+
schemaVersion: 2,
|
|
886
|
+
executor,
|
|
887
|
+
deviceIdentity: deviceIdentity || 'unavailable',
|
|
888
|
+
deviceModel: String(getDeviceType(features)),
|
|
889
|
+
firmwareType,
|
|
890
|
+
platform,
|
|
891
|
+
artifacts,
|
|
892
|
+
targetsToUpdate,
|
|
893
|
+
};
|
|
894
|
+
return assertFirmwareUpdatePlan(Object.assign(Object.assign({}, planWithoutDigest), { planDigest: digestFirmwareUpdatePlan(planWithoutDigest) }));
|
|
895
|
+
};
|
|
896
|
+
const buildProtocolV2FirmwareUpdatePlan = ({ features, firmwareType, platform, release, targetsToUpdate, forceUpdateTargets, resourceArchive, }) => {
|
|
897
|
+
const validatedForceTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
|
|
898
|
+
if (validatedForceTargets.some(target => target === 'ble' || target === 'bootloader')) {
|
|
899
|
+
planError('Protocol V2 does not support forced BLE or legacy bootloader targets');
|
|
900
|
+
}
|
|
901
|
+
const requestedComponentTargets = new Set(targetsToUpdate.filter(target => target !== 'resource'));
|
|
902
|
+
if (getDeviceType(features) === hdShared.EDeviceType.Neo &&
|
|
903
|
+
(requestedComponentTargets.has('se03') || requestedComponentTargets.has('se04'))) {
|
|
904
|
+
planError('Neo does not support Protocol V2 targets se03 or se04');
|
|
905
|
+
}
|
|
906
|
+
const protocolV2 = buildProtocolV2Artifacts(release !== null && release !== void 0 ? release : {}, {
|
|
907
|
+
includeComponents: requestedComponentTargets.size > 0,
|
|
908
|
+
componentTargets: requestedComponentTargets,
|
|
909
|
+
});
|
|
910
|
+
const resourceRequested = targetsToUpdate.includes('resource');
|
|
911
|
+
if (resourceRequested) {
|
|
912
|
+
const archive = resourceArchive;
|
|
913
|
+
if (!archive) {
|
|
914
|
+
return planError('Protocol V2 resource target has no resource archive');
|
|
915
|
+
}
|
|
916
|
+
const integrity = asIntegrity({
|
|
917
|
+
size: archive.archiveSize,
|
|
918
|
+
sha256: archive.archiveSha256,
|
|
919
|
+
});
|
|
920
|
+
if (integrity.expectedSize === undefined || integrity.expectedSha256 === undefined) {
|
|
921
|
+
planError('Protocol V2 resource archive integrity metadata is invalid');
|
|
922
|
+
}
|
|
923
|
+
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));
|
|
924
|
+
protocolV2.targets.push('resource');
|
|
925
|
+
}
|
|
926
|
+
const representedTargets = new Set(protocolV2.targets);
|
|
927
|
+
const missingTarget = Array.from(requestedComponentTargets).find(target => !representedTargets.has(target));
|
|
928
|
+
if (missingTarget) {
|
|
929
|
+
planError(`Protocol V2 release does not contain requested target ${missingTarget}`);
|
|
930
|
+
}
|
|
931
|
+
if (validatedForceTargets.includes('firmware') && protocolV2.targets.length === 0) {
|
|
932
|
+
planError('Forced firmware update target firmware is not represented by the plan');
|
|
933
|
+
}
|
|
934
|
+
if (validatedForceTargets.includes('resource') && !resourceArchive) {
|
|
935
|
+
planError('Forced firmware update target resource has no Protocol V2 resource archive');
|
|
936
|
+
}
|
|
937
|
+
return finalizeFirmwareUpdatePlan({
|
|
938
|
+
features,
|
|
939
|
+
firmwareType,
|
|
940
|
+
platform,
|
|
941
|
+
artifacts: protocolV2.artifacts,
|
|
942
|
+
targetsToUpdate: protocolV2.targets,
|
|
943
|
+
});
|
|
944
|
+
};
|
|
868
945
|
const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, ble, bootloader, forceUpdateTargets, }) => {
|
|
869
946
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
870
947
|
const executor = getExecutor(features);
|
|
@@ -886,7 +963,6 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
|
|
|
886
963
|
if (executor === 'v4' && (shouldUpdateFirmware || shouldUpdateResource)) {
|
|
887
964
|
const protocolV2 = buildProtocolV2Artifacts(firmwareRelease !== null && firmwareRelease !== void 0 ? firmwareRelease : {}, {
|
|
888
965
|
includeComponents: shouldUpdateFirmware,
|
|
889
|
-
includeResources: shouldUpdateResource,
|
|
890
966
|
});
|
|
891
967
|
artifacts = protocolV2.artifacts;
|
|
892
968
|
targetsToUpdate = protocolV2.targets;
|
|
@@ -951,25 +1027,13 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
|
|
|
951
1027
|
artifacts,
|
|
952
1028
|
targetsToUpdate,
|
|
953
1029
|
});
|
|
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)),
|
|
1030
|
+
return finalizeFirmwareUpdatePlan({
|
|
1031
|
+
features,
|
|
967
1032
|
firmwareType,
|
|
968
1033
|
platform,
|
|
969
1034
|
artifacts,
|
|
970
1035
|
targetsToUpdate,
|
|
971
|
-
};
|
|
972
|
-
return assertFirmwareUpdatePlan(Object.assign(Object.assign({}, planWithoutDigest), { planDigest: digestFirmwareUpdatePlan(planWithoutDigest) }));
|
|
1036
|
+
});
|
|
973
1037
|
};
|
|
974
1038
|
|
|
975
1039
|
const preparedPlanError = (message) => {
|
|
@@ -1090,7 +1154,7 @@ const prepareFirmwareUpdatePlan = ({ plan: value, leaseRef, artifacts, }) => {
|
|
|
1090
1154
|
return Object.assign(Object.assign({}, planWithoutDigest), { preparedPlanDigest: digestPreparedPlan(planWithoutDigest) });
|
|
1091
1155
|
};
|
|
1092
1156
|
const validateFirmwareUpdatePreparedPlan = (value) => {
|
|
1093
|
-
var _a, _b, _c;
|
|
1157
|
+
var _a, _b, _c, _d;
|
|
1094
1158
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
1095
1159
|
return preparedPlanError('Firmware prepared plan must be an object');
|
|
1096
1160
|
}
|
|
@@ -1170,7 +1234,13 @@ const validateFirmwareUpdatePreparedPlan = (value) => {
|
|
|
1170
1234
|
artifactIds.add(artifact.artifactId);
|
|
1171
1235
|
artifactTargets.add(artifact.target);
|
|
1172
1236
|
assertFirmwareArtifactReference(artifact.artifact);
|
|
1173
|
-
(_c = artifact.materializedEntries) === null || _c === void 0 ? void 0 : _c.
|
|
1237
|
+
const materializedEntryNames = (_d = (_c = artifact.materializedEntries) === null || _c === void 0 ? void 0 : _c.map(entry => {
|
|
1238
|
+
assertPreparedEntry(entry);
|
|
1239
|
+
return getFirmwareUpdateResourceName(entry.entryName).toLowerCase();
|
|
1240
|
+
})) !== null && _d !== void 0 ? _d : [];
|
|
1241
|
+
if (new Set(materializedEntryNames).size !== materializedEntryNames.length) {
|
|
1242
|
+
return preparedPlanError('Firmware prepared plan contains duplicate entry names');
|
|
1243
|
+
}
|
|
1174
1244
|
}
|
|
1175
1245
|
if (preparedPlan.targetsToUpdate.some(target => !FIRMWARE_UPDATE_PLAN_TARGETS.has(target)) ||
|
|
1176
1246
|
new Set(preparedPlan.targetsToUpdate).size !== preparedPlan.targetsToUpdate.length ||
|
|
@@ -1265,201 +1335,6 @@ const assertFirmwareUpdatePreparedPlanBinding = ({ preparedPlan: value, executor
|
|
|
1265
1335
|
return preparedPlan;
|
|
1266
1336
|
};
|
|
1267
1337
|
|
|
1268
|
-
const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1 = 'vol0:/loaders/bootloader/boot_resource.okpkg';
|
|
1269
|
-
const SHA256_HEX_LENGTH = 64;
|
|
1270
|
-
function normalizeHex$1(value, expectedLength, field) {
|
|
1271
|
-
if (typeof value !== 'string') {
|
|
1272
|
-
throw new Error(`Invalid Pro2 resource ${field}: expected a hexadecimal string`);
|
|
1273
|
-
}
|
|
1274
|
-
const normalized = value.replace(/^0x/i, '').toLowerCase();
|
|
1275
|
-
if (normalized.length !== expectedLength || !/^[0-9a-f]+$/.test(normalized)) {
|
|
1276
|
-
throw new Error(`Invalid Pro2 resource ${field}: expected ${expectedLength} hexadecimal characters`);
|
|
1277
|
-
}
|
|
1278
|
-
return normalized;
|
|
1279
|
-
}
|
|
1280
|
-
function parseProtocolV2Resources(value) {
|
|
1281
|
-
if (value === undefined)
|
|
1282
|
-
return undefined;
|
|
1283
|
-
if (!value || typeof value !== 'object') {
|
|
1284
|
-
throw new Error('Invalid Pro2 resources config');
|
|
1285
|
-
}
|
|
1286
|
-
const { source } = value;
|
|
1287
|
-
if (!source || typeof source !== 'object') {
|
|
1288
|
-
throw new Error('Invalid Pro2 resources config: source is required');
|
|
1289
|
-
}
|
|
1290
|
-
const { archiveUrl, archiveSha256, archiveSize } = source;
|
|
1291
|
-
if (typeof archiveUrl !== 'string' || !archiveUrl.startsWith('https://')) {
|
|
1292
|
-
throw new Error('Invalid Pro2 resources config: source.archiveUrl must use HTTPS');
|
|
1293
|
-
}
|
|
1294
|
-
if (typeof archiveSha256 !== 'string' || !/^[0-9a-fA-F]{64}$/.test(archiveSha256)) {
|
|
1295
|
-
throw new Error('Invalid Pro2 resources config: source.archiveSha256 must be a SHA-256 digest');
|
|
1296
|
-
}
|
|
1297
|
-
if (!Number.isSafeInteger(archiveSize) || archiveSize <= 0) {
|
|
1298
|
-
throw new Error('Invalid Pro2 resources config: source.archiveSize must be a positive integer');
|
|
1299
|
-
}
|
|
1300
|
-
return {
|
|
1301
|
-
source: {
|
|
1302
|
-
archiveUrl,
|
|
1303
|
-
archiveSha256: archiveSha256.toLowerCase(),
|
|
1304
|
-
archiveSize: archiveSize,
|
|
1305
|
-
},
|
|
1306
|
-
};
|
|
1307
|
-
}
|
|
1308
|
-
const PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS = [
|
|
1309
|
-
'vol0:/bundles/',
|
|
1310
|
-
'vol0:/loaders/rom/',
|
|
1311
|
-
];
|
|
1312
|
-
function isAllowedManifestDevicePath(path) {
|
|
1313
|
-
if (!path.endsWith('.okpkg') ||
|
|
1314
|
-
path.includes('\\') ||
|
|
1315
|
-
path.includes('//') ||
|
|
1316
|
-
path.split('/').some(part => part === '.' || part === '..')) {
|
|
1317
|
-
return false;
|
|
1318
|
-
}
|
|
1319
|
-
if (path === PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) {
|
|
1320
|
-
return true;
|
|
1321
|
-
}
|
|
1322
|
-
return PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS.some(root => path.startsWith(root));
|
|
1323
|
-
}
|
|
1324
|
-
function assertManifestString(value, field) {
|
|
1325
|
-
if (typeof value !== 'string' || value.length === 0) {
|
|
1326
|
-
throw new Error(`Invalid Pro2 resource manifest ${field}`);
|
|
1327
|
-
}
|
|
1328
|
-
return value;
|
|
1329
|
-
}
|
|
1330
|
-
function assertManifestRelativePath(value, field) {
|
|
1331
|
-
const path = assertManifestString(value, field);
|
|
1332
|
-
if (path.startsWith('/') ||
|
|
1333
|
-
path.includes('\\') ||
|
|
1334
|
-
path.includes(':') ||
|
|
1335
|
-
path.split('/').some(part => !part || part === '.' || part === '..')) {
|
|
1336
|
-
throw new Error(`Invalid Pro2 resource manifest ${field}`);
|
|
1337
|
-
}
|
|
1338
|
-
return path;
|
|
1339
|
-
}
|
|
1340
|
-
function parseProtocolV2ResourceManifestFile(value, index) {
|
|
1341
|
-
var _a;
|
|
1342
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
1343
|
-
throw new Error(`Invalid Pro2 resource manifest files[${index}]`);
|
|
1344
|
-
}
|
|
1345
|
-
const file = value;
|
|
1346
|
-
const archivePath = assertManifestRelativePath(file.archive_path, `files[${index}].archive_path`);
|
|
1347
|
-
const originalName = assertManifestRelativePath(file.original_name, `files[${index}].original_name`);
|
|
1348
|
-
if (originalName.includes('/')) {
|
|
1349
|
-
throw new Error(`Invalid Pro2 resource manifest files[${index}].original_name`);
|
|
1350
|
-
}
|
|
1351
|
-
const devicePath = assertManifestString(file.device_path, `files[${index}].device_path`);
|
|
1352
|
-
if (!isAllowedManifestDevicePath(devicePath)) {
|
|
1353
|
-
throw new Error(`Invalid Pro2 resource manifest files[${index}].device_path`);
|
|
1354
|
-
}
|
|
1355
|
-
if (!Number.isSafeInteger(file.size) || Number(file.size) <= 0) {
|
|
1356
|
-
throw new Error(`Invalid Pro2 resource manifest files[${index}].size`);
|
|
1357
|
-
}
|
|
1358
|
-
const digest = normalizeHex$1(file.sha256, SHA256_HEX_LENGTH, `files[${index}].sha256`);
|
|
1359
|
-
if (file.signed !== true) {
|
|
1360
|
-
throw new Error(`Invalid Pro2 resource manifest files[${index}].signed`);
|
|
1361
|
-
}
|
|
1362
|
-
if (file.sig_algo !== 'ed25519' && file.sig_algo !== 'mldsa65') {
|
|
1363
|
-
throw new Error(`Invalid Pro2 resource manifest files[${index}].sig_algo`);
|
|
1364
|
-
}
|
|
1365
|
-
if (file.payload_version !== null && typeof file.payload_version !== 'string') {
|
|
1366
|
-
throw new Error(`Invalid Pro2 resource manifest files[${index}].payload_version`);
|
|
1367
|
-
}
|
|
1368
|
-
if (!archivePath.endsWith('.okpkg') || !originalName.endsWith('.okpkg')) {
|
|
1369
|
-
throw new Error(`Invalid Pro2 resource manifest files[${index}] package extension`);
|
|
1370
|
-
}
|
|
1371
|
-
return {
|
|
1372
|
-
archive_path: archivePath,
|
|
1373
|
-
original_name: originalName,
|
|
1374
|
-
device_path: devicePath,
|
|
1375
|
-
size: Number(file.size),
|
|
1376
|
-
sha256: digest,
|
|
1377
|
-
signed: true,
|
|
1378
|
-
sig_algo: file.sig_algo,
|
|
1379
|
-
payload_version: (_a = file.payload_version) !== null && _a !== void 0 ? _a : null,
|
|
1380
|
-
};
|
|
1381
|
-
}
|
|
1382
|
-
function parseProtocolV2ResourceManifest(value) {
|
|
1383
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
1384
|
-
throw new Error('Invalid Pro2 resource manifest');
|
|
1385
|
-
}
|
|
1386
|
-
const manifest = value;
|
|
1387
|
-
if (manifest.schema !== 1 ||
|
|
1388
|
-
manifest.variant !== 'resource' ||
|
|
1389
|
-
manifest.device_root !== 'vol0:' ||
|
|
1390
|
-
manifest.restore_mode !== 'bootloader_update' ||
|
|
1391
|
-
!Array.isArray(manifest.trees) ||
|
|
1392
|
-
!Array.isArray(manifest.files)) {
|
|
1393
|
-
throw new Error('Invalid Pro2 resource manifest contract');
|
|
1394
|
-
}
|
|
1395
|
-
const files = manifest.files.map(parseProtocolV2ResourceManifestFile);
|
|
1396
|
-
const devicePaths = new Set(files.map(file => file.device_path));
|
|
1397
|
-
const archivePaths = new Set(files.map(file => file.archive_path));
|
|
1398
|
-
if (files.length === 0 ||
|
|
1399
|
-
devicePaths.size !== files.length ||
|
|
1400
|
-
archivePaths.size !== files.length ||
|
|
1401
|
-
!devicePaths.has(PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) ||
|
|
1402
|
-
!files.some(file => file.device_path.startsWith('vol0:/bundles/'))) {
|
|
1403
|
-
throw new Error('Invalid Pro2 resource manifest file set');
|
|
1404
|
-
}
|
|
1405
|
-
return {
|
|
1406
|
-
schema: 1,
|
|
1407
|
-
artifact_name: assertManifestString(manifest.artifact_name, 'artifact_name'),
|
|
1408
|
-
release_name: assertManifestString(manifest.release_name, 'release_name'),
|
|
1409
|
-
variant: 'resource',
|
|
1410
|
-
commit: assertManifestString(manifest.commit, 'commit'),
|
|
1411
|
-
short_sha: assertManifestString(manifest.short_sha, 'short_sha'),
|
|
1412
|
-
timestamp_utc: assertManifestString(manifest.timestamp_utc, 'timestamp_utc'),
|
|
1413
|
-
core_version: assertManifestString(manifest.core_version, 'core_version'),
|
|
1414
|
-
key_set: assertManifestString(manifest.key_set, 'key_set'),
|
|
1415
|
-
device_root: 'vol0:',
|
|
1416
|
-
restore_mode: 'bootloader_update',
|
|
1417
|
-
trees: manifest.trees.map((tree, index) => {
|
|
1418
|
-
if (!tree || typeof tree !== 'object') {
|
|
1419
|
-
throw new Error(`Invalid Pro2 resource manifest trees[${index}]`);
|
|
1420
|
-
}
|
|
1421
|
-
const item = tree;
|
|
1422
|
-
return {
|
|
1423
|
-
path: assertManifestRelativePath(item.path, `trees[${index}].path`),
|
|
1424
|
-
device: assertManifestString(item.device, `trees[${index}].device`),
|
|
1425
|
-
};
|
|
1426
|
-
}),
|
|
1427
|
-
files,
|
|
1428
|
-
};
|
|
1429
|
-
}
|
|
1430
|
-
function selectProtocolV2ResourceManifestFiles({ manifest, targetsToUpdate, }) {
|
|
1431
|
-
return targetsToUpdate.includes('resource') ? [...manifest.files] : [];
|
|
1432
|
-
}
|
|
1433
|
-
function prepareProtocolV2ResourceFiles({ manifest: value, files, targetsToUpdate, }) {
|
|
1434
|
-
const manifest = parseProtocolV2ResourceManifest(value);
|
|
1435
|
-
const selected = selectProtocolV2ResourceManifestFiles({ manifest, targetsToUpdate });
|
|
1436
|
-
const binaries = new Map(files.map(file => [file.archivePath, file.binary]));
|
|
1437
|
-
return selected.map(file => {
|
|
1438
|
-
const binary = binaries.get(file.archive_path);
|
|
1439
|
-
if (!binary ||
|
|
1440
|
-
!isProtocolV2ResourceFileValid(binary, {
|
|
1441
|
-
size: file.size,
|
|
1442
|
-
fileHash: file.sha256,
|
|
1443
|
-
})) {
|
|
1444
|
-
throw new Error(`Pro2 resource manifest file verification failed: ${file.archive_path}`);
|
|
1445
|
-
}
|
|
1446
|
-
return {
|
|
1447
|
-
binary,
|
|
1448
|
-
devicePath: file.device_path,
|
|
1449
|
-
size: file.size,
|
|
1450
|
-
fileHash: file.sha256,
|
|
1451
|
-
};
|
|
1452
|
-
});
|
|
1453
|
-
}
|
|
1454
|
-
function bytesToHex$3(bytes) {
|
|
1455
|
-
return Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('');
|
|
1456
|
-
}
|
|
1457
|
-
function isProtocolV2ResourceFileValid(binary, resource) {
|
|
1458
|
-
if (binary.byteLength !== resource.size)
|
|
1459
|
-
return false;
|
|
1460
|
-
return bytesToHex$3(sha256.sha256(new Uint8Array(binary))) === resource.fileHash.toLowerCase();
|
|
1461
|
-
}
|
|
1462
|
-
|
|
1463
1338
|
const bindingError = (message) => {
|
|
1464
1339
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, message, {
|
|
1465
1340
|
firmwareUpdateCode: 'FirmwareArtifactReaderInvalid',
|
|
@@ -1609,7 +1484,6 @@ const createCoreApi = (call) => ({
|
|
|
1609
1484
|
getFirmwareUpdateHostBindingGeneration,
|
|
1610
1485
|
prepareFirmwareUpdatePlan,
|
|
1611
1486
|
validateFirmwareUpdatePreparedPlan,
|
|
1612
|
-
prepareProtocolV2ResourceFiles,
|
|
1613
1487
|
getLogs: () => call({ method: 'getLogs' }),
|
|
1614
1488
|
clearSessionCache: params => call(Object.assign(Object.assign({}, params), { method: 'clearSessionCache' })),
|
|
1615
1489
|
searchDevices: params => call(Object.assign(Object.assign({}, params), { method: 'searchDevices' })),
|
|
@@ -40700,6 +40574,172 @@ const findLatestRelease = (releases) => {
|
|
|
40700
40574
|
return leastRelease;
|
|
40701
40575
|
};
|
|
40702
40576
|
|
|
40577
|
+
const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1 = 'vol0:/loaders/bootloader/boot_resource.okpkg';
|
|
40578
|
+
const SHA256_HEX_LENGTH = 64;
|
|
40579
|
+
function normalizeHex$1(value, expectedLength, field) {
|
|
40580
|
+
if (typeof value !== 'string') {
|
|
40581
|
+
throw new Error(`Invalid Pro2 resource ${field}: expected a hexadecimal string`);
|
|
40582
|
+
}
|
|
40583
|
+
const normalized = value.replace(/^0x/i, '').toLowerCase();
|
|
40584
|
+
if (normalized.length !== expectedLength || !/^[0-9a-f]+$/.test(normalized)) {
|
|
40585
|
+
throw new Error(`Invalid Pro2 resource ${field}: expected ${expectedLength} hexadecimal characters`);
|
|
40586
|
+
}
|
|
40587
|
+
return normalized;
|
|
40588
|
+
}
|
|
40589
|
+
function parseProtocolV2Resources(value) {
|
|
40590
|
+
if (value === undefined)
|
|
40591
|
+
return undefined;
|
|
40592
|
+
if (!value || typeof value !== 'object') {
|
|
40593
|
+
throw new Error('Invalid Pro2 resources config');
|
|
40594
|
+
}
|
|
40595
|
+
const { source } = value;
|
|
40596
|
+
if (!source || typeof source !== 'object') {
|
|
40597
|
+
throw new Error('Invalid Pro2 resources config: source is required');
|
|
40598
|
+
}
|
|
40599
|
+
const { archiveUrl, archiveSha256, archiveSize } = source;
|
|
40600
|
+
if (typeof archiveUrl !== 'string' || !archiveUrl.startsWith('https://')) {
|
|
40601
|
+
throw new Error('Invalid Pro2 resources config: source.archiveUrl must use HTTPS');
|
|
40602
|
+
}
|
|
40603
|
+
if (typeof archiveSha256 !== 'string' || !/^[0-9a-fA-F]{64}$/.test(archiveSha256)) {
|
|
40604
|
+
throw new Error('Invalid Pro2 resources config: source.archiveSha256 must be a SHA-256 digest');
|
|
40605
|
+
}
|
|
40606
|
+
if (!Number.isSafeInteger(archiveSize) || archiveSize <= 0) {
|
|
40607
|
+
throw new Error('Invalid Pro2 resources config: source.archiveSize must be a positive integer');
|
|
40608
|
+
}
|
|
40609
|
+
return {
|
|
40610
|
+
source: {
|
|
40611
|
+
archiveUrl,
|
|
40612
|
+
archiveSha256: archiveSha256.toLowerCase(),
|
|
40613
|
+
archiveSize: archiveSize,
|
|
40614
|
+
},
|
|
40615
|
+
};
|
|
40616
|
+
}
|
|
40617
|
+
const PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS = [
|
|
40618
|
+
'vol0:/bundles/',
|
|
40619
|
+
'vol0:/loaders/rom/',
|
|
40620
|
+
];
|
|
40621
|
+
function isAllowedManifestDevicePath(path) {
|
|
40622
|
+
if (!path.endsWith('.okpkg') ||
|
|
40623
|
+
path.includes('\\') ||
|
|
40624
|
+
path.includes('//') ||
|
|
40625
|
+
path.split('/').some(part => part === '.' || part === '..')) {
|
|
40626
|
+
return false;
|
|
40627
|
+
}
|
|
40628
|
+
if (path === PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) {
|
|
40629
|
+
return true;
|
|
40630
|
+
}
|
|
40631
|
+
return PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS.some(root => path.startsWith(root));
|
|
40632
|
+
}
|
|
40633
|
+
function assertManifestString(value, field) {
|
|
40634
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
40635
|
+
throw new Error(`Invalid Pro2 resource manifest ${field}`);
|
|
40636
|
+
}
|
|
40637
|
+
return value;
|
|
40638
|
+
}
|
|
40639
|
+
function assertManifestRelativePath(value, field) {
|
|
40640
|
+
const path = assertManifestString(value, field);
|
|
40641
|
+
if (path.startsWith('/') ||
|
|
40642
|
+
path.includes('\\') ||
|
|
40643
|
+
path.includes(':') ||
|
|
40644
|
+
path.split('/').some(part => !part || part === '.' || part === '..')) {
|
|
40645
|
+
throw new Error(`Invalid Pro2 resource manifest ${field}`);
|
|
40646
|
+
}
|
|
40647
|
+
return path;
|
|
40648
|
+
}
|
|
40649
|
+
function parseProtocolV2ResourceManifestFile(value, index) {
|
|
40650
|
+
var _a;
|
|
40651
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
40652
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}]`);
|
|
40653
|
+
}
|
|
40654
|
+
const file = value;
|
|
40655
|
+
const archivePath = assertManifestRelativePath(file.archive_path, `files[${index}].archive_path`);
|
|
40656
|
+
const originalName = assertManifestRelativePath(file.original_name, `files[${index}].original_name`);
|
|
40657
|
+
if (originalName.includes('/')) {
|
|
40658
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].original_name`);
|
|
40659
|
+
}
|
|
40660
|
+
const devicePath = assertManifestString(file.device_path, `files[${index}].device_path`);
|
|
40661
|
+
if (!isAllowedManifestDevicePath(devicePath)) {
|
|
40662
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].device_path`);
|
|
40663
|
+
}
|
|
40664
|
+
if (!Number.isSafeInteger(file.size) || Number(file.size) <= 0) {
|
|
40665
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].size`);
|
|
40666
|
+
}
|
|
40667
|
+
const digest = normalizeHex$1(file.sha256, SHA256_HEX_LENGTH, `files[${index}].sha256`);
|
|
40668
|
+
if (file.signed !== true) {
|
|
40669
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].signed`);
|
|
40670
|
+
}
|
|
40671
|
+
if (file.sig_algo !== 'ed25519' && file.sig_algo !== 'mldsa65') {
|
|
40672
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].sig_algo`);
|
|
40673
|
+
}
|
|
40674
|
+
if (file.payload_version !== null && typeof file.payload_version !== 'string') {
|
|
40675
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].payload_version`);
|
|
40676
|
+
}
|
|
40677
|
+
if (!archivePath.endsWith('.okpkg') || !originalName.endsWith('.okpkg')) {
|
|
40678
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}] package extension`);
|
|
40679
|
+
}
|
|
40680
|
+
return {
|
|
40681
|
+
archive_path: archivePath,
|
|
40682
|
+
original_name: originalName,
|
|
40683
|
+
device_path: devicePath,
|
|
40684
|
+
size: Number(file.size),
|
|
40685
|
+
sha256: digest,
|
|
40686
|
+
signed: true,
|
|
40687
|
+
sig_algo: file.sig_algo,
|
|
40688
|
+
payload_version: (_a = file.payload_version) !== null && _a !== void 0 ? _a : null,
|
|
40689
|
+
};
|
|
40690
|
+
}
|
|
40691
|
+
function parseProtocolV2ResourceManifest(value) {
|
|
40692
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
40693
|
+
throw new Error('Invalid Pro2 resource manifest');
|
|
40694
|
+
}
|
|
40695
|
+
const manifest = value;
|
|
40696
|
+
if (manifest.schema !== 1 ||
|
|
40697
|
+
manifest.variant !== 'resource' ||
|
|
40698
|
+
manifest.device_root !== 'vol0:' ||
|
|
40699
|
+
manifest.restore_mode !== 'bootloader_update' ||
|
|
40700
|
+
!Array.isArray(manifest.trees) ||
|
|
40701
|
+
!Array.isArray(manifest.files)) {
|
|
40702
|
+
throw new Error('Invalid Pro2 resource manifest contract');
|
|
40703
|
+
}
|
|
40704
|
+
const files = manifest.files.map(parseProtocolV2ResourceManifestFile);
|
|
40705
|
+
const devicePaths = new Set(files.map(file => file.device_path));
|
|
40706
|
+
const archivePaths = new Set(files.map(file => file.archive_path));
|
|
40707
|
+
if (files.length === 0 ||
|
|
40708
|
+
devicePaths.size !== files.length ||
|
|
40709
|
+
archivePaths.size !== files.length ||
|
|
40710
|
+
!devicePaths.has(PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) ||
|
|
40711
|
+
!files.some(file => file.device_path.startsWith('vol0:/bundles/'))) {
|
|
40712
|
+
throw new Error('Invalid Pro2 resource manifest file set');
|
|
40713
|
+
}
|
|
40714
|
+
return {
|
|
40715
|
+
schema: 1,
|
|
40716
|
+
artifact_name: assertManifestString(manifest.artifact_name, 'artifact_name'),
|
|
40717
|
+
release_name: assertManifestString(manifest.release_name, 'release_name'),
|
|
40718
|
+
variant: 'resource',
|
|
40719
|
+
commit: assertManifestString(manifest.commit, 'commit'),
|
|
40720
|
+
short_sha: assertManifestString(manifest.short_sha, 'short_sha'),
|
|
40721
|
+
timestamp_utc: assertManifestString(manifest.timestamp_utc, 'timestamp_utc'),
|
|
40722
|
+
core_version: assertManifestString(manifest.core_version, 'core_version'),
|
|
40723
|
+
key_set: assertManifestString(manifest.key_set, 'key_set'),
|
|
40724
|
+
device_root: 'vol0:',
|
|
40725
|
+
restore_mode: 'bootloader_update',
|
|
40726
|
+
trees: manifest.trees.map((tree, index) => {
|
|
40727
|
+
if (!tree || typeof tree !== 'object') {
|
|
40728
|
+
throw new Error(`Invalid Pro2 resource manifest trees[${index}]`);
|
|
40729
|
+
}
|
|
40730
|
+
const item = tree;
|
|
40731
|
+
return {
|
|
40732
|
+
path: assertManifestRelativePath(item.path, `trees[${index}].path`),
|
|
40733
|
+
device: assertManifestString(item.device, `trees[${index}].device`),
|
|
40734
|
+
};
|
|
40735
|
+
}),
|
|
40736
|
+
files,
|
|
40737
|
+
};
|
|
40738
|
+
}
|
|
40739
|
+
function selectProtocolV2ResourceManifestFiles({ manifest, targetsToUpdate, }) {
|
|
40740
|
+
return targetsToUpdate.includes('resource') ? [...manifest.files] : [];
|
|
40741
|
+
}
|
|
40742
|
+
|
|
40703
40743
|
var _a$1;
|
|
40704
40744
|
const FIRMWARE_UPDATE_CONFIG_FRESHNESS_MS = 5 * 60 * 1000;
|
|
40705
40745
|
const Log$k = getLogger(exports.LoggerNames.Core);
|
|
@@ -41925,7 +41965,7 @@ const getFirmwareUpdateField = ({ features, updateType, targetVersion, firmwareT
|
|
|
41925
41965
|
if (deviceType === hdShared.EDeviceType.Pro) {
|
|
41926
41966
|
return latestFirmwareField;
|
|
41927
41967
|
}
|
|
41928
|
-
if (deviceType === hdShared.EDeviceType.Pro2) {
|
|
41968
|
+
if (deviceType === hdShared.EDeviceType.Pro2 || deviceType === hdShared.EDeviceType.Neo) {
|
|
41929
41969
|
return 'firmware-v1';
|
|
41930
41970
|
}
|
|
41931
41971
|
return 'firmware';
|
|
@@ -41957,7 +41997,7 @@ const getFirmwareUpdateFieldArray = (features, updateType) => {
|
|
|
41957
41997
|
if (deviceType === 'pro') {
|
|
41958
41998
|
return ['firmware-v8'];
|
|
41959
41999
|
}
|
|
41960
|
-
if (deviceType === 'pro2') {
|
|
42000
|
+
if (deviceType === 'pro2' || deviceType === 'neo') {
|
|
41961
42001
|
return ['firmware-v1'];
|
|
41962
42002
|
}
|
|
41963
42003
|
return ['firmware'];
|
|
@@ -47688,9 +47728,11 @@ class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
47688
47728
|
});
|
|
47689
47729
|
}
|
|
47690
47730
|
runProtocolV2() {
|
|
47731
|
+
var _a;
|
|
47691
47732
|
return __awaiter(this, void 0, void 0, function* () {
|
|
47692
|
-
const { checkFirmwareHash = false, firmwareType: firmwareTypeParam } = this
|
|
47693
|
-
|
|
47733
|
+
const { checkFirmwareHash = false, firmwareType: firmwareTypeParam, platform, forceUpdateTargets, protocolV2ForceUpdateTargets, } = this.payload;
|
|
47734
|
+
const validatedForceUpdateTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
|
|
47735
|
+
const validatedProtocolV2ForceUpdateTargets = validateProtocolV2FirmwareUpdateTargets(protocolV2ForceUpdateTargets);
|
|
47694
47736
|
const { state, features, firmwareType, release } = yield loadProtocolV2FirmwareReleaseContext({
|
|
47695
47737
|
device: this.device,
|
|
47696
47738
|
firmwareType: firmwareTypeParam,
|
|
@@ -47709,10 +47751,54 @@ class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
47709
47751
|
const resourceSource = DataManager.getProtocolV2ResourceSource(resourceDeviceType);
|
|
47710
47752
|
const resourceStatus = 'unknown';
|
|
47711
47753
|
const resourcePreparationRequired = !!resourceSource;
|
|
47754
|
+
const detectedComponentTargets = validatedForceUpdateTargets.includes('firmware')
|
|
47755
|
+
? plan.components.flatMap(component => component.updateTarget ? [component.updateTarget] : [])
|
|
47756
|
+
: plan.targetsToUpdate;
|
|
47757
|
+
const componentTargetsToUpdate = Array.from(new Set([
|
|
47758
|
+
...detectedComponentTargets,
|
|
47759
|
+
...validatedProtocolV2ForceUpdateTargets.filter(target => target !== 'resource'),
|
|
47760
|
+
]));
|
|
47761
|
+
const forceResourceUpdate = validatedForceUpdateTargets.includes('resource') ||
|
|
47762
|
+
validatedProtocolV2ForceUpdateTargets.includes('resource');
|
|
47712
47763
|
const targetsToUpdate = Array.from(new Set([
|
|
47713
|
-
...
|
|
47714
|
-
...(resourcePreparationRequired ? ['resource'] : []),
|
|
47764
|
+
...componentTargetsToUpdate,
|
|
47765
|
+
...(resourcePreparationRequired || forceResourceUpdate ? ['resource'] : []),
|
|
47715
47766
|
]));
|
|
47767
|
+
let firmwareUpdatePlan;
|
|
47768
|
+
try {
|
|
47769
|
+
const shouldBuildFirmwareUpdatePlan = targetsToUpdate.length > 0;
|
|
47770
|
+
const requestedPlatform = platform !== null && platform !== void 0 ? platform : 'web';
|
|
47771
|
+
const requiresDeviceIdentity = requestedPlatform === 'native' || requestedPlatform === 'desktop';
|
|
47772
|
+
const canBindPreparedPlan = !requiresDeviceIdentity || !!getDeviceSerialNo(features);
|
|
47773
|
+
if (shouldBuildFirmwareUpdatePlan) {
|
|
47774
|
+
const validatedPlan = buildProtocolV2FirmwareUpdatePlan({
|
|
47775
|
+
features,
|
|
47776
|
+
firmwareType,
|
|
47777
|
+
platform: canBindPreparedPlan ? requestedPlatform : 'web',
|
|
47778
|
+
release,
|
|
47779
|
+
targetsToUpdate,
|
|
47780
|
+
forceUpdateTargets: validatedForceUpdateTargets,
|
|
47781
|
+
resourceArchive: resourceSource,
|
|
47782
|
+
});
|
|
47783
|
+
firmwareUpdatePlan = canBindPreparedPlan ? validatedPlan : undefined;
|
|
47784
|
+
if (!canBindPreparedPlan) {
|
|
47785
|
+
Log$c.warn('[CheckAllFirmwareRelease] Protocol V2 device identity is unavailable; using the release result without a prepared Plan');
|
|
47786
|
+
}
|
|
47787
|
+
}
|
|
47788
|
+
else {
|
|
47789
|
+
firmwareUpdatePlan = undefined;
|
|
47790
|
+
}
|
|
47791
|
+
}
|
|
47792
|
+
catch (error) {
|
|
47793
|
+
if (validatedForceUpdateTargets.length > 0 ||
|
|
47794
|
+
validatedProtocolV2ForceUpdateTargets.length > 0 ||
|
|
47795
|
+
!(error instanceof hdShared.HardwareError) ||
|
|
47796
|
+
((_a = error.params) === null || _a === void 0 ? void 0 : _a.firmwareUpdateCode) !== 'FirmwarePlanInvalid') {
|
|
47797
|
+
throw error;
|
|
47798
|
+
}
|
|
47799
|
+
Log$c.warn('[CheckAllFirmwareRelease] Optional Protocol V2 firmware Plan is unavailable; using the release result');
|
|
47800
|
+
firmwareUpdatePlan = undefined;
|
|
47801
|
+
}
|
|
47716
47802
|
const firmwarePlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_MAIN_FIRMWARE_TARGETS);
|
|
47717
47803
|
const blePlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_BLE_TARGETS);
|
|
47718
47804
|
const bootloaderPlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_BOOTLOADER_TARGETS);
|
|
@@ -47728,7 +47814,8 @@ class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
47728
47814
|
state,
|
|
47729
47815
|
release: getProtocolV2ComponentReleaseInfo(plan, 'BOOTLOADER'),
|
|
47730
47816
|
}), features, protocol: 'V2', deviceType: state.identity.deviceType }, plan), { status,
|
|
47731
|
-
resourceStatus, resourceArchive: resourceSource, resourcePreparationRequired, hasUpgrade:
|
|
47817
|
+
resourceStatus, resourceArchive: resourceSource, resourcePreparationRequired, hasUpgrade: targetsToUpdate.length > 0, targetsToUpdate,
|
|
47818
|
+
firmwareUpdatePlan });
|
|
47732
47819
|
});
|
|
47733
47820
|
}
|
|
47734
47821
|
}
|
|
@@ -51151,6 +51238,9 @@ const PROTOCOL_V2_OKPP_HEADER_SIZE = 0x52a0;
|
|
|
51151
51238
|
const PROTOCOL_V2_OKPP_PAYLOAD_HASH_OFFSET = 0x200;
|
|
51152
51239
|
const PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET = 0x240;
|
|
51153
51240
|
const PROTOCOL_V2_OKPP_HASH_SIZE = 64;
|
|
51241
|
+
const PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES = 1024 * 1024;
|
|
51242
|
+
const PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT = 512;
|
|
51243
|
+
const PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES = 256 * 1024 * 1024;
|
|
51154
51244
|
const PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS = new Set(['se03', 'se04']);
|
|
51155
51245
|
function assertProtocolV2FirmwareTargetsSupported(deviceType, params) {
|
|
51156
51246
|
var _a;
|
|
@@ -51404,7 +51494,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51404
51494
|
return ['V2'];
|
|
51405
51495
|
}
|
|
51406
51496
|
init() {
|
|
51407
|
-
var _a, _b
|
|
51497
|
+
var _a, _b;
|
|
51408
51498
|
this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
|
|
51409
51499
|
this.requireDeviceMode = [];
|
|
51410
51500
|
this.unlockPolicy = 'unlock-before-run';
|
|
@@ -51439,33 +51529,24 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51439
51529
|
{ name: 'targetsToUpdate', type: 'array', allowEmpty: true },
|
|
51440
51530
|
{ name: 'platform', type: 'string' },
|
|
51441
51531
|
{ name: 'expectedDeviceId', type: 'string' },
|
|
51442
|
-
{ name: 'resourceFiles', type: 'array', allowEmpty: true },
|
|
51443
51532
|
]);
|
|
51444
51533
|
if (payload.expectedDeviceId !== undefined &&
|
|
51445
51534
|
(payload.expectedDeviceId.length === 0 || payload.expectedDeviceId.length > 160)) {
|
|
51446
51535
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Protocol V2 expected device identity is invalid');
|
|
51447
51536
|
}
|
|
51448
|
-
const hostBinding = payload.preparedPlan || payload.componentArtifacts
|
|
51537
|
+
const hostBinding = payload.preparedPlan || payload.componentArtifacts
|
|
51449
51538
|
? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration)
|
|
51450
51539
|
: undefined;
|
|
51451
51540
|
if (hostBinding) {
|
|
51541
|
+
const componentArtifacts = ((_a = payload.componentArtifacts) !== null && _a !== void 0 ? _a : {});
|
|
51542
|
+
const preparedPlan = validateFirmwareUpdatePreparedPlan(payload.preparedPlan);
|
|
51452
51543
|
assertFirmwareUpdatePreparedPlanBinding({
|
|
51453
|
-
preparedPlan
|
|
51544
|
+
preparedPlan,
|
|
51454
51545
|
executor: 'v4',
|
|
51455
51546
|
platform: payload.platform,
|
|
51456
|
-
scopeTargets: [
|
|
51457
|
-
'boot',
|
|
51458
|
-
'app_v1',
|
|
51459
|
-
'app_v2',
|
|
51460
|
-
'coprocessor',
|
|
51461
|
-
'resource',
|
|
51462
|
-
'se01',
|
|
51463
|
-
'se02',
|
|
51464
|
-
'se03',
|
|
51465
|
-
'se04',
|
|
51466
|
-
],
|
|
51547
|
+
scopeTargets: ['boot', 'app_v1', 'app_v2', 'coprocessor', 'se01', 'se02', 'se03', 'se04'],
|
|
51467
51548
|
bindings: [
|
|
51468
|
-
...Object.entries(
|
|
51549
|
+
...Object.entries(componentArtifacts).flatMap(([target, artifact]) => artifact
|
|
51469
51550
|
? [
|
|
51470
51551
|
{
|
|
51471
51552
|
target: target,
|
|
@@ -51473,16 +51554,13 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51473
51554
|
},
|
|
51474
51555
|
]
|
|
51475
51556
|
: []),
|
|
51476
|
-
...((_b = payload.resourceBundleArtifacts) !== null && _b !== void 0 ? _b : []).map((entry) => ({
|
|
51477
|
-
target: 'resource',
|
|
51478
|
-
logicalName: entry.name,
|
|
51479
|
-
artifact: entry.artifact,
|
|
51480
|
-
})),
|
|
51481
51557
|
],
|
|
51482
51558
|
});
|
|
51483
51559
|
}
|
|
51484
51560
|
this.params = {
|
|
51485
|
-
preparedPlan: payload.preparedPlan
|
|
51561
|
+
preparedPlan: payload.preparedPlan
|
|
51562
|
+
? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
|
|
51563
|
+
: undefined,
|
|
51486
51564
|
chunkSize: payload.chunkSize,
|
|
51487
51565
|
forcedUpdateRes: payload.forcedUpdateRes,
|
|
51488
51566
|
bootloaderBinary: payload.bootloaderBinary,
|
|
@@ -51494,15 +51572,13 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51494
51572
|
se02Binary: payload.se02Binary,
|
|
51495
51573
|
se03Binary: payload.se03Binary,
|
|
51496
51574
|
se04Binary: payload.se04Binary,
|
|
51497
|
-
resourceFiles: payload.resourceFiles,
|
|
51498
51575
|
firmwareType: payload.firmwareType,
|
|
51499
51576
|
targetsToUpdate: payload.targetsToUpdate,
|
|
51500
51577
|
expectedTargetVersions: payload.expectedTargetVersions,
|
|
51501
51578
|
platform: payload.platform,
|
|
51502
51579
|
expectedDeviceId: payload.expectedDeviceId,
|
|
51503
|
-
artifactReader: (
|
|
51580
|
+
artifactReader: (_b = hostBinding === null || hostBinding === void 0 ? void 0 : hostBinding.artifactReader) !== null && _b !== void 0 ? _b : payload.artifactReader,
|
|
51504
51581
|
componentArtifacts: payload.componentArtifacts,
|
|
51505
|
-
resourceBundleArtifacts: payload.resourceBundleArtifacts,
|
|
51506
51582
|
};
|
|
51507
51583
|
}
|
|
51508
51584
|
getProtocolV2FirmwareChunkSize(direction, filePath) {
|
|
@@ -51533,7 +51609,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51533
51609
|
});
|
|
51534
51610
|
}
|
|
51535
51611
|
runProtocolV2() {
|
|
51536
|
-
var _a, _b, _c, _d
|
|
51612
|
+
var _a, _b, _c, _d;
|
|
51537
51613
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51538
51614
|
yield this.captureProtocolV2PhysicalIdentity();
|
|
51539
51615
|
const deviceFeatures = yield this.getProtocolV2DeviceFeatures();
|
|
@@ -51545,20 +51621,15 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51545
51621
|
const deviceFirmwareType = getFirmwareType(deviceFeatures);
|
|
51546
51622
|
const firmwareType = (_a = this.params.firmwareType) !== null && _a !== void 0 ? _a : deviceFirmwareType;
|
|
51547
51623
|
this.validateExpectedTargetVersions();
|
|
51548
|
-
if (
|
|
51549
|
-
((_b = this.params.resourceBundleArtifacts) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
51624
|
+
if (this.params.preparedPlan) {
|
|
51550
51625
|
return this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType);
|
|
51551
51626
|
}
|
|
51552
|
-
const
|
|
51553
|
-
const wantsResources = !!((_d = this.params.targetsToUpdate) === null || _d === void 0 ? void 0 : _d.includes('resource'));
|
|
51554
|
-
const needsPreparedResources = !hasExplicitResourceFiles && wantsResources;
|
|
51627
|
+
const wantsResources = !!((_b = this.params.targetsToUpdate) === null || _b === void 0 ? void 0 : _b.includes('resource'));
|
|
51555
51628
|
let fwBinaryMap = [];
|
|
51556
51629
|
let bootloaderBinary = null;
|
|
51557
51630
|
let installItems;
|
|
51558
|
-
let resourceBundles;
|
|
51559
51631
|
try {
|
|
51560
51632
|
this.postTipMessage(exports.FirmwareUpdateTipMessage.StartDownloadFirmware);
|
|
51561
|
-
resourceBundles = this.prepareExplicitProtocolV2ResourceFiles();
|
|
51562
51633
|
fwBinaryMap = this.collectExplicitTargetBinaries();
|
|
51563
51634
|
bootloaderBinary = this.prepareBootloaderBinary();
|
|
51564
51635
|
const explicitInstallItems = this.buildProtocolV2InstallItems({
|
|
@@ -51566,10 +51637,10 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51566
51637
|
fwBinaryMap,
|
|
51567
51638
|
});
|
|
51568
51639
|
const missingFirmwareTargets = this.getMissingProtocolV2FirmwareTargets(explicitInstallItems);
|
|
51569
|
-
const needsRemoteFirmware = ((
|
|
51640
|
+
const needsRemoteFirmware = ((_c = this.params.targetsToUpdate) === null || _c === void 0 ? void 0 : _c.length)
|
|
51570
51641
|
? missingFirmwareTargets.length > 0
|
|
51571
|
-
:
|
|
51572
|
-
if (
|
|
51642
|
+
: explicitInstallItems.length === 0;
|
|
51643
|
+
if (wantsResources) {
|
|
51573
51644
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource manifest must be prepared by the external firmware host', {
|
|
51574
51645
|
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
51575
51646
|
});
|
|
@@ -51596,7 +51667,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51596
51667
|
if (typeof err === 'object' &&
|
|
51597
51668
|
err !== null &&
|
|
51598
51669
|
'params' in err &&
|
|
51599
|
-
((
|
|
51670
|
+
((_d = err.params) === null || _d === void 0 ? void 0 : _d.firmwareUpdateCode) === 'FirmwareArtifactsNotPrepared') {
|
|
51600
51671
|
throw err;
|
|
51601
51672
|
}
|
|
51602
51673
|
if (err instanceof hdShared.HardwareError && err.errorCode === hdShared.HardwareErrorCode.NetworkError) {
|
|
@@ -51604,14 +51675,11 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51604
51675
|
}
|
|
51605
51676
|
throw normalizeFirmwarePreparationError(err);
|
|
51606
51677
|
}
|
|
51607
|
-
if (!bootloaderBinary &&
|
|
51608
|
-
fwBinaryMap.length === 0 &&
|
|
51609
|
-
!(installItems === null || installItems === void 0 ? void 0 : installItems.length) &&
|
|
51610
|
-
!(resourceBundles === null || resourceBundles === void 0 ? void 0 : resourceBundles.length)) {
|
|
51678
|
+
if (!bootloaderBinary && fwBinaryMap.length === 0 && !(installItems === null || installItems === void 0 ? void 0 : installItems.length)) {
|
|
51611
51679
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, 'No firmware to update');
|
|
51612
51680
|
}
|
|
51613
|
-
return this.executeProtocolV2Update(Object.assign(
|
|
51614
|
-
bootloaderBinary }, (installItems ? { installItems } : undefined))
|
|
51681
|
+
return this.executeProtocolV2Update(Object.assign({ fwBinaryMap,
|
|
51682
|
+
bootloaderBinary }, (installItems ? { installItems } : undefined)));
|
|
51615
51683
|
});
|
|
51616
51684
|
}
|
|
51617
51685
|
openProtocolV2PreparedSource(artifact) {
|
|
@@ -51678,39 +51746,87 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51678
51746
|
return installSources;
|
|
51679
51747
|
});
|
|
51680
51748
|
}
|
|
51681
|
-
prepareProtocolV2ResourceSources(
|
|
51682
|
-
var _a, _b
|
|
51749
|
+
prepareProtocolV2ResourceSources() {
|
|
51750
|
+
var _a, _b;
|
|
51683
51751
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51684
|
-
const
|
|
51685
|
-
const resourceRequested = ((_b = this.params.targetsToUpdate) === null || _b === void 0 ? void 0 : _b.includes('resource')) || preparedArtifacts.length > 0;
|
|
51752
|
+
const resourceRequested = (_b = (_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.includes('resource')) !== null && _b !== void 0 ? _b : false;
|
|
51686
51753
|
if (!resourceRequested) {
|
|
51687
51754
|
return [];
|
|
51688
51755
|
}
|
|
51689
|
-
const
|
|
51690
|
-
|
|
51691
|
-
|
|
51692
|
-
|
|
51693
|
-
|
|
51694
|
-
|
|
51695
|
-
|
|
51696
|
-
|
|
51697
|
-
|
|
51698
|
-
|
|
51699
|
-
|
|
51700
|
-
|
|
51701
|
-
|
|
51702
|
-
|
|
51703
|
-
|
|
51704
|
-
|
|
51705
|
-
|
|
51706
|
-
|
|
51707
|
-
payloadHash: descriptor.payloadHash,
|
|
51708
|
-
headerHash: descriptor.headerHash,
|
|
51709
|
-
});
|
|
51710
|
-
artifactByName.delete(descriptor.name);
|
|
51756
|
+
const archiveSources = yield this.prepareProtocolV2ResourceArchiveSources();
|
|
51757
|
+
if (archiveSources) {
|
|
51758
|
+
return archiveSources;
|
|
51759
|
+
}
|
|
51760
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource archive is not prepared', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
51761
|
+
});
|
|
51762
|
+
}
|
|
51763
|
+
prepareProtocolV2ResourceArchiveSources() {
|
|
51764
|
+
var _a, _b, _c, _d;
|
|
51765
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
51766
|
+
const archiveArtifacts = (_b = (_a = this.params.preparedPlan) === null || _a === void 0 ? void 0 : _a.artifacts.filter(artifact => artifact.role === 'resourceBundle' &&
|
|
51767
|
+
artifact.target === 'resource' &&
|
|
51768
|
+
artifact.container === 'zip')) !== null && _b !== void 0 ? _b : [];
|
|
51769
|
+
if (archiveArtifacts.length === 0) {
|
|
51770
|
+
return undefined;
|
|
51771
|
+
}
|
|
51772
|
+
if (archiveArtifacts.length !== 1) {
|
|
51773
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared plan must contain exactly one resource archive', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
51711
51774
|
}
|
|
51712
|
-
|
|
51713
|
-
|
|
51775
|
+
const entries = (_c = archiveArtifacts[0].materializedEntries) !== null && _c !== void 0 ? _c : [];
|
|
51776
|
+
const manifestEntry = entries.find(entry => entry.entryName === 'manifest.json');
|
|
51777
|
+
if (!manifestEntry ||
|
|
51778
|
+
manifestEntry.artifact.size <= 0 ||
|
|
51779
|
+
manifestEntry.artifact.size > PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES) {
|
|
51780
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive has no valid manifest.json', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
51781
|
+
}
|
|
51782
|
+
const manifestSource = yield this.openProtocolV2PreparedSource(manifestEntry.artifact);
|
|
51783
|
+
let manifestValue;
|
|
51784
|
+
try {
|
|
51785
|
+
manifestValue = JSON.parse(new TextDecoder().decode(yield readFirmwareByteSourceFully(manifestSource)));
|
|
51786
|
+
}
|
|
51787
|
+
catch (error) {
|
|
51788
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 prepared resource manifest is invalid: ${String(error)}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
51789
|
+
}
|
|
51790
|
+
const manifest = parseProtocolV2ResourceManifest(manifestValue);
|
|
51791
|
+
const selectedFiles = selectProtocolV2ResourceManifestFiles({
|
|
51792
|
+
manifest,
|
|
51793
|
+
targetsToUpdate: (_d = this.params.targetsToUpdate) !== null && _d !== void 0 ? _d : [],
|
|
51794
|
+
});
|
|
51795
|
+
if (selectedFiles.length > PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT) {
|
|
51796
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive contains too many files', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
51797
|
+
}
|
|
51798
|
+
const entriesByName = new Map(entries.map(entry => [entry.entryName, entry]));
|
|
51799
|
+
const expectedEntryNames = new Set([
|
|
51800
|
+
'manifest.json',
|
|
51801
|
+
...selectedFiles.map(file => file.archive_path),
|
|
51802
|
+
]);
|
|
51803
|
+
if (entries.some(entry => !expectedEntryNames.has(entry.entryName))) {
|
|
51804
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive contains an unexpected entry', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
51805
|
+
}
|
|
51806
|
+
let totalSize = 0;
|
|
51807
|
+
const sources = [];
|
|
51808
|
+
for (const [index, file] of selectedFiles.entries()) {
|
|
51809
|
+
const entry = entriesByName.get(file.archive_path);
|
|
51810
|
+
if (!entry ||
|
|
51811
|
+
entry.artifact.size !== file.size ||
|
|
51812
|
+
entry.artifact.sha256.toLowerCase() !== file.sha256.toLowerCase()) {
|
|
51813
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 prepared resource file does not match manifest: ${file.archive_path}`, { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
|
|
51814
|
+
}
|
|
51815
|
+
totalSize += entry.artifact.size;
|
|
51816
|
+
if (totalSize > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
|
|
51817
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive exceeds the total size limit', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
51818
|
+
}
|
|
51819
|
+
const source = yield this.openProtocolV2PreparedSource(entry.artifact);
|
|
51820
|
+
const header = source.size >= PROTOCOL_V2_OKPP_HEADER_SIZE
|
|
51821
|
+
? parseProtocolV2OkppHeader(new Uint8Array(yield source.readAt(0, PROTOCOL_V2_OKPP_HEADER_SIZE)))
|
|
51822
|
+
: null;
|
|
51823
|
+
sources.push(Object.assign({ name: file.original_name || `resource-${index}`, source, devicePath: file.device_path }, (header
|
|
51824
|
+
? {
|
|
51825
|
+
version: header.version,
|
|
51826
|
+
payloadHash: header.payloadHash,
|
|
51827
|
+
headerHash: header.headerHash,
|
|
51828
|
+
}
|
|
51829
|
+
: {})));
|
|
51714
51830
|
}
|
|
51715
51831
|
return sources;
|
|
51716
51832
|
});
|
|
@@ -51720,19 +51836,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51720
51836
|
try {
|
|
51721
51837
|
this.postTipMessage(exports.FirmwareUpdateTipMessage.StartDownloadFirmware);
|
|
51722
51838
|
const installSources = yield this.prepareProtocolV2InstallSources(firmwareType, features);
|
|
51723
|
-
const
|
|
51724
|
-
const resourceSources = (explicitResourceBundles === null || explicitResourceBundles === void 0 ? void 0 : explicitResourceBundles.length)
|
|
51725
|
-
? yield Promise.all(explicitResourceBundles.map((bundle) => __awaiter(this, void 0, void 0, function* () {
|
|
51726
|
-
return ({
|
|
51727
|
-
name: bundle.name,
|
|
51728
|
-
source: yield this.openProtocolV2MemorySource(bundle.binary),
|
|
51729
|
-
devicePath: bundle.devicePath,
|
|
51730
|
-
version: bundle.version,
|
|
51731
|
-
payloadHash: bundle.payloadHash,
|
|
51732
|
-
headerHash: bundle.headerHash,
|
|
51733
|
-
});
|
|
51734
|
-
})))
|
|
51735
|
-
: yield this.prepareProtocolV2ResourceSources(firmwareType, features);
|
|
51839
|
+
const resourceSources = yield this.prepareProtocolV2ResourceSources();
|
|
51736
51840
|
if (installSources.length === 0 && resourceSources.length === 0) {
|
|
51737
51841
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, 'No firmware to update');
|
|
51738
51842
|
}
|
|
@@ -51816,15 +51920,15 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51816
51920
|
}
|
|
51817
51921
|
}
|
|
51818
51922
|
getProtocolV2RequestedTargets() {
|
|
51819
|
-
var _a, _b, _c
|
|
51923
|
+
var _a, _b, _c;
|
|
51820
51924
|
if ((_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.length) {
|
|
51821
51925
|
return [...new Set(this.params.targetsToUpdate)];
|
|
51822
51926
|
}
|
|
51823
|
-
|
|
51824
|
-
|
|
51825
|
-
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)) {
|
|
51826
|
-
targets.add('resource');
|
|
51927
|
+
if ((_b = this.params.preparedPlan) === null || _b === void 0 ? void 0 : _b.targetsToUpdate.length) {
|
|
51928
|
+
return [...new Set(this.params.preparedPlan.targetsToUpdate)];
|
|
51827
51929
|
}
|
|
51930
|
+
const targets = new Set();
|
|
51931
|
+
Object.keys((_c = this.params.componentArtifacts) !== null && _c !== void 0 ? _c : {}).forEach(target => targets.add(target));
|
|
51828
51932
|
if (this.params.bootloaderBinary)
|
|
51829
51933
|
targets.add('boot');
|
|
51830
51934
|
if (this.params.applicationP1Binary)
|
|
@@ -51911,10 +52015,6 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51911
52015
|
var _a;
|
|
51912
52016
|
return (_a = this.params.bootloaderBinary) !== null && _a !== void 0 ? _a : null;
|
|
51913
52017
|
}
|
|
51914
|
-
hasExplicitProtocolV2Payload(installItems) {
|
|
51915
|
-
var _a;
|
|
51916
|
-
return !!((_a = this.params.resourceFiles) === null || _a === void 0 ? void 0 : _a.length) || installItems.length > 0;
|
|
51917
|
-
}
|
|
51918
52018
|
getMissingProtocolV2FirmwareTargets(installItems) {
|
|
51919
52019
|
var _a;
|
|
51920
52020
|
const preparedTargets = new Set(installItems.flatMap(item => {
|
|
@@ -52041,39 +52141,6 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52041
52141
|
};
|
|
52042
52142
|
});
|
|
52043
52143
|
}
|
|
52044
|
-
prepareExplicitProtocolV2ResourceFiles() {
|
|
52045
|
-
var _a;
|
|
52046
|
-
const files = (_a = this.params.resourceFiles) !== null && _a !== void 0 ? _a : [];
|
|
52047
|
-
if (!(files === null || files === void 0 ? void 0 : files.length))
|
|
52048
|
-
return undefined;
|
|
52049
|
-
const prepared = files.map((file, index) => {
|
|
52050
|
-
var _a;
|
|
52051
|
-
const devicePath = validateProtocolV2FilesystemPath(file.devicePath, `resourceFiles[${index}].devicePath`);
|
|
52052
|
-
const descriptor = file;
|
|
52053
|
-
if (descriptor.size !== undefined && descriptor.size !== file.binary.byteLength) {
|
|
52054
|
-
throw new Error(`resourceFiles[${index}] size mismatch`);
|
|
52055
|
-
}
|
|
52056
|
-
if (descriptor.fileHash &&
|
|
52057
|
-
!isProtocolV2ResourceFileValid(file.binary, {
|
|
52058
|
-
size: file.binary.byteLength,
|
|
52059
|
-
fileHash: descriptor.fileHash,
|
|
52060
|
-
})) {
|
|
52061
|
-
throw new Error(`resourceFiles[${index}] SHA-256 mismatch`);
|
|
52062
|
-
}
|
|
52063
|
-
const header = parseProtocolV2OkppHeader(toProtocolV2Bytes(file.binary));
|
|
52064
|
-
return Object.assign({ name: (_a = devicePath.split('/').pop()) !== null && _a !== void 0 ? _a : devicePath, binary: file.binary, devicePath }, (header
|
|
52065
|
-
? {
|
|
52066
|
-
version: header.version,
|
|
52067
|
-
payloadHash: header.payloadHash,
|
|
52068
|
-
headerHash: header.headerHash,
|
|
52069
|
-
}
|
|
52070
|
-
: {}));
|
|
52071
|
-
});
|
|
52072
|
-
if (new Set(prepared.map(file => file.devicePath)).size !== prepared.length) {
|
|
52073
|
-
throw new Error('resourceFiles contain duplicate devicePath values');
|
|
52074
|
-
}
|
|
52075
|
-
return prepared;
|
|
52076
|
-
}
|
|
52077
52144
|
getProtocolV2ResourceFilePath(path) {
|
|
52078
52145
|
if (path.startsWith('vol'))
|
|
52079
52146
|
return path;
|
|
@@ -52330,7 +52397,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52330
52397
|
});
|
|
52331
52398
|
});
|
|
52332
52399
|
}
|
|
52333
|
-
executeProtocolV2Update({ fwBinaryMap, bootloaderBinary, installItems,
|
|
52400
|
+
executeProtocolV2Update({ fwBinaryMap, bootloaderBinary, installItems, }) {
|
|
52334
52401
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52335
52402
|
const memoryInstallItems = installItems !== null && installItems !== void 0 ? installItems : this.buildProtocolV2InstallItems({
|
|
52336
52403
|
fwBinaryMap: fwBinaryMap !== null && fwBinaryMap !== void 0 ? fwBinaryMap : [],
|
|
@@ -52345,19 +52412,9 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52345
52412
|
kind: item.kind,
|
|
52346
52413
|
});
|
|
52347
52414
|
})));
|
|
52348
|
-
const resourceSources = yield Promise.all((resourceBundles !== null && resourceBundles !== void 0 ? resourceBundles : []).map((bundle) => __awaiter(this, void 0, void 0, function* () {
|
|
52349
|
-
return ({
|
|
52350
|
-
name: bundle.name,
|
|
52351
|
-
source: yield this.openProtocolV2MemorySource(bundle.binary),
|
|
52352
|
-
devicePath: bundle.devicePath,
|
|
52353
|
-
version: bundle.version,
|
|
52354
|
-
payloadHash: bundle.payloadHash,
|
|
52355
|
-
headerHash: bundle.headerHash,
|
|
52356
|
-
});
|
|
52357
|
-
})));
|
|
52358
52415
|
return yield this.executeProtocolV2Phases({
|
|
52359
52416
|
installSources,
|
|
52360
|
-
resourceSources,
|
|
52417
|
+
resourceSources: [],
|
|
52361
52418
|
});
|
|
52362
52419
|
}
|
|
52363
52420
|
finally {
|
|
@@ -64970,6 +65027,108 @@ const switchTransport = ({ env, Transport, plugin, }) => {
|
|
|
64970
65027
|
initConnector();
|
|
64971
65028
|
};
|
|
64972
65029
|
|
|
65030
|
+
let memoryHostSequence = 0;
|
|
65031
|
+
const FIRMWARE_UPDATE_V4_COMPONENT_TARGETS = new Set([
|
|
65032
|
+
'boot',
|
|
65033
|
+
'app_v1',
|
|
65034
|
+
'app_v2',
|
|
65035
|
+
'coprocessor',
|
|
65036
|
+
'se01',
|
|
65037
|
+
'se02',
|
|
65038
|
+
'se03',
|
|
65039
|
+
'se04',
|
|
65040
|
+
]);
|
|
65041
|
+
const isFirmwareUpdateV4ComponentTarget = (target) => FIRMWARE_UPDATE_V4_COMPONENT_TARGETS.has(target);
|
|
65042
|
+
const createReference = (binary, prefix) => {
|
|
65043
|
+
const digest = utils.bytesToHex(sha256.sha256(new Uint8Array(binary)));
|
|
65044
|
+
return {
|
|
65045
|
+
artifactRef: `fwmem:${prefix}:${digest.slice(0, 32)}`,
|
|
65046
|
+
size: binary.byteLength,
|
|
65047
|
+
sha256: digest,
|
|
65048
|
+
};
|
|
65049
|
+
};
|
|
65050
|
+
function prepareFirmwareUpdateV4MemoryHost({ sdk, plan, artifacts, }) {
|
|
65051
|
+
if (plan.executor !== 'v4') {
|
|
65052
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware memory host only supports V4 plans');
|
|
65053
|
+
}
|
|
65054
|
+
memoryHostSequence += 1;
|
|
65055
|
+
const hostId = `${Date.now()}:${memoryHostSequence}`;
|
|
65056
|
+
const binaries = new Map();
|
|
65057
|
+
const inputs = artifacts.map((input, artifactIndex) => {
|
|
65058
|
+
var _a;
|
|
65059
|
+
const artifact = createReference(input.binary, `${hostId}:artifact:${artifactIndex}`);
|
|
65060
|
+
binaries.set(artifact.artifactRef, new Uint8Array(input.binary));
|
|
65061
|
+
const materializedEntries = (_a = input.materializedEntries) === null || _a === void 0 ? void 0 : _a.map((entry, entryIndex) => {
|
|
65062
|
+
const entryArtifact = createReference(entry.binary, `${hostId}:entry:${artifactIndex}:${entryIndex}`);
|
|
65063
|
+
binaries.set(entryArtifact.artifactRef, new Uint8Array(entry.binary));
|
|
65064
|
+
return {
|
|
65065
|
+
entryName: entry.entryName,
|
|
65066
|
+
artifact: entryArtifact,
|
|
65067
|
+
};
|
|
65068
|
+
});
|
|
65069
|
+
return Object.assign({ artifactId: input.artifactId, artifact }, ((materializedEntries === null || materializedEntries === void 0 ? void 0 : materializedEntries.length) ? { materializedEntries } : {}));
|
|
65070
|
+
});
|
|
65071
|
+
const preparedPlan = sdk.prepareFirmwareUpdatePlan({
|
|
65072
|
+
plan,
|
|
65073
|
+
leaseRef: `fwmemlease:${hostId}`,
|
|
65074
|
+
artifacts: inputs,
|
|
65075
|
+
});
|
|
65076
|
+
const readers = new Map();
|
|
65077
|
+
let readerSequence = 0;
|
|
65078
|
+
const artifactReader = {
|
|
65079
|
+
open({ artifactRef }) {
|
|
65080
|
+
const binary = binaries.get(artifactRef);
|
|
65081
|
+
if (!binary) {
|
|
65082
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware memory artifact is unavailable');
|
|
65083
|
+
}
|
|
65084
|
+
readerSequence += 1;
|
|
65085
|
+
const readerId = `fwmemreader:${hostId}:${readerSequence}`;
|
|
65086
|
+
readers.set(readerId, binary);
|
|
65087
|
+
return Promise.resolve({ readerId, size: binary.byteLength });
|
|
65088
|
+
},
|
|
65089
|
+
read({ readerId, offset, length }) {
|
|
65090
|
+
const binary = readers.get(readerId);
|
|
65091
|
+
if (!binary || offset < 0 || length <= 0 || offset + length > binary.byteLength) {
|
|
65092
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware memory artifact read is invalid');
|
|
65093
|
+
}
|
|
65094
|
+
const data = binary.slice(offset, offset + length).buffer;
|
|
65095
|
+
return Promise.resolve({
|
|
65096
|
+
data,
|
|
65097
|
+
bytesRead: data.byteLength,
|
|
65098
|
+
eof: offset + length === binary.byteLength,
|
|
65099
|
+
});
|
|
65100
|
+
},
|
|
65101
|
+
close({ readerId }) {
|
|
65102
|
+
readers.delete(readerId);
|
|
65103
|
+
return Promise.resolve();
|
|
65104
|
+
},
|
|
65105
|
+
};
|
|
65106
|
+
const hostBindingGeneration = sdk.registerFirmwareUpdateHostBinding({ artifactReader });
|
|
65107
|
+
const componentArtifacts = {};
|
|
65108
|
+
const expectedTargetVersions = {};
|
|
65109
|
+
for (const artifact of preparedPlan.artifacts) {
|
|
65110
|
+
if (artifact.role === 'component' && isFirmwareUpdateV4ComponentTarget(artifact.target)) {
|
|
65111
|
+
componentArtifacts[artifact.target] = artifact.artifact;
|
|
65112
|
+
}
|
|
65113
|
+
if (artifact.targetVersion) {
|
|
65114
|
+
expectedTargetVersions[artifact.target] = artifact.targetVersion;
|
|
65115
|
+
}
|
|
65116
|
+
}
|
|
65117
|
+
return {
|
|
65118
|
+
preparedPlan,
|
|
65119
|
+
hostBindingGeneration,
|
|
65120
|
+
targetsToUpdate: [...preparedPlan.targetsToUpdate],
|
|
65121
|
+
expectedDeviceId: preparedPlan.deviceIdentity,
|
|
65122
|
+
expectedTargetVersions,
|
|
65123
|
+
componentArtifacts,
|
|
65124
|
+
release: () => {
|
|
65125
|
+
sdk.unregisterFirmwareUpdateHostBinding(hostBindingGeneration);
|
|
65126
|
+
readers.clear();
|
|
65127
|
+
binaries.clear();
|
|
65128
|
+
},
|
|
65129
|
+
};
|
|
65130
|
+
}
|
|
65131
|
+
|
|
64973
65132
|
const HardwareSdk = ({ init, call, dispose, eventEmitter, uiResponse, cancel, updateSettings, switchTransport, }) => inject({
|
|
64974
65133
|
init,
|
|
64975
65134
|
call,
|
|
@@ -65107,7 +65266,7 @@ exports.parseMessage = parseMessage;
|
|
|
65107
65266
|
exports.parseProtocolV2ResourceManifest = parseProtocolV2ResourceManifest;
|
|
65108
65267
|
exports.patchFeatures = patchFeatures;
|
|
65109
65268
|
exports.preloadSessionCache = preloadSessionCache;
|
|
65110
|
-
exports.
|
|
65269
|
+
exports.prepareFirmwareUpdateV4MemoryHost = prepareFirmwareUpdateV4MemoryHost;
|
|
65111
65270
|
exports.projectDeviceStateFeatures = projectFeatures;
|
|
65112
65271
|
exports.registerFirmwareUpdateHostBinding = registerFirmwareUpdateHostBinding;
|
|
65113
65272
|
exports.safeThrowError = safeThrowError;
|