@onekeyfe/hd-core 1.2.0-alpha.84 → 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.
Files changed (46) hide show
  1. package/__tests__/check-all-firmware-release-protocol-v2.test.ts +24 -18
  2. package/__tests__/firmware-memory-host.test.ts +105 -0
  3. package/__tests__/firmware-update/firmware-update-plan.test.ts +15 -70
  4. package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +53 -1
  5. package/__tests__/protocol-v2-resources.test.ts +0 -38
  6. package/__tests__/protocol-v2.test.ts +207 -318
  7. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  8. package/dist/api/FirmwareUpdateV4.d.ts +1 -2
  9. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  10. package/dist/api/firmware/FirmwareMemoryHost.d.ts +27 -0
  11. package/dist/api/firmware/FirmwareMemoryHost.d.ts.map +1 -0
  12. package/dist/api/firmware/FirmwareUpdatePlan.d.ts +3 -4
  13. package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -1
  14. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -1
  15. package/dist/api/firmware/getBinary.d.ts +0 -1
  16. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  17. package/dist/index.d.ts +24 -64
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +406 -367
  20. package/dist/inject.d.ts.map +1 -1
  21. package/dist/protocols/protocol-v2/resources.d.ts +0 -17
  22. package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
  23. package/dist/types/api/export.d.ts +0 -1
  24. package/dist/types/api/export.d.ts.map +1 -1
  25. package/dist/types/api/firmwareUpdate.d.ts +0 -10
  26. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  27. package/dist/types/api/index.d.ts +0 -2
  28. package/dist/types/api/index.d.ts.map +1 -1
  29. package/dist/types/settings.d.ts +0 -11
  30. package/dist/types/settings.d.ts.map +1 -1
  31. package/package.json +4 -4
  32. package/src/api/CheckAllFirmwareRelease.ts +2 -6
  33. package/src/api/FirmwareUpdateV4.ts +154 -165
  34. package/src/api/firmware/FirmwareMemoryHost.ts +171 -0
  35. package/src/api/firmware/FirmwareUpdatePlan.ts +28 -48
  36. package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +8 -1
  37. package/src/index.ts +6 -1
  38. package/src/inject.ts +0 -2
  39. package/src/protocols/protocol-v2/resources.ts +0 -47
  40. package/src/types/api/export.ts +0 -4
  41. package/src/types/api/firmwareUpdate.ts +0 -15
  42. package/src/types/api/index.ts +0 -2
  43. package/src/types/settings.ts +0 -20
  44. package/dist/types/api/protocolV2ResourceManifest.d.ts +0 -17
  45. package/dist/types/api/protocolV2ResourceManifest.d.ts.map +0 -1
  46. 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, includeResources = true, componentTargets: selectedComponentTargets, } = {}) => {
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, resourceArchiveAvailable, }) => {
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') && !resourceArchiveAvailable) {
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.forEach(assertPreparedEntry);
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',
@@ -1679,7 +1484,6 @@ const createCoreApi = (call) => ({
1679
1484
  getFirmwareUpdateHostBindingGeneration,
1680
1485
  prepareFirmwareUpdatePlan,
1681
1486
  validateFirmwareUpdatePreparedPlan,
1682
- prepareProtocolV2ResourceFiles,
1683
1487
  getLogs: () => call({ method: 'getLogs' }),
1684
1488
  clearSessionCache: params => call(Object.assign(Object.assign({}, params), { method: 'clearSessionCache' })),
1685
1489
  searchDevices: params => call(Object.assign(Object.assign({}, params), { method: 'searchDevices' })),
@@ -40770,6 +40574,172 @@ const findLatestRelease = (releases) => {
40770
40574
  return leastRelease;
40771
40575
  };
40772
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
+
40773
40743
  var _a$1;
40774
40744
  const FIRMWARE_UPDATE_CONFIG_FRESHNESS_MS = 5 * 60 * 1000;
40775
40745
  const Log$k = getLogger(exports.LoggerNames.Core);
@@ -47796,10 +47766,7 @@ class CheckAllFirmwareRelease extends BaseMethod {
47796
47766
  ]));
47797
47767
  let firmwareUpdatePlan;
47798
47768
  try {
47799
- const shouldBuildFirmwareUpdatePlan = componentTargetsToUpdate.length > 0 ||
47800
- validatedForceUpdateTargets.some(target => target !== 'resource') ||
47801
- validatedProtocolV2ForceUpdateTargets.some(target => target !== 'resource') ||
47802
- (forceResourceUpdate && !resourcePreparationRequired);
47769
+ const shouldBuildFirmwareUpdatePlan = targetsToUpdate.length > 0;
47803
47770
  const requestedPlatform = platform !== null && platform !== void 0 ? platform : 'web';
47804
47771
  const requiresDeviceIdentity = requestedPlatform === 'native' || requestedPlatform === 'desktop';
47805
47772
  const canBindPreparedPlan = !requiresDeviceIdentity || !!getDeviceSerialNo(features);
@@ -47811,7 +47778,7 @@ class CheckAllFirmwareRelease extends BaseMethod {
47811
47778
  release,
47812
47779
  targetsToUpdate,
47813
47780
  forceUpdateTargets: validatedForceUpdateTargets,
47814
- resourceArchiveAvailable: resourcePreparationRequired,
47781
+ resourceArchive: resourceSource,
47815
47782
  });
47816
47783
  firmwareUpdatePlan = canBindPreparedPlan ? validatedPlan : undefined;
47817
47784
  if (!canBindPreparedPlan) {
@@ -51271,6 +51238,9 @@ const PROTOCOL_V2_OKPP_HEADER_SIZE = 0x52a0;
51271
51238
  const PROTOCOL_V2_OKPP_PAYLOAD_HASH_OFFSET = 0x200;
51272
51239
  const PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET = 0x240;
51273
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;
51274
51244
  const PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS = new Set(['se03', 'se04']);
51275
51245
  function assertProtocolV2FirmwareTargetsSupported(deviceType, params) {
51276
51246
  var _a;
@@ -51524,7 +51494,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51524
51494
  return ['V2'];
51525
51495
  }
51526
51496
  init() {
51527
- var _a, _b, _c;
51497
+ var _a, _b;
51528
51498
  this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
51529
51499
  this.requireDeviceMode = [];
51530
51500
  this.unlockPolicy = 'unlock-before-run';
@@ -51559,33 +51529,24 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51559
51529
  { name: 'targetsToUpdate', type: 'array', allowEmpty: true },
51560
51530
  { name: 'platform', type: 'string' },
51561
51531
  { name: 'expectedDeviceId', type: 'string' },
51562
- { name: 'resourceFiles', type: 'array', allowEmpty: true },
51563
51532
  ]);
51564
51533
  if (payload.expectedDeviceId !== undefined &&
51565
51534
  (payload.expectedDeviceId.length === 0 || payload.expectedDeviceId.length > 160)) {
51566
51535
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Protocol V2 expected device identity is invalid');
51567
51536
  }
51568
- const hostBinding = payload.preparedPlan || payload.componentArtifacts || payload.resourceBundleArtifacts
51537
+ const hostBinding = payload.preparedPlan || payload.componentArtifacts
51569
51538
  ? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration)
51570
51539
  : undefined;
51571
51540
  if (hostBinding) {
51541
+ const componentArtifacts = ((_a = payload.componentArtifacts) !== null && _a !== void 0 ? _a : {});
51542
+ const preparedPlan = validateFirmwareUpdatePreparedPlan(payload.preparedPlan);
51572
51543
  assertFirmwareUpdatePreparedPlanBinding({
51573
- preparedPlan: payload.preparedPlan,
51544
+ preparedPlan,
51574
51545
  executor: 'v4',
51575
51546
  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
- ],
51547
+ scopeTargets: ['boot', 'app_v1', 'app_v2', 'coprocessor', 'se01', 'se02', 'se03', 'se04'],
51587
51548
  bindings: [
51588
- ...Object.entries((_a = payload.componentArtifacts) !== null && _a !== void 0 ? _a : {}).flatMap(([target, artifact]) => artifact
51549
+ ...Object.entries(componentArtifacts).flatMap(([target, artifact]) => artifact
51589
51550
  ? [
51590
51551
  {
51591
51552
  target: target,
@@ -51593,16 +51554,13 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51593
51554
  },
51594
51555
  ]
51595
51556
  : []),
51596
- ...((_b = payload.resourceBundleArtifacts) !== null && _b !== void 0 ? _b : []).map((entry) => ({
51597
- target: 'resource',
51598
- logicalName: entry.name,
51599
- artifact: entry.artifact,
51600
- })),
51601
51557
  ],
51602
51558
  });
51603
51559
  }
51604
51560
  this.params = {
51605
- preparedPlan: payload.preparedPlan,
51561
+ preparedPlan: payload.preparedPlan
51562
+ ? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
51563
+ : undefined,
51606
51564
  chunkSize: payload.chunkSize,
51607
51565
  forcedUpdateRes: payload.forcedUpdateRes,
51608
51566
  bootloaderBinary: payload.bootloaderBinary,
@@ -51614,15 +51572,13 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51614
51572
  se02Binary: payload.se02Binary,
51615
51573
  se03Binary: payload.se03Binary,
51616
51574
  se04Binary: payload.se04Binary,
51617
- resourceFiles: payload.resourceFiles,
51618
51575
  firmwareType: payload.firmwareType,
51619
51576
  targetsToUpdate: payload.targetsToUpdate,
51620
51577
  expectedTargetVersions: payload.expectedTargetVersions,
51621
51578
  platform: payload.platform,
51622
51579
  expectedDeviceId: payload.expectedDeviceId,
51623
- artifactReader: (_c = hostBinding === null || hostBinding === void 0 ? void 0 : hostBinding.artifactReader) !== null && _c !== void 0 ? _c : payload.artifactReader,
51580
+ artifactReader: (_b = hostBinding === null || hostBinding === void 0 ? void 0 : hostBinding.artifactReader) !== null && _b !== void 0 ? _b : payload.artifactReader,
51624
51581
  componentArtifacts: payload.componentArtifacts,
51625
- resourceBundleArtifacts: payload.resourceBundleArtifacts,
51626
51582
  };
51627
51583
  }
51628
51584
  getProtocolV2FirmwareChunkSize(direction, filePath) {
@@ -51653,7 +51609,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51653
51609
  });
51654
51610
  }
51655
51611
  runProtocolV2() {
51656
- var _a, _b, _c, _d, _e, _f;
51612
+ var _a, _b, _c, _d;
51657
51613
  return __awaiter(this, void 0, void 0, function* () {
51658
51614
  yield this.captureProtocolV2PhysicalIdentity();
51659
51615
  const deviceFeatures = yield this.getProtocolV2DeviceFeatures();
@@ -51665,20 +51621,15 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51665
51621
  const deviceFirmwareType = getFirmwareType(deviceFeatures);
51666
51622
  const firmwareType = (_a = this.params.firmwareType) !== null && _a !== void 0 ? _a : deviceFirmwareType;
51667
51623
  this.validateExpectedTargetVersions();
51668
- if ((this.params.componentArtifacts && Object.keys(this.params.componentArtifacts).length > 0) ||
51669
- ((_b = this.params.resourceBundleArtifacts) === null || _b === void 0 ? void 0 : _b.length)) {
51624
+ if (this.params.preparedPlan) {
51670
51625
  return this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType);
51671
51626
  }
51672
- const hasExplicitResourceFiles = !!((_c = this.params.resourceFiles) === null || _c === void 0 ? void 0 : _c.length);
51673
- const wantsResources = !!((_d = this.params.targetsToUpdate) === null || _d === void 0 ? void 0 : _d.includes('resource'));
51674
- const needsPreparedResources = !hasExplicitResourceFiles && wantsResources;
51627
+ const wantsResources = !!((_b = this.params.targetsToUpdate) === null || _b === void 0 ? void 0 : _b.includes('resource'));
51675
51628
  let fwBinaryMap = [];
51676
51629
  let bootloaderBinary = null;
51677
51630
  let installItems;
51678
- let resourceBundles;
51679
51631
  try {
51680
51632
  this.postTipMessage(exports.FirmwareUpdateTipMessage.StartDownloadFirmware);
51681
- resourceBundles = this.prepareExplicitProtocolV2ResourceFiles();
51682
51633
  fwBinaryMap = this.collectExplicitTargetBinaries();
51683
51634
  bootloaderBinary = this.prepareBootloaderBinary();
51684
51635
  const explicitInstallItems = this.buildProtocolV2InstallItems({
@@ -51686,10 +51637,10 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51686
51637
  fwBinaryMap,
51687
51638
  });
51688
51639
  const missingFirmwareTargets = this.getMissingProtocolV2FirmwareTargets(explicitInstallItems);
51689
- const needsRemoteFirmware = ((_e = this.params.targetsToUpdate) === null || _e === void 0 ? void 0 : _e.length)
51640
+ const needsRemoteFirmware = ((_c = this.params.targetsToUpdate) === null || _c === void 0 ? void 0 : _c.length)
51690
51641
  ? missingFirmwareTargets.length > 0
51691
- : !this.hasExplicitProtocolV2Payload(explicitInstallItems);
51692
- if (needsPreparedResources) {
51642
+ : explicitInstallItems.length === 0;
51643
+ if (wantsResources) {
51693
51644
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource manifest must be prepared by the external firmware host', {
51694
51645
  firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
51695
51646
  });
@@ -51716,7 +51667,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51716
51667
  if (typeof err === 'object' &&
51717
51668
  err !== null &&
51718
51669
  'params' in err &&
51719
- ((_f = err.params) === null || _f === void 0 ? void 0 : _f.firmwareUpdateCode) === 'FirmwareArtifactsNotPrepared') {
51670
+ ((_d = err.params) === null || _d === void 0 ? void 0 : _d.firmwareUpdateCode) === 'FirmwareArtifactsNotPrepared') {
51720
51671
  throw err;
51721
51672
  }
51722
51673
  if (err instanceof hdShared.HardwareError && err.errorCode === hdShared.HardwareErrorCode.NetworkError) {
@@ -51724,14 +51675,11 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51724
51675
  }
51725
51676
  throw normalizeFirmwarePreparationError(err);
51726
51677
  }
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)) {
51678
+ if (!bootloaderBinary && fwBinaryMap.length === 0 && !(installItems === null || installItems === void 0 ? void 0 : installItems.length)) {
51731
51679
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, 'No firmware to update');
51732
51680
  }
51733
- return this.executeProtocolV2Update(Object.assign(Object.assign({ fwBinaryMap,
51734
- bootloaderBinary }, (installItems ? { installItems } : undefined)), ((resourceBundles === null || resourceBundles === void 0 ? void 0 : resourceBundles.length) ? { resourceBundles } : undefined)));
51681
+ return this.executeProtocolV2Update(Object.assign({ fwBinaryMap,
51682
+ bootloaderBinary }, (installItems ? { installItems } : undefined)));
51735
51683
  });
51736
51684
  }
51737
51685
  openProtocolV2PreparedSource(artifact) {
@@ -51798,39 +51746,87 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51798
51746
  return installSources;
51799
51747
  });
51800
51748
  }
51801
- prepareProtocolV2ResourceSources(firmwareType, features) {
51802
- var _a, _b, _c;
51749
+ prepareProtocolV2ResourceSources() {
51750
+ var _a, _b;
51803
51751
  return __awaiter(this, void 0, void 0, function* () {
51804
- const preparedArtifacts = (_a = this.params.resourceBundleArtifacts) !== null && _a !== void 0 ? _a : [];
51805
- 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;
51806
51753
  if (!resourceRequested) {
51807
51754
  return [];
51808
51755
  }
51809
- const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
51810
- const descriptors = (_c = release === null || release === void 0 ? void 0 : release.resourceBundles) !== null && _c !== void 0 ? _c : [];
51811
- const artifactByName = new Map(preparedArtifacts.map(item => [item.name, item.artifact]));
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);
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' });
51774
+ }
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' });
51831
51789
  }
51832
- if (artifactByName.size > 0) {
51833
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 release does not contain resource bundle ${artifactByName.keys().next().value}`);
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
+ : {})));
51834
51830
  }
51835
51831
  return sources;
51836
51832
  });
@@ -51840,19 +51836,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51840
51836
  try {
51841
51837
  this.postTipMessage(exports.FirmwareUpdateTipMessage.StartDownloadFirmware);
51842
51838
  const installSources = yield this.prepareProtocolV2InstallSources(firmwareType, features);
51843
- const explicitResourceBundles = this.prepareExplicitProtocolV2ResourceFiles();
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);
51839
+ const resourceSources = yield this.prepareProtocolV2ResourceSources();
51856
51840
  if (installSources.length === 0 && resourceSources.length === 0) {
51857
51841
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, 'No firmware to update');
51858
51842
  }
@@ -51936,15 +51920,15 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51936
51920
  }
51937
51921
  }
51938
51922
  getProtocolV2RequestedTargets() {
51939
- var _a, _b, _c, _d;
51923
+ var _a, _b, _c;
51940
51924
  if ((_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.length) {
51941
51925
  return [...new Set(this.params.targetsToUpdate)];
51942
51926
  }
51943
- const targets = new Set();
51944
- Object.keys((_b = this.params.componentArtifacts) !== null && _b !== void 0 ? _b : {}).forEach(target => targets.add(target));
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');
51927
+ if ((_b = this.params.preparedPlan) === null || _b === void 0 ? void 0 : _b.targetsToUpdate.length) {
51928
+ return [...new Set(this.params.preparedPlan.targetsToUpdate)];
51947
51929
  }
51930
+ const targets = new Set();
51931
+ Object.keys((_c = this.params.componentArtifacts) !== null && _c !== void 0 ? _c : {}).forEach(target => targets.add(target));
51948
51932
  if (this.params.bootloaderBinary)
51949
51933
  targets.add('boot');
51950
51934
  if (this.params.applicationP1Binary)
@@ -52031,10 +52015,6 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52031
52015
  var _a;
52032
52016
  return (_a = this.params.bootloaderBinary) !== null && _a !== void 0 ? _a : null;
52033
52017
  }
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
52018
  getMissingProtocolV2FirmwareTargets(installItems) {
52039
52019
  var _a;
52040
52020
  const preparedTargets = new Set(installItems.flatMap(item => {
@@ -52161,39 +52141,6 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52161
52141
  };
52162
52142
  });
52163
52143
  }
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
52144
  getProtocolV2ResourceFilePath(path) {
52198
52145
  if (path.startsWith('vol'))
52199
52146
  return path;
@@ -52450,7 +52397,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52450
52397
  });
52451
52398
  });
52452
52399
  }
52453
- executeProtocolV2Update({ fwBinaryMap, bootloaderBinary, installItems, resourceBundles, }) {
52400
+ executeProtocolV2Update({ fwBinaryMap, bootloaderBinary, installItems, }) {
52454
52401
  return __awaiter(this, void 0, void 0, function* () {
52455
52402
  const memoryInstallItems = installItems !== null && installItems !== void 0 ? installItems : this.buildProtocolV2InstallItems({
52456
52403
  fwBinaryMap: fwBinaryMap !== null && fwBinaryMap !== void 0 ? fwBinaryMap : [],
@@ -52465,19 +52412,9 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52465
52412
  kind: item.kind,
52466
52413
  });
52467
52414
  })));
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
52415
  return yield this.executeProtocolV2Phases({
52479
52416
  installSources,
52480
- resourceSources,
52417
+ resourceSources: [],
52481
52418
  });
52482
52419
  }
52483
52420
  finally {
@@ -65090,6 +65027,108 @@ const switchTransport = ({ env, Transport, plugin, }) => {
65090
65027
  initConnector();
65091
65028
  };
65092
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
+
65093
65132
  const HardwareSdk = ({ init, call, dispose, eventEmitter, uiResponse, cancel, updateSettings, switchTransport, }) => inject({
65094
65133
  init,
65095
65134
  call,
@@ -65227,7 +65266,7 @@ exports.parseMessage = parseMessage;
65227
65266
  exports.parseProtocolV2ResourceManifest = parseProtocolV2ResourceManifest;
65228
65267
  exports.patchFeatures = patchFeatures;
65229
65268
  exports.preloadSessionCache = preloadSessionCache;
65230
- exports.prepareProtocolV2ResourceFiles = prepareProtocolV2ResourceFiles;
65269
+ exports.prepareFirmwareUpdateV4MemoryHost = prepareFirmwareUpdateV4MemoryHost;
65231
65270
  exports.projectDeviceStateFeatures = projectFeatures;
65232
65271
  exports.registerFirmwareUpdateHostBinding = registerFirmwareUpdateHostBinding;
65233
65272
  exports.safeThrowError = safeThrowError;