@onekeyfe/hd-core 1.2.0-alpha.54 → 1.2.0-alpha.56
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 +231 -0
- package/__tests__/DeviceCommands.test.ts +45 -0
- package/__tests__/DeviceEventRegistration.test.ts +6 -0
- package/__tests__/check-all-firmware-release-protocol-v2.test.ts +198 -3
- package/__tests__/connectSettings.test.ts +5 -47
- package/__tests__/device-lifecycle-events.test.ts +105 -3
- package/__tests__/device-state-contract.test.ts +1 -0
- package/__tests__/device-state-mapper.test.ts +1 -1
- package/__tests__/deviceSettings.test.ts +1 -1
- package/__tests__/deviceUploadNft.test.ts +293 -0
- package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +31 -59
- package/__tests__/get-device-state.test.ts +132 -12
- package/__tests__/homescreen.test.ts +41 -1
- package/__tests__/kaspaSignTransaction.test.ts +3 -26
- package/__tests__/logBlockEvent.test.ts +1 -1
- package/__tests__/method-protocol-support.test.ts +19 -0
- package/__tests__/open-wallet-session.test.ts +568 -37
- package/__tests__/pro2Nft.test.ts +108 -0
- package/__tests__/protocol-binding.test.ts +89 -0
- package/__tests__/protocol-v2-resources.test.ts +286 -0
- package/__tests__/protocol-v2-ui-lifecycle.test.ts +91 -0
- package/__tests__/protocol-v2-unlock-policy.test.ts +201 -35
- package/__tests__/protocol-v2.test.ts +1353 -1011
- package/__tests__/protocolV2FileWrite.test.ts +39 -0
- package/__tests__/protocolV2UiInteraction.test.ts +63 -0
- package/__tests__/public-pro2-api-boundary.test.ts +1 -0
- package/__tests__/search-devices.test.ts +12 -3
- package/__tests__/uiProgressThrottle.test.ts +74 -0
- package/__tests__/uiPromiseRegistry.test.ts +86 -0
- package/dist/api/BaseMethod.d.ts +3 -1
- package/dist/api/BaseMethod.d.ts.map +1 -1
- package/dist/api/CheckAllFirmwareRelease.d.ts +2 -1
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/DetectDeviceConnectProtocol.d.ts +7 -0
- package/dist/api/DetectDeviceConnectProtocol.d.ts.map +1 -0
- package/dist/api/FirmwareUpdate.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV2.d.ts +0 -11
- package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts +3 -7
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +11 -25
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/GetPassphraseState.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/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
- package/dist/api/device/DeviceUnlock.d.ts +2 -2
- package/dist/api/device/DeviceUnlock.d.ts.map +1 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts +1 -5
- package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +0 -9
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
- package/dist/api/firmware/getBinary.d.ts +0 -7
- package/dist/api/firmware/getBinary.d.ts.map +1 -1
- package/dist/api/firmware/updateBootloader.d.ts +0 -2
- package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/uploadFirmware.d.ts +1 -9
- package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
- package/dist/api/helpers/protocolV2FileWrite.d.ts +2 -0
- package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/kaspa/KaspaSignTransaction.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts +31 -0
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -0
- package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts.map +1 -1
- package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
- package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
- package/dist/core/deviceEventRegistration.d.ts +2 -0
- package/dist/core/deviceEventRegistration.d.ts.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/uiPromiseRegistry.d.ts +4 -0
- package/dist/core/uiPromiseRegistry.d.ts.map +1 -0
- package/dist/data-manager/DataManager.d.ts +4 -2
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/data-manager/connectSettings.d.ts.map +1 -1
- package/dist/device/Device.d.ts +29 -6
- 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/DevicePool.d.ts.map +1 -1
- package/dist/events/device.d.ts +4 -0
- package/dist/events/device.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/events/ui-promise.d.ts +4 -2
- package/dist/events/ui-promise.d.ts.map +1 -1
- package/dist/events/ui-request.d.ts +31 -2
- package/dist/events/ui-request.d.ts.map +1 -1
- package/dist/events/ui-response.d.ts +10 -2
- package/dist/events/ui-response.d.ts.map +1 -1
- package/dist/index.d.ts +214 -231
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2634 -3530
- package/dist/inject.d.ts +6 -1
- package/dist/inject.d.ts.map +1 -1
- package/dist/lowLevelInject.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/features.d.ts +0 -4
- package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/firmware.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/resources.d.ts +30 -0
- package/dist/protocols/protocol-v2/resources.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/uiInteraction.d.ts +7 -4
- package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockPolicy.d.ts +1 -3
- package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +22 -0
- package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/walletSession.d.ts +6 -1
- package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
- package/dist/topLevelInject.d.ts.map +1 -1
- package/dist/types/api/checkAllFirmwareRelease.d.ts +2 -4
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/detectDeviceConnectProtocol.d.ts +4 -0
- package/dist/types/api/detectDeviceConnectProtocol.d.ts.map +1 -0
- package/dist/types/api/deviceUnlock.d.ts +5 -1
- package/dist/types/api/deviceUnlock.d.ts.map +1 -1
- package/dist/types/api/deviceUpdateBootloader.d.ts +0 -6
- package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
- package/dist/types/api/export.d.ts +2 -4
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdate.d.ts +2 -70
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +7 -10
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/protocolV2.d.ts +3 -0
- package/dist/types/api/protocolV2.d.ts.map +1 -1
- package/dist/types/device.d.ts.map +1 -1
- package/dist/types/params.d.ts +1 -0
- package/dist/types/params.d.ts.map +1 -1
- package/dist/types/settings.d.ts +22 -13
- package/dist/types/settings.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesCompat.d.ts +0 -1
- package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesUtils.d.ts +4 -0
- package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
- package/dist/utils/homescreen.d.ts +4 -0
- package/dist/utils/homescreen.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 +31 -0
- package/dist/utils/pro2Nft.d.ts.map +1 -0
- package/dist/utils/pro2Wallpaper.d.ts +10 -0
- package/dist/utils/pro2Wallpaper.d.ts.map +1 -1
- package/dist/utils/uiProgressThrottle.d.ts +3 -0
- package/dist/utils/uiProgressThrottle.d.ts.map +1 -0
- package/package.json +4 -4
- package/src/api/BaseMethod.ts +8 -10
- package/src/api/CheckAllFirmwareRelease.ts +54 -57
- package/src/api/DetectDeviceConnectProtocol.ts +18 -0
- package/src/api/FirmwareUpdate.ts +7 -15
- package/src/api/FirmwareUpdateV2.ts +126 -316
- package/src/api/FirmwareUpdateV3.ts +63 -265
- package/src/api/FirmwareUpdateV4.ts +584 -975
- package/src/api/GetPassphraseState.ts +7 -1
- package/src/api/OpenWalletSession.ts +70 -17
- package/src/api/SearchDevices.ts +3 -1
- package/src/api/allnetwork/AllNetworkGetAddress.ts +21 -21
- package/src/api/allnetwork/AllNetworkGetAddressBase.ts +34 -11
- package/src/api/device/DeviceUnlock.ts +8 -3
- package/src/api/device/DeviceUpdateBootloader.ts +6 -122
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +16 -83
- package/src/api/firmware/updateBootloader.ts +4 -19
- package/src/api/firmware/uploadFirmware.ts +39 -144
- package/src/api/helpers/protocolV2FileWrite.ts +27 -7
- package/src/api/index.ts +2 -0
- package/src/api/kaspa/KaspaSignTransaction.ts +1 -12
- package/src/api/protocol-v2/DeviceUploadNft.ts +189 -0
- package/src/api/protocol-v2/ProtocolInfoRequest.ts +3 -1
- package/src/api/protocol-v2/helpers.ts +1 -0
- package/src/core/deviceEventRegistration.ts +4 -0
- package/src/core/index.ts +167 -83
- package/src/core/uiPromiseRegistry.ts +41 -0
- package/src/data/messages/messages-protocol-v2.json +25 -0
- package/src/data-manager/DataManager.ts +71 -39
- package/src/data-manager/connectSettings.ts +0 -11
- package/src/device/Device.ts +259 -43
- package/src/device/DeviceCommands.ts +7 -1
- package/src/device/DevicePool.ts +7 -2
- package/src/events/device.ts +4 -0
- package/src/events/logBlockEvent.ts +1 -0
- package/src/events/ui-promise.ts +4 -2
- package/src/events/ui-request.ts +36 -2
- package/src/events/ui-response.ts +12 -2
- package/src/index.ts +0 -5
- package/src/inject.ts +60 -24
- package/src/lowLevelInject.ts +7 -8
- package/src/protocols/protocol-v2/features.ts +10 -7
- package/src/protocols/protocol-v2/firmware.ts +2 -0
- package/src/protocols/protocol-v2/resources.ts +359 -0
- package/src/protocols/protocol-v2/uiInteraction.ts +46 -6
- package/src/protocols/protocol-v2/unlockPolicy.ts +1 -105
- package/src/protocols/protocol-v2/unlockPolicyRunner.ts +118 -0
- package/src/protocols/protocol-v2/walletSession.ts +214 -36
- package/src/topLevelInject.ts +7 -8
- package/src/types/api/checkAllFirmwareRelease.ts +2 -4
- package/src/types/api/detectDeviceConnectProtocol.ts +6 -0
- package/src/types/api/deviceUnlock.ts +12 -1
- package/src/types/api/deviceUpdateBootloader.ts +0 -6
- package/src/types/api/export.ts +1 -18
- package/src/types/api/firmwareUpdate.ts +3 -76
- package/src/types/api/index.ts +13 -14
- package/src/types/api/protocolV2.ts +13 -0
- package/src/types/device.ts +3 -0
- package/src/types/params.ts +7 -1
- package/src/types/settings.ts +42 -13
- package/src/utils/deviceFeaturesCompat.ts +0 -6
- package/src/utils/deviceFeaturesUtils.ts +8 -0
- package/src/utils/homescreen.ts +32 -6
- package/src/utils/index.ts +6 -1
- package/src/utils/pro2Nft.ts +142 -0
- package/src/utils/pro2Wallpaper.ts +35 -8
- package/src/utils/uiProgressThrottle.ts +63 -0
- package/__tests__/device-initialize-timeout.test.ts +0 -56
- package/__tests__/firmware-update/check-all-firmware-release.test.ts +0 -175
- package/__tests__/firmware-update/firmware-artifact-source.test.ts +0 -119
- package/__tests__/firmware-update/firmware-host-binding.test.ts +0 -70
- package/__tests__/firmware-update/firmware-preparation-error.test.ts +0 -27
- package/__tests__/firmware-update/firmware-update-bootloader-poll.test.ts +0 -200
- package/__tests__/firmware-update/firmware-update-capabilities.test.ts +0 -13
- package/__tests__/firmware-update/firmware-update-plan-bootloader-identity.test.ts +0 -294
- package/__tests__/firmware-update/firmware-update-plan.test.ts +0 -593
- package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +0 -213
- package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +0 -58
- package/__tests__/firmware-update/firmware-upload-source.test.ts +0 -70
- package/dist/api/firmware/FirmwareArtifactSource.d.ts +0 -25
- package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareHostBinding.d.ts +0 -6
- package/dist/api/firmware/FirmwareHostBinding.d.ts.map +0 -1
- package/dist/api/firmware/FirmwarePreparationError.d.ts +0 -3
- package/dist/api/firmware/FirmwarePreparationError.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +0 -3
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +0 -25
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +0 -32
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +0 -1
- package/dist/api/firmware/progressThrottle.d.ts +0 -3
- package/dist/api/firmware/progressThrottle.d.ts.map +0 -1
- package/dist/protocols/protocol-v2/lockedError.d.ts +0 -2
- package/dist/protocols/protocol-v2/lockedError.d.ts.map +0 -1
- package/dist/protocols/protocol-v2/unlockRetry.d.ts +0 -10
- package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdateCapabilities.d.ts +0 -9
- package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdatePlan.d.ts +0 -28
- package/dist/types/api/firmwareUpdatePlan.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +0 -42
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +0 -1
- package/src/api/firmware/FirmwareArtifactSource.ts +0 -278
- package/src/api/firmware/FirmwareHostBinding.ts +0 -100
- package/src/api/firmware/FirmwarePreparationError.ts +0 -12
- package/src/api/firmware/FirmwareUpdateCapabilities.ts +0 -9
- package/src/api/firmware/FirmwareUpdatePlan.ts +0 -772
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +0 -415
- package/src/api/firmware/progressThrottle.ts +0 -44
- package/src/protocols/protocol-v2/lockedError.ts +0 -10
- package/src/protocols/protocol-v2/unlockRetry.ts +0 -109
- package/src/types/api/firmwareUpdateCapabilities.ts +0 -9
- package/src/types/api/firmwareUpdatePlan.ts +0 -38
- package/src/types/api/firmwareUpdatePreparedPlan.ts +0 -53
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { ERRORS, HardwareErrorCode, createDeviceNotSupportMethodError } from '@onekeyfe/hd-shared';
|
|
2
|
+
|
|
3
|
+
import { UI_REQUEST, createUiMessage } from '../../events/ui-request';
|
|
4
|
+
import { supportsProtocolV2Message } from '../../protocols/protocol-v2/features';
|
|
5
|
+
import {
|
|
6
|
+
PRO2_NFT_DEFAULT_CHUNK_SIZE,
|
|
7
|
+
PRO2_NFT_DEFAULT_PACE_MS,
|
|
8
|
+
PRO2_NFT_DEFAULT_TIMEOUT_MS,
|
|
9
|
+
PRO2_NFT_DIRECTORY,
|
|
10
|
+
PRO2_NFT_MAX_CHUNK_SIZE,
|
|
11
|
+
PRO2_NFT_MAX_ITEMS,
|
|
12
|
+
PRO2_NFT_MIN_CHUNK_SIZE,
|
|
13
|
+
type Pro2NftBundle,
|
|
14
|
+
type Pro2NftImage,
|
|
15
|
+
buildPro2NftBundle,
|
|
16
|
+
getCompletePro2NftBasenames,
|
|
17
|
+
} from '../../utils/pro2Nft';
|
|
18
|
+
import { BaseMethod } from '../BaseMethod';
|
|
19
|
+
import { invalidParameter } from '../helpers/filesystemValidation';
|
|
20
|
+
import { isProtocolV2ResponseTimeout, writeProtocolV2File } from '../helpers/protocolV2FileWrite';
|
|
21
|
+
|
|
22
|
+
export type DeviceUploadNftParams = {
|
|
23
|
+
image: Pro2NftImage;
|
|
24
|
+
thumbnail: Pro2NftImage;
|
|
25
|
+
title: string;
|
|
26
|
+
subtitle: string;
|
|
27
|
+
timestampMs?: number;
|
|
28
|
+
chunkSize?: number;
|
|
29
|
+
paceMs?: number;
|
|
30
|
+
timeoutMs?: number;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type DeviceUploadNftResponse = {
|
|
34
|
+
basename: string;
|
|
35
|
+
imagePath: string;
|
|
36
|
+
thumbnailPath: string;
|
|
37
|
+
metadataPath: string;
|
|
38
|
+
totalSize: number;
|
|
39
|
+
nftUpdated: true;
|
|
40
|
+
message?: string;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const FILESYSTEM_FILE_WRITE_MESSAGE_TYPE = 60805;
|
|
44
|
+
const FILESYSTEM_DIR_LIST_MESSAGE_TYPE = 60808;
|
|
45
|
+
const NFT_UPDATE_MESSAGE_TYPE = 61500;
|
|
46
|
+
|
|
47
|
+
export default class DeviceUploadNft extends BaseMethod<DeviceUploadNftParams> {
|
|
48
|
+
private bundle?: Pro2NftBundle;
|
|
49
|
+
|
|
50
|
+
getSupportedProtocols() {
|
|
51
|
+
return ['V2'] as const;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
init() {
|
|
55
|
+
const {
|
|
56
|
+
image,
|
|
57
|
+
thumbnail,
|
|
58
|
+
title,
|
|
59
|
+
subtitle,
|
|
60
|
+
timestampMs = Date.now(),
|
|
61
|
+
chunkSize = PRO2_NFT_DEFAULT_CHUNK_SIZE,
|
|
62
|
+
paceMs = PRO2_NFT_DEFAULT_PACE_MS,
|
|
63
|
+
timeoutMs = PRO2_NFT_DEFAULT_TIMEOUT_MS,
|
|
64
|
+
} = this.payload;
|
|
65
|
+
if (
|
|
66
|
+
!Number.isInteger(chunkSize) ||
|
|
67
|
+
chunkSize < PRO2_NFT_MIN_CHUNK_SIZE ||
|
|
68
|
+
chunkSize > PRO2_NFT_MAX_CHUNK_SIZE
|
|
69
|
+
) {
|
|
70
|
+
throw invalidParameter(
|
|
71
|
+
`Parameter [chunkSize] must be an integer between ${PRO2_NFT_MIN_CHUNK_SIZE} and ${PRO2_NFT_MAX_CHUNK_SIZE}.`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
if (!Number.isInteger(paceMs) || paceMs < 0) {
|
|
75
|
+
throw invalidParameter('Parameter [paceMs] must be a non-negative integer.');
|
|
76
|
+
}
|
|
77
|
+
if (!Number.isInteger(timeoutMs) || timeoutMs <= 0) {
|
|
78
|
+
throw invalidParameter('Parameter [timeoutMs] must be a positive integer.');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
this.bundle = buildPro2NftBundle({ image, thumbnail, title, subtitle, timestampMs });
|
|
82
|
+
this.params = { image, thumbnail, title, subtitle, timestampMs, chunkSize, paceMs, timeoutMs };
|
|
83
|
+
this.unlockPolicy = 'none';
|
|
84
|
+
this.skipForceUpdateCheck = true;
|
|
85
|
+
this.useDevicePassphraseState = false;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private async assertCapabilities() {
|
|
89
|
+
const protocolInfo = await this.device.ensureProtocolV2RuntimeContext();
|
|
90
|
+
const hasFileWrite = supportsProtocolV2Message(
|
|
91
|
+
protocolInfo,
|
|
92
|
+
FILESYSTEM_FILE_WRITE_MESSAGE_TYPE
|
|
93
|
+
);
|
|
94
|
+
const hasDirList = supportsProtocolV2Message(protocolInfo, FILESYSTEM_DIR_LIST_MESSAGE_TYPE);
|
|
95
|
+
const hasNftUpdate = supportsProtocolV2Message(protocolInfo, NFT_UPDATE_MESSAGE_TYPE);
|
|
96
|
+
if (!hasFileWrite || !hasDirList || !hasNftUpdate) {
|
|
97
|
+
throw createDeviceNotSupportMethodError(this.name, this.device.getCurrentFirmwareType());
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private async assertStorageCapacity(basename: string) {
|
|
102
|
+
const { message } = await this.device.commands.typedCall(
|
|
103
|
+
'FilesystemDirList',
|
|
104
|
+
'FilesystemDir',
|
|
105
|
+
{ path: PRO2_NFT_DIRECTORY, depth: 1 },
|
|
106
|
+
{ timeoutMs: this.params.timeoutMs }
|
|
107
|
+
);
|
|
108
|
+
const existingBasenames = getCompletePro2NftBasenames(message.child_files);
|
|
109
|
+
if (existingBasenames.size >= PRO2_NFT_MAX_ITEMS && !existingBasenames.has(basename)) {
|
|
110
|
+
throw ERRORS.TypedError(HardwareErrorCode.NftStorageLimitReached, undefined, {
|
|
111
|
+
count: existingBasenames.size,
|
|
112
|
+
limit: PRO2_NFT_MAX_ITEMS,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private async updateNft(basename: string) {
|
|
118
|
+
const params = { file_name_no_ext: basename };
|
|
119
|
+
const options = { timeoutMs: this.params.timeoutMs };
|
|
120
|
+
try {
|
|
121
|
+
return await this.device.commands.typedCall('NftUpdate', 'Success', params, options);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
if (!isProtocolV2ResponseTimeout(error)) {
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
this.throwIfAborted();
|
|
127
|
+
return this.device.commands.typedCall('NftUpdate', 'Success', params, options);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async run(): Promise<DeviceUploadNftResponse> {
|
|
132
|
+
const { bundle } = this;
|
|
133
|
+
if (!bundle) throw invalidParameter('NFT data has not been initialized.');
|
|
134
|
+
|
|
135
|
+
await this.assertCapabilities();
|
|
136
|
+
this.throwIfAborted();
|
|
137
|
+
await this.assertStorageCapacity(bundle.basename);
|
|
138
|
+
this.throwIfAborted();
|
|
139
|
+
|
|
140
|
+
const files = [
|
|
141
|
+
{ path: `${PRO2_NFT_DIRECTORY}/${bundle.basename}.bin`, data: bundle.image },
|
|
142
|
+
{ path: `${PRO2_NFT_DIRECTORY}/${bundle.basename}_m.bin`, data: bundle.thumbnail },
|
|
143
|
+
{ path: `${PRO2_NFT_DIRECTORY}/${bundle.basename}.json`, data: bundle.metadata },
|
|
144
|
+
];
|
|
145
|
+
const totalSize = files.reduce((sum, file) => sum + file.data.byteLength, 0);
|
|
146
|
+
let transferredBeforeFile = 0;
|
|
147
|
+
|
|
148
|
+
for (const file of files) {
|
|
149
|
+
const transferredAtFileStart = transferredBeforeFile;
|
|
150
|
+
await writeProtocolV2File({
|
|
151
|
+
commands: this.device.commands,
|
|
152
|
+
path: file.path,
|
|
153
|
+
data: file.data,
|
|
154
|
+
totalSize: file.data.byteLength,
|
|
155
|
+
chunkSize: this.params.chunkSize,
|
|
156
|
+
timeoutMs: this.params.timeoutMs,
|
|
157
|
+
paceMs: this.params.paceMs,
|
|
158
|
+
overwrite: true,
|
|
159
|
+
append: false,
|
|
160
|
+
throwIfAborted: () => this.throwIfAborted(),
|
|
161
|
+
onProgress: progress => {
|
|
162
|
+
if (typeof this.postMessage !== 'function') return;
|
|
163
|
+
const transferredBytes = transferredAtFileStart + progress.transferredBytes;
|
|
164
|
+
this.postMessage(
|
|
165
|
+
createUiMessage(UI_REQUEST.DEVICE_PROGRESS, {
|
|
166
|
+
...progress,
|
|
167
|
+
progress: Math.floor((transferredBytes / totalSize) * 100),
|
|
168
|
+
transferredBytes,
|
|
169
|
+
totalBytes: totalSize,
|
|
170
|
+
})
|
|
171
|
+
);
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
transferredBeforeFile += file.data.byteLength;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
this.throwIfAborted();
|
|
178
|
+
const response = await this.updateNft(bundle.basename);
|
|
179
|
+
return {
|
|
180
|
+
basename: bundle.basename,
|
|
181
|
+
imagePath: files[0].path,
|
|
182
|
+
thumbnailPath: files[1].path,
|
|
183
|
+
metadataPath: files[2].path,
|
|
184
|
+
totalSize,
|
|
185
|
+
nftUpdated: true,
|
|
186
|
+
message: response.message?.message,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
}
|
|
@@ -13,7 +13,9 @@ export default class ProtocolInfoRequest extends BaseMethod {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
async run() {
|
|
16
|
-
const res = await this.device.commands.typedCall('ProtocolInfoRequest', 'ProtocolInfo', {
|
|
16
|
+
const res = await this.device.commands.typedCall('ProtocolInfoRequest', 'ProtocolInfo', {
|
|
17
|
+
eventless_wallet_session: true,
|
|
18
|
+
});
|
|
17
19
|
return Promise.resolve(res.message);
|
|
18
20
|
}
|
|
19
21
|
}
|
|
@@ -118,6 +118,7 @@ export const isProtocolV2DeviceDisconnectedError = (error: unknown) => {
|
|
|
118
118
|
message.includes('connection has timed out unexpectedly') ||
|
|
119
119
|
message.includes('connection error has occured') ||
|
|
120
120
|
message.includes('connection error has occurred') ||
|
|
121
|
+
message.includes('react native ble transport released') ||
|
|
121
122
|
message.includes('multiplatformbleadapter') ||
|
|
122
123
|
message.includes('multipalformebleadapter') ||
|
|
123
124
|
compactMessage.includes('rxerrorerror6') ||
|
|
@@ -4,6 +4,8 @@ import type { Device, DeviceEvents } from '../device/Device';
|
|
|
4
4
|
|
|
5
5
|
export type HardwareUiEventHandlers = {
|
|
6
6
|
pin: (...event: DeviceEvents[typeof DEVICE.PIN]) => void;
|
|
7
|
+
pinOnDevice: (...event: DeviceEvents[typeof DEVICE.PIN_ON_DEVICE]) => void;
|
|
8
|
+
pinOnDeviceComplete: (...event: DeviceEvents[typeof DEVICE.PIN_ON_DEVICE_COMPLETE]) => void;
|
|
7
9
|
button: (...event: DeviceEvents[typeof DEVICE.BUTTON]) => void;
|
|
8
10
|
passphrase: (...event: DeviceEvents[typeof DEVICE.PASSPHRASE]) => void;
|
|
9
11
|
passphraseOnDevice: (...event: DeviceEvents[typeof DEVICE.PASSPHRASE_ON_DEVICE]) => void;
|
|
@@ -15,6 +17,8 @@ export function registerHardwareUiEventListeners(
|
|
|
15
17
|
handlers: HardwareUiEventHandlers
|
|
16
18
|
) {
|
|
17
19
|
device.on(DEVICE.PIN, handlers.pin);
|
|
20
|
+
device.on(DEVICE.PIN_ON_DEVICE, handlers.pinOnDevice);
|
|
21
|
+
device.on(DEVICE.PIN_ON_DEVICE_COMPLETE, handlers.pinOnDeviceComplete);
|
|
18
22
|
device.on(DEVICE.BUTTON, handlers.button);
|
|
19
23
|
device.on(DEVICE.PASSPHRASE, handlers.passphrase);
|
|
20
24
|
device.on(DEVICE.PASSPHRASE_ON_DEVICE, handlers.passphraseOnDevice);
|
package/src/core/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import semver from 'semver';
|
|
2
2
|
import EventEmitter from 'events';
|
|
3
|
-
import { TRANSPORT_EVENT } from '@onekeyfe/hd-transport';
|
|
3
|
+
import { DeviceSessionPinType, TRANSPORT_EVENT } from '@onekeyfe/hd-transport';
|
|
4
4
|
import {
|
|
5
5
|
ERRORS,
|
|
6
6
|
ERROR_CODES_REQUIRE_RELEASE,
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
createRequestContext,
|
|
27
27
|
createSdkTracingContext,
|
|
28
28
|
formatRequestContext,
|
|
29
|
+
generateInstanceId,
|
|
29
30
|
getActiveRequestsByDeviceInstance,
|
|
30
31
|
updateRequestContext,
|
|
31
32
|
} from '../utils/tracing';
|
|
@@ -53,13 +54,15 @@ import {
|
|
|
53
54
|
import TransportManager from '../data-manager/TransportManager';
|
|
54
55
|
import DeviceConnector from '../device/DeviceConnector';
|
|
55
56
|
import RequestQueue from './RequestQueue';
|
|
57
|
+
import { findUiPromiseForResponse } from './uiPromiseRegistry';
|
|
56
58
|
import { registerHardwareUiEventListeners } from './deviceEventRegistration';
|
|
57
59
|
import { getSynchronize } from '../utils/getSynchronize';
|
|
58
|
-
import {
|
|
60
|
+
import { runMethodWithUnlockPolicy } from '../protocols/protocol-v2/unlockPolicyRunner';
|
|
59
61
|
import {
|
|
60
62
|
ProtocolV2UiInteractionCoordinator,
|
|
61
63
|
isProtocolV2UiEnabled,
|
|
62
64
|
} from '../protocols/protocol-v2/uiInteraction';
|
|
65
|
+
import { createUiProgressMessageFilter } from '../utils/uiProgressThrottle';
|
|
63
66
|
|
|
64
67
|
import type { ConnectSettings, Features, KnownDevice } from '../types';
|
|
65
68
|
import type { CoreMessage, IFrameCallMessage, UiPromise, UiPromiseResponse } from '../events';
|
|
@@ -103,6 +106,7 @@ const parseInitOptions = (method?: BaseMethod): InitOptions => ({
|
|
|
103
106
|
deviceId: method?.payload.deviceId,
|
|
104
107
|
deriveCardano: method && hasDeriveCardano(method),
|
|
105
108
|
connectProtocol: method?.payload.connectProtocol,
|
|
109
|
+
forceProtocolDetection: method?.payload.forceProtocolDetection,
|
|
106
110
|
protocolV2DeviceInfoTimeoutMs: method?.payload.protocolV2DeviceInfoTimeoutMs,
|
|
107
111
|
});
|
|
108
112
|
|
|
@@ -154,7 +158,12 @@ export const callAPI = async (context: CoreContext, message: CoreMessage) => {
|
|
|
154
158
|
try {
|
|
155
159
|
method = findMethod(message as IFrameCallMessage);
|
|
156
160
|
method.connector = _connector;
|
|
157
|
-
|
|
161
|
+
const shouldPostMessage = createUiProgressMessageFilter();
|
|
162
|
+
method.postMessage = event => {
|
|
163
|
+
if (shouldPostMessage(event)) {
|
|
164
|
+
postMessage(event);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
158
167
|
method.setContext?.(context);
|
|
159
168
|
|
|
160
169
|
method.requestContext = createRequestContext(method.responseID, method.name, {
|
|
@@ -406,6 +415,8 @@ const onCallDevice = async (
|
|
|
406
415
|
|
|
407
416
|
registerHardwareUiEventListeners(device, {
|
|
408
417
|
pin: onDevicePinHandler,
|
|
418
|
+
pinOnDevice: onEnterPinOnDeviceHandler,
|
|
419
|
+
pinOnDeviceComplete: onPinOnDeviceCompleteHandler,
|
|
409
420
|
button: onDeviceButtonHandler,
|
|
410
421
|
passphrase: message.payload.useEmptyPassphrase
|
|
411
422
|
? onEmptyPassphraseHandler
|
|
@@ -421,6 +432,9 @@ const onCallDevice = async (
|
|
|
421
432
|
);
|
|
422
433
|
|
|
423
434
|
const protocolV2UiCoordinator = new ProtocolV2UiInteractionCoordinator(device, postMessage);
|
|
435
|
+
let protocolV2Operation = false;
|
|
436
|
+
let protocolV2CloseEmitted = false;
|
|
437
|
+
device.beginProtocolV2UiInteraction();
|
|
424
438
|
device.on(
|
|
425
439
|
DEVICE.SELECT_DEVICE_FOR_SWITCH_FIRMWARE_WEB_DEVICE,
|
|
426
440
|
onSelectDeviceForSwitchFirmwareWebDeviceHandler
|
|
@@ -438,6 +452,7 @@ const onCallDevice = async (
|
|
|
438
452
|
// Protocol is established from an active device response during acquire/initialize.
|
|
439
453
|
// Reject unsupported methods before any method-specific device command is sent.
|
|
440
454
|
method.assertProtocolSupported(device.getProtocol(), device.getCurrentFirmwareType());
|
|
455
|
+
protocolV2Operation = device.isProtocolV2();
|
|
441
456
|
|
|
442
457
|
// check firmware version
|
|
443
458
|
const versionRange = device.getCurrentMethodVersionRange(
|
|
@@ -547,89 +562,92 @@ const onCallDevice = async (
|
|
|
547
562
|
);
|
|
548
563
|
}
|
|
549
564
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
565
|
+
try {
|
|
566
|
+
let deviceIdCheckedDuringUnlockPreflight = false;
|
|
567
|
+
const response = await runMethodWithUnlockPolicy<object>(method, device, {
|
|
568
|
+
uiCoordinator: protocolV2UiCoordinator,
|
|
569
|
+
afterStatusBeforeUnlock: () => {
|
|
570
|
+
if (method.deviceId && method.checkDeviceId) {
|
|
571
|
+
if (!device.checkDeviceId(method.deviceId)) {
|
|
572
|
+
throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckDeviceIdError);
|
|
573
|
+
}
|
|
574
|
+
deviceIdCheckedDuringUnlockPreflight = true;
|
|
575
|
+
}
|
|
576
|
+
},
|
|
577
|
+
prepare: async () => {
|
|
578
|
+
if (method.deviceId && method.checkDeviceId && !deviceIdCheckedDuringUnlockPreflight) {
|
|
579
|
+
const isSameDeviceID = await checkLiveDeviceId(device, method.deviceId);
|
|
580
|
+
if (!isSameDeviceID) {
|
|
581
|
+
throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckDeviceIdError);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
561
584
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
585
|
+
/**
|
|
586
|
+
* check firmware release info
|
|
587
|
+
*/
|
|
588
|
+
method.checkFirmwareRelease();
|
|
566
589
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
590
|
+
/**
|
|
591
|
+
* check additional supported feature
|
|
592
|
+
*/
|
|
593
|
+
method.checkDeviceSupportFeature();
|
|
571
594
|
|
|
572
|
-
|
|
573
|
-
|
|
595
|
+
// reconfigure messages
|
|
596
|
+
if (_deviceList && device.features && !device.isProtocolV2()) {
|
|
597
|
+
await TransportManager.reconfigure(device.features);
|
|
598
|
+
}
|
|
574
599
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
600
|
+
// Check to see if it is safe to use Passphrase
|
|
601
|
+
checkPassphraseEnableState(method, device.features);
|
|
602
|
+
|
|
603
|
+
if (shouldCheckPassphraseState(method, device)) {
|
|
604
|
+
// check version
|
|
605
|
+
const support = device.supportNewPassphrase();
|
|
606
|
+
if (!support.support) {
|
|
607
|
+
throw ERRORS.TypedError(
|
|
608
|
+
HardwareErrorCode.DeviceNotSupportPassphrase,
|
|
609
|
+
`Device not support passphrase, please update to ${support.require}`,
|
|
610
|
+
{
|
|
611
|
+
require: support.require,
|
|
612
|
+
}
|
|
613
|
+
);
|
|
585
614
|
}
|
|
586
|
-
)
|
|
587
|
-
);
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
// Check Device passphrase State
|
|
591
|
-
const passphraseStateSafety = await device.checkPassphraseStateSafety(
|
|
592
|
-
method.payload?.passphraseState,
|
|
593
|
-
method.payload?.useEmptyPassphrase,
|
|
594
|
-
method.payload?.skipPassphraseCheck
|
|
595
|
-
);
|
|
596
615
|
|
|
597
|
-
|
|
598
|
-
|
|
616
|
+
// Check Device passphrase State after the Protocol V2 pre-unlock gate.
|
|
617
|
+
const passphraseStateSafety = await device.checkPassphraseStateSafety(
|
|
618
|
+
method.payload?.passphraseState,
|
|
619
|
+
method.payload?.useEmptyPassphrase,
|
|
620
|
+
method.payload?.skipPassphraseCheck,
|
|
621
|
+
hasDeriveCardano(method)
|
|
622
|
+
);
|
|
599
623
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
return Promise.reject(
|
|
603
|
-
ERRORS.TypedError(HardwareErrorCode.DeviceCheckPassphraseStateError)
|
|
604
|
-
);
|
|
605
|
-
}
|
|
624
|
+
// Double check, handles the special case of Touch/Pro
|
|
625
|
+
checkPassphraseEnableState(method, device.features);
|
|
606
626
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
627
|
+
if (!passphraseStateSafety) {
|
|
628
|
+
DevicePool.clearDeviceCache(method.payload.connectId);
|
|
629
|
+
throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckPassphraseStateError);
|
|
630
|
+
}
|
|
610
631
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
? e
|
|
618
|
-
: ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'open safety check failed.');
|
|
619
|
-
// messageResponse = createResponseMessage(method.responseID, false, { error });
|
|
620
|
-
// requestQueue.resolveRequest(method.responseID, messageResponse);
|
|
621
|
-
// return;
|
|
622
|
-
throw error;
|
|
623
|
-
}
|
|
632
|
+
// Protocol V2 emits the PIN phase completion from DeviceSessionAskPin.
|
|
633
|
+
// Keep the legacy compatibility close for Protocol V1 only.
|
|
634
|
+
if (!device.isProtocolV2()) {
|
|
635
|
+
postMessage(createUiMessage(UI_REQUEST.CLOSE_UI_PIN_WINDOW));
|
|
636
|
+
}
|
|
637
|
+
}
|
|
624
638
|
|
|
625
|
-
|
|
639
|
+
// Automatic check safety_check level for Kovan, Ropsten, Rinkeby, Goerli test networks.
|
|
640
|
+
try {
|
|
641
|
+
await method.checkSafetyLevelOnTestNet();
|
|
642
|
+
} catch (e) {
|
|
643
|
+
throw e instanceof HardwareError
|
|
644
|
+
? e
|
|
645
|
+
: ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'open safety check failed.');
|
|
646
|
+
}
|
|
626
647
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
device,
|
|
631
|
-
protocolV2UiCoordinator
|
|
632
|
-
);
|
|
648
|
+
method.device?.commands?.checkDisposed();
|
|
649
|
+
},
|
|
650
|
+
});
|
|
633
651
|
messageResponse = createResponseMessage(method.responseID, true, response);
|
|
634
652
|
requestQueue.resolveRequest(method.responseID, messageResponse);
|
|
635
653
|
completeMethodRequestContext(method);
|
|
@@ -647,7 +665,12 @@ const onCallDevice = async (
|
|
|
647
665
|
throw error;
|
|
648
666
|
}
|
|
649
667
|
} finally {
|
|
650
|
-
|
|
668
|
+
if (isProtocolV2UiEnabled(method)) {
|
|
669
|
+
protocolV2CloseEmitted = protocolV2UiCoordinator.close({
|
|
670
|
+
ensureOperationClose: protocolV2Operation,
|
|
671
|
+
protocolV2Operation,
|
|
672
|
+
});
|
|
673
|
+
}
|
|
651
674
|
}
|
|
652
675
|
};
|
|
653
676
|
Log.debug('Call API - Device Run: ', device.mainId);
|
|
@@ -702,7 +725,15 @@ const onCallDevice = async (
|
|
|
702
725
|
requestQueue.releaseTask(method.responseID);
|
|
703
726
|
|
|
704
727
|
if (isProtocolV2UiEnabled(method)) {
|
|
705
|
-
|
|
728
|
+
if (!protocolV2CloseEmitted && protocolV2Operation) {
|
|
729
|
+
protocolV2CloseEmitted = protocolV2UiCoordinator.close({
|
|
730
|
+
ensureOperationClose: true,
|
|
731
|
+
protocolV2Operation: true,
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
if (!protocolV2CloseEmitted) {
|
|
735
|
+
closePopup();
|
|
736
|
+
}
|
|
706
737
|
}
|
|
707
738
|
|
|
708
739
|
cleanup();
|
|
@@ -865,10 +896,18 @@ function isRetryableBleProtocolV2ProbeError(method: BaseMethod, error: unknown)
|
|
|
865
896
|
*/
|
|
866
897
|
async function connectDeviceForBle(method: BaseMethod, device: Device, retryCount = 0) {
|
|
867
898
|
try {
|
|
899
|
+
if (method.payload.forceProtocolDetection && device.hasDeviceAcquire()) {
|
|
900
|
+
await device.release();
|
|
901
|
+
}
|
|
868
902
|
const shouldAcquire =
|
|
869
|
-
|
|
903
|
+
method.payload.forceProtocolDetection ||
|
|
904
|
+
!device.hasDeviceAcquire() ||
|
|
905
|
+
!device.commands ||
|
|
906
|
+
device.commands.disposed;
|
|
870
907
|
if (shouldAcquire) {
|
|
871
|
-
await device.acquire(method.payload.connectProtocol
|
|
908
|
+
await device.acquire(method.payload.connectProtocol, {
|
|
909
|
+
forceProtocolDetection: method.payload.forceProtocolDetection,
|
|
910
|
+
});
|
|
872
911
|
}
|
|
873
912
|
if (method.payload?.onlyConnectBleDevice) {
|
|
874
913
|
if (shouldAcquire) {
|
|
@@ -1232,6 +1271,7 @@ const onDevicePinHandler = async (...[device, type, callback]: DeviceEvents['pin
|
|
|
1232
1271
|
createUiMessage(UI_REQUEST.REQUEST_PIN, {
|
|
1233
1272
|
device: device.toMessageObject() as unknown as KnownDevice,
|
|
1234
1273
|
type,
|
|
1274
|
+
responseCorrelation: uiPromise.responseCorrelation,
|
|
1235
1275
|
})
|
|
1236
1276
|
);
|
|
1237
1277
|
// wait for pin
|
|
@@ -1279,6 +1319,8 @@ const onDevicePassphraseHandler = async (
|
|
|
1279
1319
|
source: requestPayload.source,
|
|
1280
1320
|
reason: requestPayload.reason,
|
|
1281
1321
|
expectedPassphraseState: requestPayload.expectedPassphraseState,
|
|
1322
|
+
...(requestPayload.interaction ? { interaction: requestPayload.interaction } : {}),
|
|
1323
|
+
responseCorrelation: uiPromise.responseCorrelation,
|
|
1282
1324
|
})
|
|
1283
1325
|
);
|
|
1284
1326
|
// wait for passphrase
|
|
@@ -1308,6 +1350,7 @@ const onEnterPassphraseOnDeviceHandler = (
|
|
|
1308
1350
|
passphraseState: device.passphraseState,
|
|
1309
1351
|
source: requestPayload?.source,
|
|
1310
1352
|
reason: requestPayload?.reason,
|
|
1353
|
+
...(requestPayload?.interaction ? { interaction: requestPayload.interaction } : {}),
|
|
1311
1354
|
})
|
|
1312
1355
|
);
|
|
1313
1356
|
};
|
|
@@ -1321,10 +1364,39 @@ const onEnterAttachPinOnDeviceHandler = (
|
|
|
1321
1364
|
type: 'ButtonRequest_AttachPin',
|
|
1322
1365
|
source: requestPayload?.source,
|
|
1323
1366
|
reason: requestPayload?.reason,
|
|
1367
|
+
...(requestPayload?.interaction ? { interaction: requestPayload.interaction } : {}),
|
|
1368
|
+
})
|
|
1369
|
+
);
|
|
1370
|
+
};
|
|
1371
|
+
|
|
1372
|
+
const onEnterPinOnDeviceHandler = (
|
|
1373
|
+
...[device, pinType, metadata]: [...DeviceEvents['pin_on_device']]
|
|
1374
|
+
) => {
|
|
1375
|
+
postMessage(
|
|
1376
|
+
createUiMessage(UI_REQUEST.REQUEST_PIN, {
|
|
1377
|
+
device: device.toMessageObject() as KnownDevice,
|
|
1378
|
+
type:
|
|
1379
|
+
pinType === DeviceSessionPinType.AttachToPin
|
|
1380
|
+
? 'ButtonRequest_AttachPin'
|
|
1381
|
+
: 'ButtonRequest_PinEntry',
|
|
1382
|
+
source: metadata?.source,
|
|
1383
|
+
reason: metadata?.reason,
|
|
1384
|
+
deviceOnly: metadata?.deviceOnly ?? true,
|
|
1385
|
+
completion: metadata?.completion,
|
|
1386
|
+
method: metadata?.method,
|
|
1387
|
+
page: metadata?.page,
|
|
1388
|
+
operation: metadata?.operation,
|
|
1389
|
+
...(metadata?.interaction ? { interaction: metadata.interaction } : {}),
|
|
1324
1390
|
})
|
|
1325
1391
|
);
|
|
1326
1392
|
};
|
|
1327
1393
|
|
|
1394
|
+
const onPinOnDeviceCompleteHandler = (
|
|
1395
|
+
...[_, metadata]: [...DeviceEvents['pin_on_device_complete']]
|
|
1396
|
+
) => {
|
|
1397
|
+
postMessage(createUiMessage(UI_REQUEST.CLOSE_UI_PIN_WINDOW, metadata));
|
|
1398
|
+
};
|
|
1399
|
+
|
|
1328
1400
|
const onSelectDeviceInBootloaderForWebDeviceHandler = async (
|
|
1329
1401
|
...[device, callback]: [...DeviceEvents['select_device_in_bootloader_for_web_device']]
|
|
1330
1402
|
) => {
|
|
@@ -1372,14 +1444,21 @@ const postMessage = (message: CoreMessage) => {
|
|
|
1372
1444
|
|
|
1373
1445
|
const createUiPromise = <T extends UiPromiseResponse['type']>(promiseEvent: T, device?: Device) => {
|
|
1374
1446
|
const uiPromise: UiPromise<T> = createDeferred(promiseEvent, device);
|
|
1447
|
+
if (
|
|
1448
|
+
device &&
|
|
1449
|
+
(promiseEvent === UI_RESPONSE.RECEIVE_PIN || promiseEvent === UI_RESPONSE.RECEIVE_PASSPHRASE)
|
|
1450
|
+
) {
|
|
1451
|
+
const publicDeviceId = device.toMessageObject()?.deviceId;
|
|
1452
|
+
uiPromise.responseCorrelation = {
|
|
1453
|
+
interactionId: generateInstanceId('UiResponse', device.sdkInstanceId),
|
|
1454
|
+
deviceId: publicDeviceId || device.instanceId,
|
|
1455
|
+
};
|
|
1456
|
+
}
|
|
1375
1457
|
_uiPromises.push(uiPromise as any);
|
|
1376
1458
|
|
|
1377
1459
|
return uiPromise;
|
|
1378
1460
|
};
|
|
1379
1461
|
|
|
1380
|
-
const findUiPromise = <T extends UiPromiseResponse['type']>(promiseEvent: T) =>
|
|
1381
|
-
_uiPromises.find(p => p.id === promiseEvent);
|
|
1382
|
-
|
|
1383
1462
|
const removeUiPromise = (promise: Deferred<any>) => {
|
|
1384
1463
|
_uiPromises = _uiPromises.filter(p => p !== promise);
|
|
1385
1464
|
};
|
|
@@ -1431,11 +1510,16 @@ export default class Core extends EventEmitter {
|
|
|
1431
1510
|
case UI_RESPONSE.RECEIVE_PASSPHRASE:
|
|
1432
1511
|
case UI_RESPONSE.SELECT_DEVICE_IN_BOOTLOADER_FOR_WEB_DEVICE:
|
|
1433
1512
|
case UI_RESPONSE.SELECT_DEVICE_FOR_SWITCH_FIRMWARE_WEB_DEVICE: {
|
|
1434
|
-
const uiPromise =
|
|
1513
|
+
const uiPromise = findUiPromiseForResponse(_uiPromises, message);
|
|
1435
1514
|
if (uiPromise) {
|
|
1436
1515
|
Log.log('receive UI Response: ', message.type);
|
|
1437
1516
|
uiPromise.resolve(message);
|
|
1438
1517
|
removeUiPromise(uiPromise);
|
|
1518
|
+
} else if (
|
|
1519
|
+
message.type === UI_RESPONSE.RECEIVE_PIN ||
|
|
1520
|
+
message.type === UI_RESPONSE.RECEIVE_PASSPHRASE
|
|
1521
|
+
) {
|
|
1522
|
+
Log.warn('Ignored unmatched or ambiguous sensitive UI response:', message.type);
|
|
1439
1523
|
}
|
|
1440
1524
|
break;
|
|
1441
1525
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { UI_RESPONSE } from '../events/ui-response';
|
|
2
|
+
|
|
3
|
+
import type { UiPromise, UiPromiseResponse } from '../events/ui-promise';
|
|
4
|
+
import type { UiResponseEvent } from '../events/ui-response';
|
|
5
|
+
|
|
6
|
+
const isSensitiveUiResponse = (
|
|
7
|
+
response: UiResponseEvent
|
|
8
|
+
): response is Extract<
|
|
9
|
+
UiResponseEvent,
|
|
10
|
+
{ type: typeof UI_RESPONSE.RECEIVE_PIN | typeof UI_RESPONSE.RECEIVE_PASSPHRASE }
|
|
11
|
+
> => response.type === UI_RESPONSE.RECEIVE_PIN || response.type === UI_RESPONSE.RECEIVE_PASSPHRASE;
|
|
12
|
+
|
|
13
|
+
export const findUiPromiseForResponse = (
|
|
14
|
+
uiPromises: UiPromise<UiPromiseResponse['type']>[],
|
|
15
|
+
response: UiResponseEvent
|
|
16
|
+
) => {
|
|
17
|
+
const candidates = uiPromises.filter(promise => promise.id === response.type);
|
|
18
|
+
if (!isSensitiveUiResponse(response)) {
|
|
19
|
+
return candidates[0];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const hasInteractionId = typeof response.interactionId === 'string';
|
|
23
|
+
const hasDeviceId = typeof response.deviceId === 'string';
|
|
24
|
+
if (hasInteractionId !== hasDeviceId) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (hasInteractionId && hasDeviceId) {
|
|
29
|
+
return candidates.find(promise => {
|
|
30
|
+
const correlation = promise.responseCorrelation;
|
|
31
|
+
return (
|
|
32
|
+
correlation?.interactionId === response.interactionId &&
|
|
33
|
+
correlation?.deviceId === response.deviceId
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Legacy clients do not return correlation metadata. Preserve their single-request
|
|
39
|
+
// behavior, but never guess when multiple sensitive requests are pending.
|
|
40
|
+
return candidates.length === 1 ? candidates[0] : undefined;
|
|
41
|
+
};
|