@onekeyfe/hd-core 1.2.0-alpha.84 → 1.2.0-alpha.86
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 +69 -26
- package/__tests__/check-firmware-release-protocol-v2.test.ts +1 -2
- package/__tests__/firmware-memory-host.test.ts +108 -0
- package/__tests__/firmware-update/device-update-bootloader.test.ts +4 -1
- package/__tests__/firmware-update/firmware-host-binding.test.ts +9 -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 +59 -39
- package/__tests__/protocol-v2.test.ts +255 -306
- 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/FirmwareHostBinding.d.ts +1 -1
- package/dist/api/firmware/FirmwareHostBinding.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 +3 -4
- 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/data-manager/DataManager.d.ts +3 -1
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/index.d.ts +32 -70
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +450 -390
- 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 +0 -1
- 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 +1 -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 +3 -15
- package/dist/types/settings.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/CheckAllFirmwareRelease.ts +4 -13
- package/src/api/FirmwareUpdateV4.ts +166 -170
- package/src/api/firmware/FirmwareHostBinding.ts +16 -3
- package/src/api/firmware/FirmwareMemoryHost.ts +174 -0
- package/src/api/firmware/FirmwareUpdatePlan.ts +28 -48
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +8 -1
- package/src/data-manager/DataManager.ts +33 -13
- 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 +0 -1
- package/src/types/api/export.ts +0 -4
- package/src/types/api/firmwareUpdate.ts +2 -15
- package/src/types/api/index.ts +0 -2
- package/src/types/settings.ts +3 -25
- 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
|
@@ -798,7 +798,7 @@ const getExecutor = (features) => {
|
|
|
798
798
|
}
|
|
799
799
|
return 'v2';
|
|
800
800
|
};
|
|
801
|
-
const buildProtocolV2Artifacts = (release, { includeComponents = true,
|
|
801
|
+
const buildProtocolV2Artifacts = (release, { includeComponents = true, componentTargets: selectedComponentTargets, } = {}) => {
|
|
802
802
|
var _a;
|
|
803
803
|
const components = asRecord(release.components);
|
|
804
804
|
if (includeComponents && !components) {
|
|
@@ -842,26 +842,6 @@ const buildProtocolV2Artifacts = (release, { includeComponents = true, includeRe
|
|
|
842
842
|
})), (asVersion(component.version) ? { targetVersion: asVersion(component.version) } : {})));
|
|
843
843
|
targets.push(target);
|
|
844
844
|
}
|
|
845
|
-
const bundles = includeResources && Array.isArray(release.resourceBundles) ? release.resourceBundles : [];
|
|
846
|
-
const resourceBundleNames = new Set();
|
|
847
|
-
for (const value of bundles) {
|
|
848
|
-
const bundle = asRecord(value);
|
|
849
|
-
const name = asString(bundle === null || bundle === void 0 ? void 0 : bundle.name);
|
|
850
|
-
if (!bundle || !name) {
|
|
851
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource bundle is invalid', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
852
|
-
}
|
|
853
|
-
if (resourceBundleNames.has(name)) {
|
|
854
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 resource bundle duplicates name ${name}`, { firmwareUpdateCode: 'FirmwarePlanInvalid' });
|
|
855
|
-
}
|
|
856
|
-
resourceBundleNames.add(name);
|
|
857
|
-
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({
|
|
858
|
-
size: bundle.expectedSize,
|
|
859
|
-
sha256: bundle.fingerprint,
|
|
860
|
-
})));
|
|
861
|
-
}
|
|
862
|
-
if (bundles.length > 0) {
|
|
863
|
-
targets.push('resource');
|
|
864
|
-
}
|
|
865
845
|
return { artifacts, targets: [...new Set(targets)] };
|
|
866
846
|
};
|
|
867
847
|
const isForcedTargetRepresented = ({ executor, forcedTarget, artifacts, targetsToUpdate, }) => {
|
|
@@ -913,7 +893,7 @@ const finalizeFirmwareUpdatePlan = ({ features, firmwareType, platform, artifact
|
|
|
913
893
|
};
|
|
914
894
|
return assertFirmwareUpdatePlan(Object.assign(Object.assign({}, planWithoutDigest), { planDigest: digestFirmwareUpdatePlan(planWithoutDigest) }));
|
|
915
895
|
};
|
|
916
|
-
const buildProtocolV2FirmwareUpdatePlan = ({ features, firmwareType, platform, release, targetsToUpdate, forceUpdateTargets,
|
|
896
|
+
const buildProtocolV2FirmwareUpdatePlan = ({ features, firmwareType, platform, release, targetsToUpdate, forceUpdateTargets, resourceArchive, }) => {
|
|
917
897
|
const validatedForceTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
|
|
918
898
|
if (validatedForceTargets.some(target => target === 'ble' || target === 'bootloader')) {
|
|
919
899
|
planError('Protocol V2 does not support forced BLE or legacy bootloader targets');
|
|
@@ -925,9 +905,24 @@ const buildProtocolV2FirmwareUpdatePlan = ({ features, firmwareType, platform, r
|
|
|
925
905
|
}
|
|
926
906
|
const protocolV2 = buildProtocolV2Artifacts(release !== null && release !== void 0 ? release : {}, {
|
|
927
907
|
includeComponents: requestedComponentTargets.size > 0,
|
|
928
|
-
includeResources: false,
|
|
929
908
|
componentTargets: requestedComponentTargets,
|
|
930
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
|
+
}
|
|
931
926
|
const representedTargets = new Set(protocolV2.targets);
|
|
932
927
|
const missingTarget = Array.from(requestedComponentTargets).find(target => !representedTargets.has(target));
|
|
933
928
|
if (missingTarget) {
|
|
@@ -936,7 +931,7 @@ const buildProtocolV2FirmwareUpdatePlan = ({ features, firmwareType, platform, r
|
|
|
936
931
|
if (validatedForceTargets.includes('firmware') && protocolV2.targets.length === 0) {
|
|
937
932
|
planError('Forced firmware update target firmware is not represented by the plan');
|
|
938
933
|
}
|
|
939
|
-
if (validatedForceTargets.includes('resource') && !
|
|
934
|
+
if (validatedForceTargets.includes('resource') && !resourceArchive) {
|
|
940
935
|
planError('Forced firmware update target resource has no Protocol V2 resource archive');
|
|
941
936
|
}
|
|
942
937
|
return finalizeFirmwareUpdatePlan({
|
|
@@ -968,7 +963,6 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
|
|
|
968
963
|
if (executor === 'v4' && (shouldUpdateFirmware || shouldUpdateResource)) {
|
|
969
964
|
const protocolV2 = buildProtocolV2Artifacts(firmwareRelease !== null && firmwareRelease !== void 0 ? firmwareRelease : {}, {
|
|
970
965
|
includeComponents: shouldUpdateFirmware,
|
|
971
|
-
includeResources: shouldUpdateResource,
|
|
972
966
|
});
|
|
973
967
|
artifacts = protocolV2.artifacts;
|
|
974
968
|
targetsToUpdate = protocolV2.targets;
|
|
@@ -1160,7 +1154,7 @@ const prepareFirmwareUpdatePlan = ({ plan: value, leaseRef, artifacts, }) => {
|
|
|
1160
1154
|
return Object.assign(Object.assign({}, planWithoutDigest), { preparedPlanDigest: digestPreparedPlan(planWithoutDigest) });
|
|
1161
1155
|
};
|
|
1162
1156
|
const validateFirmwareUpdatePreparedPlan = (value) => {
|
|
1163
|
-
var _a, _b, _c;
|
|
1157
|
+
var _a, _b, _c, _d;
|
|
1164
1158
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
1165
1159
|
return preparedPlanError('Firmware prepared plan must be an object');
|
|
1166
1160
|
}
|
|
@@ -1240,7 +1234,13 @@ const validateFirmwareUpdatePreparedPlan = (value) => {
|
|
|
1240
1234
|
artifactIds.add(artifact.artifactId);
|
|
1241
1235
|
artifactTargets.add(artifact.target);
|
|
1242
1236
|
assertFirmwareArtifactReference(artifact.artifact);
|
|
1243
|
-
(_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
|
+
}
|
|
1244
1244
|
}
|
|
1245
1245
|
if (preparedPlan.targetsToUpdate.some(target => !FIRMWARE_UPDATE_PLAN_TARGETS.has(target)) ||
|
|
1246
1246
|
new Set(preparedPlan.targetsToUpdate).size !== preparedPlan.targetsToUpdate.length ||
|
|
@@ -1335,201 +1335,6 @@ const assertFirmwareUpdatePreparedPlanBinding = ({ preparedPlan: value, executor
|
|
|
1335
1335
|
return preparedPlan;
|
|
1336
1336
|
};
|
|
1337
1337
|
|
|
1338
|
-
const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1 = 'vol0:/loaders/bootloader/boot_resource.okpkg';
|
|
1339
|
-
const SHA256_HEX_LENGTH = 64;
|
|
1340
|
-
function normalizeHex$1(value, expectedLength, field) {
|
|
1341
|
-
if (typeof value !== 'string') {
|
|
1342
|
-
throw new Error(`Invalid Pro2 resource ${field}: expected a hexadecimal string`);
|
|
1343
|
-
}
|
|
1344
|
-
const normalized = value.replace(/^0x/i, '').toLowerCase();
|
|
1345
|
-
if (normalized.length !== expectedLength || !/^[0-9a-f]+$/.test(normalized)) {
|
|
1346
|
-
throw new Error(`Invalid Pro2 resource ${field}: expected ${expectedLength} hexadecimal characters`);
|
|
1347
|
-
}
|
|
1348
|
-
return normalized;
|
|
1349
|
-
}
|
|
1350
|
-
function parseProtocolV2Resources(value) {
|
|
1351
|
-
if (value === undefined)
|
|
1352
|
-
return undefined;
|
|
1353
|
-
if (!value || typeof value !== 'object') {
|
|
1354
|
-
throw new Error('Invalid Pro2 resources config');
|
|
1355
|
-
}
|
|
1356
|
-
const { source } = value;
|
|
1357
|
-
if (!source || typeof source !== 'object') {
|
|
1358
|
-
throw new Error('Invalid Pro2 resources config: source is required');
|
|
1359
|
-
}
|
|
1360
|
-
const { archiveUrl, archiveSha256, archiveSize } = source;
|
|
1361
|
-
if (typeof archiveUrl !== 'string' || !archiveUrl.startsWith('https://')) {
|
|
1362
|
-
throw new Error('Invalid Pro2 resources config: source.archiveUrl must use HTTPS');
|
|
1363
|
-
}
|
|
1364
|
-
if (typeof archiveSha256 !== 'string' || !/^[0-9a-fA-F]{64}$/.test(archiveSha256)) {
|
|
1365
|
-
throw new Error('Invalid Pro2 resources config: source.archiveSha256 must be a SHA-256 digest');
|
|
1366
|
-
}
|
|
1367
|
-
if (!Number.isSafeInteger(archiveSize) || archiveSize <= 0) {
|
|
1368
|
-
throw new Error('Invalid Pro2 resources config: source.archiveSize must be a positive integer');
|
|
1369
|
-
}
|
|
1370
|
-
return {
|
|
1371
|
-
source: {
|
|
1372
|
-
archiveUrl,
|
|
1373
|
-
archiveSha256: archiveSha256.toLowerCase(),
|
|
1374
|
-
archiveSize: archiveSize,
|
|
1375
|
-
},
|
|
1376
|
-
};
|
|
1377
|
-
}
|
|
1378
|
-
const PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS = [
|
|
1379
|
-
'vol0:/bundles/',
|
|
1380
|
-
'vol0:/loaders/rom/',
|
|
1381
|
-
];
|
|
1382
|
-
function isAllowedManifestDevicePath(path) {
|
|
1383
|
-
if (!path.endsWith('.okpkg') ||
|
|
1384
|
-
path.includes('\\') ||
|
|
1385
|
-
path.includes('//') ||
|
|
1386
|
-
path.split('/').some(part => part === '.' || part === '..')) {
|
|
1387
|
-
return false;
|
|
1388
|
-
}
|
|
1389
|
-
if (path === PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) {
|
|
1390
|
-
return true;
|
|
1391
|
-
}
|
|
1392
|
-
return PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS.some(root => path.startsWith(root));
|
|
1393
|
-
}
|
|
1394
|
-
function assertManifestString(value, field) {
|
|
1395
|
-
if (typeof value !== 'string' || value.length === 0) {
|
|
1396
|
-
throw new Error(`Invalid Pro2 resource manifest ${field}`);
|
|
1397
|
-
}
|
|
1398
|
-
return value;
|
|
1399
|
-
}
|
|
1400
|
-
function assertManifestRelativePath(value, field) {
|
|
1401
|
-
const path = assertManifestString(value, field);
|
|
1402
|
-
if (path.startsWith('/') ||
|
|
1403
|
-
path.includes('\\') ||
|
|
1404
|
-
path.includes(':') ||
|
|
1405
|
-
path.split('/').some(part => !part || part === '.' || part === '..')) {
|
|
1406
|
-
throw new Error(`Invalid Pro2 resource manifest ${field}`);
|
|
1407
|
-
}
|
|
1408
|
-
return path;
|
|
1409
|
-
}
|
|
1410
|
-
function parseProtocolV2ResourceManifestFile(value, index) {
|
|
1411
|
-
var _a;
|
|
1412
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
1413
|
-
throw new Error(`Invalid Pro2 resource manifest files[${index}]`);
|
|
1414
|
-
}
|
|
1415
|
-
const file = value;
|
|
1416
|
-
const archivePath = assertManifestRelativePath(file.archive_path, `files[${index}].archive_path`);
|
|
1417
|
-
const originalName = assertManifestRelativePath(file.original_name, `files[${index}].original_name`);
|
|
1418
|
-
if (originalName.includes('/')) {
|
|
1419
|
-
throw new Error(`Invalid Pro2 resource manifest files[${index}].original_name`);
|
|
1420
|
-
}
|
|
1421
|
-
const devicePath = assertManifestString(file.device_path, `files[${index}].device_path`);
|
|
1422
|
-
if (!isAllowedManifestDevicePath(devicePath)) {
|
|
1423
|
-
throw new Error(`Invalid Pro2 resource manifest files[${index}].device_path`);
|
|
1424
|
-
}
|
|
1425
|
-
if (!Number.isSafeInteger(file.size) || Number(file.size) <= 0) {
|
|
1426
|
-
throw new Error(`Invalid Pro2 resource manifest files[${index}].size`);
|
|
1427
|
-
}
|
|
1428
|
-
const digest = normalizeHex$1(file.sha256, SHA256_HEX_LENGTH, `files[${index}].sha256`);
|
|
1429
|
-
if (file.signed !== true) {
|
|
1430
|
-
throw new Error(`Invalid Pro2 resource manifest files[${index}].signed`);
|
|
1431
|
-
}
|
|
1432
|
-
if (file.sig_algo !== 'ed25519' && file.sig_algo !== 'mldsa65') {
|
|
1433
|
-
throw new Error(`Invalid Pro2 resource manifest files[${index}].sig_algo`);
|
|
1434
|
-
}
|
|
1435
|
-
if (file.payload_version !== null && typeof file.payload_version !== 'string') {
|
|
1436
|
-
throw new Error(`Invalid Pro2 resource manifest files[${index}].payload_version`);
|
|
1437
|
-
}
|
|
1438
|
-
if (!archivePath.endsWith('.okpkg') || !originalName.endsWith('.okpkg')) {
|
|
1439
|
-
throw new Error(`Invalid Pro2 resource manifest files[${index}] package extension`);
|
|
1440
|
-
}
|
|
1441
|
-
return {
|
|
1442
|
-
archive_path: archivePath,
|
|
1443
|
-
original_name: originalName,
|
|
1444
|
-
device_path: devicePath,
|
|
1445
|
-
size: Number(file.size),
|
|
1446
|
-
sha256: digest,
|
|
1447
|
-
signed: true,
|
|
1448
|
-
sig_algo: file.sig_algo,
|
|
1449
|
-
payload_version: (_a = file.payload_version) !== null && _a !== void 0 ? _a : null,
|
|
1450
|
-
};
|
|
1451
|
-
}
|
|
1452
|
-
function parseProtocolV2ResourceManifest(value) {
|
|
1453
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
1454
|
-
throw new Error('Invalid Pro2 resource manifest');
|
|
1455
|
-
}
|
|
1456
|
-
const manifest = value;
|
|
1457
|
-
if (manifest.schema !== 1 ||
|
|
1458
|
-
manifest.variant !== 'resource' ||
|
|
1459
|
-
manifest.device_root !== 'vol0:' ||
|
|
1460
|
-
manifest.restore_mode !== 'bootloader_update' ||
|
|
1461
|
-
!Array.isArray(manifest.trees) ||
|
|
1462
|
-
!Array.isArray(manifest.files)) {
|
|
1463
|
-
throw new Error('Invalid Pro2 resource manifest contract');
|
|
1464
|
-
}
|
|
1465
|
-
const files = manifest.files.map(parseProtocolV2ResourceManifestFile);
|
|
1466
|
-
const devicePaths = new Set(files.map(file => file.device_path));
|
|
1467
|
-
const archivePaths = new Set(files.map(file => file.archive_path));
|
|
1468
|
-
if (files.length === 0 ||
|
|
1469
|
-
devicePaths.size !== files.length ||
|
|
1470
|
-
archivePaths.size !== files.length ||
|
|
1471
|
-
!devicePaths.has(PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) ||
|
|
1472
|
-
!files.some(file => file.device_path.startsWith('vol0:/bundles/'))) {
|
|
1473
|
-
throw new Error('Invalid Pro2 resource manifest file set');
|
|
1474
|
-
}
|
|
1475
|
-
return {
|
|
1476
|
-
schema: 1,
|
|
1477
|
-
artifact_name: assertManifestString(manifest.artifact_name, 'artifact_name'),
|
|
1478
|
-
release_name: assertManifestString(manifest.release_name, 'release_name'),
|
|
1479
|
-
variant: 'resource',
|
|
1480
|
-
commit: assertManifestString(manifest.commit, 'commit'),
|
|
1481
|
-
short_sha: assertManifestString(manifest.short_sha, 'short_sha'),
|
|
1482
|
-
timestamp_utc: assertManifestString(manifest.timestamp_utc, 'timestamp_utc'),
|
|
1483
|
-
core_version: assertManifestString(manifest.core_version, 'core_version'),
|
|
1484
|
-
key_set: assertManifestString(manifest.key_set, 'key_set'),
|
|
1485
|
-
device_root: 'vol0:',
|
|
1486
|
-
restore_mode: 'bootloader_update',
|
|
1487
|
-
trees: manifest.trees.map((tree, index) => {
|
|
1488
|
-
if (!tree || typeof tree !== 'object') {
|
|
1489
|
-
throw new Error(`Invalid Pro2 resource manifest trees[${index}]`);
|
|
1490
|
-
}
|
|
1491
|
-
const item = tree;
|
|
1492
|
-
return {
|
|
1493
|
-
path: assertManifestRelativePath(item.path, `trees[${index}].path`),
|
|
1494
|
-
device: assertManifestString(item.device, `trees[${index}].device`),
|
|
1495
|
-
};
|
|
1496
|
-
}),
|
|
1497
|
-
files,
|
|
1498
|
-
};
|
|
1499
|
-
}
|
|
1500
|
-
function selectProtocolV2ResourceManifestFiles({ manifest, targetsToUpdate, }) {
|
|
1501
|
-
return targetsToUpdate.includes('resource') ? [...manifest.files] : [];
|
|
1502
|
-
}
|
|
1503
|
-
function prepareProtocolV2ResourceFiles({ manifest: value, files, targetsToUpdate, }) {
|
|
1504
|
-
const manifest = parseProtocolV2ResourceManifest(value);
|
|
1505
|
-
const selected = selectProtocolV2ResourceManifestFiles({ manifest, targetsToUpdate });
|
|
1506
|
-
const binaries = new Map(files.map(file => [file.archivePath, file.binary]));
|
|
1507
|
-
return selected.map(file => {
|
|
1508
|
-
const binary = binaries.get(file.archive_path);
|
|
1509
|
-
if (!binary ||
|
|
1510
|
-
!isProtocolV2ResourceFileValid(binary, {
|
|
1511
|
-
size: file.size,
|
|
1512
|
-
fileHash: file.sha256,
|
|
1513
|
-
})) {
|
|
1514
|
-
throw new Error(`Pro2 resource manifest file verification failed: ${file.archive_path}`);
|
|
1515
|
-
}
|
|
1516
|
-
return {
|
|
1517
|
-
binary,
|
|
1518
|
-
devicePath: file.device_path,
|
|
1519
|
-
size: file.size,
|
|
1520
|
-
fileHash: file.sha256,
|
|
1521
|
-
};
|
|
1522
|
-
});
|
|
1523
|
-
}
|
|
1524
|
-
function bytesToHex$3(bytes) {
|
|
1525
|
-
return Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('');
|
|
1526
|
-
}
|
|
1527
|
-
function isProtocolV2ResourceFileValid(binary, resource) {
|
|
1528
|
-
if (binary.byteLength !== resource.size)
|
|
1529
|
-
return false;
|
|
1530
|
-
return bytesToHex$3(sha256.sha256(new Uint8Array(binary))) === resource.fileHash.toLowerCase();
|
|
1531
|
-
}
|
|
1532
|
-
|
|
1533
1338
|
const bindingError = (message) => {
|
|
1534
1339
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, message, {
|
|
1535
1340
|
firmwareUpdateCode: 'FirmwareArtifactReaderInvalid',
|
|
@@ -1542,6 +1347,8 @@ class FirmwareHostBindingRegistry {
|
|
|
1542
1347
|
register(binding) {
|
|
1543
1348
|
var _a;
|
|
1544
1349
|
if (!binding ||
|
|
1350
|
+
typeof binding.preparedPlanDigest !== 'string' ||
|
|
1351
|
+
!/^[0-9a-f]{64}$/i.test(binding.preparedPlanDigest) ||
|
|
1545
1352
|
typeof ((_a = binding.artifactReader) === null || _a === void 0 ? void 0 : _a.open) !== 'function' ||
|
|
1546
1353
|
typeof binding.artifactReader.read !== 'function' ||
|
|
1547
1354
|
typeof binding.artifactReader.close !== 'function') {
|
|
@@ -1562,7 +1369,7 @@ class FirmwareHostBindingRegistry {
|
|
|
1562
1369
|
getGeneration() {
|
|
1563
1370
|
return this.generation;
|
|
1564
1371
|
}
|
|
1565
|
-
resolve(generation) {
|
|
1372
|
+
resolve(generation, preparedPlanDigest) {
|
|
1566
1373
|
if (!Number.isSafeInteger(generation) ||
|
|
1567
1374
|
generation <= 0 ||
|
|
1568
1375
|
generation !== this.generation ||
|
|
@@ -1570,12 +1377,17 @@ class FirmwareHostBindingRegistry {
|
|
|
1570
1377
|
return bindingError(`Firmware host binding generation ${generation} is stale`);
|
|
1571
1378
|
}
|
|
1572
1379
|
const { binding } = this;
|
|
1380
|
+
if (preparedPlanDigest !== undefined &&
|
|
1381
|
+
binding.preparedPlanDigest.toLowerCase() !== preparedPlanDigest.toLowerCase()) {
|
|
1382
|
+
return bindingError(`Firmware host binding generation ${generation} does not match the prepared plan`);
|
|
1383
|
+
}
|
|
1573
1384
|
const assertCurrent = () => {
|
|
1574
1385
|
if (generation !== this.generation || binding !== this.binding) {
|
|
1575
1386
|
bindingError(`Firmware host binding generation ${generation} is stale`);
|
|
1576
1387
|
}
|
|
1577
1388
|
};
|
|
1578
1389
|
return {
|
|
1390
|
+
preparedPlanDigest: binding.preparedPlanDigest,
|
|
1579
1391
|
artifactReader: {
|
|
1580
1392
|
open: (input) => __awaiter(this, void 0, void 0, function* () {
|
|
1581
1393
|
assertCurrent();
|
|
@@ -1608,7 +1420,7 @@ const firmwareHostBindingRegistry = new FirmwareHostBindingRegistry();
|
|
|
1608
1420
|
const registerFirmwareUpdateHostBinding = (binding) => firmwareHostBindingRegistry.register(binding);
|
|
1609
1421
|
const unregisterFirmwareUpdateHostBinding = (generation) => firmwareHostBindingRegistry.unregister(generation);
|
|
1610
1422
|
const getFirmwareUpdateHostBindingGeneration = () => firmwareHostBindingRegistry.getGeneration();
|
|
1611
|
-
const resolveFirmwareUpdateHostBinding = (generation) => firmwareHostBindingRegistry.resolve(generation !== null && generation !== void 0 ? generation : Number.NaN);
|
|
1423
|
+
const resolveFirmwareUpdateHostBinding = (generation, preparedPlanDigest) => firmwareHostBindingRegistry.resolve(generation !== null && generation !== void 0 ? generation : Number.NaN, preparedPlanDigest);
|
|
1612
1424
|
|
|
1613
1425
|
const callbackManager = new Map();
|
|
1614
1426
|
const generateCallbackId = () => `callback_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
|
|
@@ -1679,7 +1491,6 @@ const createCoreApi = (call) => ({
|
|
|
1679
1491
|
getFirmwareUpdateHostBindingGeneration,
|
|
1680
1492
|
prepareFirmwareUpdatePlan,
|
|
1681
1493
|
validateFirmwareUpdatePreparedPlan,
|
|
1682
|
-
prepareProtocolV2ResourceFiles,
|
|
1683
1494
|
getLogs: () => call({ method: 'getLogs' }),
|
|
1684
1495
|
clearSessionCache: params => call(Object.assign(Object.assign({}, params), { method: 'clearSessionCache' })),
|
|
1685
1496
|
searchDevices: params => call(Object.assign(Object.assign({}, params), { method: 'searchDevices' })),
|
|
@@ -40770,6 +40581,172 @@ const findLatestRelease = (releases) => {
|
|
|
40770
40581
|
return leastRelease;
|
|
40771
40582
|
};
|
|
40772
40583
|
|
|
40584
|
+
const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1 = 'vol0:/loaders/bootloader/boot_resource.okpkg';
|
|
40585
|
+
const SHA256_HEX_LENGTH = 64;
|
|
40586
|
+
function normalizeHex$1(value, expectedLength, field) {
|
|
40587
|
+
if (typeof value !== 'string') {
|
|
40588
|
+
throw new Error(`Invalid Pro2 resource ${field}: expected a hexadecimal string`);
|
|
40589
|
+
}
|
|
40590
|
+
const normalized = value.replace(/^0x/i, '').toLowerCase();
|
|
40591
|
+
if (normalized.length !== expectedLength || !/^[0-9a-f]+$/.test(normalized)) {
|
|
40592
|
+
throw new Error(`Invalid Pro2 resource ${field}: expected ${expectedLength} hexadecimal characters`);
|
|
40593
|
+
}
|
|
40594
|
+
return normalized;
|
|
40595
|
+
}
|
|
40596
|
+
function parseProtocolV2Resources(value) {
|
|
40597
|
+
if (value === undefined)
|
|
40598
|
+
return undefined;
|
|
40599
|
+
if (!value || typeof value !== 'object') {
|
|
40600
|
+
throw new Error('Invalid Pro2 resources config');
|
|
40601
|
+
}
|
|
40602
|
+
const { source } = value;
|
|
40603
|
+
if (!source || typeof source !== 'object') {
|
|
40604
|
+
throw new Error('Invalid Pro2 resources config: source is required');
|
|
40605
|
+
}
|
|
40606
|
+
const { archiveUrl, archiveSha256, archiveSize } = source;
|
|
40607
|
+
if (typeof archiveUrl !== 'string' || !archiveUrl.startsWith('https://')) {
|
|
40608
|
+
throw new Error('Invalid Pro2 resources config: source.archiveUrl must use HTTPS');
|
|
40609
|
+
}
|
|
40610
|
+
if (typeof archiveSha256 !== 'string' || !/^[0-9a-fA-F]{64}$/.test(archiveSha256)) {
|
|
40611
|
+
throw new Error('Invalid Pro2 resources config: source.archiveSha256 must be a SHA-256 digest');
|
|
40612
|
+
}
|
|
40613
|
+
if (!Number.isSafeInteger(archiveSize) || archiveSize <= 0) {
|
|
40614
|
+
throw new Error('Invalid Pro2 resources config: source.archiveSize must be a positive integer');
|
|
40615
|
+
}
|
|
40616
|
+
return {
|
|
40617
|
+
source: {
|
|
40618
|
+
archiveUrl,
|
|
40619
|
+
archiveSha256: archiveSha256.toLowerCase(),
|
|
40620
|
+
archiveSize: archiveSize,
|
|
40621
|
+
},
|
|
40622
|
+
};
|
|
40623
|
+
}
|
|
40624
|
+
const PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS = [
|
|
40625
|
+
'vol0:/bundles/',
|
|
40626
|
+
'vol0:/loaders/rom/',
|
|
40627
|
+
];
|
|
40628
|
+
function isAllowedManifestDevicePath(path) {
|
|
40629
|
+
if (!path.endsWith('.okpkg') ||
|
|
40630
|
+
path.includes('\\') ||
|
|
40631
|
+
path.includes('//') ||
|
|
40632
|
+
path.split('/').some(part => part === '.' || part === '..')) {
|
|
40633
|
+
return false;
|
|
40634
|
+
}
|
|
40635
|
+
if (path === PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) {
|
|
40636
|
+
return true;
|
|
40637
|
+
}
|
|
40638
|
+
return PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS.some(root => path.startsWith(root));
|
|
40639
|
+
}
|
|
40640
|
+
function assertManifestString(value, field) {
|
|
40641
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
40642
|
+
throw new Error(`Invalid Pro2 resource manifest ${field}`);
|
|
40643
|
+
}
|
|
40644
|
+
return value;
|
|
40645
|
+
}
|
|
40646
|
+
function assertManifestRelativePath(value, field) {
|
|
40647
|
+
const path = assertManifestString(value, field);
|
|
40648
|
+
if (path.startsWith('/') ||
|
|
40649
|
+
path.includes('\\') ||
|
|
40650
|
+
path.includes(':') ||
|
|
40651
|
+
path.split('/').some(part => !part || part === '.' || part === '..')) {
|
|
40652
|
+
throw new Error(`Invalid Pro2 resource manifest ${field}`);
|
|
40653
|
+
}
|
|
40654
|
+
return path;
|
|
40655
|
+
}
|
|
40656
|
+
function parseProtocolV2ResourceManifestFile(value, index) {
|
|
40657
|
+
var _a;
|
|
40658
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
40659
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}]`);
|
|
40660
|
+
}
|
|
40661
|
+
const file = value;
|
|
40662
|
+
const archivePath = assertManifestRelativePath(file.archive_path, `files[${index}].archive_path`);
|
|
40663
|
+
const originalName = assertManifestRelativePath(file.original_name, `files[${index}].original_name`);
|
|
40664
|
+
if (originalName.includes('/')) {
|
|
40665
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].original_name`);
|
|
40666
|
+
}
|
|
40667
|
+
const devicePath = assertManifestString(file.device_path, `files[${index}].device_path`);
|
|
40668
|
+
if (!isAllowedManifestDevicePath(devicePath)) {
|
|
40669
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].device_path`);
|
|
40670
|
+
}
|
|
40671
|
+
if (!Number.isSafeInteger(file.size) || Number(file.size) <= 0) {
|
|
40672
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].size`);
|
|
40673
|
+
}
|
|
40674
|
+
const digest = normalizeHex$1(file.sha256, SHA256_HEX_LENGTH, `files[${index}].sha256`);
|
|
40675
|
+
if (file.signed !== true) {
|
|
40676
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].signed`);
|
|
40677
|
+
}
|
|
40678
|
+
if (file.sig_algo !== 'ed25519' && file.sig_algo !== 'mldsa65') {
|
|
40679
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].sig_algo`);
|
|
40680
|
+
}
|
|
40681
|
+
if (file.payload_version !== null && typeof file.payload_version !== 'string') {
|
|
40682
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}].payload_version`);
|
|
40683
|
+
}
|
|
40684
|
+
if (!archivePath.endsWith('.okpkg') || !originalName.endsWith('.okpkg')) {
|
|
40685
|
+
throw new Error(`Invalid Pro2 resource manifest files[${index}] package extension`);
|
|
40686
|
+
}
|
|
40687
|
+
return {
|
|
40688
|
+
archive_path: archivePath,
|
|
40689
|
+
original_name: originalName,
|
|
40690
|
+
device_path: devicePath,
|
|
40691
|
+
size: Number(file.size),
|
|
40692
|
+
sha256: digest,
|
|
40693
|
+
signed: true,
|
|
40694
|
+
sig_algo: file.sig_algo,
|
|
40695
|
+
payload_version: (_a = file.payload_version) !== null && _a !== void 0 ? _a : null,
|
|
40696
|
+
};
|
|
40697
|
+
}
|
|
40698
|
+
function parseProtocolV2ResourceManifest(value) {
|
|
40699
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
40700
|
+
throw new Error('Invalid Pro2 resource manifest');
|
|
40701
|
+
}
|
|
40702
|
+
const manifest = value;
|
|
40703
|
+
if (manifest.schema !== 1 ||
|
|
40704
|
+
manifest.variant !== 'resource' ||
|
|
40705
|
+
manifest.device_root !== 'vol0:' ||
|
|
40706
|
+
manifest.restore_mode !== 'bootloader_update' ||
|
|
40707
|
+
!Array.isArray(manifest.trees) ||
|
|
40708
|
+
!Array.isArray(manifest.files)) {
|
|
40709
|
+
throw new Error('Invalid Pro2 resource manifest contract');
|
|
40710
|
+
}
|
|
40711
|
+
const files = manifest.files.map(parseProtocolV2ResourceManifestFile);
|
|
40712
|
+
const devicePaths = new Set(files.map(file => file.device_path));
|
|
40713
|
+
const archivePaths = new Set(files.map(file => file.archive_path));
|
|
40714
|
+
if (files.length === 0 ||
|
|
40715
|
+
devicePaths.size !== files.length ||
|
|
40716
|
+
archivePaths.size !== files.length ||
|
|
40717
|
+
!devicePaths.has(PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) ||
|
|
40718
|
+
!files.some(file => file.device_path.startsWith('vol0:/bundles/'))) {
|
|
40719
|
+
throw new Error('Invalid Pro2 resource manifest file set');
|
|
40720
|
+
}
|
|
40721
|
+
return {
|
|
40722
|
+
schema: 1,
|
|
40723
|
+
artifact_name: assertManifestString(manifest.artifact_name, 'artifact_name'),
|
|
40724
|
+
release_name: assertManifestString(manifest.release_name, 'release_name'),
|
|
40725
|
+
variant: 'resource',
|
|
40726
|
+
commit: assertManifestString(manifest.commit, 'commit'),
|
|
40727
|
+
short_sha: assertManifestString(manifest.short_sha, 'short_sha'),
|
|
40728
|
+
timestamp_utc: assertManifestString(manifest.timestamp_utc, 'timestamp_utc'),
|
|
40729
|
+
core_version: assertManifestString(manifest.core_version, 'core_version'),
|
|
40730
|
+
key_set: assertManifestString(manifest.key_set, 'key_set'),
|
|
40731
|
+
device_root: 'vol0:',
|
|
40732
|
+
restore_mode: 'bootloader_update',
|
|
40733
|
+
trees: manifest.trees.map((tree, index) => {
|
|
40734
|
+
if (!tree || typeof tree !== 'object') {
|
|
40735
|
+
throw new Error(`Invalid Pro2 resource manifest trees[${index}]`);
|
|
40736
|
+
}
|
|
40737
|
+
const item = tree;
|
|
40738
|
+
return {
|
|
40739
|
+
path: assertManifestRelativePath(item.path, `trees[${index}].path`),
|
|
40740
|
+
device: assertManifestString(item.device, `trees[${index}].device`),
|
|
40741
|
+
};
|
|
40742
|
+
}),
|
|
40743
|
+
files,
|
|
40744
|
+
};
|
|
40745
|
+
}
|
|
40746
|
+
function selectProtocolV2ResourceManifestFiles({ manifest, targetsToUpdate, }) {
|
|
40747
|
+
return targetsToUpdate.includes('resource') ? [...manifest.files] : [];
|
|
40748
|
+
}
|
|
40749
|
+
|
|
40773
40750
|
var _a$1;
|
|
40774
40751
|
const FIRMWARE_UPDATE_CONFIG_FRESHNESS_MS = 5 * 60 * 1000;
|
|
40775
40752
|
const Log$k = getLogger(exports.LoggerNames.Core);
|
|
@@ -40828,6 +40805,7 @@ class DataManager {
|
|
|
40828
40805
|
return __awaiter(this, void 0, void 0, function* () {
|
|
40829
40806
|
this.settings = settings;
|
|
40830
40807
|
this.protocolV2ResourcesConfigError = undefined;
|
|
40808
|
+
this.protocolV2NeoResourcesConfigError = undefined;
|
|
40831
40809
|
const manifestMode = (_b = settings.firmwareManifestMode) !== null && _b !== void 0 ? _b : (settings.fetchConfig ? 'sdk-managed' : undefined);
|
|
40832
40810
|
if (settings.preloadedConfig) {
|
|
40833
40811
|
this.applyRemoteConfig(settings.preloadedConfig);
|
|
@@ -40888,12 +40866,19 @@ class DataManager {
|
|
|
40888
40866
|
let neoResources;
|
|
40889
40867
|
try {
|
|
40890
40868
|
pro2Resources = parseProtocolV2Resources((_b = data.pro2) === null || _b === void 0 ? void 0 : _b.resources);
|
|
40891
|
-
neoResources = parseProtocolV2Resources((_c = data.neo) === null || _c === void 0 ? void 0 : _c.resources);
|
|
40892
40869
|
}
|
|
40893
40870
|
catch (error) {
|
|
40894
40871
|
this.protocolV2ResourcesConfigError =
|
|
40895
40872
|
error instanceof Error ? error : new Error(String(error));
|
|
40896
|
-
Log$k.warn('[DataConfig] Ignoring invalid
|
|
40873
|
+
Log$k.warn('[DataConfig] Ignoring invalid Pro2 resources config:', error);
|
|
40874
|
+
}
|
|
40875
|
+
try {
|
|
40876
|
+
neoResources = parseProtocolV2Resources((_c = data.neo) === null || _c === void 0 ? void 0 : _c.resources);
|
|
40877
|
+
}
|
|
40878
|
+
catch (error) {
|
|
40879
|
+
this.protocolV2NeoResourcesConfigError =
|
|
40880
|
+
error instanceof Error ? error : new Error(String(error));
|
|
40881
|
+
Log$k.warn('[DataConfig] Ignoring invalid Neo resources config:', error);
|
|
40897
40882
|
}
|
|
40898
40883
|
const enrichedPro2Config = this.enrichFirmwareReleaseInfo(data.pro2);
|
|
40899
40884
|
const enrichedNeoConfig = this.enrichFirmwareReleaseInfo(data.neo);
|
|
@@ -40931,16 +40916,20 @@ class DataManager {
|
|
|
40931
40916
|
}
|
|
40932
40917
|
});
|
|
40933
40918
|
}
|
|
40934
|
-
static forceReloadData({ requireResources = false, } = {}) {
|
|
40919
|
+
static forceReloadData({ requireResources = false, resourceDeviceType = hdShared.EDeviceType.Pro2, } = {}) {
|
|
40935
40920
|
return __awaiter(this, void 0, void 0, function* () {
|
|
40921
|
+
const resourceDeviceName = resourceDeviceType === hdShared.EDeviceType.Pro2 ? 'Pro2' : 'Neo';
|
|
40936
40922
|
if (!this.settings) {
|
|
40937
40923
|
throw new Error('Remote config settings are not initialized');
|
|
40938
40924
|
}
|
|
40939
40925
|
const hasFreshConfig = this.lastCheckTimestamp > 0 &&
|
|
40940
40926
|
getTimeStamp() - this.lastCheckTimestamp <= FIRMWARE_UPDATE_CONFIG_FRESHNESS_MS;
|
|
40941
40927
|
if (hasFreshConfig) {
|
|
40942
|
-
|
|
40943
|
-
|
|
40928
|
+
const resourcesConfigError = resourceDeviceType === hdShared.EDeviceType.Pro2
|
|
40929
|
+
? this.protocolV2ResourcesConfigError
|
|
40930
|
+
: this.protocolV2NeoResourcesConfigError;
|
|
40931
|
+
if (requireResources && resourcesConfigError) {
|
|
40932
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, `Invalid ${resourceDeviceName} resources config: ${resourcesConfigError.message}`);
|
|
40944
40933
|
}
|
|
40945
40934
|
return;
|
|
40946
40935
|
}
|
|
@@ -40948,8 +40937,11 @@ class DataManager {
|
|
|
40948
40937
|
if (!loaded) {
|
|
40949
40938
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.NetworkError, 'Unable to refresh the latest remote config');
|
|
40950
40939
|
}
|
|
40951
|
-
|
|
40952
|
-
|
|
40940
|
+
const resourcesConfigError = resourceDeviceType === hdShared.EDeviceType.Pro2
|
|
40941
|
+
? this.protocolV2ResourcesConfigError
|
|
40942
|
+
: this.protocolV2NeoResourcesConfigError;
|
|
40943
|
+
if (requireResources && resourcesConfigError) {
|
|
40944
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, `Invalid ${resourceDeviceName} resources config: ${resourcesConfigError.message}`);
|
|
40953
40945
|
}
|
|
40954
40946
|
this.lastCheckTimestamp = getTimeStamp();
|
|
40955
40947
|
});
|
|
@@ -40993,12 +40985,10 @@ DataManager.deviceMap = {
|
|
|
40993
40985
|
ble: [],
|
|
40994
40986
|
},
|
|
40995
40987
|
[hdShared.EDeviceType.Pro2]: {
|
|
40996
|
-
firmware: [],
|
|
40997
|
-
ble: [],
|
|
40988
|
+
'firmware-v1': [],
|
|
40998
40989
|
},
|
|
40999
40990
|
[hdShared.EDeviceType.Neo]: {
|
|
41000
|
-
firmware: [],
|
|
41001
|
-
ble: [],
|
|
40991
|
+
'firmware-v1': [],
|
|
41002
40992
|
},
|
|
41003
40993
|
[hdShared.EDeviceType.ClassicPure]: {
|
|
41004
40994
|
firmware: [],
|
|
@@ -47780,7 +47770,6 @@ class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
47780
47770
|
const resourceDeviceType = state.identity.deviceType === 'neo' ? hdShared.EDeviceType.Neo : hdShared.EDeviceType.Pro2;
|
|
47781
47771
|
const resourceSource = DataManager.getProtocolV2ResourceSource(resourceDeviceType);
|
|
47782
47772
|
const resourceStatus = 'unknown';
|
|
47783
|
-
const resourcePreparationRequired = !!resourceSource;
|
|
47784
47773
|
const detectedComponentTargets = validatedForceUpdateTargets.includes('firmware')
|
|
47785
47774
|
? plan.components.flatMap(component => component.updateTarget ? [component.updateTarget] : [])
|
|
47786
47775
|
: plan.targetsToUpdate;
|
|
@@ -47792,14 +47781,11 @@ class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
47792
47781
|
validatedProtocolV2ForceUpdateTargets.includes('resource');
|
|
47793
47782
|
const targetsToUpdate = Array.from(new Set([
|
|
47794
47783
|
...componentTargetsToUpdate,
|
|
47795
|
-
...(
|
|
47784
|
+
...(forceResourceUpdate ? ['resource'] : []),
|
|
47796
47785
|
]));
|
|
47797
47786
|
let firmwareUpdatePlan;
|
|
47798
47787
|
try {
|
|
47799
|
-
const shouldBuildFirmwareUpdatePlan =
|
|
47800
|
-
validatedForceUpdateTargets.some(target => target !== 'resource') ||
|
|
47801
|
-
validatedProtocolV2ForceUpdateTargets.some(target => target !== 'resource') ||
|
|
47802
|
-
(forceResourceUpdate && !resourcePreparationRequired);
|
|
47788
|
+
const shouldBuildFirmwareUpdatePlan = targetsToUpdate.length > 0;
|
|
47803
47789
|
const requestedPlatform = platform !== null && platform !== void 0 ? platform : 'web';
|
|
47804
47790
|
const requiresDeviceIdentity = requestedPlatform === 'native' || requestedPlatform === 'desktop';
|
|
47805
47791
|
const canBindPreparedPlan = !requiresDeviceIdentity || !!getDeviceSerialNo(features);
|
|
@@ -47811,7 +47797,7 @@ class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
47811
47797
|
release,
|
|
47812
47798
|
targetsToUpdate,
|
|
47813
47799
|
forceUpdateTargets: validatedForceUpdateTargets,
|
|
47814
|
-
|
|
47800
|
+
resourceArchive: resourceSource,
|
|
47815
47801
|
});
|
|
47816
47802
|
firmwareUpdatePlan = canBindPreparedPlan ? validatedPlan : undefined;
|
|
47817
47803
|
if (!canBindPreparedPlan) {
|
|
@@ -47835,9 +47821,7 @@ class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
47835
47821
|
const firmwarePlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_MAIN_FIRMWARE_TARGETS);
|
|
47836
47822
|
const blePlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_BLE_TARGETS);
|
|
47837
47823
|
const bootloaderPlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_BOOTLOADER_TARGETS);
|
|
47838
|
-
const
|
|
47839
|
-
? 'unknown'
|
|
47840
|
-
: plan.status;
|
|
47824
|
+
const { status } = plan;
|
|
47841
47825
|
return Object.assign(Object.assign({ firmware: toProtocolV2FirmwareReleaseInfo({ plan: firmwarePlan, state, release }), ble: toProtocolV2FirmwareReleaseInfo({
|
|
47842
47826
|
plan: blePlan,
|
|
47843
47827
|
state,
|
|
@@ -47847,7 +47831,7 @@ class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
47847
47831
|
state,
|
|
47848
47832
|
release: getProtocolV2ComponentReleaseInfo(plan, 'BOOTLOADER'),
|
|
47849
47833
|
}), features, protocol: 'V2', deviceType: state.identity.deviceType }, plan), { status,
|
|
47850
|
-
resourceStatus, resourceArchive: resourceSource,
|
|
47834
|
+
resourceStatus, resourceArchive: resourceSource, hasUpgrade: targetsToUpdate.length > 0, targetsToUpdate,
|
|
47851
47835
|
firmwareUpdatePlan });
|
|
47852
47836
|
});
|
|
47853
47837
|
}
|
|
@@ -51271,6 +51255,9 @@ const PROTOCOL_V2_OKPP_HEADER_SIZE = 0x52a0;
|
|
|
51271
51255
|
const PROTOCOL_V2_OKPP_PAYLOAD_HASH_OFFSET = 0x200;
|
|
51272
51256
|
const PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET = 0x240;
|
|
51273
51257
|
const PROTOCOL_V2_OKPP_HASH_SIZE = 64;
|
|
51258
|
+
const PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES = 1024 * 1024;
|
|
51259
|
+
const PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT = 512;
|
|
51260
|
+
const PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES = 256 * 1024 * 1024;
|
|
51274
51261
|
const PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS = new Set(['se03', 'se04']);
|
|
51275
51262
|
function assertProtocolV2FirmwareTargetsSupported(deviceType, params) {
|
|
51276
51263
|
var _a;
|
|
@@ -51524,7 +51511,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51524
51511
|
return ['V2'];
|
|
51525
51512
|
}
|
|
51526
51513
|
init() {
|
|
51527
|
-
var _a, _b
|
|
51514
|
+
var _a, _b;
|
|
51528
51515
|
this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
|
|
51529
51516
|
this.requireDeviceMode = [];
|
|
51530
51517
|
this.unlockPolicy = 'unlock-before-run';
|
|
@@ -51559,33 +51546,26 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51559
51546
|
{ name: 'targetsToUpdate', type: 'array', allowEmpty: true },
|
|
51560
51547
|
{ name: 'platform', type: 'string' },
|
|
51561
51548
|
{ name: 'expectedDeviceId', type: 'string' },
|
|
51562
|
-
{ name: 'resourceFiles', type: 'array', allowEmpty: true },
|
|
51563
51549
|
]);
|
|
51564
51550
|
if (payload.expectedDeviceId !== undefined &&
|
|
51565
51551
|
(payload.expectedDeviceId.length === 0 || payload.expectedDeviceId.length > 160)) {
|
|
51566
51552
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Protocol V2 expected device identity is invalid');
|
|
51567
51553
|
}
|
|
51568
|
-
const
|
|
51569
|
-
?
|
|
51554
|
+
const preparedPlan = payload.preparedPlan
|
|
51555
|
+
? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
|
|
51556
|
+
: undefined;
|
|
51557
|
+
const hostBinding = preparedPlan || payload.componentArtifacts
|
|
51558
|
+
? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration, preparedPlan === null || preparedPlan === void 0 ? void 0 : preparedPlan.preparedPlanDigest)
|
|
51570
51559
|
: undefined;
|
|
51571
51560
|
if (hostBinding) {
|
|
51561
|
+
const componentArtifacts = ((_a = payload.componentArtifacts) !== null && _a !== void 0 ? _a : {});
|
|
51572
51562
|
assertFirmwareUpdatePreparedPlanBinding({
|
|
51573
|
-
preparedPlan: payload.preparedPlan,
|
|
51563
|
+
preparedPlan: preparedPlan !== null && preparedPlan !== void 0 ? preparedPlan : payload.preparedPlan,
|
|
51574
51564
|
executor: 'v4',
|
|
51575
51565
|
platform: payload.platform,
|
|
51576
|
-
scopeTargets: [
|
|
51577
|
-
'boot',
|
|
51578
|
-
'app_v1',
|
|
51579
|
-
'app_v2',
|
|
51580
|
-
'coprocessor',
|
|
51581
|
-
'resource',
|
|
51582
|
-
'se01',
|
|
51583
|
-
'se02',
|
|
51584
|
-
'se03',
|
|
51585
|
-
'se04',
|
|
51586
|
-
],
|
|
51566
|
+
scopeTargets: ['boot', 'app_v1', 'app_v2', 'coprocessor', 'se01', 'se02', 'se03', 'se04'],
|
|
51587
51567
|
bindings: [
|
|
51588
|
-
...Object.entries(
|
|
51568
|
+
...Object.entries(componentArtifacts).flatMap(([target, artifact]) => artifact
|
|
51589
51569
|
? [
|
|
51590
51570
|
{
|
|
51591
51571
|
target: target,
|
|
@@ -51593,16 +51573,11 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51593
51573
|
},
|
|
51594
51574
|
]
|
|
51595
51575
|
: []),
|
|
51596
|
-
...((_b = payload.resourceBundleArtifacts) !== null && _b !== void 0 ? _b : []).map((entry) => ({
|
|
51597
|
-
target: 'resource',
|
|
51598
|
-
logicalName: entry.name,
|
|
51599
|
-
artifact: entry.artifact,
|
|
51600
|
-
})),
|
|
51601
51576
|
],
|
|
51602
51577
|
});
|
|
51603
51578
|
}
|
|
51604
51579
|
this.params = {
|
|
51605
|
-
preparedPlan
|
|
51580
|
+
preparedPlan,
|
|
51606
51581
|
chunkSize: payload.chunkSize,
|
|
51607
51582
|
forcedUpdateRes: payload.forcedUpdateRes,
|
|
51608
51583
|
bootloaderBinary: payload.bootloaderBinary,
|
|
@@ -51614,15 +51589,13 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51614
51589
|
se02Binary: payload.se02Binary,
|
|
51615
51590
|
se03Binary: payload.se03Binary,
|
|
51616
51591
|
se04Binary: payload.se04Binary,
|
|
51617
|
-
resourceFiles: payload.resourceFiles,
|
|
51618
51592
|
firmwareType: payload.firmwareType,
|
|
51619
51593
|
targetsToUpdate: payload.targetsToUpdate,
|
|
51620
51594
|
expectedTargetVersions: payload.expectedTargetVersions,
|
|
51621
51595
|
platform: payload.platform,
|
|
51622
51596
|
expectedDeviceId: payload.expectedDeviceId,
|
|
51623
|
-
artifactReader: (
|
|
51597
|
+
artifactReader: (_b = hostBinding === null || hostBinding === void 0 ? void 0 : hostBinding.artifactReader) !== null && _b !== void 0 ? _b : payload.artifactReader,
|
|
51624
51598
|
componentArtifacts: payload.componentArtifacts,
|
|
51625
|
-
resourceBundleArtifacts: payload.resourceBundleArtifacts,
|
|
51626
51599
|
};
|
|
51627
51600
|
}
|
|
51628
51601
|
getProtocolV2FirmwareChunkSize(direction, filePath) {
|
|
@@ -51653,7 +51626,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51653
51626
|
});
|
|
51654
51627
|
}
|
|
51655
51628
|
runProtocolV2() {
|
|
51656
|
-
var _a, _b, _c, _d
|
|
51629
|
+
var _a, _b, _c, _d;
|
|
51657
51630
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51658
51631
|
yield this.captureProtocolV2PhysicalIdentity();
|
|
51659
51632
|
const deviceFeatures = yield this.getProtocolV2DeviceFeatures();
|
|
@@ -51665,20 +51638,15 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51665
51638
|
const deviceFirmwareType = getFirmwareType(deviceFeatures);
|
|
51666
51639
|
const firmwareType = (_a = this.params.firmwareType) !== null && _a !== void 0 ? _a : deviceFirmwareType;
|
|
51667
51640
|
this.validateExpectedTargetVersions();
|
|
51668
|
-
if (
|
|
51669
|
-
((_b = this.params.resourceBundleArtifacts) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
51641
|
+
if (this.params.preparedPlan) {
|
|
51670
51642
|
return this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType);
|
|
51671
51643
|
}
|
|
51672
|
-
const
|
|
51673
|
-
const wantsResources = !!((_d = this.params.targetsToUpdate) === null || _d === void 0 ? void 0 : _d.includes('resource'));
|
|
51674
|
-
const needsPreparedResources = !hasExplicitResourceFiles && wantsResources;
|
|
51644
|
+
const wantsResources = !!((_b = this.params.targetsToUpdate) === null || _b === void 0 ? void 0 : _b.includes('resource'));
|
|
51675
51645
|
let fwBinaryMap = [];
|
|
51676
51646
|
let bootloaderBinary = null;
|
|
51677
51647
|
let installItems;
|
|
51678
|
-
let resourceBundles;
|
|
51679
51648
|
try {
|
|
51680
51649
|
this.postTipMessage(exports.FirmwareUpdateTipMessage.StartDownloadFirmware);
|
|
51681
|
-
resourceBundles = this.prepareExplicitProtocolV2ResourceFiles();
|
|
51682
51650
|
fwBinaryMap = this.collectExplicitTargetBinaries();
|
|
51683
51651
|
bootloaderBinary = this.prepareBootloaderBinary();
|
|
51684
51652
|
const explicitInstallItems = this.buildProtocolV2InstallItems({
|
|
@@ -51686,10 +51654,10 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51686
51654
|
fwBinaryMap,
|
|
51687
51655
|
});
|
|
51688
51656
|
const missingFirmwareTargets = this.getMissingProtocolV2FirmwareTargets(explicitInstallItems);
|
|
51689
|
-
const needsRemoteFirmware = ((
|
|
51657
|
+
const needsRemoteFirmware = ((_c = this.params.targetsToUpdate) === null || _c === void 0 ? void 0 : _c.length)
|
|
51690
51658
|
? missingFirmwareTargets.length > 0
|
|
51691
|
-
:
|
|
51692
|
-
if (
|
|
51659
|
+
: explicitInstallItems.length === 0;
|
|
51660
|
+
if (wantsResources) {
|
|
51693
51661
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource manifest must be prepared by the external firmware host', {
|
|
51694
51662
|
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
51695
51663
|
});
|
|
@@ -51716,7 +51684,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51716
51684
|
if (typeof err === 'object' &&
|
|
51717
51685
|
err !== null &&
|
|
51718
51686
|
'params' in err &&
|
|
51719
|
-
((
|
|
51687
|
+
((_d = err.params) === null || _d === void 0 ? void 0 : _d.firmwareUpdateCode) === 'FirmwareArtifactsNotPrepared') {
|
|
51720
51688
|
throw err;
|
|
51721
51689
|
}
|
|
51722
51690
|
if (err instanceof hdShared.HardwareError && err.errorCode === hdShared.HardwareErrorCode.NetworkError) {
|
|
@@ -51724,14 +51692,11 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51724
51692
|
}
|
|
51725
51693
|
throw normalizeFirmwarePreparationError(err);
|
|
51726
51694
|
}
|
|
51727
|
-
if (!bootloaderBinary &&
|
|
51728
|
-
fwBinaryMap.length === 0 &&
|
|
51729
|
-
!(installItems === null || installItems === void 0 ? void 0 : installItems.length) &&
|
|
51730
|
-
!(resourceBundles === null || resourceBundles === void 0 ? void 0 : resourceBundles.length)) {
|
|
51695
|
+
if (!bootloaderBinary && fwBinaryMap.length === 0 && !(installItems === null || installItems === void 0 ? void 0 : installItems.length)) {
|
|
51731
51696
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, 'No firmware to update');
|
|
51732
51697
|
}
|
|
51733
|
-
return this.executeProtocolV2Update(Object.assign(
|
|
51734
|
-
bootloaderBinary }, (installItems ? { installItems } : undefined))
|
|
51698
|
+
return this.executeProtocolV2Update(Object.assign({ fwBinaryMap,
|
|
51699
|
+
bootloaderBinary }, (installItems ? { installItems } : undefined)));
|
|
51735
51700
|
});
|
|
51736
51701
|
}
|
|
51737
51702
|
openProtocolV2PreparedSource(artifact) {
|
|
@@ -51798,39 +51763,87 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51798
51763
|
return installSources;
|
|
51799
51764
|
});
|
|
51800
51765
|
}
|
|
51801
|
-
prepareProtocolV2ResourceSources(
|
|
51802
|
-
var _a, _b
|
|
51766
|
+
prepareProtocolV2ResourceSources() {
|
|
51767
|
+
var _a, _b;
|
|
51803
51768
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51804
|
-
const
|
|
51805
|
-
const resourceRequested = ((_b = this.params.targetsToUpdate) === null || _b === void 0 ? void 0 : _b.includes('resource')) || preparedArtifacts.length > 0;
|
|
51769
|
+
const resourceRequested = (_b = (_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.includes('resource')) !== null && _b !== void 0 ? _b : false;
|
|
51806
51770
|
if (!resourceRequested) {
|
|
51807
51771
|
return [];
|
|
51808
51772
|
}
|
|
51809
|
-
const
|
|
51810
|
-
|
|
51811
|
-
|
|
51812
|
-
const sources = [];
|
|
51813
|
-
for (const descriptor of descriptors) {
|
|
51814
|
-
const artifact = artifactByName.get(descriptor.name);
|
|
51815
|
-
if (!artifact) {
|
|
51816
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 resource bundle ${descriptor.name} is not prepared`, {
|
|
51817
|
-
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
51818
|
-
artifactName: descriptor.name,
|
|
51819
|
-
});
|
|
51820
|
-
}
|
|
51821
|
-
const devicePath = validateProtocolV2FilesystemPath(descriptor.devicePath, 'resourceBundles[].devicePath');
|
|
51822
|
-
sources.push({
|
|
51823
|
-
name: descriptor.name,
|
|
51824
|
-
source: yield this.openProtocolV2PreparedSource(artifact),
|
|
51825
|
-
devicePath,
|
|
51826
|
-
version: descriptor.version,
|
|
51827
|
-
payloadHash: descriptor.payloadHash,
|
|
51828
|
-
headerHash: descriptor.headerHash,
|
|
51829
|
-
});
|
|
51830
|
-
artifactByName.delete(descriptor.name);
|
|
51773
|
+
const archiveSources = yield this.prepareProtocolV2ResourceArchiveSources();
|
|
51774
|
+
if (archiveSources) {
|
|
51775
|
+
return archiveSources;
|
|
51831
51776
|
}
|
|
51832
|
-
|
|
51833
|
-
|
|
51777
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource archive is not prepared', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
51778
|
+
});
|
|
51779
|
+
}
|
|
51780
|
+
prepareProtocolV2ResourceArchiveSources() {
|
|
51781
|
+
var _a, _b, _c, _d;
|
|
51782
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
51783
|
+
const archiveArtifacts = (_b = (_a = this.params.preparedPlan) === null || _a === void 0 ? void 0 : _a.artifacts.filter(artifact => artifact.role === 'resourceBundle' &&
|
|
51784
|
+
artifact.target === 'resource' &&
|
|
51785
|
+
artifact.container === 'zip')) !== null && _b !== void 0 ? _b : [];
|
|
51786
|
+
if (archiveArtifacts.length === 0) {
|
|
51787
|
+
return undefined;
|
|
51788
|
+
}
|
|
51789
|
+
if (archiveArtifacts.length !== 1) {
|
|
51790
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared plan must contain exactly one resource archive', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
51791
|
+
}
|
|
51792
|
+
const entries = (_c = archiveArtifacts[0].materializedEntries) !== null && _c !== void 0 ? _c : [];
|
|
51793
|
+
const manifestEntry = entries.find(entry => entry.entryName === 'manifest.json');
|
|
51794
|
+
if (!manifestEntry ||
|
|
51795
|
+
manifestEntry.artifact.size <= 0 ||
|
|
51796
|
+
manifestEntry.artifact.size > PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES) {
|
|
51797
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive has no valid manifest.json', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
51798
|
+
}
|
|
51799
|
+
const manifestSource = yield this.openProtocolV2PreparedSource(manifestEntry.artifact);
|
|
51800
|
+
let manifestValue;
|
|
51801
|
+
try {
|
|
51802
|
+
manifestValue = JSON.parse(new TextDecoder().decode(yield readFirmwareByteSourceFully(manifestSource)));
|
|
51803
|
+
}
|
|
51804
|
+
catch (error) {
|
|
51805
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 prepared resource manifest is invalid: ${String(error)}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
51806
|
+
}
|
|
51807
|
+
const manifest = parseProtocolV2ResourceManifest(manifestValue);
|
|
51808
|
+
const selectedFiles = selectProtocolV2ResourceManifestFiles({
|
|
51809
|
+
manifest,
|
|
51810
|
+
targetsToUpdate: (_d = this.params.targetsToUpdate) !== null && _d !== void 0 ? _d : [],
|
|
51811
|
+
});
|
|
51812
|
+
if (selectedFiles.length > PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT) {
|
|
51813
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive contains too many files', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
51814
|
+
}
|
|
51815
|
+
const entriesByName = new Map(entries.map(entry => [entry.entryName, entry]));
|
|
51816
|
+
const expectedEntryNames = new Set([
|
|
51817
|
+
'manifest.json',
|
|
51818
|
+
...selectedFiles.map(file => file.archive_path),
|
|
51819
|
+
]);
|
|
51820
|
+
if (entries.some(entry => !expectedEntryNames.has(entry.entryName))) {
|
|
51821
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive contains an unexpected entry', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
51822
|
+
}
|
|
51823
|
+
let totalSize = 0;
|
|
51824
|
+
const sources = [];
|
|
51825
|
+
for (const [index, file] of selectedFiles.entries()) {
|
|
51826
|
+
const entry = entriesByName.get(file.archive_path);
|
|
51827
|
+
if (!entry ||
|
|
51828
|
+
entry.artifact.size !== file.size ||
|
|
51829
|
+
entry.artifact.sha256.toLowerCase() !== file.sha256.toLowerCase()) {
|
|
51830
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 prepared resource file does not match manifest: ${file.archive_path}`, { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
|
|
51831
|
+
}
|
|
51832
|
+
totalSize += entry.artifact.size;
|
|
51833
|
+
if (totalSize > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
|
|
51834
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive exceeds the total size limit', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
|
|
51835
|
+
}
|
|
51836
|
+
const source = yield this.openProtocolV2PreparedSource(entry.artifact);
|
|
51837
|
+
const header = source.size >= PROTOCOL_V2_OKPP_HEADER_SIZE
|
|
51838
|
+
? parseProtocolV2OkppHeader(new Uint8Array(yield source.readAt(0, PROTOCOL_V2_OKPP_HEADER_SIZE)))
|
|
51839
|
+
: null;
|
|
51840
|
+
sources.push(Object.assign({ name: file.original_name || `resource-${index}`, source, devicePath: file.device_path }, (header
|
|
51841
|
+
? {
|
|
51842
|
+
version: header.version,
|
|
51843
|
+
payloadHash: header.payloadHash,
|
|
51844
|
+
headerHash: header.headerHash,
|
|
51845
|
+
}
|
|
51846
|
+
: {})));
|
|
51834
51847
|
}
|
|
51835
51848
|
return sources;
|
|
51836
51849
|
});
|
|
@@ -51840,19 +51853,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51840
51853
|
try {
|
|
51841
51854
|
this.postTipMessage(exports.FirmwareUpdateTipMessage.StartDownloadFirmware);
|
|
51842
51855
|
const installSources = yield this.prepareProtocolV2InstallSources(firmwareType, features);
|
|
51843
|
-
const
|
|
51844
|
-
const resourceSources = (explicitResourceBundles === null || explicitResourceBundles === void 0 ? void 0 : explicitResourceBundles.length)
|
|
51845
|
-
? yield Promise.all(explicitResourceBundles.map((bundle) => __awaiter(this, void 0, void 0, function* () {
|
|
51846
|
-
return ({
|
|
51847
|
-
name: bundle.name,
|
|
51848
|
-
source: yield this.openProtocolV2MemorySource(bundle.binary),
|
|
51849
|
-
devicePath: bundle.devicePath,
|
|
51850
|
-
version: bundle.version,
|
|
51851
|
-
payloadHash: bundle.payloadHash,
|
|
51852
|
-
headerHash: bundle.headerHash,
|
|
51853
|
-
});
|
|
51854
|
-
})))
|
|
51855
|
-
: yield this.prepareProtocolV2ResourceSources(firmwareType, features);
|
|
51856
|
+
const resourceSources = yield this.prepareProtocolV2ResourceSources();
|
|
51856
51857
|
if (installSources.length === 0 && resourceSources.length === 0) {
|
|
51857
51858
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, 'No firmware to update');
|
|
51858
51859
|
}
|
|
@@ -51936,15 +51937,15 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51936
51937
|
}
|
|
51937
51938
|
}
|
|
51938
51939
|
getProtocolV2RequestedTargets() {
|
|
51939
|
-
var _a, _b, _c
|
|
51940
|
+
var _a, _b, _c;
|
|
51940
51941
|
if ((_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.length) {
|
|
51941
51942
|
return [...new Set(this.params.targetsToUpdate)];
|
|
51942
51943
|
}
|
|
51943
|
-
|
|
51944
|
-
|
|
51945
|
-
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)) {
|
|
51946
|
-
targets.add('resource');
|
|
51944
|
+
if ((_b = this.params.preparedPlan) === null || _b === void 0 ? void 0 : _b.targetsToUpdate.length) {
|
|
51945
|
+
return [...new Set(this.params.preparedPlan.targetsToUpdate)];
|
|
51947
51946
|
}
|
|
51947
|
+
const targets = new Set();
|
|
51948
|
+
Object.keys((_c = this.params.componentArtifacts) !== null && _c !== void 0 ? _c : {}).forEach(target => targets.add(target));
|
|
51948
51949
|
if (this.params.bootloaderBinary)
|
|
51949
51950
|
targets.add('boot');
|
|
51950
51951
|
if (this.params.applicationP1Binary)
|
|
@@ -52031,10 +52032,6 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52031
52032
|
var _a;
|
|
52032
52033
|
return (_a = this.params.bootloaderBinary) !== null && _a !== void 0 ? _a : null;
|
|
52033
52034
|
}
|
|
52034
|
-
hasExplicitProtocolV2Payload(installItems) {
|
|
52035
|
-
var _a;
|
|
52036
|
-
return !!((_a = this.params.resourceFiles) === null || _a === void 0 ? void 0 : _a.length) || installItems.length > 0;
|
|
52037
|
-
}
|
|
52038
52035
|
getMissingProtocolV2FirmwareTargets(installItems) {
|
|
52039
52036
|
var _a;
|
|
52040
52037
|
const preparedTargets = new Set(installItems.flatMap(item => {
|
|
@@ -52161,39 +52158,6 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52161
52158
|
};
|
|
52162
52159
|
});
|
|
52163
52160
|
}
|
|
52164
|
-
prepareExplicitProtocolV2ResourceFiles() {
|
|
52165
|
-
var _a;
|
|
52166
|
-
const files = (_a = this.params.resourceFiles) !== null && _a !== void 0 ? _a : [];
|
|
52167
|
-
if (!(files === null || files === void 0 ? void 0 : files.length))
|
|
52168
|
-
return undefined;
|
|
52169
|
-
const prepared = files.map((file, index) => {
|
|
52170
|
-
var _a;
|
|
52171
|
-
const devicePath = validateProtocolV2FilesystemPath(file.devicePath, `resourceFiles[${index}].devicePath`);
|
|
52172
|
-
const descriptor = file;
|
|
52173
|
-
if (descriptor.size !== undefined && descriptor.size !== file.binary.byteLength) {
|
|
52174
|
-
throw new Error(`resourceFiles[${index}] size mismatch`);
|
|
52175
|
-
}
|
|
52176
|
-
if (descriptor.fileHash &&
|
|
52177
|
-
!isProtocolV2ResourceFileValid(file.binary, {
|
|
52178
|
-
size: file.binary.byteLength,
|
|
52179
|
-
fileHash: descriptor.fileHash,
|
|
52180
|
-
})) {
|
|
52181
|
-
throw new Error(`resourceFiles[${index}] SHA-256 mismatch`);
|
|
52182
|
-
}
|
|
52183
|
-
const header = parseProtocolV2OkppHeader(toProtocolV2Bytes(file.binary));
|
|
52184
|
-
return Object.assign({ name: (_a = devicePath.split('/').pop()) !== null && _a !== void 0 ? _a : devicePath, binary: file.binary, devicePath }, (header
|
|
52185
|
-
? {
|
|
52186
|
-
version: header.version,
|
|
52187
|
-
payloadHash: header.payloadHash,
|
|
52188
|
-
headerHash: header.headerHash,
|
|
52189
|
-
}
|
|
52190
|
-
: {}));
|
|
52191
|
-
});
|
|
52192
|
-
if (new Set(prepared.map(file => file.devicePath)).size !== prepared.length) {
|
|
52193
|
-
throw new Error('resourceFiles contain duplicate devicePath values');
|
|
52194
|
-
}
|
|
52195
|
-
return prepared;
|
|
52196
|
-
}
|
|
52197
52161
|
getProtocolV2ResourceFilePath(path) {
|
|
52198
52162
|
if (path.startsWith('vol'))
|
|
52199
52163
|
return path;
|
|
@@ -52201,7 +52165,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52201
52165
|
return `vol0:${path}`;
|
|
52202
52166
|
return `vol0:/${path}`;
|
|
52203
52167
|
}
|
|
52204
|
-
readProtocolV2DeviceFileHeader(path) {
|
|
52168
|
+
readProtocolV2DeviceFileHeader(path, expectedSize) {
|
|
52205
52169
|
var _a, _b, _c, _d;
|
|
52206
52170
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52207
52171
|
const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
|
|
@@ -52213,7 +52177,8 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52213
52177
|
if (!((_b = pathInfoRes.message) === null || _b === void 0 ? void 0 : _b.exist) ||
|
|
52214
52178
|
((_c = pathInfoRes.message) === null || _c === void 0 ? void 0 : _c.directory) ||
|
|
52215
52179
|
fileSize === undefined ||
|
|
52216
|
-
fileSize < PROTOCOL_V2_OKPP_HEADER_SIZE
|
|
52180
|
+
fileSize < PROTOCOL_V2_OKPP_HEADER_SIZE ||
|
|
52181
|
+
(expectedSize !== undefined && fileSize !== expectedSize)) {
|
|
52217
52182
|
return null;
|
|
52218
52183
|
}
|
|
52219
52184
|
const chunkSize = this.getProtocolV2FirmwareChunkSize('read');
|
|
@@ -52253,7 +52218,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52253
52218
|
if (!bundle.payloadHash || !bundle.headerHash)
|
|
52254
52219
|
return false;
|
|
52255
52220
|
try {
|
|
52256
|
-
const header = yield this.readProtocolV2DeviceFileHeader(bundle.devicePath);
|
|
52221
|
+
const header = yield this.readProtocolV2DeviceFileHeader(bundle.devicePath, bundle.source.size);
|
|
52257
52222
|
if (!header)
|
|
52258
52223
|
return false;
|
|
52259
52224
|
if (bundle.version) {
|
|
@@ -52450,7 +52415,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52450
52415
|
});
|
|
52451
52416
|
});
|
|
52452
52417
|
}
|
|
52453
|
-
executeProtocolV2Update({ fwBinaryMap, bootloaderBinary, installItems,
|
|
52418
|
+
executeProtocolV2Update({ fwBinaryMap, bootloaderBinary, installItems, }) {
|
|
52454
52419
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52455
52420
|
const memoryInstallItems = installItems !== null && installItems !== void 0 ? installItems : this.buildProtocolV2InstallItems({
|
|
52456
52421
|
fwBinaryMap: fwBinaryMap !== null && fwBinaryMap !== void 0 ? fwBinaryMap : [],
|
|
@@ -52465,19 +52430,9 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52465
52430
|
kind: item.kind,
|
|
52466
52431
|
});
|
|
52467
52432
|
})));
|
|
52468
|
-
const resourceSources = yield Promise.all((resourceBundles !== null && resourceBundles !== void 0 ? resourceBundles : []).map((bundle) => __awaiter(this, void 0, void 0, function* () {
|
|
52469
|
-
return ({
|
|
52470
|
-
name: bundle.name,
|
|
52471
|
-
source: yield this.openProtocolV2MemorySource(bundle.binary),
|
|
52472
|
-
devicePath: bundle.devicePath,
|
|
52473
|
-
version: bundle.version,
|
|
52474
|
-
payloadHash: bundle.payloadHash,
|
|
52475
|
-
headerHash: bundle.headerHash,
|
|
52476
|
-
});
|
|
52477
|
-
})));
|
|
52478
52433
|
return yield this.executeProtocolV2Phases({
|
|
52479
52434
|
installSources,
|
|
52480
|
-
resourceSources,
|
|
52435
|
+
resourceSources: [],
|
|
52481
52436
|
});
|
|
52482
52437
|
}
|
|
52483
52438
|
finally {
|
|
@@ -65090,6 +65045,111 @@ const switchTransport = ({ env, Transport, plugin, }) => {
|
|
|
65090
65045
|
initConnector();
|
|
65091
65046
|
};
|
|
65092
65047
|
|
|
65048
|
+
let memoryHostSequence = 0;
|
|
65049
|
+
const FIRMWARE_UPDATE_V4_COMPONENT_TARGETS = new Set([
|
|
65050
|
+
'boot',
|
|
65051
|
+
'app_v1',
|
|
65052
|
+
'app_v2',
|
|
65053
|
+
'coprocessor',
|
|
65054
|
+
'se01',
|
|
65055
|
+
'se02',
|
|
65056
|
+
'se03',
|
|
65057
|
+
'se04',
|
|
65058
|
+
]);
|
|
65059
|
+
const isFirmwareUpdateV4ComponentTarget = (target) => FIRMWARE_UPDATE_V4_COMPONENT_TARGETS.has(target);
|
|
65060
|
+
const createReference = (binary, prefix) => {
|
|
65061
|
+
const digest = utils.bytesToHex(sha256.sha256(new Uint8Array(binary)));
|
|
65062
|
+
return {
|
|
65063
|
+
artifactRef: `fwmem:${prefix}:${digest.slice(0, 32)}`,
|
|
65064
|
+
size: binary.byteLength,
|
|
65065
|
+
sha256: digest,
|
|
65066
|
+
};
|
|
65067
|
+
};
|
|
65068
|
+
function prepareFirmwareUpdateV4MemoryHost({ sdk, plan, artifacts, }) {
|
|
65069
|
+
if (plan.executor !== 'v4') {
|
|
65070
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware memory host only supports V4 plans');
|
|
65071
|
+
}
|
|
65072
|
+
memoryHostSequence += 1;
|
|
65073
|
+
const hostId = `${Date.now()}:${memoryHostSequence}`;
|
|
65074
|
+
const binaries = new Map();
|
|
65075
|
+
const inputs = artifacts.map((input, artifactIndex) => {
|
|
65076
|
+
var _a;
|
|
65077
|
+
const artifact = createReference(input.binary, `${hostId}:artifact:${artifactIndex}`);
|
|
65078
|
+
binaries.set(artifact.artifactRef, new Uint8Array(input.binary));
|
|
65079
|
+
const materializedEntries = (_a = input.materializedEntries) === null || _a === void 0 ? void 0 : _a.map((entry, entryIndex) => {
|
|
65080
|
+
const entryArtifact = createReference(entry.binary, `${hostId}:entry:${artifactIndex}:${entryIndex}`);
|
|
65081
|
+
binaries.set(entryArtifact.artifactRef, new Uint8Array(entry.binary));
|
|
65082
|
+
return {
|
|
65083
|
+
entryName: entry.entryName,
|
|
65084
|
+
artifact: entryArtifact,
|
|
65085
|
+
};
|
|
65086
|
+
});
|
|
65087
|
+
return Object.assign({ artifactId: input.artifactId, artifact }, ((materializedEntries === null || materializedEntries === void 0 ? void 0 : materializedEntries.length) ? { materializedEntries } : {}));
|
|
65088
|
+
});
|
|
65089
|
+
const preparedPlan = sdk.prepareFirmwareUpdatePlan({
|
|
65090
|
+
plan,
|
|
65091
|
+
leaseRef: `fwmemlease:${hostId}`,
|
|
65092
|
+
artifacts: inputs,
|
|
65093
|
+
});
|
|
65094
|
+
const readers = new Map();
|
|
65095
|
+
let readerSequence = 0;
|
|
65096
|
+
const artifactReader = {
|
|
65097
|
+
open({ artifactRef }) {
|
|
65098
|
+
const binary = binaries.get(artifactRef);
|
|
65099
|
+
if (!binary) {
|
|
65100
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware memory artifact is unavailable');
|
|
65101
|
+
}
|
|
65102
|
+
readerSequence += 1;
|
|
65103
|
+
const readerId = `fwmemreader:${hostId}:${readerSequence}`;
|
|
65104
|
+
readers.set(readerId, binary);
|
|
65105
|
+
return Promise.resolve({ readerId, size: binary.byteLength });
|
|
65106
|
+
},
|
|
65107
|
+
read({ readerId, offset, length }) {
|
|
65108
|
+
const binary = readers.get(readerId);
|
|
65109
|
+
if (!binary || offset < 0 || length <= 0 || offset + length > binary.byteLength) {
|
|
65110
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware memory artifact read is invalid');
|
|
65111
|
+
}
|
|
65112
|
+
const data = binary.slice(offset, offset + length).buffer;
|
|
65113
|
+
return Promise.resolve({
|
|
65114
|
+
data,
|
|
65115
|
+
bytesRead: data.byteLength,
|
|
65116
|
+
eof: offset + length === binary.byteLength,
|
|
65117
|
+
});
|
|
65118
|
+
},
|
|
65119
|
+
close({ readerId }) {
|
|
65120
|
+
readers.delete(readerId);
|
|
65121
|
+
return Promise.resolve();
|
|
65122
|
+
},
|
|
65123
|
+
};
|
|
65124
|
+
const hostBindingGeneration = sdk.registerFirmwareUpdateHostBinding({
|
|
65125
|
+
artifactReader,
|
|
65126
|
+
preparedPlanDigest: preparedPlan.preparedPlanDigest,
|
|
65127
|
+
});
|
|
65128
|
+
const componentArtifacts = {};
|
|
65129
|
+
const expectedTargetVersions = {};
|
|
65130
|
+
for (const artifact of preparedPlan.artifacts) {
|
|
65131
|
+
if (artifact.role === 'component' && isFirmwareUpdateV4ComponentTarget(artifact.target)) {
|
|
65132
|
+
componentArtifacts[artifact.target] = artifact.artifact;
|
|
65133
|
+
}
|
|
65134
|
+
if (artifact.targetVersion) {
|
|
65135
|
+
expectedTargetVersions[artifact.target] = artifact.targetVersion;
|
|
65136
|
+
}
|
|
65137
|
+
}
|
|
65138
|
+
return {
|
|
65139
|
+
preparedPlan,
|
|
65140
|
+
hostBindingGeneration,
|
|
65141
|
+
targetsToUpdate: [...preparedPlan.targetsToUpdate],
|
|
65142
|
+
expectedDeviceId: preparedPlan.deviceIdentity,
|
|
65143
|
+
expectedTargetVersions,
|
|
65144
|
+
componentArtifacts,
|
|
65145
|
+
release: () => {
|
|
65146
|
+
sdk.unregisterFirmwareUpdateHostBinding(hostBindingGeneration);
|
|
65147
|
+
readers.clear();
|
|
65148
|
+
binaries.clear();
|
|
65149
|
+
},
|
|
65150
|
+
};
|
|
65151
|
+
}
|
|
65152
|
+
|
|
65093
65153
|
const HardwareSdk = ({ init, call, dispose, eventEmitter, uiResponse, cancel, updateSettings, switchTransport, }) => inject({
|
|
65094
65154
|
init,
|
|
65095
65155
|
call,
|
|
@@ -65227,7 +65287,7 @@ exports.parseMessage = parseMessage;
|
|
|
65227
65287
|
exports.parseProtocolV2ResourceManifest = parseProtocolV2ResourceManifest;
|
|
65228
65288
|
exports.patchFeatures = patchFeatures;
|
|
65229
65289
|
exports.preloadSessionCache = preloadSessionCache;
|
|
65230
|
-
exports.
|
|
65290
|
+
exports.prepareFirmwareUpdateV4MemoryHost = prepareFirmwareUpdateV4MemoryHost;
|
|
65231
65291
|
exports.projectDeviceStateFeatures = projectFeatures;
|
|
65232
65292
|
exports.registerFirmwareUpdateHostBinding = registerFirmwareUpdateHostBinding;
|
|
65233
65293
|
exports.safeThrowError = safeThrowError;
|