@onekeyfe/hd-core 1.2.0-alpha.58 → 1.2.0-alpha.59
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__/DeviceCommands.test.ts +5 -15
- package/__tests__/device-pool-state.test.ts +22 -0
- package/__tests__/device-state-mapper.test.ts +12 -0
- package/__tests__/device-utils.test.ts +48 -1
- package/__tests__/deviceSettings.test.ts +10 -0
- package/__tests__/deviceUploadNft.test.ts +4 -28
- package/__tests__/kaspa-use-tweak-pro2.test.ts +2 -2
- package/__tests__/protocol-v2-resources.test.ts +28 -13
- package/__tests__/protocol-v2-unlock-policy.test.ts +34 -0
- package/__tests__/protocol-v2.test.ts +159 -137
- package/__tests__/tron-sign-message-init.test.ts +2 -2
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +4 -3
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/OpenWalletSession.d.ts.map +1 -1
- package/dist/api/kaspa/KaspaGetAddress.d.ts +1 -1
- package/dist/api/kaspa/KaspaSignTransaction.d.ts +1 -1
- package/dist/api/polkadot/PolkadotGetAddress.d.ts +1 -1
- package/dist/api/polkadot/networks.d.ts +1 -1
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -1
- package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
- package/dist/api/solana/SolSignMessage.d.ts +1 -1
- package/dist/api/solana/SolSignOffchainMessage.d.ts +1 -1
- package/dist/api/solana/SolSignTransaction.d.ts +2 -2
- package/dist/api/sui/SuiGetAddress.d.ts +1 -1
- package/dist/api/sui/SuiGetPublicKey.d.ts +1 -1
- package/dist/api/sui/SuiSignMessage.d.ts +1 -1
- package/dist/api/sui/SuiSignTransaction.d.ts +1 -1
- package/dist/api/ton/TonGetAddress.d.ts +1 -1
- package/dist/api/ton/TonSignMessage.d.ts +1 -1
- package/dist/api/ton/TonSignProof.d.ts +1 -1
- package/dist/api/tron/TronSignMessage.d.ts +2 -2
- package/dist/api/tron/TronSignTransaction.d.ts +1 -1
- package/dist/data-manager/DataManager.d.ts +7 -5
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/device/DevicePool.d.ts.map +1 -1
- package/dist/deviceProfile/protocolV2DeviceIdentity.d.ts.map +1 -1
- package/dist/index.d.ts +44 -34
- package/dist/index.js +231 -168
- package/dist/protocols/protocol-v2/resources.d.ts +2 -2
- package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
- package/dist/types/api/checkAllFirmwareRelease.d.ts +1 -1
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdate.d.ts +3 -2
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/dist/types/device.d.ts +2 -2
- package/dist/types/device.d.ts.map +1 -1
- package/dist/types/settings.d.ts +22 -14
- package/dist/types/settings.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
- package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
- package/dist/utils/deviceSettings.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/CheckAllFirmwareRelease.ts +7 -5
- package/src/api/FirmwareUpdateV4.ts +115 -102
- package/src/api/OpenWalletSession.ts +1 -0
- package/src/api/kaspa/KaspaGetAddress.ts +1 -1
- package/src/api/kaspa/KaspaSignTransaction.ts +1 -1
- package/src/api/polkadot/networks.ts +3 -3
- package/src/api/protocol-v2/DeviceUploadNft.ts +7 -12
- package/src/api/protocol-v2/helpers.ts +0 -1
- package/src/api/solana/SolSignMessage.ts +1 -1
- package/src/api/solana/SolSignOffchainMessage.ts +1 -1
- package/src/api/solana/SolSignTransaction.ts +2 -2
- package/src/api/sui/SuiGetAddress.ts +1 -1
- package/src/api/sui/SuiGetPublicKey.ts +1 -1
- package/src/api/sui/SuiSignMessage.ts +1 -1
- package/src/api/sui/SuiSignTransaction.ts +1 -1
- package/src/api/ton/TonGetAddress.ts +1 -1
- package/src/api/ton/TonSignMessage.ts +1 -1
- package/src/api/ton/TonSignProof.ts +1 -1
- package/src/api/tron/TronSignMessage.ts +2 -2
- package/src/api/tron/TronSignTransaction.ts +1 -1
- package/src/data-manager/DataManager.ts +28 -9
- package/src/device/Device.ts +15 -6
- package/src/device/DeviceCommands.ts +13 -10
- package/src/device/DevicePool.ts +17 -8
- package/src/deviceProfile/buildDeviceFeatures.ts +2 -2
- package/src/deviceProfile/protocolV2DeviceIdentity.ts +3 -0
- package/src/protocols/protocol-v2/resources.ts +44 -13
- package/src/types/api/checkAllFirmwareRelease.ts +1 -1
- package/src/types/api/firmwareUpdate.ts +5 -5
- package/src/types/device.ts +12 -3
- package/src/types/settings.ts +30 -21
- package/src/utils/deviceFeaturesCompat.ts +5 -0
- package/src/utils/deviceFeaturesUtils.ts +6 -3
- package/src/utils/deviceInfoUtils.ts +2 -0
- package/src/utils/deviceSettings.ts +3 -0
|
@@ -46,9 +46,9 @@ import type { TypedResponseMessage } from '../device/DeviceCommands';
|
|
|
46
46
|
import type {
|
|
47
47
|
Features,
|
|
48
48
|
IFirmwareReleaseInfo,
|
|
49
|
-
IProtocolV2BootResources,
|
|
50
49
|
IProtocolV2FirmwareComponent,
|
|
51
50
|
IProtocolV2Resource,
|
|
51
|
+
IProtocolV2ResourceFile,
|
|
52
52
|
IVersionArray,
|
|
53
53
|
} from '../types';
|
|
54
54
|
|
|
@@ -77,7 +77,6 @@ const PROTOCOL_V2_OKPP_HEADER_SIZE = 0x52a0;
|
|
|
77
77
|
const PROTOCOL_V2_OKPP_PAYLOAD_HASH_OFFSET = 0x200;
|
|
78
78
|
const PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET = 0x240;
|
|
79
79
|
const PROTOCOL_V2_OKPP_HASH_SIZE = 64;
|
|
80
|
-
const PROTOCOL_V2_BOOT_RESOURCES_FILE_NAME = 'boot_resources.crate.okpkg';
|
|
81
80
|
|
|
82
81
|
const getProtocolV2DeviceTransferProgress = (
|
|
83
82
|
bytesBeforeChunk: number,
|
|
@@ -112,7 +111,7 @@ type ProtocolV2FirmwareUpdateStartResponse = TypedResponseMessage<'Success'>;
|
|
|
112
111
|
|
|
113
112
|
type ProtocolV2TargetBinary = { fileName: string; binary: ArrayBuffer; targetId: number };
|
|
114
113
|
type ProtocolV2InstallItem = ProtocolV2TargetBinary & {
|
|
115
|
-
kind: ProtocolV2RemoteComponentTarget['kind']
|
|
114
|
+
kind: ProtocolV2RemoteComponentTarget['kind'];
|
|
116
115
|
};
|
|
117
116
|
type ProtocolV2InstallTarget = ProtocolV2InstallItem & {
|
|
118
117
|
path: string;
|
|
@@ -125,7 +124,7 @@ type ProtocolV2FileTransferParams = PROTO.FirmwareUpload & {
|
|
|
125
124
|
onTransferredBytes?: (transferredBytes: number) => void;
|
|
126
125
|
};
|
|
127
126
|
|
|
128
|
-
/**
|
|
127
|
+
/** Protocol V2 resource file written independently to devicePath through FileWrite. */
|
|
129
128
|
type ProtocolV2ResourceBundleBinary = {
|
|
130
129
|
name: string;
|
|
131
130
|
binary: ArrayBuffer;
|
|
@@ -371,19 +370,30 @@ export const isProtocolV2FirmwareFingerprintValid = (
|
|
|
371
370
|
|
|
372
371
|
export const assertProtocolV2ReconnectIdentity = (
|
|
373
372
|
expectedSerialNumber?: string,
|
|
374
|
-
actualSerialNumber?: string
|
|
373
|
+
actualSerialNumber?: string,
|
|
374
|
+
expectedPath?: string,
|
|
375
|
+
actualPath?: string
|
|
375
376
|
) => {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
377
|
+
if (expectedSerialNumber && actualSerialNumber) {
|
|
378
|
+
if (actualSerialNumber !== expectedSerialNumber) {
|
|
379
|
+
throw ERRORS.TypedError(
|
|
380
|
+
HardwareErrorCode.DeviceNotFound,
|
|
381
|
+
`Protocol V2 reconnect physical identity mismatch: expected ${expectedSerialNumber}, received ${actualSerialNumber}`
|
|
382
|
+
);
|
|
383
|
+
}
|
|
379
384
|
return;
|
|
380
385
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
`Protocol V2 reconnect physical identity mismatch: expected ${expectedSerialNumber}, received ${actualSerialNumber}`
|
|
385
|
-
);
|
|
386
|
+
|
|
387
|
+
if (expectedPath && actualPath && expectedPath === actualPath) {
|
|
388
|
+
return;
|
|
386
389
|
}
|
|
390
|
+
|
|
391
|
+
throw ERRORS.TypedError(
|
|
392
|
+
HardwareErrorCode.DeviceNotFound,
|
|
393
|
+
`Protocol V2 reconnect physical identity unavailable: expected path ${
|
|
394
|
+
expectedPath ?? 'unknown'
|
|
395
|
+
}, received ${actualPath ?? 'unknown'}`
|
|
396
|
+
);
|
|
387
397
|
};
|
|
388
398
|
|
|
389
399
|
/**
|
|
@@ -397,6 +407,8 @@ export const assertProtocolV2ReconnectIdentity = (
|
|
|
397
407
|
export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareUpdateV4Params> {
|
|
398
408
|
private protocolV2ExpectedSerialNumber?: string;
|
|
399
409
|
|
|
410
|
+
private protocolV2ExpectedPath?: string;
|
|
411
|
+
|
|
400
412
|
getSupportedProtocols() {
|
|
401
413
|
return ['V2'] as const;
|
|
402
414
|
}
|
|
@@ -427,7 +439,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
427
439
|
{ name: 'chunkSize', type: 'number' },
|
|
428
440
|
{ name: 'forcedUpdateRes', type: 'boolean' },
|
|
429
441
|
{ name: 'bootloaderBinary', type: 'buffer' },
|
|
430
|
-
{ name: 'bootResourcesBinary', type: 'buffer' },
|
|
431
442
|
{ name: 'romloaderBinary', type: 'buffer' },
|
|
432
443
|
{ name: 'applicationP1Binary', type: 'buffer' },
|
|
433
444
|
{ name: 'applicationP2Binary', type: 'buffer' },
|
|
@@ -439,14 +450,13 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
439
450
|
{ name: 'firmwareType', type: 'string' },
|
|
440
451
|
{ name: 'targetsToUpdate', type: 'array', allowEmpty: true },
|
|
441
452
|
{ name: 'platform', type: 'string' },
|
|
442
|
-
{ name: '
|
|
453
|
+
{ name: 'resourceFiles', type: 'array', allowEmpty: true },
|
|
443
454
|
]);
|
|
444
455
|
|
|
445
456
|
this.params = {
|
|
446
457
|
chunkSize: payload.chunkSize,
|
|
447
458
|
forcedUpdateRes: payload.forcedUpdateRes,
|
|
448
459
|
bootloaderBinary: payload.bootloaderBinary,
|
|
449
|
-
bootResourcesBinary: payload.bootResourcesBinary,
|
|
450
460
|
romloaderBinary: payload.romloaderBinary,
|
|
451
461
|
applicationP1Binary: payload.applicationP1Binary,
|
|
452
462
|
applicationP2Binary: payload.applicationP2Binary,
|
|
@@ -455,7 +465,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
455
465
|
se02Binary: payload.se02Binary,
|
|
456
466
|
se03Binary: payload.se03Binary,
|
|
457
467
|
se04Binary: payload.se04Binary,
|
|
458
|
-
|
|
468
|
+
resourceFiles: payload.resourceFiles,
|
|
459
469
|
firmwareType: payload.firmwareType,
|
|
460
470
|
targetsToUpdate: payload.targetsToUpdate,
|
|
461
471
|
platform: payload.platform,
|
|
@@ -490,26 +500,24 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
490
500
|
const deviceFirmwareType = getFirmwareType(deviceFeatures);
|
|
491
501
|
const firmwareType = this.params.firmwareType ?? deviceFirmwareType;
|
|
492
502
|
const needsRemoteResources =
|
|
493
|
-
!this.params.
|
|
494
|
-
!!this.params.targetsToUpdate?.includes('resource');
|
|
503
|
+
!this.params.resourceFiles?.length && !!this.params.targetsToUpdate?.includes('resource');
|
|
495
504
|
|
|
496
505
|
let fwBinaryMap: ProtocolV2TargetBinary[] = [];
|
|
497
506
|
let bootloaderBinary: ArrayBuffer | null = null;
|
|
498
|
-
let bootResourcesInstallItem: ProtocolV2InstallItem | undefined;
|
|
499
507
|
let installItems: ProtocolV2InstallItem[] | undefined;
|
|
500
508
|
let resourceBundles: ProtocolV2ResourceBundleBinary[] | undefined;
|
|
501
509
|
try {
|
|
502
510
|
this.postTipMessage(FirmwareUpdateTipMessage.StartDownloadFirmware);
|
|
503
|
-
resourceBundles = this.
|
|
511
|
+
resourceBundles = this.prepareExplicitProtocolV2ResourceFiles();
|
|
504
512
|
fwBinaryMap = this.collectExplicitTargetBinaries();
|
|
505
513
|
bootloaderBinary = this.prepareBootloaderBinary();
|
|
506
514
|
const needsRemoteFirmware = !this.hasExplicitProtocolV2Payload(fwBinaryMap);
|
|
507
|
-
const needsRemoteBootResources =
|
|
508
|
-
!this.params.bootResourcesBinary &&
|
|
509
|
-
!!this.params.targetsToUpdate?.includes('boot_resources');
|
|
515
|
+
const needsRemoteBootResources = !!this.params.targetsToUpdate?.includes('boot_resources');
|
|
510
516
|
if (needsRemoteFirmware || needsRemoteResources || needsRemoteBootResources) {
|
|
511
517
|
// Remote updates must use a freshly fetched config before any reboot or file write.
|
|
512
|
-
await DataManager.forceReloadData(
|
|
518
|
+
await DataManager.forceReloadData({
|
|
519
|
+
requireResources: needsRemoteResources || needsRemoteBootResources,
|
|
520
|
+
});
|
|
513
521
|
}
|
|
514
522
|
if (needsRemoteFirmware) {
|
|
515
523
|
const remoteBinaries = await this.prepareRemoteProtocolV2Binaries(
|
|
@@ -520,12 +528,9 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
520
528
|
fwBinaryMap = remoteBinaries.fwBinaryMap;
|
|
521
529
|
installItems = remoteBinaries.installItems;
|
|
522
530
|
}
|
|
523
|
-
|
|
524
|
-
if (
|
|
525
|
-
|
|
526
|
-
bootResourcesInstallItem,
|
|
527
|
-
...(installItems ?? this.buildProtocolV2InstallItems({ bootloaderBinary, fwBinaryMap })),
|
|
528
|
-
];
|
|
531
|
+
const bootResourceFiles = await this.prepareProtocolV2BootResources();
|
|
532
|
+
if (bootResourceFiles?.length) {
|
|
533
|
+
resourceBundles = [...(resourceBundles ?? []), ...bootResourceFiles];
|
|
529
534
|
}
|
|
530
535
|
if (!needsRemoteResources) {
|
|
531
536
|
this.postTipMessage(FirmwareUpdateTipMessage.FinishDownloadFirmware);
|
|
@@ -554,7 +559,8 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
554
559
|
|
|
555
560
|
if (needsRemoteResources) {
|
|
556
561
|
try {
|
|
557
|
-
|
|
562
|
+
const stableResources = await this.prepareProtocolV2ResourceBundles();
|
|
563
|
+
resourceBundles = [...(resourceBundles ?? []), ...(stableResources ?? [])];
|
|
558
564
|
this.postTipMessage(FirmwareUpdateTipMessage.FinishDownloadFirmware);
|
|
559
565
|
} catch (err) {
|
|
560
566
|
if (enteredBootloader) {
|
|
@@ -607,7 +613,9 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
607
613
|
private assertProtocolV2DeviceInfoIdentity(deviceInfo: ProtocolV2DeviceInfo) {
|
|
608
614
|
assertProtocolV2ReconnectIdentity(
|
|
609
615
|
this.protocolV2ExpectedSerialNumber,
|
|
610
|
-
this.getProtocolV2SerialNumber(deviceInfo)
|
|
616
|
+
this.getProtocolV2SerialNumber(deviceInfo),
|
|
617
|
+
this.protocolV2ExpectedPath,
|
|
618
|
+
this.device.originalDescriptor.path
|
|
611
619
|
);
|
|
612
620
|
}
|
|
613
621
|
|
|
@@ -627,8 +635,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
627
635
|
private async captureProtocolV2PhysicalIdentity() {
|
|
628
636
|
const deviceInfo = await this.requestProtocolV2PhysicalIdentity();
|
|
629
637
|
const serialNumber = this.getProtocolV2SerialNumber(deviceInfo);
|
|
630
|
-
|
|
638
|
+
const path = this.device.originalDescriptor.path?.trim() || undefined;
|
|
639
|
+
assertProtocolV2ReconnectIdentity(serialNumber, serialNumber, path, path);
|
|
631
640
|
this.protocolV2ExpectedSerialNumber = serialNumber;
|
|
641
|
+
this.protocolV2ExpectedPath = path;
|
|
632
642
|
}
|
|
633
643
|
|
|
634
644
|
private async verifyProtocolV2ReconnectIdentity() {
|
|
@@ -643,9 +653,8 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
643
653
|
|
|
644
654
|
private hasExplicitProtocolV2Payload(fwBinaryMap: ProtocolV2TargetBinary[]) {
|
|
645
655
|
return (
|
|
646
|
-
!!this.params.
|
|
656
|
+
!!this.params.resourceFiles?.length ||
|
|
647
657
|
!!this.params.bootloaderBinary ||
|
|
648
|
-
!!this.params.bootResourcesBinary ||
|
|
649
658
|
fwBinaryMap.length > 0
|
|
650
659
|
);
|
|
651
660
|
}
|
|
@@ -795,68 +804,68 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
795
804
|
};
|
|
796
805
|
}
|
|
797
806
|
|
|
798
|
-
private
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
if (resource && !isProtocolV2ResourceFileValid(binary, resource)) {
|
|
803
|
-
throw new Error('Pro2 boot resources file verification failed');
|
|
804
|
-
}
|
|
805
|
-
const header = parseProtocolV2OkppHeader(toProtocolV2Bytes(binary));
|
|
806
|
-
if (!header || header.type !== 'CRAT') {
|
|
807
|
-
throw new Error('Invalid Pro2 boot resources CRATE header');
|
|
808
|
-
}
|
|
809
|
-
if (resource) {
|
|
810
|
-
const expectedPayloadHash = normalizeProtocolV2Hex(resource.payloadHash);
|
|
811
|
-
const expectedHeaderHash = normalizeProtocolV2Hex(resource.headerHash);
|
|
812
|
-
if (header.payloadHash !== expectedPayloadHash) {
|
|
813
|
-
throw new Error('Pro2 boot resources payload hash mismatch');
|
|
814
|
-
}
|
|
815
|
-
if (header.headerHash !== expectedHeaderHash) {
|
|
816
|
-
throw new Error('Pro2 boot resources header hash mismatch');
|
|
817
|
-
}
|
|
818
|
-
}
|
|
807
|
+
private getProtocolV2DeviceType(): EDeviceType.Pro2 | EDeviceType.Neo {
|
|
808
|
+
const deviceType = this.device.getCurrentDeviceType();
|
|
809
|
+
if (deviceType === EDeviceType.Pro2 || deviceType === EDeviceType.Neo) return deviceType;
|
|
810
|
+
throw new Error(`Unsupported Protocol V2 device type: ${deviceType}`);
|
|
819
811
|
}
|
|
820
812
|
|
|
821
|
-
private async prepareProtocolV2BootResources(): Promise<
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
813
|
+
private async prepareProtocolV2BootResources(): Promise<
|
|
814
|
+
ProtocolV2ResourceBundleBinary[] | undefined
|
|
815
|
+
> {
|
|
816
|
+
if (!this.params.targetsToUpdate?.includes('boot_resources')) return undefined;
|
|
817
|
+
const resource = DataManager.getProtocolV2BootResources(this.getProtocolV2DeviceType());
|
|
818
|
+
if (!resource) throw new Error('Missing Protocol V2 boot resources configuration');
|
|
819
|
+
|
|
820
|
+
const files: ProtocolV2ResourceBundleBinary[] = [];
|
|
821
|
+
for (const file of resource.files) {
|
|
822
|
+
Log.log(`[FirmwareUpdateV4] downloading boot resource ${file.devicePath}`);
|
|
823
|
+
const { binary } = await getSysResourceBinary(file.url);
|
|
824
|
+
if (!isProtocolV2ResourceFileValid(binary, file)) {
|
|
825
|
+
throw new Error(`Boot resource file verification failed: ${file.devicePath}`);
|
|
832
826
|
}
|
|
833
|
-
|
|
834
|
-
|
|
827
|
+
files.push({
|
|
828
|
+
name: file.name ?? file.devicePath.split('/').pop() ?? file.devicePath,
|
|
829
|
+
binary,
|
|
830
|
+
devicePath: file.devicePath,
|
|
831
|
+
});
|
|
835
832
|
}
|
|
836
|
-
|
|
837
|
-
this.validateProtocolV2BootResourcesBinary(binary, resource);
|
|
838
|
-
return {
|
|
839
|
-
fileName: PROTOCOL_V2_BOOT_RESOURCES_FILE_NAME,
|
|
840
|
-
binary,
|
|
841
|
-
targetId: ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_CRATE,
|
|
842
|
-
kind: 'boot_resources',
|
|
843
|
-
};
|
|
833
|
+
return files;
|
|
844
834
|
}
|
|
845
835
|
|
|
846
|
-
private
|
|
847
|
-
|
|
836
|
+
private prepareExplicitProtocolV2ResourceFiles(): ProtocolV2ResourceBundleBinary[] | undefined {
|
|
837
|
+
const files = this.params.resourceFiles ?? [];
|
|
838
|
+
if (!files?.length) return undefined;
|
|
848
839
|
|
|
849
|
-
|
|
840
|
+
const prepared = files.map((file, index) => {
|
|
850
841
|
const devicePath = validateProtocolV2FilesystemPath(
|
|
851
842
|
file.devicePath,
|
|
852
|
-
`
|
|
843
|
+
`resourceFiles[${index}].devicePath`
|
|
853
844
|
);
|
|
845
|
+
const descriptor = file as typeof file &
|
|
846
|
+
Pick<Partial<IProtocolV2ResourceFile>, 'size' | 'fileHash'>;
|
|
847
|
+
if (descriptor.size !== undefined && descriptor.size !== file.binary.byteLength) {
|
|
848
|
+
throw new Error(`resourceFiles[${index}] size mismatch`);
|
|
849
|
+
}
|
|
850
|
+
if (
|
|
851
|
+
descriptor.fileHash &&
|
|
852
|
+
!isProtocolV2ResourceFileValid(file.binary, {
|
|
853
|
+
size: file.binary.byteLength,
|
|
854
|
+
fileHash: descriptor.fileHash,
|
|
855
|
+
})
|
|
856
|
+
) {
|
|
857
|
+
throw new Error(`resourceFiles[${index}] SHA-256 mismatch`);
|
|
858
|
+
}
|
|
854
859
|
return {
|
|
855
860
|
name: devicePath.split('/').pop() ?? devicePath,
|
|
856
861
|
binary: file.binary,
|
|
857
862
|
devicePath,
|
|
858
863
|
};
|
|
859
864
|
});
|
|
865
|
+
if (new Set(prepared.map(file => file.devicePath)).size !== prepared.length) {
|
|
866
|
+
throw new Error('resourceFiles contain duplicate devicePath values');
|
|
867
|
+
}
|
|
868
|
+
return prepared;
|
|
860
869
|
}
|
|
861
870
|
|
|
862
871
|
private async prepareProtocolV2ResourceBundles(): Promise<
|
|
@@ -866,7 +875,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
866
875
|
return undefined;
|
|
867
876
|
}
|
|
868
877
|
|
|
869
|
-
const resources = DataManager.getProtocolV2Resources();
|
|
878
|
+
const resources = DataManager.getProtocolV2Resources(this.getProtocolV2DeviceType());
|
|
870
879
|
if (!resources?.length) {
|
|
871
880
|
throw new Error('Missing Pro2 stable resource configuration');
|
|
872
881
|
}
|
|
@@ -886,7 +895,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
886
895
|
forced: this.params.forcedUpdateRes,
|
|
887
896
|
});
|
|
888
897
|
Log.log(
|
|
889
|
-
`[FirmwareUpdateV4]
|
|
898
|
+
`[FirmwareUpdateV4] Protocol V2 resource plan mode=bootloader-recovery status=${plan.status} count=${plan.resources.length}`
|
|
890
899
|
);
|
|
891
900
|
|
|
892
901
|
const bundles: ProtocolV2ResourceBundleBinary[] = [];
|
|
@@ -926,7 +935,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
926
935
|
let processedSize = 0;
|
|
927
936
|
for (const bundle of bundles) {
|
|
928
937
|
Log.log(
|
|
929
|
-
`[FirmwareUpdateV4] syncing
|
|
938
|
+
`[FirmwareUpdateV4] syncing resource ${bundle.name} -> ${bundle.devicePath} bytes=${bundle.binary.byteLength}`
|
|
930
939
|
);
|
|
931
940
|
processedSize = await this.protocolV2CommonUpdateProcess({
|
|
932
941
|
payload: bundle.binary,
|
|
@@ -938,7 +947,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
938
947
|
|
|
939
948
|
const elapsedMs = Date.now() - transferStartTime;
|
|
940
949
|
Log.log(
|
|
941
|
-
`[FirmwareUpdateV4]
|
|
950
|
+
`[FirmwareUpdateV4] resource sync finished transport=${transferTransport} bytes=${totalSize} elapsed=${(
|
|
942
951
|
elapsedMs / 1000
|
|
943
952
|
).toFixed(2)}s speed=${formatProtocolV2TransferSpeed(totalSize, elapsedMs)} KB/s`
|
|
944
953
|
);
|
|
@@ -956,7 +965,11 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
956
965
|
}
|
|
957
966
|
|
|
958
967
|
private isProtocolV2RomloaderMode() {
|
|
959
|
-
|
|
968
|
+
const deviceType = this.device.getCurrentDeviceType();
|
|
969
|
+
if (
|
|
970
|
+
!this.device.isProtocolV2() ||
|
|
971
|
+
(deviceType !== EDeviceType.Pro2 && deviceType !== EDeviceType.Neo)
|
|
972
|
+
) {
|
|
960
973
|
return false;
|
|
961
974
|
}
|
|
962
975
|
if (typeof this.device.isRomloader === 'function') {
|
|
@@ -1112,9 +1125,9 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1112
1125
|
totalSize = resourceTransfer.totalSize;
|
|
1113
1126
|
}
|
|
1114
1127
|
|
|
1115
|
-
// Skip staging and installation when the update contains
|
|
1128
|
+
// Skip staging and installation when the update contains resource files only.
|
|
1116
1129
|
if (orderedInstallItems.length === 0) {
|
|
1117
|
-
Log.log('[FirmwareUpdateV4] no firmware targets to install (
|
|
1130
|
+
Log.log('[FirmwareUpdateV4] no firmware targets to install (resource files only)');
|
|
1118
1131
|
if (totalSize > 0) {
|
|
1119
1132
|
this.postProgressMessage(100, 'transferData');
|
|
1120
1133
|
}
|
|
@@ -1537,9 +1550,13 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1537
1550
|
DataManager.isBrowserWebUsb(DataManager.getSettings('env')) &&
|
|
1538
1551
|
devicesDescriptor.length === 1
|
|
1539
1552
|
) {
|
|
1553
|
+
const descriptor = devicesDescriptor[0];
|
|
1554
|
+
if (!this.protocolV2ExpectedSerialNumber && descriptor.path !== this.protocolV2ExpectedPath) {
|
|
1555
|
+
throw ERRORS.TypedError(HardwareErrorCode.DeviceNotFound);
|
|
1556
|
+
}
|
|
1540
1557
|
this.device.updateDescriptor(
|
|
1541
1558
|
{
|
|
1542
|
-
...
|
|
1559
|
+
...descriptor,
|
|
1543
1560
|
protocolType: PROTOCOL_V2_CONNECT_PROTOCOL,
|
|
1544
1561
|
},
|
|
1545
1562
|
true
|
|
@@ -1556,18 +1573,14 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1556
1573
|
connectProtocol: PROTOCOL_V2_CONNECT_PROTOCOL,
|
|
1557
1574
|
});
|
|
1558
1575
|
const expectedSerialNumber = this.protocolV2ExpectedSerialNumber?.trim();
|
|
1559
|
-
const
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
identityMatch ??
|
|
1568
|
-
(singleCandidate && (!expectedSerialNumber || !singleCandidateSerialNumber)
|
|
1569
|
-
? singleCandidate
|
|
1570
|
-
: undefined);
|
|
1576
|
+
const expectedPath = this.protocolV2ExpectedPath?.trim();
|
|
1577
|
+
const reconnectDevice = deviceList.find(candidate => {
|
|
1578
|
+
const candidateSerialNumber = candidate.getCurrentSerialNo?.().trim();
|
|
1579
|
+
if (expectedSerialNumber && candidateSerialNumber) {
|
|
1580
|
+
return candidateSerialNumber === expectedSerialNumber;
|
|
1581
|
+
}
|
|
1582
|
+
return !!expectedPath && candidate.getConnectId() === expectedPath;
|
|
1583
|
+
});
|
|
1571
1584
|
if (!reconnectDevice) {
|
|
1572
1585
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceNotFound);
|
|
1573
1586
|
}
|
|
@@ -84,6 +84,7 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
|
|
|
84
84
|
|
|
85
85
|
init() {
|
|
86
86
|
this.useDevicePassphraseState = false;
|
|
87
|
+
this.unlockPolicy = 'unlock-before-run';
|
|
87
88
|
this.skipForceUpdateCheck = true;
|
|
88
89
|
this.params = normalizeParams(this.payload as unknown as Record<string, unknown>);
|
|
89
90
|
this.payload.useEmptyPassphrase = this.params.mode === OpenWalletSessionMode.Standard;
|
|
@@ -23,7 +23,7 @@ const baseVersionRange = {
|
|
|
23
23
|
model_touch: {
|
|
24
24
|
min: '4.3.0',
|
|
25
25
|
},
|
|
26
|
-
|
|
26
|
+
model_pro2: {
|
|
27
27
|
min: '0.0.0',
|
|
28
28
|
},
|
|
29
29
|
};
|
|
@@ -36,7 +36,7 @@ const specialVersionRange: Record<string, DeviceFirmwareRange> = {
|
|
|
36
36
|
model_touch: {
|
|
37
37
|
min: '4.7.0',
|
|
38
38
|
},
|
|
39
|
-
|
|
39
|
+
model_pro2: {
|
|
40
40
|
min: '0.0.0',
|
|
41
41
|
},
|
|
42
42
|
},
|
|
@@ -47,7 +47,7 @@ const specialVersionRange: Record<string, DeviceFirmwareRange> = {
|
|
|
47
47
|
model_touch: {
|
|
48
48
|
min: '4.9.0',
|
|
49
49
|
},
|
|
50
|
-
|
|
50
|
+
model_pro2: {
|
|
51
51
|
min: '0.0.0',
|
|
52
52
|
},
|
|
53
53
|
},
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
} from '../../utils/pro2Nft';
|
|
18
18
|
import { BaseMethod } from '../BaseMethod';
|
|
19
19
|
import { invalidParameter } from '../helpers/filesystemValidation';
|
|
20
|
-
import {
|
|
20
|
+
import { writeProtocolV2File } from '../helpers/protocolV2FileWrite';
|
|
21
21
|
|
|
22
22
|
export type DeviceUploadNftParams = {
|
|
23
23
|
image: Pro2NftImage;
|
|
@@ -115,17 +115,12 @@ export default class DeviceUploadNft extends BaseMethod<DeviceUploadNftParams> {
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
private async updateNft(basename: string) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
throw error;
|
|
125
|
-
}
|
|
126
|
-
this.throwIfAborted();
|
|
127
|
-
return this.device.commands.typedCall('NftUpdate', 'Success', params, options);
|
|
128
|
-
}
|
|
118
|
+
return this.device.commands.typedCall(
|
|
119
|
+
'NftUpdate',
|
|
120
|
+
'Success',
|
|
121
|
+
{ file_name_no_ext: basename },
|
|
122
|
+
{ timeoutMs: this.params.timeoutMs }
|
|
123
|
+
);
|
|
129
124
|
}
|
|
130
125
|
|
|
131
126
|
async run(): Promise<DeviceUploadNftResponse> {
|
|
@@ -138,7 +138,6 @@ export function normalizeRebootType(value: RebootTypeInput | undefined): DeviceR
|
|
|
138
138
|
|
|
139
139
|
// 与 firmware-pro2 的 proto_target_to_firmware_target 安装白名单保持一致。
|
|
140
140
|
const INSTALLABLE_FIRMWARE_TARGET_IDS = new Set<number>([
|
|
141
|
-
ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_CRATE,
|
|
142
141
|
ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER,
|
|
143
142
|
ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P1,
|
|
144
143
|
ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P2,
|
|
@@ -47,7 +47,7 @@ export default class SolSignTransaction extends BaseMethod<HardwareSolanaSignTx[
|
|
|
47
47
|
getVersionRange() {
|
|
48
48
|
if (this.existsVersionedTx()) {
|
|
49
49
|
return {
|
|
50
|
-
|
|
50
|
+
model_pro2: {
|
|
51
51
|
min: '0.0.0',
|
|
52
52
|
},
|
|
53
53
|
model_mini: {
|
|
@@ -60,7 +60,7 @@ export default class SolSignTransaction extends BaseMethod<HardwareSolanaSignTx[
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
return {
|
|
63
|
-
|
|
63
|
+
model_pro2: {
|
|
64
64
|
min: '0.0.0',
|
|
65
65
|
},
|
|
66
66
|
classic: {
|
|
@@ -46,7 +46,7 @@ export default class TronSignMessage extends BaseMethod<HardwareTronSignMessage>
|
|
|
46
46
|
|
|
47
47
|
getVersionRange() {
|
|
48
48
|
return {
|
|
49
|
-
|
|
49
|
+
model_pro2: {
|
|
50
50
|
min: '0.0.0',
|
|
51
51
|
},
|
|
52
52
|
model_mini: {
|
|
@@ -57,7 +57,7 @@ export default class TronSignMessage extends BaseMethod<HardwareTronSignMessage>
|
|
|
57
57
|
|
|
58
58
|
getMessageV2VersionRange() {
|
|
59
59
|
return {
|
|
60
|
-
|
|
60
|
+
model_pro2: {
|
|
61
61
|
min: '0.0.0',
|
|
62
62
|
},
|
|
63
63
|
pro: {
|