@onekeyfe/hd-core 1.2.0-alpha.92 → 1.2.0-alpha.94
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__/protocol-v2.test.ts +127 -115
- package/dist/api/FirmwareUpdateV4.d.ts +1 -2
- package/dist/api/FirmwareUpdateV4.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/index.d.ts +1 -26
- package/dist/index.js +68 -150
- package/dist/types/api/firmwareUpdate.d.ts +0 -10
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/dist/types/settings.d.ts +0 -11
- package/dist/types/settings.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/FirmwareUpdateV4.ts +78 -215
- package/src/types/api/firmwareUpdate.ts +0 -12
- package/src/types/settings.ts +0 -14
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
import { sha256 } from '@noble/hashes/sha256';
|
|
11
11
|
|
|
12
12
|
import { FirmwareUpdateTipMessage, UI_REQUEST } from '../events/ui-request';
|
|
13
|
-
import { validateProtocolV2FilesystemPath } from './helpers/filesystemValidation';
|
|
14
13
|
import { validateParams } from './helpers/paramsValidator';
|
|
15
14
|
import {
|
|
16
15
|
LoggerNames,
|
|
@@ -214,10 +213,6 @@ type ProtocolV2ResourceBundleSource = {
|
|
|
214
213
|
headerHash?: string;
|
|
215
214
|
};
|
|
216
215
|
|
|
217
|
-
type ProtocolV2ResourceBundleBinary = Omit<ProtocolV2ResourceBundleSource, 'source'> & {
|
|
218
|
-
binary: ArrayBuffer;
|
|
219
|
-
};
|
|
220
|
-
|
|
221
216
|
type ProtocolV2LocalResourceArchive = {
|
|
222
217
|
binary: ArrayBuffer;
|
|
223
218
|
materializedEntries: FirmwareMemoryArtifactEntry[];
|
|
@@ -610,8 +605,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
610
605
|
{ name: 'se03Binary', type: 'buffer' },
|
|
611
606
|
{ name: 'se04Binary', type: 'buffer' },
|
|
612
607
|
{ name: 'resourceArchiveBinary', type: 'buffer' },
|
|
613
|
-
{ name: 'resourceFiles', type: 'array', allowEmpty: true },
|
|
614
|
-
{ name: 'resourceBundleArtifacts', type: 'array', allowEmpty: true },
|
|
615
608
|
{ name: 'firmwareType', type: 'string' },
|
|
616
609
|
{ name: 'targetsToUpdate', type: 'array', allowEmpty: true },
|
|
617
610
|
{ name: 'platform', type: 'string' },
|
|
@@ -640,9 +633,8 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
640
633
|
payload.se03Binary,
|
|
641
634
|
payload.se04Binary,
|
|
642
635
|
payload.resourceArchiveBinary,
|
|
643
|
-
payload.resourceFiles?.length,
|
|
644
636
|
].some(Boolean);
|
|
645
|
-
if (preparedPlan &&
|
|
637
|
+
if (preparedPlan && hasLocalArtifacts) {
|
|
646
638
|
throw ERRORS.TypedError(
|
|
647
639
|
HardwareErrorCode.CallMethodInvalidParameter,
|
|
648
640
|
'Prepared firmware plans cannot be combined with legacy or local firmware inputs'
|
|
@@ -706,9 +698,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
706
698
|
target === 'boot_resources' ? 'resource' : target
|
|
707
699
|
);
|
|
708
700
|
if (
|
|
709
|
-
|
|
710
|
-
payload.resourceFiles?.length ||
|
|
711
|
-
payload.resourceBundleArtifacts?.length) &&
|
|
701
|
+
payload.resourceArchiveBinary &&
|
|
712
702
|
localTargetsToUpdate &&
|
|
713
703
|
!localTargetsToUpdate.includes('resource')
|
|
714
704
|
) {
|
|
@@ -716,12 +706,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
716
706
|
}
|
|
717
707
|
// 本地 ZIP 本身就是明确的资源升级请求,不要求调用方重复声明 target。
|
|
718
708
|
const resolvedLocalTargetsToUpdate =
|
|
719
|
-
localTargetsToUpdate ??
|
|
720
|
-
(payload.resourceArchiveBinary ||
|
|
721
|
-
payload.resourceFiles?.length ||
|
|
722
|
-
payload.resourceBundleArtifacts?.length
|
|
723
|
-
? ['resource']
|
|
724
|
-
: undefined);
|
|
709
|
+
localTargetsToUpdate ?? (payload.resourceArchiveBinary ? ['resource'] : undefined);
|
|
725
710
|
|
|
726
711
|
this.params = {
|
|
727
712
|
preparedPlan,
|
|
@@ -737,7 +722,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
737
722
|
se03Binary: payload.se03Binary,
|
|
738
723
|
se04Binary: payload.se04Binary,
|
|
739
724
|
resourceArchiveBinary: payload.resourceArchiveBinary,
|
|
740
|
-
resourceFiles: payload.resourceFiles,
|
|
741
725
|
firmwareType: preparedPlan?.firmwareType ?? payload.firmwareType,
|
|
742
726
|
targetsToUpdate: preparedPlan
|
|
743
727
|
? ([...preparedPlan.targetsToUpdate] as FirmwareUpdateV4Target[])
|
|
@@ -749,7 +733,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
749
733
|
expectedDeviceId: payload.expectedDeviceId,
|
|
750
734
|
artifactReader: hostBinding?.artifactReader ?? payload.artifactReader,
|
|
751
735
|
componentArtifacts: preparedPlan ? undefined : payload.componentArtifacts,
|
|
752
|
-
resourceBundleArtifacts: preparedPlan ? undefined : payload.resourceBundleArtifacts,
|
|
753
736
|
};
|
|
754
737
|
}
|
|
755
738
|
|
|
@@ -795,34 +778,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
795
778
|
const firmwareType = this.params.firmwareType ?? deviceFirmwareType;
|
|
796
779
|
this.validateExpectedTargetVersions();
|
|
797
780
|
|
|
798
|
-
if (!this.params.preparedPlan && this.params.resourceFiles?.length) {
|
|
799
|
-
if (this.params.resourceArchiveBinary || this.params.resourceBundleArtifacts?.length) {
|
|
800
|
-
throw ERRORS.TypedError(
|
|
801
|
-
HardwareErrorCode.CallMethodInvalidParameter,
|
|
802
|
-
'Legacy resourceFiles cannot be combined with another Protocol V2 resource input'
|
|
803
|
-
);
|
|
804
|
-
}
|
|
805
|
-
this.postTipMessage(FirmwareUpdateTipMessage.StartDownloadFirmware);
|
|
806
|
-
const installItems = this.buildProtocolV2InstallItems({
|
|
807
|
-
bootloaderBinary: this.prepareBootloaderBinary(),
|
|
808
|
-
fwBinaryMap: this.collectExplicitTargetBinaries(),
|
|
809
|
-
});
|
|
810
|
-
const missingFirmwareTarget = this.getMissingProtocolV2FirmwareTargets(installItems)[0];
|
|
811
|
-
if (missingFirmwareTarget) {
|
|
812
|
-
throw ERRORS.TypedError(
|
|
813
|
-
HardwareErrorCode.RuntimeError,
|
|
814
|
-
`Protocol V2 legacy local update has no binary for requested target ${missingFirmwareTarget}`,
|
|
815
|
-
{
|
|
816
|
-
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
817
|
-
artifactName: missingFirmwareTarget,
|
|
818
|
-
}
|
|
819
|
-
);
|
|
820
|
-
}
|
|
821
|
-
const resourceBundles = this.prepareLegacyProtocolV2ResourceFiles();
|
|
822
|
-
this.postTipMessage(FirmwareUpdateTipMessage.FinishDownloadFirmware);
|
|
823
|
-
return this.executeProtocolV2Update({ installItems, resourceBundles });
|
|
824
|
-
}
|
|
825
|
-
|
|
826
781
|
if (
|
|
827
782
|
!this.params.preparedPlan &&
|
|
828
783
|
this.params.resourceArchiveBinary &&
|
|
@@ -842,11 +797,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
842
797
|
const hasPreparedComponentArtifacts = Object.values(this.params.componentArtifacts ?? {}).some(
|
|
843
798
|
Boolean
|
|
844
799
|
);
|
|
845
|
-
if (
|
|
846
|
-
this.params.preparedPlan ||
|
|
847
|
-
hasPreparedComponentArtifacts ||
|
|
848
|
-
this.params.resourceBundleArtifacts?.length
|
|
849
|
-
) {
|
|
800
|
+
if (this.params.preparedPlan || hasPreparedComponentArtifacts) {
|
|
850
801
|
return this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType);
|
|
851
802
|
}
|
|
852
803
|
const wantsResources = !!this.params.targetsToUpdate?.includes('resource');
|
|
@@ -1178,6 +1129,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1178
1129
|
assertFirmwareUpdatePreparedPlanDeviceIdentity({
|
|
1179
1130
|
preparedPlan,
|
|
1180
1131
|
deviceIdentity: this.protocolV2ExpectedSerialNumber,
|
|
1132
|
+
deviceModel: this.getProtocolV2PreparedPlanDeviceModel(features),
|
|
1181
1133
|
});
|
|
1182
1134
|
const hostBinding = resolveFirmwareUpdateHostBinding(
|
|
1183
1135
|
memoryHost.hostBindingGeneration,
|
|
@@ -1332,10 +1284,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1332
1284
|
return { binary, materializedEntries };
|
|
1333
1285
|
}
|
|
1334
1286
|
|
|
1335
|
-
private async prepareProtocolV2ResourceSources(
|
|
1336
|
-
firmwareType: EFirmwareType,
|
|
1337
|
-
features: Features
|
|
1338
|
-
): Promise<ProtocolV2ResourceBundleSource[]> {
|
|
1287
|
+
private async prepareProtocolV2ResourceSources(): Promise<ProtocolV2ResourceBundleSource[]> {
|
|
1339
1288
|
const resourceRequested = this.params.targetsToUpdate?.includes('resource') ?? false;
|
|
1340
1289
|
if (!resourceRequested) {
|
|
1341
1290
|
return [];
|
|
@@ -1344,9 +1293,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1344
1293
|
if (archiveSources) {
|
|
1345
1294
|
return archiveSources;
|
|
1346
1295
|
}
|
|
1347
|
-
if (!this.params.preparedPlan && this.params.resourceBundleArtifacts?.length) {
|
|
1348
|
-
return this.prepareLegacyProtocolV2ResourceBundleSources(firmwareType, features);
|
|
1349
|
-
}
|
|
1350
1296
|
throw ERRORS.TypedError(
|
|
1351
1297
|
HardwareErrorCode.RuntimeError,
|
|
1352
1298
|
'Protocol V2 resource archive is not prepared',
|
|
@@ -1354,117 +1300,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1354
1300
|
);
|
|
1355
1301
|
}
|
|
1356
1302
|
|
|
1357
|
-
private async prepareLegacyProtocolV2ResourceBundleSources(
|
|
1358
|
-
firmwareType: EFirmwareType,
|
|
1359
|
-
features: Features
|
|
1360
|
-
): Promise<ProtocolV2ResourceBundleSource[]> {
|
|
1361
|
-
const artifacts = this.params.resourceBundleArtifacts ?? [];
|
|
1362
|
-
if (artifacts.length > PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT) {
|
|
1363
|
-
throw ERRORS.TypedError(
|
|
1364
|
-
HardwareErrorCode.RuntimeError,
|
|
1365
|
-
'Protocol V2 legacy resource artifact count exceeds the allowed limit',
|
|
1366
|
-
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
1367
|
-
);
|
|
1368
|
-
}
|
|
1369
|
-
const names = new Set<string>();
|
|
1370
|
-
const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
|
|
1371
|
-
const descriptors = new Map(
|
|
1372
|
-
(release?.resourceBundles ?? []).map(descriptor => [descriptor.name, descriptor] as const)
|
|
1373
|
-
);
|
|
1374
|
-
const sources: ProtocolV2ResourceBundleSource[] = [];
|
|
1375
|
-
let totalSize = 0;
|
|
1376
|
-
for (const [index, item] of artifacts.entries()) {
|
|
1377
|
-
if (!item.name || names.has(item.name)) {
|
|
1378
|
-
throw ERRORS.TypedError(
|
|
1379
|
-
HardwareErrorCode.RuntimeError,
|
|
1380
|
-
`Protocol V2 legacy resource artifact name is invalid: ${item.name || index}`,
|
|
1381
|
-
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
1382
|
-
);
|
|
1383
|
-
}
|
|
1384
|
-
names.add(item.name);
|
|
1385
|
-
const descriptor = descriptors.get(item.name);
|
|
1386
|
-
if (!descriptor) {
|
|
1387
|
-
throw ERRORS.TypedError(
|
|
1388
|
-
HardwareErrorCode.RuntimeError,
|
|
1389
|
-
`Protocol V2 release does not contain legacy resource bundle ${item.name}`,
|
|
1390
|
-
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared', artifactName: item.name }
|
|
1391
|
-
);
|
|
1392
|
-
}
|
|
1393
|
-
const source = await this.openProtocolV2PreparedSource(item.artifact);
|
|
1394
|
-
totalSize += source.size;
|
|
1395
|
-
if (source.size <= 0 || totalSize > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
|
|
1396
|
-
throw ERRORS.TypedError(
|
|
1397
|
-
HardwareErrorCode.RuntimeError,
|
|
1398
|
-
'Protocol V2 legacy resource artifacts exceed the allowed size limit',
|
|
1399
|
-
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
1400
|
-
);
|
|
1401
|
-
}
|
|
1402
|
-
const devicePath = validateProtocolV2FilesystemPath(
|
|
1403
|
-
descriptor.devicePath,
|
|
1404
|
-
`resourceBundleArtifacts[${index}].devicePath`
|
|
1405
|
-
);
|
|
1406
|
-
sources.push({
|
|
1407
|
-
name: descriptor.name,
|
|
1408
|
-
source,
|
|
1409
|
-
devicePath,
|
|
1410
|
-
version: descriptor.version,
|
|
1411
|
-
payloadHash: descriptor.payloadHash,
|
|
1412
|
-
headerHash: descriptor.headerHash,
|
|
1413
|
-
});
|
|
1414
|
-
}
|
|
1415
|
-
return sources;
|
|
1416
|
-
}
|
|
1417
|
-
|
|
1418
|
-
private prepareLegacyProtocolV2ResourceFiles(): ProtocolV2ResourceBundleBinary[] {
|
|
1419
|
-
const files = this.params.resourceFiles ?? [];
|
|
1420
|
-
if (files.length === 0 || files.length > PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT) {
|
|
1421
|
-
throw ERRORS.TypedError(
|
|
1422
|
-
HardwareErrorCode.CallMethodInvalidParameter,
|
|
1423
|
-
'Protocol V2 legacy resource file count is invalid'
|
|
1424
|
-
);
|
|
1425
|
-
}
|
|
1426
|
-
const paths = new Set<string>();
|
|
1427
|
-
let totalSize = 0;
|
|
1428
|
-
return files.map((file, index) => {
|
|
1429
|
-
const devicePath = validateProtocolV2FilesystemPath(
|
|
1430
|
-
file.devicePath,
|
|
1431
|
-
`resourceFiles[${index}].devicePath`
|
|
1432
|
-
);
|
|
1433
|
-
if (paths.has(devicePath)) {
|
|
1434
|
-
throw ERRORS.TypedError(
|
|
1435
|
-
HardwareErrorCode.CallMethodInvalidParameter,
|
|
1436
|
-
`Protocol V2 resourceFiles contain duplicate devicePath: ${devicePath}`
|
|
1437
|
-
);
|
|
1438
|
-
}
|
|
1439
|
-
paths.add(devicePath);
|
|
1440
|
-
totalSize += file.binary.byteLength;
|
|
1441
|
-
if (
|
|
1442
|
-
file.binary.byteLength <= 0 ||
|
|
1443
|
-
totalSize > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES ||
|
|
1444
|
-
(file.size !== undefined && file.size !== file.binary.byteLength)
|
|
1445
|
-
) {
|
|
1446
|
-
throw ERRORS.TypedError(
|
|
1447
|
-
HardwareErrorCode.CallMethodInvalidParameter,
|
|
1448
|
-
`Protocol V2 resourceFiles[${index}] size is invalid`
|
|
1449
|
-
);
|
|
1450
|
-
}
|
|
1451
|
-
if (
|
|
1452
|
-
file.fileHash &&
|
|
1453
|
-
bytesToHex(sha256(new Uint8Array(file.binary))) !== file.fileHash.toLowerCase()
|
|
1454
|
-
) {
|
|
1455
|
-
throw ERRORS.TypedError(
|
|
1456
|
-
HardwareErrorCode.CallMethodInvalidParameter,
|
|
1457
|
-
`Protocol V2 resourceFiles[${index}] SHA-256 mismatch`
|
|
1458
|
-
);
|
|
1459
|
-
}
|
|
1460
|
-
return {
|
|
1461
|
-
name: devicePath.split('/').pop() ?? devicePath,
|
|
1462
|
-
binary: file.binary,
|
|
1463
|
-
devicePath,
|
|
1464
|
-
};
|
|
1465
|
-
});
|
|
1466
|
-
}
|
|
1467
|
-
|
|
1468
1303
|
private async prepareProtocolV2ResourceArchiveSources(): Promise<
|
|
1469
1304
|
ProtocolV2ResourceBundleSource[] | undefined
|
|
1470
1305
|
> {
|
|
@@ -1486,13 +1321,59 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1486
1321
|
);
|
|
1487
1322
|
}
|
|
1488
1323
|
|
|
1489
|
-
const
|
|
1490
|
-
const
|
|
1324
|
+
const archiveArtifact = archiveArtifacts[0];
|
|
1325
|
+
const archiveSource = await this.openProtocolV2PreparedSource(archiveArtifact.artifact);
|
|
1326
|
+
if (archiveSource.size > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
|
|
1327
|
+
throw ERRORS.TypedError(
|
|
1328
|
+
HardwareErrorCode.RuntimeError,
|
|
1329
|
+
'Protocol V2 prepared resource archive exceeds the total size limit',
|
|
1330
|
+
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
1331
|
+
);
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
let archiveBinary: ArrayBuffer;
|
|
1335
|
+
try {
|
|
1336
|
+
archiveBinary = await readFirmwareByteSourceFully(archiveSource);
|
|
1337
|
+
} finally {
|
|
1338
|
+
await archiveSource.close();
|
|
1339
|
+
}
|
|
1340
|
+
const archiveDigest = bytesToHex(sha256(new Uint8Array(archiveBinary)));
|
|
1341
|
+
if (archiveDigest !== archiveArtifact.artifact.sha256.toLowerCase()) {
|
|
1342
|
+
throw ERRORS.TypedError(
|
|
1343
|
+
HardwareErrorCode.RuntimeError,
|
|
1344
|
+
'Protocol V2 prepared resource archive does not match its approved receipt',
|
|
1345
|
+
{ firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' }
|
|
1346
|
+
);
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
// materializedEntries 由宿主生成,只有与获批 ZIP 的规范字节完全一致后才能使用。
|
|
1350
|
+
const verifiedArchive = await this.prepareProtocolV2LocalResourceArchive(archiveBinary);
|
|
1351
|
+
const entries = archiveArtifact.materializedEntries ?? [];
|
|
1352
|
+
const entriesByName = new Map(entries.map(entry => [entry.entryName, entry] as const));
|
|
1491
1353
|
if (
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1354
|
+
entries.length !== verifiedArchive.materializedEntries.length ||
|
|
1355
|
+
verifiedArchive.materializedEntries.some(entry => {
|
|
1356
|
+
const preparedEntry = entriesByName.get(entry.entryName);
|
|
1357
|
+
const digest = bytesToHex(sha256(new Uint8Array(entry.binary)));
|
|
1358
|
+
return (
|
|
1359
|
+
!preparedEntry ||
|
|
1360
|
+
preparedEntry.artifact.size !== entry.binary.byteLength ||
|
|
1361
|
+
preparedEntry.artifact.sha256.toLowerCase() !== digest
|
|
1362
|
+
);
|
|
1363
|
+
})
|
|
1495
1364
|
) {
|
|
1365
|
+
throw ERRORS.TypedError(
|
|
1366
|
+
HardwareErrorCode.RuntimeError,
|
|
1367
|
+
'Protocol V2 prepared resource entries do not match the approved archive',
|
|
1368
|
+
{ firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' }
|
|
1369
|
+
);
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
const verifiedEntriesByName = new Map(
|
|
1373
|
+
verifiedArchive.materializedEntries.map(entry => [entry.entryName, entry.binary] as const)
|
|
1374
|
+
);
|
|
1375
|
+
const manifestBinary = verifiedEntriesByName.get('manifest.json');
|
|
1376
|
+
if (!manifestBinary) {
|
|
1496
1377
|
throw ERRORS.TypedError(
|
|
1497
1378
|
HardwareErrorCode.RuntimeError,
|
|
1498
1379
|
'Protocol V2 prepared resource archive has no valid manifest.json',
|
|
@@ -1500,12 +1381,9 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1500
1381
|
);
|
|
1501
1382
|
}
|
|
1502
1383
|
|
|
1503
|
-
const manifestSource = await this.openProtocolV2PreparedSource(manifestEntry.artifact);
|
|
1504
1384
|
let manifestValue: unknown;
|
|
1505
1385
|
try {
|
|
1506
|
-
manifestValue = JSON.parse(
|
|
1507
|
-
new TextDecoder().decode(await readFirmwareByteSourceFully(manifestSource))
|
|
1508
|
-
);
|
|
1386
|
+
manifestValue = JSON.parse(new TextDecoder().decode(manifestBinary));
|
|
1509
1387
|
} catch (error) {
|
|
1510
1388
|
throw ERRORS.TypedError(
|
|
1511
1389
|
HardwareErrorCode.RuntimeError,
|
|
@@ -1526,35 +1404,18 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1526
1404
|
);
|
|
1527
1405
|
}
|
|
1528
1406
|
|
|
1529
|
-
const entriesByName = new Map(entries.map(entry => [entry.entryName, entry] as const));
|
|
1530
|
-
const expectedEntryNames = new Set([
|
|
1531
|
-
'manifest.json',
|
|
1532
|
-
...selectedFiles.map(file => file.archive_path),
|
|
1533
|
-
]);
|
|
1534
|
-
if (entries.some(entry => !expectedEntryNames.has(entry.entryName))) {
|
|
1535
|
-
throw ERRORS.TypedError(
|
|
1536
|
-
HardwareErrorCode.RuntimeError,
|
|
1537
|
-
'Protocol V2 prepared resource archive contains an unexpected entry',
|
|
1538
|
-
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
1539
|
-
);
|
|
1540
|
-
}
|
|
1541
|
-
|
|
1542
1407
|
let totalSize = 0;
|
|
1543
1408
|
const sources: ProtocolV2ResourceBundleSource[] = [];
|
|
1544
1409
|
for (const [index, file] of selectedFiles.entries()) {
|
|
1545
|
-
const
|
|
1546
|
-
if (
|
|
1547
|
-
!entry ||
|
|
1548
|
-
entry.artifact.size !== file.size ||
|
|
1549
|
-
entry.artifact.sha256.toLowerCase() !== file.sha256.toLowerCase()
|
|
1550
|
-
) {
|
|
1410
|
+
const binary = verifiedEntriesByName.get(file.archive_path);
|
|
1411
|
+
if (!binary || binary.byteLength !== file.size) {
|
|
1551
1412
|
throw ERRORS.TypedError(
|
|
1552
1413
|
HardwareErrorCode.RuntimeError,
|
|
1553
1414
|
`Protocol V2 prepared resource file does not match manifest: ${file.archive_path}`,
|
|
1554
1415
|
{ firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' }
|
|
1555
1416
|
);
|
|
1556
1417
|
}
|
|
1557
|
-
totalSize +=
|
|
1418
|
+
totalSize += binary.byteLength;
|
|
1558
1419
|
if (totalSize > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
|
|
1559
1420
|
throw ERRORS.TypedError(
|
|
1560
1421
|
HardwareErrorCode.RuntimeError,
|
|
@@ -1562,7 +1423,8 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1562
1423
|
{ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
|
|
1563
1424
|
);
|
|
1564
1425
|
}
|
|
1565
|
-
|
|
1426
|
+
// 使用从获批 ZIP 中提取的规范字节,避免宿主在校验后替换 entry reader 内容。
|
|
1427
|
+
const source = await this.openProtocolV2MemorySource(binary);
|
|
1566
1428
|
const header =
|
|
1567
1429
|
source.size >= PROTOCOL_V2_OKPP_HEADER_SIZE
|
|
1568
1430
|
? parseProtocolV2OkppHeader(
|
|
@@ -1589,7 +1451,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1589
1451
|
try {
|
|
1590
1452
|
this.postTipMessage(FirmwareUpdateTipMessage.StartDownloadFirmware);
|
|
1591
1453
|
const installSources = await this.prepareProtocolV2InstallSources(firmwareType, features);
|
|
1592
|
-
const resourceSources = await this.prepareProtocolV2ResourceSources(
|
|
1454
|
+
const resourceSources = await this.prepareProtocolV2ResourceSources();
|
|
1593
1455
|
if (installSources.length === 0 && resourceSources.length === 0) {
|
|
1594
1456
|
throw ERRORS.TypedError(
|
|
1595
1457
|
HardwareErrorCode.FirmwareUpdateDownloadFailed,
|
|
@@ -1739,6 +1601,18 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1739
1601
|
return serialNumber || undefined;
|
|
1740
1602
|
}
|
|
1741
1603
|
|
|
1604
|
+
private getProtocolV2PreparedPlanDeviceModel(features?: Features) {
|
|
1605
|
+
const currentDeviceType = this.device.getCurrentDeviceType();
|
|
1606
|
+
const featureDeviceType = features ? getDeviceType(features) : undefined;
|
|
1607
|
+
const deviceType =
|
|
1608
|
+
currentDeviceType === EDeviceType.Pro2 || currentDeviceType === EDeviceType.Neo
|
|
1609
|
+
? currentDeviceType
|
|
1610
|
+
: featureDeviceType;
|
|
1611
|
+
return deviceType === EDeviceType.Pro2 || deviceType === EDeviceType.Neo
|
|
1612
|
+
? String(deviceType)
|
|
1613
|
+
: undefined;
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1742
1616
|
private getProtocolV2ConnectionRoute() {
|
|
1743
1617
|
const descriptor = this.device.originalDescriptor;
|
|
1744
1618
|
return (
|
|
@@ -1779,6 +1653,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1779
1653
|
assertFirmwareUpdatePreparedPlanDeviceIdentity({
|
|
1780
1654
|
preparedPlan: this.params.preparedPlan,
|
|
1781
1655
|
deviceIdentity: serialNumber,
|
|
1656
|
+
deviceModel: this.getProtocolV2PreparedPlanDeviceModel(this.device.features),
|
|
1782
1657
|
});
|
|
1783
1658
|
} else if (this.params?.expectedDeviceId) {
|
|
1784
1659
|
assertProtocolV2ReconnectIdentity(this.params?.expectedDeviceId, serialNumber);
|
|
@@ -2323,12 +2198,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2323
2198
|
fwBinaryMap,
|
|
2324
2199
|
bootloaderBinary,
|
|
2325
2200
|
installItems,
|
|
2326
|
-
resourceBundles = [],
|
|
2327
2201
|
}: {
|
|
2328
2202
|
fwBinaryMap?: ProtocolV2TargetBinary[];
|
|
2329
2203
|
bootloaderBinary?: ArrayBuffer | null;
|
|
2330
2204
|
installItems?: ProtocolV2InstallItem[];
|
|
2331
|
-
resourceBundles?: ProtocolV2ResourceBundleBinary[];
|
|
2332
2205
|
}) {
|
|
2333
2206
|
const memoryInstallItems =
|
|
2334
2207
|
installItems ??
|
|
@@ -2345,19 +2218,9 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2345
2218
|
kind: item.kind,
|
|
2346
2219
|
}))
|
|
2347
2220
|
);
|
|
2348
|
-
const resourceSources = await Promise.all(
|
|
2349
|
-
resourceBundles.map(async resource => ({
|
|
2350
|
-
name: resource.name,
|
|
2351
|
-
source: await this.openProtocolV2MemorySource(resource.binary),
|
|
2352
|
-
devicePath: resource.devicePath,
|
|
2353
|
-
...(resource.version ? { version: resource.version } : {}),
|
|
2354
|
-
...(resource.payloadHash ? { payloadHash: resource.payloadHash } : {}),
|
|
2355
|
-
...(resource.headerHash ? { headerHash: resource.headerHash } : {}),
|
|
2356
|
-
}))
|
|
2357
|
-
);
|
|
2358
2221
|
return await this.executeProtocolV2Phases({
|
|
2359
2222
|
installSources,
|
|
2360
|
-
resourceSources,
|
|
2223
|
+
resourceSources: [],
|
|
2361
2224
|
});
|
|
2362
2225
|
} finally {
|
|
2363
2226
|
await this.closeProtocolV2PreparedSources();
|
|
@@ -158,13 +158,6 @@ export interface FirmwareUpdateV4Params {
|
|
|
158
158
|
se04Binary?: ArrayBuffer;
|
|
159
159
|
/** Complete Protocol V2 resource ZIP for local development; Core converts it to a local PreparedPlan. */
|
|
160
160
|
resourceArchiveBinary?: ArrayBuffer;
|
|
161
|
-
/** @deprecated Package the complete signed resource set as a ZIP and use resourceArchiveBinary. */
|
|
162
|
-
resourceFiles?: Array<{
|
|
163
|
-
binary: ArrayBuffer;
|
|
164
|
-
devicePath: string;
|
|
165
|
-
size?: number;
|
|
166
|
-
fileHash?: string;
|
|
167
|
-
}>;
|
|
168
161
|
forcedUpdateRes?: boolean;
|
|
169
162
|
artifactReader?: FirmwareArtifactReader;
|
|
170
163
|
componentArtifacts?: Partial<
|
|
@@ -173,11 +166,6 @@ export interface FirmwareUpdateV4Params {
|
|
|
173
166
|
FirmwareArtifactReference
|
|
174
167
|
>
|
|
175
168
|
>;
|
|
176
|
-
/** @deprecated Use a ZIP artifact in preparedPlan instead. */
|
|
177
|
-
resourceBundleArtifacts?: Array<{
|
|
178
|
-
name: string;
|
|
179
|
-
artifact: FirmwareArtifactReference;
|
|
180
|
-
}>;
|
|
181
169
|
}
|
|
182
170
|
|
|
183
171
|
export declare function registerFirmwareUpdateHostBinding(
|
package/src/types/settings.ts
CHANGED
|
@@ -74,18 +74,6 @@ export type IProtocolV2Resources = {
|
|
|
74
74
|
source: IProtocolV2ResourceSource;
|
|
75
75
|
};
|
|
76
76
|
|
|
77
|
-
/** @deprecated Legacy per-bundle resource descriptor retained for published V4 callers. */
|
|
78
|
-
export type IProtocolV2ResourceBundle = {
|
|
79
|
-
name: string;
|
|
80
|
-
url: string;
|
|
81
|
-
fingerprint?: string;
|
|
82
|
-
expectedSize?: number;
|
|
83
|
-
devicePath: string;
|
|
84
|
-
version?: IVersionArray;
|
|
85
|
-
payloadHash?: string;
|
|
86
|
-
headerHash?: string;
|
|
87
|
-
};
|
|
88
|
-
|
|
89
77
|
export type IProtocolV2ResourceManifestFile = {
|
|
90
78
|
archive_path: string;
|
|
91
79
|
original_name: string;
|
|
@@ -143,8 +131,6 @@ export type IFirmwareReleaseInfo = {
|
|
|
143
131
|
upgradeType?: 'payload-package-set' | string;
|
|
144
132
|
components?: Record<string, IProtocolV2FirmwareComponent>;
|
|
145
133
|
installOrder?: string[];
|
|
146
|
-
/** @deprecated New Protocol V2 releases use the independent signed resource ZIP. */
|
|
147
|
-
resourceBundles?: IProtocolV2ResourceBundle[];
|
|
148
134
|
bootloaderChangelog?: {
|
|
149
135
|
[k in ILocale]: string;
|
|
150
136
|
};
|