@onekeyfe/hd-core 1.2.0-alpha.99 → 1.2.1-alpha.0
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__/AllNetworkGetAddressBase.tracing.test.ts +20 -4
- package/__tests__/DeviceCommands.test.ts +203 -27
- package/__tests__/base64Data.test.ts +69 -0
- package/__tests__/check-all-firmware-release-protocol-v2.test.ts +48 -2
- package/__tests__/check-firmware-release-protocol-v2.test.ts +82 -13
- package/__tests__/device-connector-protocol.test.ts +21 -0
- package/__tests__/device-lifecycle-events.test.ts +427 -7
- package/__tests__/device-pool-state.test.ts +25 -0
- package/__tests__/device-settings.test.ts +237 -9
- package/__tests__/device-state-events.test.ts +2 -2
- package/__tests__/device-state-mapper.test.ts +61 -5
- package/__tests__/device-utils.test.ts +15 -1
- package/__tests__/device-wallet-session-store.test.ts +147 -21
- package/__tests__/deviceSettings.test.ts +7 -3
- package/__tests__/deviceUploadNft.test.ts +36 -4
- package/__tests__/firmware-update/device-update-bootloader.test.ts +13 -3
- package/__tests__/firmware-update/firmware-artifact-source.test.ts +61 -9
- package/__tests__/firmware-update/firmware-prepared-host-digest.test.ts +19 -9
- package/__tests__/firmware-update/firmware-prepared-resource-archive.test.ts +21 -0
- package/__tests__/firmware-update/firmware-update-bootloader-poll.test.ts +63 -0
- package/__tests__/firmware-update/firmware-update-plan.test.ts +59 -55
- package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +19 -5
- package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +116 -0
- package/__tests__/firmware-update/firmware-update-v4-install-poll.test.ts +979 -0
- package/__tests__/firmware-update/firmware-update-v4-parameters.test.ts +85 -0
- package/__tests__/get-device-state.test.ts +60 -21
- package/__tests__/logBlockEvent.test.ts +13 -1
- package/__tests__/open-wallet-session.test.ts +127 -1
- package/__tests__/protocol-v2-firmware-targets.test.ts +23 -0
- package/__tests__/protocol-v2-resources.test.ts +185 -88
- package/__tests__/protocol-v2-unlock-policy.test.ts +235 -2
- package/__tests__/protocol-v2.test.ts +2199 -486
- package/__tests__/refresh-device-state.test.ts +3 -1
- package/__tests__/resourceBase64Boundary.test.ts +48 -0
- package/__tests__/search-devices.test.ts +79 -32
- package/__tests__/ton-sign-message.test.ts +84 -0
- package/dist/api/BaseMethod.d.ts +2 -1
- package/dist/api/BaseMethod.d.ts.map +1 -1
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/CheckBootloaderRelease.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +20 -6
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/OpenWalletSession.d.ts.map +1 -1
- package/dist/api/SearchDevices.d.ts.map +1 -1
- package/dist/api/UploadPortfolio.d.ts +1 -1
- package/dist/api/UploadPortfolio.d.ts.map +1 -1
- package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
- package/dist/api/device/DeviceChangePin.d.ts.map +1 -1
- package/dist/api/device/DeviceRebootToBoardloader.d.ts.map +1 -1
- package/dist/api/device/DeviceRebootToBootloader.d.ts.map +1 -1
- package/dist/api/device/DeviceSettings.d.ts.map +1 -1
- package/dist/api/device/DeviceVerify.d.ts +1 -0
- package/dist/api/device/DeviceVerify.d.ts.map +1 -1
- package/dist/api/device/DeviceWipe.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareArtifactSource.d.ts +5 -1
- package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +1 -1
- package/dist/api/firmware/FirmwarePreparedResourceArchive.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +2 -2
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +0 -15
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -1
- package/dist/api/firmware/getBinary.d.ts +3 -2
- package/dist/api/firmware/getBinary.d.ts.map +1 -1
- package/dist/api/firmware/protocolV2Release.d.ts.map +1 -1
- package/dist/api/helpers/base64Data.d.ts +16 -0
- package/dist/api/helpers/base64Data.d.ts.map +1 -0
- package/dist/api/protocol-v2/DeviceFirmwareUpdate.d.ts +3 -1
- package/dist/api/protocol-v2/DeviceFirmwareUpdate.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceInfoGet.d.ts +1 -1
- package/dist/api/protocol-v2/DeviceInfoGet.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceReboot.d.ts +1 -1
- package/dist/api/protocol-v2/DeviceReboot.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts +2 -3
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts +2 -3
- package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts.map +1 -1
- package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
- package/dist/api/ton/TonSignMessage.d.ts.map +1 -1
- package/dist/core/index.d.ts +6 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/data-manager/DataManager.d.ts +4 -3
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/data-manager/TransportManager.d.ts.map +1 -1
- package/dist/device/Device.d.ts +16 -3
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts +4 -4
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/device/DeviceConnector.d.ts +1 -1
- package/dist/device/DeviceConnector.d.ts.map +1 -1
- package/dist/device/DevicePool.d.ts.map +1 -1
- package/dist/device/DeviceStateMapper.d.ts.map +1 -1
- package/dist/deviceProfile/buildDeviceFeatures.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/events/ui-request.d.ts +3 -0
- package/dist/events/ui-request.d.ts.map +1 -1
- package/dist/index.d.ts +54 -84
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2150 -1469
- package/dist/protocols/protocol-v2/features.d.ts +13 -5
- package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/index.d.ts +2 -2
- package/dist/protocols/protocol-v2/index.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/resources.d.ts +12 -7
- package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +3 -1
- package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/walletSession.d.ts +3 -0
- package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdatePlan.d.ts +2 -2
- package/dist/types/api/firmwareUpdatePlan.d.ts.map +1 -1
- package/dist/types/api/protocolV2.d.ts +1 -1
- package/dist/types/api/protocolV2.d.ts.map +1 -1
- package/dist/types/device.d.ts.map +1 -1
- package/dist/types/settings.d.ts +3 -31
- package/dist/types/settings.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesUtils.d.ts +3 -0
- package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
- package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
- package/dist/utils/deviceSettings.d.ts +1 -0
- package/dist/utils/deviceSettings.d.ts.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/dist/utils/pro2Nft.d.ts +7 -0
- package/dist/utils/pro2Nft.d.ts.map +1 -1
- package/package.json +6 -4
- package/src/api/BaseMethod.ts +8 -1
- package/src/api/CheckAllFirmwareRelease.ts +2 -4
- package/src/api/CheckBLEFirmwareRelease.ts +2 -2
- package/src/api/CheckBootloaderRelease.ts +3 -2
- package/src/api/CheckFirmwareRelease.ts +2 -2
- package/src/api/FirmwareUpdateV2.ts +12 -9
- package/src/api/FirmwareUpdateV3.ts +29 -19
- package/src/api/FirmwareUpdateV4.ts +934 -739
- package/src/api/OpenWalletSession.ts +39 -9
- package/src/api/PromptWebDeviceAccess.ts +2 -2
- package/src/api/SearchDevices.ts +6 -3
- package/src/api/UploadPortfolio.ts +9 -2
- package/src/api/allnetwork/AllNetworkGetAddressBase.ts +2 -1
- package/src/api/device/DeviceChangePin.ts +4 -1
- package/src/api/device/DeviceRebootToBoardloader.ts +3 -1
- package/src/api/device/DeviceRebootToBootloader.ts +3 -1
- package/src/api/device/DeviceSettings.ts +34 -20
- package/src/api/device/DeviceVerify.ts +25 -0
- package/src/api/device/DeviceWipe.ts +4 -1
- package/src/api/firmware/FirmwareArtifactSource.ts +41 -14
- package/src/api/firmware/FirmwarePreparedResourceArchive.ts +16 -27
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +9 -3
- package/src/api/firmware/FirmwareUpdatePlan.ts +37 -77
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +10 -6
- package/src/api/firmware/protocolV2Release.ts +7 -2
- package/src/api/helpers/base64Data.ts +85 -0
- package/src/api/protocol-v2/DeviceFactoryInfoSet.ts +1 -1
- package/src/api/protocol-v2/DeviceFirmwareUpdate.ts +6 -28
- package/src/api/protocol-v2/DeviceGetFirmwareUpdateStatus.ts +7 -1
- package/src/api/protocol-v2/DeviceInfoGet.ts +3 -3
- package/src/api/protocol-v2/DeviceReboot.ts +5 -0
- package/src/api/protocol-v2/DeviceUploadNft.ts +61 -9
- package/src/api/protocol-v2/DeviceUploadWallpaper.ts +53 -19
- package/src/api/protocol-v2/helpers.ts +8 -0
- package/src/api/ton/TonSignMessage.ts +5 -3
- package/src/core/index.ts +264 -55
- package/src/data/messages/messages-protocol-v2.json +140 -13
- package/src/data-manager/DataManager.ts +46 -39
- package/src/data-manager/TransportManager.ts +3 -1
- package/src/device/Device.ts +210 -44
- package/src/device/DeviceCommands.ts +27 -18
- package/src/device/DeviceConnector.ts +17 -3
- package/src/device/DevicePool.ts +9 -2
- package/src/device/DeviceStateMapper.ts +30 -24
- package/src/deviceProfile/buildDeviceFeatures.ts +10 -5
- package/src/events/logBlockEvent.ts +14 -1
- package/src/events/ui-request.ts +3 -0
- package/src/index.ts +0 -10
- package/src/protocols/protocol-v2/features.ts +22 -5
- package/src/protocols/protocol-v2/index.ts +2 -0
- package/src/protocols/protocol-v2/resources.ts +110 -147
- package/src/protocols/protocol-v2/unlockPolicyRunner.ts +13 -1
- package/src/protocols/protocol-v2/walletSession.ts +65 -22
- package/src/types/api/firmwareUpdate.ts +1 -1
- package/src/types/api/firmwareUpdatePlan.ts +2 -2
- package/src/types/api/protocolV2.ts +1 -1
- package/src/types/device.ts +2 -1
- package/src/types/settings.ts +6 -34
- package/src/utils/deviceFeaturesCompat.ts +9 -4
- package/src/utils/deviceFeaturesUtils.ts +4 -0
- package/src/utils/deviceInfoUtils.ts +9 -2
- package/src/utils/deviceSettings.ts +11 -4
- package/src/utils/index.ts +1 -0
- package/src/utils/pro2Nft.ts +31 -8
- package/__tests__/firmware-memory-host.test.ts +0 -126
- package/dist/api/firmware/FirmwareMemoryHost.d.ts +0 -22
- package/dist/api/firmware/FirmwareMemoryHost.d.ts.map +0 -1
- package/src/api/firmware/FirmwareMemoryHost.ts +0 -143
|
@@ -328,8 +328,8 @@ export const assertFirmwareUpdatePlan = (value: unknown): FirmwareUpdatePlan =>
|
|
|
328
328
|
}
|
|
329
329
|
assertExactKeys(
|
|
330
330
|
artifact,
|
|
331
|
-
['artifactId', 'role', 'target', 'url', 'container'
|
|
332
|
-
['logicalName', 'targetVersion']
|
|
331
|
+
['artifactId', 'role', 'target', 'url', 'container'],
|
|
332
|
+
['logicalName', 'expectedSize', 'expectedSha256', 'targetVersion']
|
|
333
333
|
);
|
|
334
334
|
const artifactId = assertBoundedString(artifact.artifactId, 'artifact id', 160);
|
|
335
335
|
if (artifactIds.has(artifactId)) {
|
|
@@ -348,15 +348,25 @@ export const assertFirmwareUpdatePlan = (value: unknown): FirmwareUpdatePlan =>
|
|
|
348
348
|
if (artifact.logicalName !== undefined) {
|
|
349
349
|
assertBoundedString(artifact.logicalName, 'logical name', 256);
|
|
350
350
|
}
|
|
351
|
-
if (
|
|
351
|
+
if (
|
|
352
|
+
artifact.expectedSize !== undefined &&
|
|
353
|
+
(!Number.isSafeInteger(artifact.expectedSize) || (artifact.expectedSize as number) <= 0)
|
|
354
|
+
) {
|
|
352
355
|
return planError('Firmware update plan artifact size is invalid');
|
|
353
356
|
}
|
|
354
357
|
if (
|
|
355
|
-
|
|
356
|
-
|
|
358
|
+
artifact.expectedSha256 !== undefined &&
|
|
359
|
+
(typeof artifact.expectedSha256 !== 'string' ||
|
|
360
|
+
!/^[a-f0-9]{64}$/u.test(artifact.expectedSha256))
|
|
357
361
|
) {
|
|
358
362
|
return planError('Firmware update plan artifact digest is invalid');
|
|
359
363
|
}
|
|
364
|
+
if (
|
|
365
|
+
plan.executor === 'v4' &&
|
|
366
|
+
(artifact.expectedSize === undefined || artifact.expectedSha256 === undefined)
|
|
367
|
+
) {
|
|
368
|
+
return planError('Protocol V2 firmware artifact integrity metadata is invalid');
|
|
369
|
+
}
|
|
360
370
|
if (artifact.targetVersion !== undefined) {
|
|
361
371
|
assertBoundedString(artifact.targetVersion, 'target version', 64);
|
|
362
372
|
}
|
|
@@ -644,47 +654,6 @@ const finalizeFirmwareUpdatePlan = ({
|
|
|
644
654
|
});
|
|
645
655
|
};
|
|
646
656
|
|
|
647
|
-
export type ProtocolV2LocalFirmwareUpdatePlanArtifact = {
|
|
648
|
-
artifactId: string;
|
|
649
|
-
target: Exclude<FirmwareUpdateV4Target, 'boot_resources'>;
|
|
650
|
-
container: 'raw' | 'zip';
|
|
651
|
-
logicalName: string;
|
|
652
|
-
expectedSize: number;
|
|
653
|
-
expectedSha256: string;
|
|
654
|
-
targetVersion?: string;
|
|
655
|
-
};
|
|
656
|
-
|
|
657
|
-
export const buildProtocolV2LocalFirmwareUpdatePlan = ({
|
|
658
|
-
features,
|
|
659
|
-
firmwareType,
|
|
660
|
-
platform,
|
|
661
|
-
artifacts,
|
|
662
|
-
}: {
|
|
663
|
-
features: Features;
|
|
664
|
-
firmwareType: EFirmwareType;
|
|
665
|
-
platform: FirmwareUpdatePlatform;
|
|
666
|
-
artifacts: ProtocolV2LocalFirmwareUpdatePlanArtifact[];
|
|
667
|
-
}): FirmwareUpdatePlan => {
|
|
668
|
-
if (artifacts.length === 0) {
|
|
669
|
-
return planError('Protocol V2 local firmware plan has no artifacts');
|
|
670
|
-
}
|
|
671
|
-
const plan = finalizeFirmwareUpdatePlan({
|
|
672
|
-
features,
|
|
673
|
-
firmwareType,
|
|
674
|
-
platform,
|
|
675
|
-
artifacts: artifacts.map(artifact => ({
|
|
676
|
-
...artifact,
|
|
677
|
-
role: artifact.target === 'resource' ? 'resourceBundle' : 'component',
|
|
678
|
-
url: `https://local-firmware.invalid/${encodeURIComponent(artifact.artifactId)}`,
|
|
679
|
-
})),
|
|
680
|
-
targetsToUpdate: artifacts.map(artifact => artifact.target),
|
|
681
|
-
});
|
|
682
|
-
if (plan.executor !== 'v4') {
|
|
683
|
-
return planError('Protocol V2 local firmware plan requires executor v4');
|
|
684
|
-
}
|
|
685
|
-
return plan;
|
|
686
|
-
};
|
|
687
|
-
|
|
688
657
|
export const buildProtocolV2FirmwareUpdatePlan = ({
|
|
689
658
|
features,
|
|
690
659
|
firmwareType,
|
|
@@ -822,13 +791,10 @@ export const buildFirmwareUpdatePlan = ({
|
|
|
822
791
|
} else {
|
|
823
792
|
if (isUpgrade(bootloader) || forcedTargets.has('bootloader')) {
|
|
824
793
|
const bootloaderRelease = asRelease(bootloader);
|
|
825
|
-
const integrity =
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
},
|
|
830
|
-
'Bootloader release'
|
|
831
|
-
);
|
|
794
|
+
const integrity = asIntegrity({
|
|
795
|
+
size: bootloaderRelease?.bootloaderExpectedSize,
|
|
796
|
+
sha256: bootloaderRelease?.bootloaderFingerprint,
|
|
797
|
+
});
|
|
832
798
|
artifacts.push({
|
|
833
799
|
artifactId: 'bootloader',
|
|
834
800
|
role: 'bootloader',
|
|
@@ -850,10 +816,10 @@ export const buildFirmwareUpdatePlan = ({
|
|
|
850
816
|
});
|
|
851
817
|
}
|
|
852
818
|
if (shouldUpdateFirmware) {
|
|
853
|
-
const integrity =
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
);
|
|
819
|
+
const integrity = asIntegrity({
|
|
820
|
+
size: firmwareRelease.expectedSize,
|
|
821
|
+
sha256: firmwareRelease.fingerprint,
|
|
822
|
+
});
|
|
857
823
|
artifacts.push({
|
|
858
824
|
artifactId: 'firmware',
|
|
859
825
|
role: 'firmware',
|
|
@@ -873,19 +839,16 @@ export const buildFirmwareUpdatePlan = ({
|
|
|
873
839
|
platform,
|
|
874
840
|
});
|
|
875
841
|
if (resourceUrl) {
|
|
876
|
-
const integrity =
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
},
|
|
887
|
-
'Legacy resource archive'
|
|
888
|
-
);
|
|
842
|
+
const integrity = asIntegrity({
|
|
843
|
+
size:
|
|
844
|
+
resourceUrl === asString(firmwareRelease.fullResource)
|
|
845
|
+
? firmwareRelease.fullResourceExpectedSize
|
|
846
|
+
: firmwareRelease.resourceExpectedSize,
|
|
847
|
+
sha256:
|
|
848
|
+
resourceUrl === asString(firmwareRelease.fullResource)
|
|
849
|
+
? firmwareRelease.fullResourceFingerprint
|
|
850
|
+
: firmwareRelease.resourceFingerprint,
|
|
851
|
+
});
|
|
889
852
|
artifacts.push({
|
|
890
853
|
artifactId: 'resource',
|
|
891
854
|
role: 'resource',
|
|
@@ -899,13 +862,10 @@ export const buildFirmwareUpdatePlan = ({
|
|
|
899
862
|
}
|
|
900
863
|
if (isUpgrade(ble) || isRecoveryInstall(ble) || forcedTargets.has('ble')) {
|
|
901
864
|
const bleRelease = asRelease(ble);
|
|
902
|
-
const integrity =
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
},
|
|
907
|
-
'BLE release'
|
|
908
|
-
);
|
|
865
|
+
const integrity = asIntegrity({
|
|
866
|
+
size: bleRelease?.expectedSize,
|
|
867
|
+
sha256: bleRelease?.fingerprintWeb ?? bleRelease?.fingerprint,
|
|
868
|
+
});
|
|
909
869
|
artifacts.push({
|
|
910
870
|
artifactId: 'ble',
|
|
911
871
|
role: 'ble',
|
|
@@ -71,6 +71,13 @@ export const getFirmwareUpdateResourceName = (value: unknown): string => {
|
|
|
71
71
|
return resourceName;
|
|
72
72
|
};
|
|
73
73
|
|
|
74
|
+
const getPreparedEntryIdentity = (entryName: unknown): string => {
|
|
75
|
+
getFirmwareUpdateResourceName(entryName);
|
|
76
|
+
// Protocol V2 resource ZIPs can ship the same basename from different
|
|
77
|
+
// directories, such as rom/params.okpkg and bootloader/params.okpkg.
|
|
78
|
+
return (entryName as string).toLowerCase();
|
|
79
|
+
};
|
|
80
|
+
|
|
74
81
|
const assertPreparedEntry = (value: unknown): FirmwareUpdatePreparedEntry => {
|
|
75
82
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
76
83
|
return preparedPlanError('Firmware prepared plan entry must be an object');
|
|
@@ -141,11 +148,8 @@ const assertPreparedArtifacts = ({
|
|
|
141
148
|
}
|
|
142
149
|
if (
|
|
143
150
|
materializedEntries &&
|
|
144
|
-
new Set(
|
|
145
|
-
materializedEntries.
|
|
146
|
-
getFirmwareUpdateResourceName(entry.entryName).toLowerCase()
|
|
147
|
-
)
|
|
148
|
-
).size !== materializedEntries.length
|
|
151
|
+
new Set(materializedEntries.map(entry => getPreparedEntryIdentity(entry.entryName))).size !==
|
|
152
|
+
materializedEntries.length
|
|
149
153
|
) {
|
|
150
154
|
return preparedPlanError('Firmware prepared plan contains duplicate entry names');
|
|
151
155
|
}
|
|
@@ -281,7 +285,7 @@ export const validateFirmwareUpdatePreparedPlan = (value: unknown): FirmwareUpda
|
|
|
281
285
|
const materializedEntryNames =
|
|
282
286
|
artifact.materializedEntries?.map(entry => {
|
|
283
287
|
assertPreparedEntry(entry);
|
|
284
|
-
return
|
|
288
|
+
return getPreparedEntryIdentity(entry.entryName);
|
|
285
289
|
}) ?? [];
|
|
286
290
|
if (new Set(materializedEntryNames).size !== materializedEntryNames.length) {
|
|
287
291
|
return preparedPlanError('Firmware prepared plan contains duplicate entry names');
|
|
@@ -77,11 +77,16 @@ export async function loadProtocolV2FirmwareReleaseContext({
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
const firmwareType = firmwareTypeParam ?? state.identity.firmwareType ?? EFirmwareType.Universal;
|
|
80
|
+
const normalizedFeatures: Features = {
|
|
81
|
+
...features,
|
|
82
|
+
deviceType: state.identity.deviceType,
|
|
83
|
+
firmwareType,
|
|
84
|
+
};
|
|
80
85
|
return {
|
|
81
86
|
state: state as ProtocolV2FirmwareReleaseContext['state'],
|
|
82
|
-
features,
|
|
87
|
+
features: normalizedFeatures,
|
|
83
88
|
firmwareType,
|
|
84
|
-
release: DataManager.getFirmwareLatestRelease(
|
|
89
|
+
release: DataManager.getFirmwareLatestRelease(normalizedFeatures, firmwareType),
|
|
85
90
|
};
|
|
86
91
|
}
|
|
87
92
|
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
import { decode as decodeJpeg } from 'jpeg-js';
|
|
3
|
+
|
|
4
|
+
import { invalidParameter } from './filesystemValidation';
|
|
5
|
+
|
|
6
|
+
const BASE64_PATTERN = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
|
|
7
|
+
const JPEG_CONTAINER_OVERHEAD_BYTES = 64 * 1024;
|
|
8
|
+
const JPEG_MAX_MEMORY_USAGE_IN_MB = 32;
|
|
9
|
+
const JPEG_MAX_RESOLUTION_IN_MP = 1;
|
|
10
|
+
|
|
11
|
+
export function decodeCanonicalBase64({
|
|
12
|
+
value,
|
|
13
|
+
parameterName,
|
|
14
|
+
maxBytes,
|
|
15
|
+
}: {
|
|
16
|
+
value: unknown;
|
|
17
|
+
parameterName: string;
|
|
18
|
+
maxBytes: number;
|
|
19
|
+
}): Uint8Array {
|
|
20
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
21
|
+
throw invalidParameter(`Parameter [${parameterName}] must be a non-empty Base64 string.`);
|
|
22
|
+
}
|
|
23
|
+
if (value.length > Math.ceil(maxBytes / 3) * 4) {
|
|
24
|
+
throw invalidParameter(`Parameter [${parameterName}] exceeds the maximum supported size.`);
|
|
25
|
+
}
|
|
26
|
+
if (value.length % 4 !== 0 || !BASE64_PATTERN.test(value)) {
|
|
27
|
+
throw invalidParameter(`Parameter [${parameterName}] must use canonical Base64 encoding.`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const decoded = Buffer.from(value, 'base64');
|
|
31
|
+
if (decoded.byteLength === 0 || decoded.byteLength > maxBytes) {
|
|
32
|
+
throw invalidParameter(`Parameter [${parameterName}] exceeds the maximum supported size.`);
|
|
33
|
+
}
|
|
34
|
+
if (decoded.toString('base64') !== value) {
|
|
35
|
+
throw invalidParameter(`Parameter [${parameterName}] must use canonical Base64 encoding.`);
|
|
36
|
+
}
|
|
37
|
+
return Uint8Array.from(decoded);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function decodeJpegBase64ToRgba({
|
|
41
|
+
jpegBase64,
|
|
42
|
+
parameterName,
|
|
43
|
+
expectedWidth,
|
|
44
|
+
expectedHeight,
|
|
45
|
+
}: {
|
|
46
|
+
jpegBase64: unknown;
|
|
47
|
+
parameterName: string;
|
|
48
|
+
expectedWidth: number;
|
|
49
|
+
expectedHeight: number;
|
|
50
|
+
}): { width: number; height: number; data: Uint8Array } {
|
|
51
|
+
const jpegBytes = decodeCanonicalBase64({
|
|
52
|
+
value: jpegBase64,
|
|
53
|
+
parameterName,
|
|
54
|
+
maxBytes: expectedWidth * expectedHeight * 8 + JPEG_CONTAINER_OVERHEAD_BYTES,
|
|
55
|
+
});
|
|
56
|
+
if (jpegBytes[0] !== 0xff || jpegBytes[1] !== 0xd8) {
|
|
57
|
+
throw invalidParameter(`Parameter [${parameterName}] must contain a JPEG image.`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let decoded: { width: number; height: number; data: Uint8Array };
|
|
61
|
+
try {
|
|
62
|
+
decoded = decodeJpeg(jpegBytes, {
|
|
63
|
+
useTArray: true,
|
|
64
|
+
formatAsRGBA: true,
|
|
65
|
+
tolerantDecoding: false,
|
|
66
|
+
maxResolutionInMP: JPEG_MAX_RESOLUTION_IN_MP,
|
|
67
|
+
maxMemoryUsageInMB: JPEG_MAX_MEMORY_USAGE_IN_MB,
|
|
68
|
+
});
|
|
69
|
+
} catch {
|
|
70
|
+
throw invalidParameter(`Parameter [${parameterName}] must contain a valid JPEG image.`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (decoded.width !== expectedWidth || decoded.height !== expectedHeight) {
|
|
74
|
+
throw invalidParameter(
|
|
75
|
+
`Parameter [${parameterName}] must contain a ${expectedWidth}x${expectedHeight} JPEG image.`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
const expectedLength = expectedWidth * expectedHeight * 4;
|
|
79
|
+
if (decoded.data.byteLength !== expectedLength) {
|
|
80
|
+
throw invalidParameter(
|
|
81
|
+
`Decoded parameter [${parameterName}] must contain ${expectedLength} RGBA bytes.`
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
return decoded;
|
|
85
|
+
}
|
|
@@ -25,7 +25,7 @@ export default class DeviceFactoryInfoSet extends BaseMethod<DeviceFactoryInfoSe
|
|
|
25
25
|
info: {
|
|
26
26
|
version: this.params.version,
|
|
27
27
|
serial_number: this.params.serial_number,
|
|
28
|
-
|
|
28
|
+
factory_burn_in_completed: this.params.burn_in_completed,
|
|
29
29
|
factory_test_completed: this.params.factory_test_completed,
|
|
30
30
|
manufacture_time: this.params.manufacture_time,
|
|
31
31
|
},
|
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
import { BaseMethod } from '../BaseMethod';
|
|
2
|
-
import {
|
|
3
|
-
PROTOCOL_V2_FIRMWARE_UPDATE_OPTIONS,
|
|
4
|
-
PROTOCOL_V2_FIRMWARE_UPDATE_RESPONSE_TYPES,
|
|
5
|
-
isProtocolV2DeviceDisconnectedError,
|
|
6
|
-
normalizeFirmwareTargets,
|
|
7
|
-
} from './helpers';
|
|
8
|
-
import { UI_REQUEST, createUiMessage } from '../../events/ui-request';
|
|
2
|
+
import { isProtocolV2DeviceDisconnectedError, normalizeFirmwareTargets } from './helpers';
|
|
9
3
|
|
|
10
|
-
import type { KnownDevice } from '../../types';
|
|
11
|
-
import type { MessageFromOneKey } from '@onekeyfe/hd-transport';
|
|
12
4
|
import type { DeviceFirmwareUpdateParams } from './helpers';
|
|
13
5
|
|
|
14
6
|
export default class DeviceFirmwareUpdate extends BaseMethod<DeviceFirmwareUpdateParams> {
|
|
@@ -31,27 +23,13 @@ export default class DeviceFirmwareUpdate extends BaseMethod<DeviceFirmwareUpdat
|
|
|
31
23
|
async run() {
|
|
32
24
|
const targets = normalizeFirmwareTargets(this.params);
|
|
33
25
|
try {
|
|
34
|
-
|
|
26
|
+
await this.device.commands.typedCall('DeviceFirmwareUpdateStage', 'Success', { targets });
|
|
27
|
+
await this.device.commands.call(
|
|
35
28
|
'DeviceFirmwareUpdateRequest',
|
|
36
|
-
|
|
37
|
-
{
|
|
38
|
-
targets,
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
...PROTOCOL_V2_FIRMWARE_UPDATE_OPTIONS,
|
|
42
|
-
onIntermediateResponse: (response: MessageFromOneKey) => {
|
|
43
|
-
if (response.type !== 'DeviceFirmwareUpdateStatus') return;
|
|
44
|
-
this.postMessage(
|
|
45
|
-
createUiMessage(UI_REQUEST.FIRMWARE_PROGRESS, {
|
|
46
|
-
device: this.device.toMessageObject() as KnownDevice,
|
|
47
|
-
progress: 99,
|
|
48
|
-
progressType: 'installingFirmware',
|
|
49
|
-
})
|
|
50
|
-
);
|
|
51
|
-
},
|
|
52
|
-
}
|
|
29
|
+
{},
|
|
30
|
+
{ returnAfterWrite: true }
|
|
53
31
|
);
|
|
54
|
-
return
|
|
32
|
+
return { message: 'Device firmware update started' };
|
|
55
33
|
} catch (error) {
|
|
56
34
|
if (isProtocolV2DeviceDisconnectedError(error)) {
|
|
57
35
|
return {
|
|
@@ -4,7 +4,13 @@ import { invalidParameter } from '../helpers/filesystemValidation';
|
|
|
4
4
|
import type { DeviceFirmwareUpdateStatusGetParams } from './helpers';
|
|
5
5
|
import type { DeviceFirmwareUpdateRecordFields } from '@onekeyfe/hd-transport';
|
|
6
6
|
|
|
7
|
-
const DEVICE_FIRMWARE_UPDATE_STATUS_FIELDS = [
|
|
7
|
+
const DEVICE_FIRMWARE_UPDATE_STATUS_FIELDS = [
|
|
8
|
+
'status',
|
|
9
|
+
'progress_percent',
|
|
10
|
+
'phase_info',
|
|
11
|
+
'payload_version',
|
|
12
|
+
'path',
|
|
13
|
+
] as const;
|
|
8
14
|
|
|
9
15
|
function normalizeStatusFields(
|
|
10
16
|
fields: DeviceFirmwareUpdateStatusGetParams['fields']
|
|
@@ -5,7 +5,7 @@ import { invalidParameter } from '../helpers/filesystemValidation';
|
|
|
5
5
|
|
|
6
6
|
export type DeviceInfoGetTargets = {
|
|
7
7
|
hw?: boolean;
|
|
8
|
-
|
|
8
|
+
main_mcu?: boolean;
|
|
9
9
|
coprocessor?: boolean;
|
|
10
10
|
se1?: boolean;
|
|
11
11
|
se2?: boolean;
|
|
@@ -27,7 +27,7 @@ export type DeviceInfoGetParams = {
|
|
|
27
27
|
|
|
28
28
|
const TARGET_KEYS: (keyof DeviceInfoGetTargets)[] = [
|
|
29
29
|
'hw',
|
|
30
|
-
'
|
|
30
|
+
'main_mcu',
|
|
31
31
|
'coprocessor',
|
|
32
32
|
'se1',
|
|
33
33
|
'se2',
|
|
@@ -39,7 +39,7 @@ const TYPE_KEYS: (keyof DeviceInfoGetTypes)[] = ['version', 'build_id', 'hash',
|
|
|
39
39
|
|
|
40
40
|
const DEFAULT_TARGETS: DeviceInfoGetTargets = {
|
|
41
41
|
hw: true,
|
|
42
|
-
|
|
42
|
+
main_mcu: true,
|
|
43
43
|
coprocessor: true,
|
|
44
44
|
};
|
|
45
45
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { DeviceSessionPinType } from '@onekeyfe/hd-transport';
|
|
2
|
+
|
|
1
3
|
import { BaseMethod } from '../BaseMethod';
|
|
2
4
|
import { normalizeRebootType } from './helpers';
|
|
3
5
|
|
|
@@ -11,6 +13,9 @@ export default class DeviceReboot extends BaseMethod<DeviceRebootParams> {
|
|
|
11
13
|
init() {
|
|
12
14
|
this.skipForceUpdateCheck = true;
|
|
13
15
|
this.useDevicePassphraseState = false;
|
|
16
|
+
this.unlockPolicy = 'unlock-before-run';
|
|
17
|
+
// Device-management action: main PIN or Attach PIN may authorize reboot.
|
|
18
|
+
this.protocolV2PreUnlockPinType = DeviceSessionPinType.Any;
|
|
14
19
|
this.params = {
|
|
15
20
|
rebootType: this.payload.rebootType,
|
|
16
21
|
reboot_type: this.payload.reboot_type,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ERRORS, HardwareErrorCode, createDeviceNotSupportMethodError } from '@onekeyfe/hd-shared';
|
|
2
|
+
import { DeviceSessionPinType } from '@onekeyfe/hd-transport';
|
|
2
3
|
|
|
3
4
|
import { UI_REQUEST, createUiMessage } from '../../events/ui-request';
|
|
4
5
|
import { supportsProtocolV2Message } from '../../protocols/protocol-v2/features';
|
|
@@ -7,21 +8,26 @@ import {
|
|
|
7
8
|
PRO2_NFT_DEFAULT_PACE_MS,
|
|
8
9
|
PRO2_NFT_DEFAULT_TIMEOUT_MS,
|
|
9
10
|
PRO2_NFT_DIRECTORY,
|
|
11
|
+
PRO2_NFT_IMAGE_HEIGHT,
|
|
12
|
+
PRO2_NFT_IMAGE_WIDTH,
|
|
10
13
|
PRO2_NFT_MAX_CHUNK_SIZE,
|
|
11
14
|
PRO2_NFT_MAX_ITEMS,
|
|
12
15
|
PRO2_NFT_MIN_CHUNK_SIZE,
|
|
16
|
+
PRO2_NFT_THUMBNAIL_HEIGHT,
|
|
17
|
+
PRO2_NFT_THUMBNAIL_WIDTH,
|
|
13
18
|
type Pro2NftBundle,
|
|
14
|
-
|
|
15
|
-
buildPro2NftBundle,
|
|
19
|
+
buildPro2NftBundleFromEncodedImages,
|
|
16
20
|
getCompletePro2NftBasenames,
|
|
17
21
|
} from '../../utils/pro2Nft';
|
|
22
|
+
import { encodePro2Image } from '../../utils/pro2Wallpaper';
|
|
18
23
|
import { BaseMethod } from '../BaseMethod';
|
|
24
|
+
import { decodeJpegBase64ToRgba } from '../helpers/base64Data';
|
|
19
25
|
import { invalidParameter } from '../helpers/filesystemValidation';
|
|
20
26
|
import { writeProtocolV2File } from '../helpers/protocolV2FileWrite';
|
|
21
27
|
|
|
22
28
|
export type DeviceUploadNftParams = {
|
|
23
|
-
|
|
24
|
-
|
|
29
|
+
imageJpegBase64: string;
|
|
30
|
+
thumbnailJpegBase64: string;
|
|
25
31
|
title: string;
|
|
26
32
|
subtitle: string;
|
|
27
33
|
timestampMs?: number;
|
|
@@ -54,8 +60,8 @@ export default class DeviceUploadNft extends BaseMethod<DeviceUploadNftParams> {
|
|
|
54
60
|
|
|
55
61
|
init() {
|
|
56
62
|
const {
|
|
57
|
-
|
|
58
|
-
|
|
63
|
+
imageJpegBase64,
|
|
64
|
+
thumbnailJpegBase64,
|
|
59
65
|
title,
|
|
60
66
|
subtitle,
|
|
61
67
|
timestampMs = Date.now(),
|
|
@@ -79,9 +85,55 @@ export default class DeviceUploadNft extends BaseMethod<DeviceUploadNftParams> {
|
|
|
79
85
|
throw invalidParameter('Parameter [timeoutMs] must be a positive integer.');
|
|
80
86
|
}
|
|
81
87
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
88
|
+
const encodedImage = (() => {
|
|
89
|
+
const decoded = decodeJpegBase64ToRgba({
|
|
90
|
+
jpegBase64: imageJpegBase64,
|
|
91
|
+
parameterName: 'imageJpegBase64',
|
|
92
|
+
expectedWidth: PRO2_NFT_IMAGE_WIDTH,
|
|
93
|
+
expectedHeight: PRO2_NFT_IMAGE_HEIGHT,
|
|
94
|
+
});
|
|
95
|
+
return encodePro2Image({
|
|
96
|
+
width: PRO2_NFT_IMAGE_WIDTH,
|
|
97
|
+
height: PRO2_NFT_IMAGE_HEIGHT,
|
|
98
|
+
rgba: decoded.data,
|
|
99
|
+
alphaMode: 'black-background',
|
|
100
|
+
}).data;
|
|
101
|
+
})();
|
|
102
|
+
const encodedThumbnail = (() => {
|
|
103
|
+
const decoded = decodeJpegBase64ToRgba({
|
|
104
|
+
jpegBase64: thumbnailJpegBase64,
|
|
105
|
+
parameterName: 'thumbnailJpegBase64',
|
|
106
|
+
expectedWidth: PRO2_NFT_THUMBNAIL_WIDTH,
|
|
107
|
+
expectedHeight: PRO2_NFT_THUMBNAIL_HEIGHT,
|
|
108
|
+
});
|
|
109
|
+
return encodePro2Image({
|
|
110
|
+
width: PRO2_NFT_THUMBNAIL_WIDTH,
|
|
111
|
+
height: PRO2_NFT_THUMBNAIL_HEIGHT,
|
|
112
|
+
rgba: decoded.data,
|
|
113
|
+
alphaMode: 'black-background',
|
|
114
|
+
}).data;
|
|
115
|
+
})();
|
|
116
|
+
this.bundle = buildPro2NftBundleFromEncodedImages({
|
|
117
|
+
image: encodedImage,
|
|
118
|
+
thumbnail: encodedThumbnail,
|
|
119
|
+
title,
|
|
120
|
+
subtitle,
|
|
121
|
+
timestampMs,
|
|
122
|
+
});
|
|
123
|
+
this.params = {
|
|
124
|
+
imageJpegBase64,
|
|
125
|
+
thumbnailJpegBase64,
|
|
126
|
+
title,
|
|
127
|
+
subtitle,
|
|
128
|
+
timestampMs,
|
|
129
|
+
chunkSize,
|
|
130
|
+
paceMs,
|
|
131
|
+
timeoutMs,
|
|
132
|
+
};
|
|
133
|
+
this.unlockPolicy = 'unlock-before-run';
|
|
134
|
+
// File writes and NftUpdate require an unlocked device. Either PIN may
|
|
135
|
+
// authorize this device-management action.
|
|
136
|
+
this.protocolV2PreUnlockPinType = DeviceSessionPinType.Any;
|
|
85
137
|
this.skipForceUpdateCheck = true;
|
|
86
138
|
this.useDevicePassphraseState = false;
|
|
87
139
|
}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { blake2s } from '@noble/hashes/blake2s';
|
|
2
2
|
import { bytesToHex } from '@noble/hashes/utils';
|
|
3
|
+
import { createDeviceNotSupportMethodError } from '@onekeyfe/hd-shared';
|
|
4
|
+
import { DeviceSessionPinType } from '@onekeyfe/hd-transport';
|
|
3
5
|
|
|
4
6
|
import { BaseMethod } from '../BaseMethod';
|
|
7
|
+
import { decodeJpegBase64ToRgba } from '../helpers/base64Data';
|
|
5
8
|
import { invalidParameter } from '../helpers/filesystemValidation';
|
|
6
9
|
import { writeProtocolV2File } from '../helpers/protocolV2FileWrite';
|
|
7
10
|
import { UI_REQUEST, createUiMessage } from '../../events/ui-request';
|
|
11
|
+
import { supportsProtocolV2Message } from '../../protocols/protocol-v2/features';
|
|
12
|
+
import { LoggerNames, getLogger } from '../../utils';
|
|
8
13
|
import {
|
|
9
14
|
PRO2_WALLPAPER_HEIGHT,
|
|
10
15
|
PRO2_WALLPAPER_WIDTH,
|
|
@@ -13,9 +18,7 @@ import {
|
|
|
13
18
|
} from '../../utils/pro2Wallpaper';
|
|
14
19
|
|
|
15
20
|
export type DeviceUploadWallpaperParams = {
|
|
16
|
-
|
|
17
|
-
height: number;
|
|
18
|
-
rgba: Uint8Array | ArrayBuffer;
|
|
21
|
+
jpegBase64: string;
|
|
19
22
|
fileName?: string;
|
|
20
23
|
chunkSize?: number;
|
|
21
24
|
};
|
|
@@ -29,6 +32,10 @@ export type DeviceUploadWallpaperResponse = {
|
|
|
29
32
|
|
|
30
33
|
const WALLPAPER_DIRECTORY = 'vol1:/wallpapers';
|
|
31
34
|
const SAFE_FILE_NAME = /^[A-Za-z0-9_-]+(?:\.bin)?$/;
|
|
35
|
+
const DEVICE_SETTINGS_SET_MESSAGE_TYPE = 60412;
|
|
36
|
+
const FILESYSTEM_FILE_WRITE_MESSAGE_TYPE = 60805;
|
|
37
|
+
const FILESYSTEM_DIR_MAKE_MESSAGE_TYPE = 60809;
|
|
38
|
+
const Log = getLogger(LoggerNames.Method);
|
|
32
39
|
|
|
33
40
|
function normalizeFileName(fileName: string | undefined, data: Uint8Array): string {
|
|
34
41
|
if (fileName !== undefined && (!fileName || !SAFE_FILE_NAME.test(fileName))) {
|
|
@@ -54,31 +61,48 @@ export default class DeviceUploadWallpaper extends BaseMethod<DeviceUploadWallpa
|
|
|
54
61
|
private path = '';
|
|
55
62
|
|
|
56
63
|
init() {
|
|
57
|
-
const {
|
|
58
|
-
if (width !== PRO2_WALLPAPER_WIDTH || height !== PRO2_WALLPAPER_HEIGHT) {
|
|
59
|
-
throw invalidParameter(
|
|
60
|
-
`Pro2 wallpaper dimensions must be ${PRO2_WALLPAPER_WIDTH}x${PRO2_WALLPAPER_HEIGHT}.`
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
if (!(rgba instanceof ArrayBuffer) && !ArrayBuffer.isView(rgba)) {
|
|
64
|
-
throw invalidParameter('Parameter [rgba] must be an ArrayBuffer or Uint8Array.');
|
|
65
|
-
}
|
|
64
|
+
const { jpegBase64, fileName, chunkSize } = this.payload;
|
|
66
65
|
if (chunkSize !== undefined && (!Number.isInteger(chunkSize) || chunkSize <= 0)) {
|
|
67
66
|
throw invalidParameter('Parameter [chunkSize] must be a positive integer.');
|
|
68
67
|
}
|
|
69
68
|
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
69
|
+
const decoded = decodeJpegBase64ToRgba({
|
|
70
|
+
jpegBase64,
|
|
71
|
+
parameterName: 'jpegBase64',
|
|
72
|
+
expectedWidth: PRO2_WALLPAPER_WIDTH,
|
|
73
|
+
expectedHeight: PRO2_WALLPAPER_HEIGHT,
|
|
74
|
+
});
|
|
75
|
+
this.encoded = encodePro2Wallpaper({
|
|
76
|
+
width: PRO2_WALLPAPER_WIDTH,
|
|
77
|
+
height: PRO2_WALLPAPER_HEIGHT,
|
|
78
|
+
rgba: decoded.data,
|
|
79
|
+
});
|
|
75
80
|
this.path = `${WALLPAPER_DIRECTORY}/${normalizeFileName(fileName, this.encoded.data)}`;
|
|
76
|
-
this.params = {
|
|
77
|
-
this.unlockPolicy = '
|
|
81
|
+
this.params = { jpegBase64, fileName, chunkSize };
|
|
82
|
+
this.unlockPolicy = 'unlock-before-run';
|
|
83
|
+
// File writes and wallpaper apply require an unlocked device. Either PIN
|
|
84
|
+
// may authorize this device-management action.
|
|
85
|
+
this.protocolV2PreUnlockPinType = DeviceSessionPinType.Any;
|
|
78
86
|
this.skipForceUpdateCheck = true;
|
|
79
87
|
this.useDevicePassphraseState = false;
|
|
80
88
|
}
|
|
81
89
|
|
|
90
|
+
private async assertCapabilities() {
|
|
91
|
+
const protocolInfo = await this.device.ensureProtocolV2RuntimeContext();
|
|
92
|
+
const requiredMessageTypes = [
|
|
93
|
+
DEVICE_SETTINGS_SET_MESSAGE_TYPE,
|
|
94
|
+
FILESYSTEM_FILE_WRITE_MESSAGE_TYPE,
|
|
95
|
+
FILESYSTEM_DIR_MAKE_MESSAGE_TYPE,
|
|
96
|
+
];
|
|
97
|
+
if (
|
|
98
|
+
requiredMessageTypes.some(
|
|
99
|
+
messageType => !supportsProtocolV2Message(protocolInfo, messageType)
|
|
100
|
+
)
|
|
101
|
+
) {
|
|
102
|
+
throw createDeviceNotSupportMethodError(this.name, this.device.getCurrentFirmwareType());
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
82
106
|
private async ensureDirectory() {
|
|
83
107
|
if (this.directoryReady) return;
|
|
84
108
|
try {
|
|
@@ -119,11 +143,21 @@ export default class DeviceUploadWallpaper extends BaseMethod<DeviceUploadWallpa
|
|
|
119
143
|
async run(): Promise<DeviceUploadWallpaperResponse> {
|
|
120
144
|
const { encoded } = this;
|
|
121
145
|
if (!encoded) throw invalidParameter('Wallpaper data has not been initialized.');
|
|
146
|
+
await this.assertCapabilities();
|
|
122
147
|
await this.ensureDirectory();
|
|
123
148
|
await this.upload();
|
|
124
149
|
const response = await this.device.commands.typedCall('DeviceSettingsSet', 'Success', {
|
|
125
150
|
settings: { wallpaper_path: this.path },
|
|
126
151
|
});
|
|
152
|
+
try {
|
|
153
|
+
await this.device.refreshProtocolV2SettingsAfterMutation();
|
|
154
|
+
} catch (error) {
|
|
155
|
+
// The wallpaper is already applied. A transient read-back failure must not
|
|
156
|
+
// make callers retry the completed file upload.
|
|
157
|
+
Log.warn('Protocol V2 wallpaper settings refresh failed after apply', {
|
|
158
|
+
error: error instanceof Error ? error.message : String(error),
|
|
159
|
+
});
|
|
160
|
+
}
|
|
127
161
|
return {
|
|
128
162
|
path: this.path,
|
|
129
163
|
size: encoded.data.byteLength,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DeviceRebootType } from '@onekeyfe/hd-transport';
|
|
2
|
+
import { HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
3
|
|
|
3
4
|
import { invalidParameter, validateNonEmptyString } from '../helpers/filesystemValidation';
|
|
4
5
|
import { ProtocolV2FirmwareTargetType } from '../../protocols/protocol-v2/firmware';
|
|
@@ -103,6 +104,13 @@ export const getProtocolV2UnknownErrorText = (error: unknown) => {
|
|
|
103
104
|
};
|
|
104
105
|
|
|
105
106
|
export const isProtocolV2DeviceDisconnectedError = (error: unknown) => {
|
|
107
|
+
const errorCode =
|
|
108
|
+
error && typeof error === 'object'
|
|
109
|
+
? (error as { errorCode?: number; code?: number }).errorCode ??
|
|
110
|
+
(error as { errorCode?: number; code?: number }).code
|
|
111
|
+
: undefined;
|
|
112
|
+
if (errorCode === HardwareErrorCode.BleDeviceDisconnected) return true;
|
|
113
|
+
|
|
106
114
|
const message = getProtocolV2UnknownErrorText(error).toLowerCase();
|
|
107
115
|
const compactMessage = message.replace(/\s+/g, '');
|
|
108
116
|
return (
|