@onekeyfe/hd-core 1.2.0-alpha.67 → 1.2.0-alpha.68
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 +313 -0
- package/__tests__/DeviceCommands.test.ts +59 -13
- package/__tests__/DeviceEventRegistration.test.ts +6 -0
- package/__tests__/check-all-firmware-release-protocol-v2.test.ts +198 -3
- package/__tests__/core-initialization.test.ts +23 -0
- package/__tests__/device-connector-protocol.test.ts +81 -0
- package/__tests__/device-lifecycle-events.test.ts +105 -3
- package/__tests__/device-pool-state.test.ts +22 -0
- package/__tests__/device-settings.test.ts +39 -18
- package/__tests__/device-state-contract.test.ts +1 -0
- package/__tests__/device-state-mapper.test.ts +13 -1
- package/__tests__/device-utils.test.ts +48 -1
- package/__tests__/deviceSettings.test.ts +11 -1
- package/__tests__/deviceUploadNft.test.ts +316 -0
- package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +5 -0
- package/__tests__/get-device-state.test.ts +132 -12
- package/__tests__/homescreen.test.ts +41 -1
- package/__tests__/kaspa-use-tweak-pro2.test.ts +2 -2
- 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 +340 -0
- package/__tests__/protocol-v2-ui-lifecycle.test.ts +91 -0
- package/__tests__/protocol-v2-unlock-policy.test.ts +300 -37
- package/__tests__/protocol-v2.test.ts +1449 -867
- package/__tests__/protocolV2FileWrite.test.ts +152 -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__/tron-sign-message-init.test.ts +2 -2
- package/__tests__/uiProgressThrottle.test.ts +74 -0
- package/__tests__/uiPromiseRegistry.test.ts +115 -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.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +11 -4
- 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/DeviceSettings.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/firmware/FirmwareUpdateBaseMethod.d.ts +4 -3
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
- package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
- package/dist/api/helpers/protocolV2FileWrite.d.ts +9 -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/KaspaGetAddress.d.ts +1 -1
- package/dist/api/kaspa/KaspaSignTransaction.d.ts +1 -1
- package/dist/api/kaspa/KaspaSignTransaction.d.ts.map +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 +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/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/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 +6 -0
- package/dist/core/uiPromiseRegistry.d.ts.map +1 -0
- package/dist/data-manager/DataManager.d.ts +9 -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 +29 -5
- 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 +2 -1
- package/dist/device/DeviceConnector.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/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 +243 -69
- package/dist/index.js +2563 -1217
- 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 +3 -1
- 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/export.d.ts +1 -0
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdate.d.ts +4 -2
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +6 -1
- 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 +2 -2
- 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 +38 -8
- package/dist/types/settings.d.ts.map +1 -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/deviceInfoUtils.d.ts.map +1 -1
- package/dist/utils/deviceSettings.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 +61 -11
- package/src/api/DetectDeviceConnectProtocol.ts +18 -0
- package/src/api/FirmwareUpdate.ts +6 -2
- package/src/api/FirmwareUpdateV2.ts +5 -2
- package/src/api/FirmwareUpdateV3.ts +6 -2
- package/src/api/FirmwareUpdateV4.ts +463 -258
- package/src/api/GetPassphraseState.ts +7 -1
- package/src/api/OpenWalletSession.ts +71 -17
- package/src/api/SearchDevices.ts +3 -1
- package/src/api/allnetwork/AllNetworkGetAddress.ts +21 -21
- package/src/api/allnetwork/AllNetworkGetAddressBase.ts +36 -11
- package/src/api/device/DeviceSettings.ts +5 -4
- package/src/api/device/DeviceUnlock.ts +8 -3
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +27 -12
- package/src/api/firmware/uploadFirmware.ts +17 -4
- package/src/api/helpers/protocolV2FileWrite.ts +202 -63
- package/src/api/index.ts +2 -0
- package/src/api/kaspa/KaspaGetAddress.ts +1 -1
- package/src/api/kaspa/KaspaSignTransaction.ts +2 -13
- package/src/api/polkadot/networks.ts +3 -3
- package/src/api/protocol-v2/DeviceUploadNft.ts +197 -0
- package/src/api/protocol-v2/ProtocolInfoRequest.ts +3 -1
- package/src/api/protocol-v2/helpers.ts +1 -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/core/deviceEventRegistration.ts +4 -0
- package/src/core/index.ts +213 -111
- package/src/core/uiPromiseRegistry.ts +63 -0
- package/src/data/messages/messages-protocol-v2.json +25 -0
- package/src/data-manager/DataManager.ts +88 -11
- package/src/data-manager/TransportManager.ts +6 -0
- package/src/device/Device.ts +273 -43
- package/src/device/DeviceCommands.ts +31 -4
- package/src/device/DeviceConnector.ts +33 -13
- package/src/device/DevicePool.ts +21 -7
- package/src/deviceProfile/buildDeviceFeatures.ts +2 -2
- package/src/deviceProfile/protocolV2DeviceIdentity.ts +3 -0
- 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/inject.ts +58 -2
- package/src/lowLevelInject.ts +6 -3
- 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 +390 -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 +131 -0
- package/src/protocols/protocol-v2/walletSession.ts +214 -36
- package/src/topLevelInject.ts +6 -3
- package/src/types/api/checkAllFirmwareRelease.ts +3 -1
- package/src/types/api/detectDeviceConnectProtocol.ts +6 -0
- package/src/types/api/deviceUnlock.ts +12 -1
- package/src/types/api/export.ts +1 -0
- package/src/types/api/firmwareUpdate.ts +6 -3
- package/src/types/api/index.ts +13 -0
- package/src/types/api/protocolV2.ts +13 -0
- package/src/types/device.ts +15 -3
- package/src/types/params.ts +7 -1
- package/src/types/settings.ts +60 -9
- package/src/utils/deviceFeaturesCompat.ts +5 -0
- package/src/utils/deviceFeaturesUtils.ts +14 -3
- package/src/utils/deviceInfoUtils.ts +2 -0
- package/src/utils/deviceSettings.ts +3 -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/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/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
|
@@ -5,6 +5,7 @@ import CheckAllFirmwareRelease, {
|
|
|
5
5
|
} from '../src/api/CheckAllFirmwareRelease';
|
|
6
6
|
import { DataManager } from '../src/data-manager';
|
|
7
7
|
import { createCoreApi } from '../src/inject';
|
|
8
|
+
import { PROTOCOL_V2_RESOURCE_DEVICE_PATHS } from '../src/protocols/protocol-v2/resources';
|
|
8
9
|
|
|
9
10
|
import type { CoreApi } from '../src/types/api';
|
|
10
11
|
import type { DeviceStateVersions, IFirmwareReleaseInfo } from '../src/types';
|
|
@@ -72,7 +73,74 @@ const release: IFirmwareReleaseInfo = {
|
|
|
72
73
|
],
|
|
73
74
|
};
|
|
74
75
|
|
|
76
|
+
const stableResources = ['images', 'animation', 'wallpaper', 'translations', 'roobert', 'noto'].map(
|
|
77
|
+
(type, index) => ({
|
|
78
|
+
type,
|
|
79
|
+
url: `https://example.com/${type}.okpkg`,
|
|
80
|
+
size: 0x52a0 + index + 1,
|
|
81
|
+
fileHash: 'a'.repeat(64),
|
|
82
|
+
headerHash: index.toString(16).padStart(128, '0'),
|
|
83
|
+
})
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const createFilesystemTypedCall = (missingAll = false) => {
|
|
87
|
+
const resourceByPath = new Map(
|
|
88
|
+
stableResources.map(resource => [
|
|
89
|
+
PROTOCOL_V2_RESOURCE_DEVICE_PATHS[
|
|
90
|
+
resource.type as keyof typeof PROTOCOL_V2_RESOURCE_DEVICE_PATHS
|
|
91
|
+
],
|
|
92
|
+
resource,
|
|
93
|
+
])
|
|
94
|
+
);
|
|
95
|
+
return jest.fn((requestType: string, _responseType: string, payload: Record<string, any>) => {
|
|
96
|
+
if (requestType === 'ResourceInventoryGet') {
|
|
97
|
+
throw new Error('ResourceInventoryGet is unavailable on released firmware');
|
|
98
|
+
}
|
|
99
|
+
if (requestType === 'FilesystemPathInfoQuery') {
|
|
100
|
+
const resource = resourceByPath.get(payload.path);
|
|
101
|
+
return {
|
|
102
|
+
message: {
|
|
103
|
+
exist: Boolean(resource) && !missingAll,
|
|
104
|
+
directory: false,
|
|
105
|
+
size: missingAll ? 0 : resource?.size,
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (requestType === 'FilesystemFileRead') {
|
|
110
|
+
const resource = resourceByPath.get(payload.file.path);
|
|
111
|
+
if (!resource || missingAll) throw new Error('missing resource');
|
|
112
|
+
const header = new Uint8Array(0x52a0);
|
|
113
|
+
const view = new DataView(header.buffer);
|
|
114
|
+
'OKPP'.split('').forEach((char, index) => {
|
|
115
|
+
header[index] = char.charCodeAt(0);
|
|
116
|
+
});
|
|
117
|
+
'RESC'.split('').forEach((char, index) => {
|
|
118
|
+
header[0x08 + index] = char.charCodeAt(0);
|
|
119
|
+
});
|
|
120
|
+
view.setUint32(0x0c, header.byteLength, true);
|
|
121
|
+
for (let index = 0; index < resource.headerHash.length / 2; index++) {
|
|
122
|
+
header[0x240 + index] = Number.parseInt(
|
|
123
|
+
resource.headerHash.slice(index * 2, index * 2 + 2),
|
|
124
|
+
16
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
const offset = Number(payload.file.offset);
|
|
128
|
+
const chunkLength = Number(payload.chunk_len);
|
|
129
|
+
return {
|
|
130
|
+
message: {
|
|
131
|
+
data: header.slice(offset, offset + chunkLength),
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
throw new Error(`Unexpected request: ${requestType}`);
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
|
|
75
139
|
describe('checkAllFirmwareRelease Protocol V2 support', () => {
|
|
140
|
+
afterEach(() => {
|
|
141
|
+
jest.restoreAllMocks();
|
|
142
|
+
});
|
|
143
|
+
|
|
76
144
|
test('builds ordered firmwareUpdateV4 targets from recommended component versions', () => {
|
|
77
145
|
const result = buildProtocolV2FirmwareRelease({
|
|
78
146
|
currentVersions,
|
|
@@ -84,7 +152,7 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
|
|
|
84
152
|
status: 'required',
|
|
85
153
|
hasUpgrade: true,
|
|
86
154
|
required: true,
|
|
87
|
-
targetsToUpdate: ['boot', 'app_v1'
|
|
155
|
+
targetsToUpdate: ['boot', 'app_v1'],
|
|
88
156
|
components: [
|
|
89
157
|
{ configKey: 'bootloader', status: 'outdated', updateTarget: 'boot' },
|
|
90
158
|
{ configKey: 'applicationP1', status: 'outdated', updateTarget: 'app_v1' },
|
|
@@ -142,6 +210,7 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
|
|
|
142
210
|
applicationP1Hash: 'aa'.repeat(32),
|
|
143
211
|
applicationP2Hash: 'bb'.repeat(32),
|
|
144
212
|
},
|
|
213
|
+
checkFirmwareHash: true,
|
|
145
214
|
remotePayloadHashes: {
|
|
146
215
|
applicationP1: 'aa'.repeat(64),
|
|
147
216
|
applicationP2: 'cc'.repeat(64),
|
|
@@ -160,6 +229,37 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
|
|
|
160
229
|
});
|
|
161
230
|
});
|
|
162
231
|
|
|
232
|
+
test('uses version-only comparison for same-version packages by default', () => {
|
|
233
|
+
const packageSet: IFirmwareReleaseInfo = {
|
|
234
|
+
...release,
|
|
235
|
+
required: false,
|
|
236
|
+
resourceBundles: undefined,
|
|
237
|
+
installOrder: ['applicationP1'],
|
|
238
|
+
components: {
|
|
239
|
+
applicationP1: {
|
|
240
|
+
target: 'APPLICATION_P1',
|
|
241
|
+
version: [1, 0, 0],
|
|
242
|
+
url: 'https://example.com/application-p1.okpkg',
|
|
243
|
+
payloadHash: 'cc'.repeat(64),
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
expect(
|
|
249
|
+
buildProtocolV2FirmwareRelease({
|
|
250
|
+
currentVersions: { ...currentVersions, applicationP1: '1.0.0' },
|
|
251
|
+
currentVerification: { applicationP1Hash: 'aa'.repeat(32) },
|
|
252
|
+
firmwareType: EFirmwareType.Universal,
|
|
253
|
+
release: packageSet,
|
|
254
|
+
})
|
|
255
|
+
).toMatchObject({
|
|
256
|
+
status: 'valid',
|
|
257
|
+
hasUpgrade: false,
|
|
258
|
+
targetsToUpdate: [],
|
|
259
|
+
components: [{ configKey: 'applicationP1', status: 'valid' }],
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
|
|
163
263
|
test('keeps same-version hash-aware components unknown without metadata payloadHash', () => {
|
|
164
264
|
const packageSet: IFirmwareReleaseInfo = {
|
|
165
265
|
...release,
|
|
@@ -180,6 +280,7 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
|
|
|
180
280
|
buildProtocolV2FirmwareRelease({
|
|
181
281
|
currentVersions: { ...currentVersions, applicationP1: '1.0.0' },
|
|
182
282
|
currentVerification: { applicationP1Hash: 'aa'.repeat(32) },
|
|
283
|
+
checkFirmwareHash: true,
|
|
183
284
|
firmwareType: EFirmwareType.Universal,
|
|
184
285
|
release: packageSet,
|
|
185
286
|
})
|
|
@@ -215,6 +316,7 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
|
|
|
215
316
|
const result = buildProtocolV2FirmwareRelease({
|
|
216
317
|
currentVersions,
|
|
217
318
|
currentVerification: { applicationP1Hash: 'aa'.repeat(32) },
|
|
319
|
+
checkFirmwareHash: true,
|
|
218
320
|
remotePayloadHashes: { applicationP1: 'cc'.repeat(64) },
|
|
219
321
|
firmwareType: EFirmwareType.Universal,
|
|
220
322
|
release: packageSet,
|
|
@@ -223,7 +325,7 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
|
|
|
223
325
|
expect(result.targetsToUpdate).toEqual(['app_v1', 'app_v2']);
|
|
224
326
|
});
|
|
225
327
|
|
|
226
|
-
test('
|
|
328
|
+
test('does not read vol0 resource inventory while Protocol V2 is in Application mode', async () => {
|
|
227
329
|
const method = new CheckAllFirmwareRelease({
|
|
228
330
|
id: 1,
|
|
229
331
|
payload: {
|
|
@@ -240,6 +342,7 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
|
|
|
240
342
|
status: { mode: 'normal' },
|
|
241
343
|
versions: currentVersions,
|
|
242
344
|
});
|
|
345
|
+
const typedCall = createFilesystemTypedCall(true);
|
|
243
346
|
method.device = {
|
|
244
347
|
isProtocolV2: () => true,
|
|
245
348
|
features: {
|
|
@@ -247,32 +350,124 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
|
|
|
247
350
|
firmwareVersion: '1.0.0',
|
|
248
351
|
},
|
|
249
352
|
getDeviceState,
|
|
353
|
+
getCommands: () => ({ typedCall }),
|
|
250
354
|
} as unknown as CheckAllFirmwareRelease['device'];
|
|
251
355
|
jest.spyOn(DataManager, 'getFirmwareLatestRelease').mockReturnValue(release);
|
|
356
|
+
jest.spyOn(DataManager, 'getProtocolV2Resources').mockReturnValue(stableResources as any);
|
|
252
357
|
|
|
253
358
|
await expect(method.run()).resolves.toMatchObject({
|
|
254
359
|
protocol: 'V2',
|
|
255
360
|
deviceType: 'pro2',
|
|
256
361
|
status: 'required',
|
|
257
|
-
|
|
362
|
+
resourceStatus: 'unknown',
|
|
363
|
+
targetsToUpdate: ['boot', 'app_v1'],
|
|
258
364
|
firmware: {
|
|
259
365
|
status: 'required',
|
|
260
366
|
},
|
|
261
367
|
});
|
|
368
|
+
expect(typedCall).not.toHaveBeenCalled();
|
|
369
|
+
expect(getDeviceState).toHaveBeenCalledWith({
|
|
370
|
+
refreshSections: ['identity', 'versions'],
|
|
371
|
+
});
|
|
262
372
|
expect(method.getSupportedProtocols()).toEqual(['V1', 'V2']);
|
|
263
373
|
});
|
|
264
374
|
|
|
375
|
+
test('requests and compares firmware hashes only when explicitly enabled', async () => {
|
|
376
|
+
const packageSet: IFirmwareReleaseInfo = {
|
|
377
|
+
...release,
|
|
378
|
+
required: false,
|
|
379
|
+
resourceBundles: undefined,
|
|
380
|
+
installOrder: ['applicationP1'],
|
|
381
|
+
components: {
|
|
382
|
+
applicationP1: {
|
|
383
|
+
target: 'APPLICATION_P1',
|
|
384
|
+
version: [1, 0, 0],
|
|
385
|
+
url: 'https://example.com/application-p1.okpkg',
|
|
386
|
+
payloadHash: 'cc'.repeat(64),
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
};
|
|
390
|
+
const method = new CheckAllFirmwareRelease({
|
|
391
|
+
id: 1,
|
|
392
|
+
payload: {
|
|
393
|
+
method: 'checkAllFirmwareRelease',
|
|
394
|
+
firmwareType: EFirmwareType.Universal,
|
|
395
|
+
checkFirmwareHash: true,
|
|
396
|
+
},
|
|
397
|
+
});
|
|
398
|
+
method.init();
|
|
399
|
+
const getDeviceState = jest.fn().mockResolvedValue({
|
|
400
|
+
identity: { deviceType: 'pro2', firmwareType: EFirmwareType.Universal },
|
|
401
|
+
status: { mode: 'normal' },
|
|
402
|
+
versions: { ...currentVersions, applicationP1: '1.0.0' },
|
|
403
|
+
verification: { applicationP1Hash: 'aa'.repeat(32) },
|
|
404
|
+
});
|
|
405
|
+
method.device = {
|
|
406
|
+
isProtocolV2: () => true,
|
|
407
|
+
features: { deviceType: 'pro2', firmwareVersion: '1.0.0' },
|
|
408
|
+
getDeviceState,
|
|
409
|
+
getCommands: () => ({ typedCall: jest.fn() }),
|
|
410
|
+
} as unknown as CheckAllFirmwareRelease['device'];
|
|
411
|
+
jest.spyOn(DataManager, 'getFirmwareLatestRelease').mockReturnValue(packageSet);
|
|
412
|
+
jest.spyOn(DataManager, 'getProtocolV2Resources').mockReturnValue(undefined);
|
|
413
|
+
|
|
414
|
+
await expect(method.run()).resolves.toMatchObject({
|
|
415
|
+
status: 'outdated',
|
|
416
|
+
targetsToUpdate: ['app_v1'],
|
|
417
|
+
});
|
|
418
|
+
expect(getDeviceState).toHaveBeenCalledWith({
|
|
419
|
+
refreshSections: ['identity', 'versions', 'verification'],
|
|
420
|
+
});
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
test.each(['bootloader', 'romloader'] as const)(
|
|
424
|
+
'uses filesystem inventory in %s mode instead of forcing all resources',
|
|
425
|
+
async mode => {
|
|
426
|
+
const method = new CheckAllFirmwareRelease({
|
|
427
|
+
id: 1,
|
|
428
|
+
payload: {
|
|
429
|
+
method: 'checkAllFirmwareRelease',
|
|
430
|
+
firmwareType: EFirmwareType.Universal,
|
|
431
|
+
},
|
|
432
|
+
});
|
|
433
|
+
method.init();
|
|
434
|
+
const typedCall = createFilesystemTypedCall();
|
|
435
|
+
method.device = {
|
|
436
|
+
isProtocolV2: () => true,
|
|
437
|
+
features: { deviceType: 'pro2', firmwareVersion: '1.0.0' },
|
|
438
|
+
getDeviceState: jest.fn().mockResolvedValue({
|
|
439
|
+
identity: { deviceType: 'pro2', firmwareType: EFirmwareType.Universal },
|
|
440
|
+
status: { mode },
|
|
441
|
+
versions: currentVersions,
|
|
442
|
+
}),
|
|
443
|
+
getCommands: () => ({ typedCall }),
|
|
444
|
+
} as unknown as CheckAllFirmwareRelease['device'];
|
|
445
|
+
jest.spyOn(DataManager, 'getFirmwareLatestRelease').mockReturnValue(release);
|
|
446
|
+
jest.spyOn(DataManager, 'getProtocolV2Resources').mockReturnValue(stableResources as any);
|
|
447
|
+
|
|
448
|
+
await expect(method.run()).resolves.toMatchObject({
|
|
449
|
+
protocol: 'V2',
|
|
450
|
+
resourceStatus: 'valid',
|
|
451
|
+
targetsToUpdate: ['boot', 'app_v1'],
|
|
452
|
+
});
|
|
453
|
+
expect(typedCall.mock.calls.some(call => call[0] === 'ResourceInventoryGet')).toBe(false);
|
|
454
|
+
expect(typedCall.mock.calls.some(call => call[0] === 'FilesystemFileRead')).toBe(true);
|
|
455
|
+
}
|
|
456
|
+
);
|
|
457
|
+
|
|
265
458
|
test('continues forwarding the existing public method', async () => {
|
|
266
459
|
const call = jest.fn().mockResolvedValue({ success: true, payload: {} });
|
|
267
460
|
const api = createCoreApi(call as CoreApi['call']) as CoreApi;
|
|
268
461
|
|
|
269
462
|
await api.checkAllFirmwareRelease('pro2-connect-id', {
|
|
463
|
+
checkFirmwareHash: true,
|
|
270
464
|
firmwareType: EFirmwareType.Universal,
|
|
271
465
|
retryCount: 0,
|
|
272
466
|
});
|
|
273
467
|
|
|
274
468
|
expect(call).toHaveBeenCalledWith({
|
|
275
469
|
connectId: 'pro2-connect-id',
|
|
470
|
+
checkFirmwareHash: true,
|
|
276
471
|
firmwareType: EFirmwareType.Universal,
|
|
277
472
|
retryCount: 0,
|
|
278
473
|
method: 'checkAllFirmwareRelease',
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { DataManager } from '../src/data-manager';
|
|
2
|
+
import { init } from '../src/core';
|
|
3
|
+
|
|
4
|
+
import type { ConnectSettings } from '../src/types';
|
|
5
|
+
|
|
6
|
+
jest.mock('../src/data/config', () => ({
|
|
7
|
+
getSDKVersion: jest.fn(() => '1.0.0-test'),
|
|
8
|
+
DEFAULT_DOMAIN: 'https://jssdk.onekey.so/1.0.0-test/',
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
describe('Core initialization', () => {
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
jest.restoreAllMocks();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('does not create a partially initialized core when settings loading fails', async () => {
|
|
17
|
+
jest.spyOn(DataManager, 'load').mockRejectedValue(new Error('settings load failed'));
|
|
18
|
+
|
|
19
|
+
await expect(init({} as ConnectSettings, class TestTransport {})).rejects.toThrow(
|
|
20
|
+
'settings load failed'
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
+
|
|
3
|
+
import DeviceConnector from '../src/device/DeviceConnector';
|
|
4
|
+
|
|
5
|
+
jest.mock('../src/data-manager/TransportManager', () => ({
|
|
6
|
+
__esModule: true,
|
|
7
|
+
default: {
|
|
8
|
+
load: jest.fn(),
|
|
9
|
+
getTransport: jest.fn(),
|
|
10
|
+
},
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
jest.mock('../src/data-manager', () => ({
|
|
14
|
+
DataManager: {
|
|
15
|
+
getSettings: jest.fn(() => 'desktop-web-ble'),
|
|
16
|
+
isBleConnect: jest.fn(() => true),
|
|
17
|
+
},
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
jest.mock('../src/device/DevicePool', () => ({
|
|
21
|
+
DevicePool: {
|
|
22
|
+
setConnector: jest.fn(),
|
|
23
|
+
},
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
const transportManagerMock: {
|
|
27
|
+
default: {
|
|
28
|
+
getTransport: jest.Mock;
|
|
29
|
+
};
|
|
30
|
+
} = jest.requireMock('../src/data-manager/TransportManager');
|
|
31
|
+
|
|
32
|
+
describe('DeviceConnector protocol validation', () => {
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
jest.clearAllMocks();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('reports an explicit transport error when connector initialization ran too early', async () => {
|
|
38
|
+
transportManagerMock.default.getTransport.mockReturnValue(undefined);
|
|
39
|
+
const connector = new DeviceConnector();
|
|
40
|
+
|
|
41
|
+
await expect(connector.enumerate()).rejects.toMatchObject({
|
|
42
|
+
errorCode: HardwareErrorCode.TransportNotConfigured,
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('uses the actively probed protocol returned by acquire when the cache was cleared', async () => {
|
|
47
|
+
const acquire = jest.fn().mockResolvedValue({
|
|
48
|
+
id: 'pro2-id',
|
|
49
|
+
path: 'pro2-id',
|
|
50
|
+
protocolType: 'V2',
|
|
51
|
+
});
|
|
52
|
+
transportManagerMock.default.getTransport.mockReturnValue({
|
|
53
|
+
acquire,
|
|
54
|
+
getProtocolType: jest.fn(() => undefined),
|
|
55
|
+
});
|
|
56
|
+
const connector = new DeviceConnector();
|
|
57
|
+
|
|
58
|
+
await expect(connector.acquire('pro2-id', undefined, undefined, 'V2')).resolves.toEqual(
|
|
59
|
+
expect.objectContaining({ protocolType: 'V2' })
|
|
60
|
+
);
|
|
61
|
+
expect(acquire).toHaveBeenCalledWith(
|
|
62
|
+
expect.objectContaining({ uuid: 'pro2-id', expectedProtocol: 'V2' })
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('still rejects a real mismatch reported by the active protocol probe', async () => {
|
|
67
|
+
transportManagerMock.default.getTransport.mockReturnValue({
|
|
68
|
+
acquire: jest.fn().mockResolvedValue({
|
|
69
|
+
id: 'classic-id',
|
|
70
|
+
path: 'classic-id',
|
|
71
|
+
protocolType: 'V1',
|
|
72
|
+
}),
|
|
73
|
+
getProtocolType: jest.fn(() => 'V1'),
|
|
74
|
+
});
|
|
75
|
+
const connector = new DeviceConnector();
|
|
76
|
+
|
|
77
|
+
await expect(connector.acquire('classic-id', undefined, undefined, 'V2')).rejects.toThrow(
|
|
78
|
+
'Device protocol mismatch: expected V2, detected V1'
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
1
2
|
import { TRANSPORT_EVENT } from '@onekeyfe/hd-transport';
|
|
2
3
|
|
|
3
4
|
import { initConnector, initCore } from '../src/core';
|
|
@@ -95,7 +96,7 @@ describe('public device lifecycle events', () => {
|
|
|
95
96
|
expect(messages.filter(message => message.type === DEVICE.DISCONNECT)).toHaveLength(1);
|
|
96
97
|
});
|
|
97
98
|
|
|
98
|
-
test('uses a cached protocol as a
|
|
99
|
+
test('uses a verified cached protocol as a strict expected protocol', async () => {
|
|
99
100
|
jest.spyOn(DataManager, 'getSettings').mockReturnValue('react-native' as never);
|
|
100
101
|
const device = Device.fromDescriptor({
|
|
101
102
|
id: 'ble-id',
|
|
@@ -103,16 +104,117 @@ describe('public device lifecycle events', () => {
|
|
|
103
104
|
commType: 'ble',
|
|
104
105
|
protocolType: 'V1',
|
|
105
106
|
} as never);
|
|
106
|
-
const acquire = jest.fn().mockResolvedValue({ uuid: 'ble-id', protocolType: '
|
|
107
|
+
const acquire = jest.fn().mockResolvedValue({ uuid: 'ble-id', protocolType: 'V1' });
|
|
107
108
|
device.deviceConnector = { acquire } as never;
|
|
108
109
|
|
|
109
110
|
await device.acquire();
|
|
110
111
|
|
|
111
|
-
expect(acquire).toHaveBeenCalledWith('ble-id', undefined, true,
|
|
112
|
+
expect(acquire).toHaveBeenCalledWith('ble-id', undefined, true, 'V1', undefined);
|
|
113
|
+
expect(device.getProtocol()).toBe('V1');
|
|
114
|
+
expect(device.originalDescriptor.protocolType).toBe('V1');
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('bypasses a cached protocol only for explicit active detection', async () => {
|
|
118
|
+
jest.spyOn(DataManager, 'getSettings').mockReturnValue('react-native' as never);
|
|
119
|
+
const device = Device.fromDescriptor({
|
|
120
|
+
id: 'ble-id',
|
|
121
|
+
path: 'ble-id',
|
|
122
|
+
commType: 'ble',
|
|
123
|
+
protocolType: 'V1',
|
|
124
|
+
} as never);
|
|
125
|
+
const acquire = jest.fn().mockResolvedValue({ uuid: 'ble-id', protocolType: 'V2' });
|
|
126
|
+
device.deviceConnector = { acquire } as never;
|
|
127
|
+
|
|
128
|
+
await device.acquire(undefined, { forceProtocolDetection: true });
|
|
129
|
+
|
|
130
|
+
expect(acquire).toHaveBeenCalledWith('ble-id', undefined, true, undefined, undefined);
|
|
112
131
|
expect(device.getProtocol()).toBe('V2');
|
|
113
132
|
expect(device.originalDescriptor.protocolType).toBe('V2');
|
|
114
133
|
});
|
|
115
134
|
|
|
135
|
+
test('does not reuse a stale protocol when active detection returns no protocol', async () => {
|
|
136
|
+
jest.spyOn(DataManager, 'getSettings').mockReturnValue('react-native' as never);
|
|
137
|
+
const device = Device.fromDescriptor({
|
|
138
|
+
id: 'ble-id',
|
|
139
|
+
path: 'ble-id',
|
|
140
|
+
commType: 'ble',
|
|
141
|
+
protocolType: 'V1',
|
|
142
|
+
} as never);
|
|
143
|
+
const acquire = jest.fn().mockResolvedValue({ uuid: 'ble-id' });
|
|
144
|
+
const release = jest.fn().mockResolvedValue(undefined);
|
|
145
|
+
device.deviceConnector = { acquire, release } as never;
|
|
146
|
+
await expect(
|
|
147
|
+
device.acquire(undefined, {
|
|
148
|
+
forceProtocolDetection: true,
|
|
149
|
+
throwOnRunPromiseError: true,
|
|
150
|
+
})
|
|
151
|
+
).rejects.toMatchObject({ errorCode: HardwareErrorCode.RuntimeError });
|
|
152
|
+
expect(device.originalDescriptor.protocolType).toBe('V1');
|
|
153
|
+
expect(device.hasDeviceAcquire()).toBe(false);
|
|
154
|
+
expect(release).toHaveBeenCalledWith('ble-id', false);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test('actively reacquires an already connected device without initializing it', async () => {
|
|
158
|
+
jest.spyOn(DataManager, 'getSettings').mockReturnValue('webusb' as never);
|
|
159
|
+
const device = Device.fromDescriptor({
|
|
160
|
+
id: 'usb-device',
|
|
161
|
+
path: 'usb-device',
|
|
162
|
+
session: 'old-session',
|
|
163
|
+
protocolType: 'V1',
|
|
164
|
+
} as never);
|
|
165
|
+
device.mainId = 'old-session';
|
|
166
|
+
device.commands = { disposed: false } as never;
|
|
167
|
+
const release = jest.spyOn(device, 'release').mockImplementation(() => {
|
|
168
|
+
device.mainId = null;
|
|
169
|
+
device.originalDescriptor.session = null;
|
|
170
|
+
device.commands.disposed = true;
|
|
171
|
+
return Promise.resolve();
|
|
172
|
+
});
|
|
173
|
+
const acquire = jest.spyOn(device, 'acquire').mockImplementation(() => {
|
|
174
|
+
device.mainId = 'new-session';
|
|
175
|
+
device.originalDescriptor.session = 'new-session';
|
|
176
|
+
device.originalDescriptor.protocolType = 'V2';
|
|
177
|
+
device.commands.disposed = false;
|
|
178
|
+
return Promise.resolve();
|
|
179
|
+
});
|
|
180
|
+
const initialize = jest.spyOn(device, 'initialize').mockResolvedValue(undefined);
|
|
181
|
+
|
|
182
|
+
await device.run(() => Promise.resolve(undefined), {
|
|
183
|
+
forceProtocolDetection: true,
|
|
184
|
+
skipInitialize: true,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
expect(release).toHaveBeenCalled();
|
|
188
|
+
expect(acquire).toHaveBeenCalledWith(undefined, {
|
|
189
|
+
forceProtocolDetection: true,
|
|
190
|
+
});
|
|
191
|
+
expect(initialize).not.toHaveBeenCalled();
|
|
192
|
+
expect(device.getProtocol()).toBe('V2');
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
test('keeps the freshly probed React Native BLE session until the call completes', async () => {
|
|
196
|
+
jest.spyOn(DataManager, 'getSettings').mockReturnValue('react-native' as never);
|
|
197
|
+
const device = Device.fromDescriptor({
|
|
198
|
+
id: 'ble-device',
|
|
199
|
+
path: 'ble-device',
|
|
200
|
+
commType: 'ble',
|
|
201
|
+
protocolType: 'V1',
|
|
202
|
+
} as never);
|
|
203
|
+
device.mainId = 'ble-device';
|
|
204
|
+
device.commands = { disposed: false } as never;
|
|
205
|
+
(device as unknown as { deviceAcquired: boolean }).deviceAcquired = true;
|
|
206
|
+
const release = jest.spyOn(device, 'release').mockResolvedValue(undefined);
|
|
207
|
+
const run = jest.fn().mockResolvedValue(undefined);
|
|
208
|
+
|
|
209
|
+
await device.run(run, {
|
|
210
|
+
forceProtocolDetection: true,
|
|
211
|
+
skipInitialize: true,
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
expect(run).toHaveBeenCalledTimes(1);
|
|
215
|
+
expect(release).toHaveBeenCalledTimes(1);
|
|
216
|
+
});
|
|
217
|
+
|
|
116
218
|
test('keeps an explicit connectProtocol as a strict expected protocol', async () => {
|
|
117
219
|
jest.spyOn(DataManager, 'getSettings').mockReturnValue('react-native' as never);
|
|
118
220
|
const device = Device.fromDescriptor({
|
|
@@ -38,6 +38,28 @@ describe('DevicePool state lifecycle', () => {
|
|
|
38
38
|
expect(getDeviceState).toHaveBeenNthCalledWith(2, { refreshSections: ['settings'] });
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
+
test('actively re-detects a cached device when protocol detection is forced', async () => {
|
|
42
|
+
const descriptor = { path: 'cached-path', protocolType: 'V1' } as any;
|
|
43
|
+
const device = Device.fromDescriptor(descriptor);
|
|
44
|
+
const acquire = jest.spyOn(device, 'acquire').mockImplementation(() => {
|
|
45
|
+
device.originalDescriptor.protocolType = 'V2';
|
|
46
|
+
return Promise.resolve(true);
|
|
47
|
+
});
|
|
48
|
+
const initialize = jest.spyOn(device, 'initialize').mockResolvedValue(undefined);
|
|
49
|
+
const release = jest.spyOn(device, 'release').mockResolvedValue(undefined);
|
|
50
|
+
DevicePool.devicesCache = { 'cached-id': device };
|
|
51
|
+
|
|
52
|
+
const result = await DevicePool.getDevices([descriptor], 'cached-id', {
|
|
53
|
+
forceProtocolDetection: true,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
expect(acquire).toHaveBeenCalledWith(undefined, { forceProtocolDetection: true });
|
|
57
|
+
expect(initialize).toHaveBeenCalledWith({ forceProtocolDetection: true });
|
|
58
|
+
expect(release).toHaveBeenCalledTimes(1);
|
|
59
|
+
expect(device.originalDescriptor.protocolType).toBe('V2');
|
|
60
|
+
expect(result.deviceList).toEqual([device]);
|
|
61
|
+
});
|
|
62
|
+
|
|
41
63
|
test('keeps a discovered device when its Protocol V2 label cannot be read', async () => {
|
|
42
64
|
const labelError = new Error('settings unavailable');
|
|
43
65
|
const getDeviceState = jest
|
|
@@ -115,8 +115,8 @@ describe('DeviceSettings protocol routing', () => {
|
|
|
115
115
|
);
|
|
116
116
|
});
|
|
117
117
|
|
|
118
|
-
it('uses DeviceSettingsSet and
|
|
119
|
-
const { device, typedCall, updateState } = createDevice({ protocol: 'V2' });
|
|
118
|
+
it('uses DeviceSettingsSet and reloads Protocol V2 status and settings from the device', async () => {
|
|
119
|
+
const { device, typedCall, updateState, getDeviceState } = createDevice({ protocol: 'V2' });
|
|
120
120
|
const method = new DeviceSettings({
|
|
121
121
|
id: 2,
|
|
122
122
|
payload: {
|
|
@@ -141,21 +141,10 @@ describe('DeviceSettings protocol routing', () => {
|
|
|
141
141
|
haptic_feedback: true,
|
|
142
142
|
},
|
|
143
143
|
});
|
|
144
|
-
expect(
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
language: 'ja',
|
|
149
|
-
bleEnabled: true,
|
|
150
|
-
autoLockDelayMs: 60_000,
|
|
151
|
-
hapticFeedback: true,
|
|
152
|
-
},
|
|
153
|
-
},
|
|
154
|
-
'settings-write'
|
|
155
|
-
);
|
|
156
|
-
expect(typedCall.mock.calls.map(call => call[0])).not.toEqual(
|
|
157
|
-
expect.arrayContaining(['DeviceInfoGet', 'DeviceStatusGet', 'DeviceSettingsGet'])
|
|
158
|
-
);
|
|
144
|
+
expect(getDeviceState).toHaveBeenCalledWith({
|
|
145
|
+
refreshSections: ['status', 'settings'],
|
|
146
|
+
});
|
|
147
|
+
expect(updateState).not.toHaveBeenCalled();
|
|
159
148
|
});
|
|
160
149
|
|
|
161
150
|
it('uses the Pro2 passphrase page as a device-side toggle and verifies the target state', async () => {
|
|
@@ -183,7 +172,39 @@ describe('DeviceSettings protocol routing', () => {
|
|
|
183
172
|
});
|
|
184
173
|
expect(typedCall).not.toHaveBeenCalledWith('DeviceSettingsSet', 'Success', expect.anything());
|
|
185
174
|
expect(getDeviceState).toHaveBeenNthCalledWith(1, { refreshSections: ['status'] });
|
|
186
|
-
expect(getDeviceState).toHaveBeenNthCalledWith(2, {
|
|
175
|
+
expect(getDeviceState).toHaveBeenNthCalledWith(2, {
|
|
176
|
+
refreshSections: ['status', 'settings'],
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('reloads Protocol V2 status and settings after changing air-gap mode', async () => {
|
|
181
|
+
const { device, typedCall, getDeviceState } = createDevice({ protocol: 'V2' });
|
|
182
|
+
getDeviceState
|
|
183
|
+
.mockResolvedValueOnce({
|
|
184
|
+
settings: { airgapMode: false },
|
|
185
|
+
})
|
|
186
|
+
.mockResolvedValueOnce({
|
|
187
|
+
status: { unlocked: true },
|
|
188
|
+
settings: { airgapMode: true },
|
|
189
|
+
});
|
|
190
|
+
const method = new DeviceSettings({
|
|
191
|
+
id: 4,
|
|
192
|
+
payload: {
|
|
193
|
+
method: 'deviceSettings',
|
|
194
|
+
airgapMode: true,
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
method.init();
|
|
198
|
+
(method as any).device = device;
|
|
199
|
+
|
|
200
|
+
await expect(method.run()).resolves.toEqual({ message: 'Success' });
|
|
201
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSettingsPageShow', 'Success', {
|
|
202
|
+
page: DeviceSettingsPage.DeviceAirgap,
|
|
203
|
+
});
|
|
204
|
+
expect(getDeviceState).toHaveBeenNthCalledWith(1, { refreshSections: ['settings'] });
|
|
205
|
+
expect(getDeviceState).toHaveBeenNthCalledWith(2, {
|
|
206
|
+
refreshSections: ['status', 'settings'],
|
|
207
|
+
});
|
|
187
208
|
});
|
|
188
209
|
|
|
189
210
|
it('does not open a Pro2 settings page when the hardware already matches the target', async () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EDeviceType, EFirmwareType } from '@onekeyfe/hd-shared';
|
|
2
|
-
|
|
3
2
|
import { DeviceType, Enum_SafetyCheckLevel } from '@onekeyfe/hd-transport';
|
|
3
|
+
|
|
4
4
|
import {
|
|
5
5
|
mapApplySettingsToState,
|
|
6
6
|
mapDeviceSettingsToState,
|
|
@@ -145,6 +145,18 @@ describe('DeviceStateMapper', () => {
|
|
|
145
145
|
expect(patch.status?.unlocked).toBeUndefined();
|
|
146
146
|
});
|
|
147
147
|
|
|
148
|
+
test('maps the Protocol V2 Neo device type without treating it as Pro2', () => {
|
|
149
|
+
const patch = mapProtocolV2DeviceInfoToState({
|
|
150
|
+
hw: { Device_type: DeviceType.NEO, serial_no: 'NEO-SERIAL-1' },
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
expect(patch.identity).toMatchObject({
|
|
154
|
+
deviceType: EDeviceType.Neo,
|
|
155
|
+
model: 'neo',
|
|
156
|
+
serialNo: 'NEO-SERIAL-1',
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
148
160
|
test('maps the hardware model independently from Protocol V2', () => {
|
|
149
161
|
const pro = mapProtocolV2DeviceInfoToState({
|
|
150
162
|
protocol_version: 2,
|