@onekeyfe/hd-core 1.2.0-alpha.99 → 1.2.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 +678 -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 +2198 -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 +19 -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 +2135 -1470
- 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 +918 -741
- 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
|
@@ -95,7 +95,8 @@ describe('AllNetworkGetAddressBase tracing', () => {
|
|
|
95
95
|
'hidden-state',
|
|
96
96
|
false,
|
|
97
97
|
undefined,
|
|
98
|
-
false
|
|
98
|
+
false,
|
|
99
|
+
undefined
|
|
99
100
|
);
|
|
100
101
|
expect(calls).toEqual(['resume-hidden-session', 'run-chain-method']);
|
|
101
102
|
expect(typedCall).not.toHaveBeenCalled();
|
|
@@ -173,7 +174,13 @@ describe('AllNetworkGetAddressBase tracing', () => {
|
|
|
173
174
|
0
|
|
174
175
|
);
|
|
175
176
|
|
|
176
|
-
expect(checkPassphraseStateSafety).toHaveBeenCalledWith(
|
|
177
|
+
expect(checkPassphraseStateSafety).toHaveBeenCalledWith(
|
|
178
|
+
'hidden-state',
|
|
179
|
+
false,
|
|
180
|
+
undefined,
|
|
181
|
+
true,
|
|
182
|
+
undefined
|
|
183
|
+
);
|
|
177
184
|
expect(calls).toEqual(['resume-cardano-session', 'run-cardano-method']);
|
|
178
185
|
expect(typedCall).not.toHaveBeenCalled();
|
|
179
186
|
});
|
|
@@ -212,7 +219,10 @@ describe('AllNetworkGetAddressBase tracing', () => {
|
|
|
212
219
|
bundle: [],
|
|
213
220
|
},
|
|
214
221
|
});
|
|
215
|
-
method.protocolV2UnlockContext = {
|
|
222
|
+
method.protocolV2UnlockContext = {
|
|
223
|
+
preflightCompleted: true,
|
|
224
|
+
preflightMainPinSelected: true,
|
|
225
|
+
};
|
|
216
226
|
const typedCall = jest.fn();
|
|
217
227
|
method.device = {
|
|
218
228
|
checkPassphraseStateSafety,
|
|
@@ -250,7 +260,13 @@ describe('AllNetworkGetAddressBase tracing', () => {
|
|
|
250
260
|
0
|
|
251
261
|
);
|
|
252
262
|
|
|
253
|
-
expect(checkPassphraseStateSafety).toHaveBeenCalledWith(
|
|
263
|
+
expect(checkPassphraseStateSafety).toHaveBeenCalledWith(
|
|
264
|
+
undefined,
|
|
265
|
+
true,
|
|
266
|
+
undefined,
|
|
267
|
+
false,
|
|
268
|
+
true
|
|
269
|
+
);
|
|
254
270
|
expect(calls).toEqual(['resume-standard-session', 'run-chain-method']);
|
|
255
271
|
expect(typedCall).not.toHaveBeenCalled();
|
|
256
272
|
});
|
|
@@ -19,12 +19,28 @@ const createCommands = () => {
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
describe('DeviceCommands failure mapping', () => {
|
|
22
|
-
it('
|
|
22
|
+
it.each(['File already exists', 'NFT already exists'])(
|
|
23
|
+
'maps duplicate file response "%s" to FileAlreadyExists',
|
|
24
|
+
async message => {
|
|
25
|
+
const commands = createCommands();
|
|
26
|
+
await expect(
|
|
27
|
+
commands._filterCommonTypes(
|
|
28
|
+
{
|
|
29
|
+
type: 'Failure',
|
|
30
|
+
message: { code: 'Failure_DataError', message },
|
|
31
|
+
} as any,
|
|
32
|
+
'NFTUpdate'
|
|
33
|
+
)
|
|
34
|
+
).rejects.toMatchObject({ errorCode: HardwareErrorCode.FileAlreadyExists });
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
it('logs passphrase request and canonical response without exposing the passphrase', async () => {
|
|
23
39
|
const commands = createCommands();
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
40
|
+
const log = getLogger(LoggerNames.DeviceCommands);
|
|
41
|
+
const coreLog = getLogger(LoggerNames.Core);
|
|
42
|
+
log.messages.length = 0;
|
|
43
|
+
coreLog.messages.length = 0;
|
|
28
44
|
commands.mainId = 'main-id';
|
|
29
45
|
commands.transport = {
|
|
30
46
|
call: jest.fn().mockResolvedValue({
|
|
@@ -36,13 +52,13 @@ describe('DeviceCommands failure mapping', () => {
|
|
|
36
52
|
} as any;
|
|
37
53
|
|
|
38
54
|
await expect(
|
|
39
|
-
commands.
|
|
55
|
+
commands._commonCall('DeviceSessionAskPassphrase', {
|
|
40
56
|
passphrase: 'hidden-wallet-secret',
|
|
41
57
|
on_device: false,
|
|
42
58
|
})
|
|
43
59
|
).resolves.toMatchObject({ type: 'Success' });
|
|
44
60
|
|
|
45
|
-
expect(
|
|
61
|
+
expect(log.messages.at(-2)?.message).toEqual([
|
|
46
62
|
'[DeviceCommands] [call] Sending',
|
|
47
63
|
'DeviceSessionAskPassphrase',
|
|
48
64
|
{
|
|
@@ -50,21 +66,82 @@ describe('DeviceCommands failure mapping', () => {
|
|
|
50
66
|
on_device: false,
|
|
51
67
|
},
|
|
52
68
|
]);
|
|
53
|
-
expect(
|
|
54
|
-
'
|
|
55
|
-
|
|
69
|
+
expect(log.messages.at(-1)?.message).toEqual([
|
|
70
|
+
'_filterCommonTypes: ',
|
|
71
|
+
{
|
|
72
|
+
request: 'DeviceSessionAskPassphrase',
|
|
73
|
+
response: {
|
|
74
|
+
type: 'Success',
|
|
75
|
+
message: {
|
|
76
|
+
message: 'Passphrase accepted',
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
]);
|
|
81
|
+
expect(
|
|
82
|
+
coreLog.messages.some(entry => entry.message[0] === '[DeviceCommands] [call] Received')
|
|
83
|
+
).toBe(false);
|
|
84
|
+
expect(JSON.stringify([...log.messages, ...coreLog.messages])).not.toContain(
|
|
85
|
+
'hidden-wallet-secret'
|
|
86
|
+
);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('redacts passphrases from transport errors logged through Core', async () => {
|
|
90
|
+
const commands = createCommands();
|
|
91
|
+
const log = getLogger(LoggerNames.DeviceCommands);
|
|
92
|
+
const coreLog = getLogger(LoggerNames.Core);
|
|
93
|
+
log.messages.length = 0;
|
|
94
|
+
coreLog.messages.length = 0;
|
|
95
|
+
const transportError = Object.assign(new Error('transport failed'), {
|
|
96
|
+
response: {
|
|
97
|
+
data: {
|
|
98
|
+
passphrase: 'hidden-wallet-secret',
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
commands.mainId = 'main-id';
|
|
103
|
+
commands.transport = {
|
|
104
|
+
call: jest.fn().mockRejectedValue(transportError),
|
|
105
|
+
} as any;
|
|
106
|
+
|
|
107
|
+
await expect(
|
|
108
|
+
commands._commonCall('DeviceSessionAskPassphrase', {
|
|
109
|
+
passphrase: 'hidden-wallet-secret',
|
|
110
|
+
on_device: false,
|
|
111
|
+
})
|
|
112
|
+
).rejects.toBe(transportError);
|
|
113
|
+
|
|
114
|
+
expect(coreLog.messages.at(-1)?.message).toEqual([
|
|
115
|
+
'[DeviceCommands] [call] Received error',
|
|
56
116
|
{
|
|
57
|
-
|
|
117
|
+
request: 'DeviceSessionAskPassphrase',
|
|
118
|
+
errorCode: undefined,
|
|
119
|
+
response: {
|
|
120
|
+
passphrase: '[REDACTED]',
|
|
121
|
+
},
|
|
58
122
|
},
|
|
59
123
|
]);
|
|
60
|
-
expect(JSON.stringify([...
|
|
124
|
+
expect(JSON.stringify([...log.messages, ...coreLog.messages])).not.toContain(
|
|
61
125
|
'hidden-wallet-secret'
|
|
62
126
|
);
|
|
63
127
|
});
|
|
64
128
|
|
|
65
|
-
it('
|
|
129
|
+
it('preserves the Protocol V2 peer-removed pairing error code', async () => {
|
|
66
130
|
const commands = createCommands();
|
|
67
|
-
const
|
|
131
|
+
const transportError = Object.assign(new Error('Peer removed pairing information'), {
|
|
132
|
+
errorCode: HardwareErrorCode.BlePeerRemovedPairingInformation,
|
|
133
|
+
});
|
|
134
|
+
commands.mainId = 'main-id';
|
|
135
|
+
commands.transport = {
|
|
136
|
+
call: jest.fn().mockRejectedValue(transportError),
|
|
137
|
+
} as any;
|
|
138
|
+
|
|
139
|
+
await expect(commands._commonCall('DeviceInfoGet', {})).rejects.toBe(transportError);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('logs canonical DeviceStatus response fields without exposing the device ID', async () => {
|
|
143
|
+
const commands = createCommands();
|
|
144
|
+
const log = getLogger(LoggerNames.DeviceCommands);
|
|
68
145
|
log.messages.length = 0;
|
|
69
146
|
commands.mainId = 'main-id';
|
|
70
147
|
commands.transport = {
|
|
@@ -82,22 +159,27 @@ describe('DeviceCommands failure mapping', () => {
|
|
|
82
159
|
}),
|
|
83
160
|
} as any;
|
|
84
161
|
|
|
85
|
-
await expect(commands.
|
|
162
|
+
await expect(commands._commonCall('DeviceStatusGet', {})).resolves.toMatchObject({
|
|
86
163
|
type: 'DeviceStatus',
|
|
87
164
|
});
|
|
88
165
|
|
|
89
166
|
const receivedLog = log.messages.at(-1)?.message;
|
|
90
167
|
expect(receivedLog).toEqual([
|
|
91
|
-
'
|
|
92
|
-
'DeviceStatus',
|
|
168
|
+
'_filterCommonTypes: ',
|
|
93
169
|
{
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
170
|
+
request: 'DeviceStatusGet',
|
|
171
|
+
response: {
|
|
172
|
+
type: 'DeviceStatus',
|
|
173
|
+
message: {
|
|
174
|
+
device_id: '[REDACTED]',
|
|
175
|
+
unlocked: true,
|
|
176
|
+
init_states: true,
|
|
177
|
+
backup_required: false,
|
|
178
|
+
passphrase_enabled: true,
|
|
179
|
+
attach_to_pin_enabled: false,
|
|
180
|
+
unlocked_by_attach_to_pin: false,
|
|
181
|
+
},
|
|
182
|
+
},
|
|
101
183
|
},
|
|
102
184
|
]);
|
|
103
185
|
expect(JSON.stringify(receivedLog)).not.toContain('sensitive-device-id');
|
|
@@ -125,6 +207,59 @@ describe('DeviceCommands failure mapping', () => {
|
|
|
125
207
|
expect(JSON.stringify(log.messages)).not.toContain('secret-wallet-address');
|
|
126
208
|
});
|
|
127
209
|
|
|
210
|
+
it('logs the sanitized DeviceInfo response payload', async () => {
|
|
211
|
+
const commands = createCommands();
|
|
212
|
+
const log = getLogger(LoggerNames.DeviceCommands);
|
|
213
|
+
log.messages.length = 0;
|
|
214
|
+
|
|
215
|
+
await expect(
|
|
216
|
+
commands._filterCommonTypes(
|
|
217
|
+
{
|
|
218
|
+
type: 'DeviceInfo',
|
|
219
|
+
message: {
|
|
220
|
+
protocol_version: 2,
|
|
221
|
+
hw: {
|
|
222
|
+
Device_type: 7,
|
|
223
|
+
hardware_version: '1.0.0',
|
|
224
|
+
},
|
|
225
|
+
main_mcu: {
|
|
226
|
+
application: {
|
|
227
|
+
version: '5.0.0',
|
|
228
|
+
build_id: '20260811',
|
|
229
|
+
hash: 'firmware-hash',
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
} as any,
|
|
234
|
+
'DeviceInfoGet'
|
|
235
|
+
)
|
|
236
|
+
).resolves.toMatchObject({ type: 'DeviceInfo' });
|
|
237
|
+
|
|
238
|
+
expect(log.messages.at(-1)?.message).toEqual([
|
|
239
|
+
'_filterCommonTypes: ',
|
|
240
|
+
{
|
|
241
|
+
request: 'DeviceInfoGet',
|
|
242
|
+
response: {
|
|
243
|
+
type: 'DeviceInfo',
|
|
244
|
+
message: {
|
|
245
|
+
protocol_version: 2,
|
|
246
|
+
hw: {
|
|
247
|
+
Device_type: 7,
|
|
248
|
+
hardware_version: '1.0.0',
|
|
249
|
+
},
|
|
250
|
+
main_mcu: {
|
|
251
|
+
application: {
|
|
252
|
+
version: '5.0.0',
|
|
253
|
+
build_id: '20260811',
|
|
254
|
+
hash: 'firmware-hash',
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
]);
|
|
261
|
+
});
|
|
262
|
+
|
|
128
263
|
it('logs the sanitized DeviceFirmwareUpdateStatus response payload', async () => {
|
|
129
264
|
const commands = createCommands();
|
|
130
265
|
const log = getLogger(LoggerNames.DeviceCommands);
|
|
@@ -170,6 +305,32 @@ describe('DeviceCommands failure mapping', () => {
|
|
|
170
305
|
]);
|
|
171
306
|
});
|
|
172
307
|
|
|
308
|
+
it.each(['Failure_ProcessError', 5])(
|
|
309
|
+
'maps USB-priority link disabled to public BLE error 723 for code %s',
|
|
310
|
+
async code => {
|
|
311
|
+
const commands = createCommands();
|
|
312
|
+
|
|
313
|
+
await expect(
|
|
314
|
+
commands._filterCommonTypes(
|
|
315
|
+
{
|
|
316
|
+
type: 'Failure',
|
|
317
|
+
message: {
|
|
318
|
+
code,
|
|
319
|
+
message: ' link disabled ',
|
|
320
|
+
},
|
|
321
|
+
} as any,
|
|
322
|
+
'DeviceInfo'
|
|
323
|
+
)
|
|
324
|
+
).rejects.toMatchObject({
|
|
325
|
+
errorCode: HardwareErrorCode.BleUnavailableWhileUsbConnected,
|
|
326
|
+
params: {
|
|
327
|
+
failureCode: code,
|
|
328
|
+
firmwareMessage: ' link disabled ',
|
|
329
|
+
},
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
);
|
|
333
|
+
|
|
173
334
|
it('maps an invalid DeviceSessionGet resume to WalletSessionInvalid', async () => {
|
|
174
335
|
const commands = createCommands();
|
|
175
336
|
|
|
@@ -337,7 +498,7 @@ describe('DeviceCommands failure mapping', () => {
|
|
|
337
498
|
});
|
|
338
499
|
});
|
|
339
500
|
|
|
340
|
-
it.each(['Cancelled on device', 'Confirm dismissed'])(
|
|
501
|
+
it.each(['Cancelled on device', 'Confirm dismissed', 'Update cancelled'])(
|
|
341
502
|
'maps legacy Protocol V2 cancellation message "%s" without a subcode',
|
|
342
503
|
async message => {
|
|
343
504
|
const commands = createCommands();
|
|
@@ -561,17 +722,22 @@ describe('DeviceCommands failure mapping', () => {
|
|
|
561
722
|
});
|
|
562
723
|
|
|
563
724
|
describe('DeviceCommands Protocol V2 interactive response compatibility', () => {
|
|
564
|
-
it('
|
|
725
|
+
it('auto-acks Pro2 ButtonRequest and registers Cancel instead of Initialize', async () => {
|
|
565
726
|
const commands = createCommands();
|
|
566
727
|
const emit = jest.fn();
|
|
728
|
+
const cancelDevice = jest.spyOn(commands, 'cancelDevice').mockResolvedValue(undefined);
|
|
729
|
+
const cancelDeviceOnOneKeyDevice = jest
|
|
730
|
+
.spyOn(commands, 'cancelDeviceOnOneKeyDevice')
|
|
731
|
+
.mockResolvedValue(undefined);
|
|
567
732
|
const commonCall = jest.fn().mockResolvedValue({
|
|
568
733
|
type: 'Success',
|
|
569
734
|
message: {},
|
|
570
735
|
});
|
|
736
|
+
const setCancelableAction = jest.fn();
|
|
571
737
|
commands.device = {
|
|
572
738
|
...commands.device,
|
|
573
739
|
getCurrentDeviceType: jest.fn(() => 'pro2'),
|
|
574
|
-
setCancelableAction
|
|
740
|
+
setCancelableAction,
|
|
575
741
|
emit,
|
|
576
742
|
listenerCount: jest.fn(() => 0),
|
|
577
743
|
} as any;
|
|
@@ -593,6 +759,9 @@ describe('DeviceCommands Protocol V2 interactive response compatibility', () =>
|
|
|
593
759
|
expect.objectContaining({ code: 'ButtonRequest_PinEntry' })
|
|
594
760
|
);
|
|
595
761
|
expect(commonCall).toHaveBeenCalledWith('ButtonAck', {}, undefined);
|
|
762
|
+
await setCancelableAction.mock.calls[0][0]();
|
|
763
|
+
expect(cancelDevice).toHaveBeenCalledTimes(1);
|
|
764
|
+
expect(cancelDeviceOnOneKeyDevice).not.toHaveBeenCalled();
|
|
596
765
|
});
|
|
597
766
|
|
|
598
767
|
it('rejects PassphraseRequest when the Pro2 UI listener is not registered', async () => {
|
|
@@ -644,7 +813,13 @@ describe('DeviceCommands cancellation', () => {
|
|
|
644
813
|
try {
|
|
645
814
|
const commands = createCommands();
|
|
646
815
|
commands.disposed = false;
|
|
816
|
+
commands.mainId = 'main-id';
|
|
647
817
|
commands.callPromise = new Promise(() => {});
|
|
818
|
+
const disconnect = jest.fn().mockResolvedValue(undefined);
|
|
819
|
+
commands.transport = {
|
|
820
|
+
name: 'ReactNativeBleTransport',
|
|
821
|
+
disconnect,
|
|
822
|
+
} as any;
|
|
648
823
|
const dispose = jest.fn().mockResolvedValue(undefined);
|
|
649
824
|
commands.dispose = dispose;
|
|
650
825
|
|
|
@@ -654,6 +829,7 @@ describe('DeviceCommands cancellation', () => {
|
|
|
654
829
|
|
|
655
830
|
await expect(cancellation).resolves.toBeUndefined();
|
|
656
831
|
expect(dispose).toHaveBeenCalledWith(true);
|
|
832
|
+
expect(disconnect).toHaveBeenCalledWith('main-id');
|
|
657
833
|
expect(commands.callPromise).toBeUndefined();
|
|
658
834
|
} finally {
|
|
659
835
|
jest.useRealTimers();
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
import { encode as encodeJpeg } from 'jpeg-js';
|
|
3
|
+
|
|
4
|
+
import { decodeCanonicalBase64, decodeJpegBase64ToRgba } from '../src/api/helpers/base64Data';
|
|
5
|
+
|
|
6
|
+
const createJpegBase64 = (width: number, height: number) => {
|
|
7
|
+
const rgba = new Uint8Array(width * height * 4).fill(0xff);
|
|
8
|
+
return encodeJpeg({ width, height, data: rgba }, 80).data.toString('base64');
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
describe('Base64 resource data', () => {
|
|
12
|
+
test('decodes canonical Base64 to a detached Uint8Array', () => {
|
|
13
|
+
const decoded = decodeCanonicalBase64({
|
|
14
|
+
value: 'AQID',
|
|
15
|
+
parameterName: 'packageBase64',
|
|
16
|
+
maxBytes: 3,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
expect(decoded).toBeInstanceOf(Uint8Array);
|
|
20
|
+
expect(Array.from(decoded)).toEqual([1, 2, 3]);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test.each(['', 'not-base64', 'AB==', 'data:image/jpeg;base64,AQID'])(
|
|
24
|
+
'rejects non-canonical Base64 input %p',
|
|
25
|
+
value => {
|
|
26
|
+
expect(() =>
|
|
27
|
+
decodeCanonicalBase64({ value, parameterName: 'data', maxBytes: 1024 })
|
|
28
|
+
).toThrow();
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
test('rejects oversized Base64 before decoding', () => {
|
|
33
|
+
const value = Buffer.alloc(64 * 1024 + 17).toString('base64');
|
|
34
|
+
expect(() =>
|
|
35
|
+
decodeCanonicalBase64({ value, parameterName: 'data', maxBytes: 64 * 1024 })
|
|
36
|
+
).toThrow('maximum supported size');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('decodes and validates a JPEG with the expected dimensions', () => {
|
|
40
|
+
const decoded = decodeJpegBase64ToRgba({
|
|
41
|
+
jpegBase64: createJpegBase64(2, 1),
|
|
42
|
+
parameterName: 'jpegBase64',
|
|
43
|
+
expectedWidth: 2,
|
|
44
|
+
expectedHeight: 1,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
expect(decoded).toMatchObject({ width: 2, height: 1 });
|
|
48
|
+
expect(decoded.data).toHaveLength(8);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('rejects non-JPEG bytes and unexpected dimensions', () => {
|
|
52
|
+
expect(() =>
|
|
53
|
+
decodeJpegBase64ToRgba({
|
|
54
|
+
jpegBase64: 'AQID',
|
|
55
|
+
parameterName: 'jpegBase64',
|
|
56
|
+
expectedWidth: 2,
|
|
57
|
+
expectedHeight: 1,
|
|
58
|
+
})
|
|
59
|
+
).toThrow('JPEG image');
|
|
60
|
+
expect(() =>
|
|
61
|
+
decodeJpegBase64ToRgba({
|
|
62
|
+
jpegBase64: createJpegBase64(2, 1),
|
|
63
|
+
parameterName: 'jpegBase64',
|
|
64
|
+
expectedWidth: 1,
|
|
65
|
+
expectedHeight: 1,
|
|
66
|
+
})
|
|
67
|
+
).toThrow('1x1');
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -33,8 +33,6 @@ const validComponentIntegrity = {
|
|
|
33
33
|
const release: IFirmwareReleaseInfo = {
|
|
34
34
|
required: true,
|
|
35
35
|
version: [2, 0, 0],
|
|
36
|
-
url: 'https://example.com/application-p1.bin',
|
|
37
|
-
fingerprint: 'release-fingerprint',
|
|
38
36
|
changelog: {
|
|
39
37
|
'zh-CN': '更新',
|
|
40
38
|
'en-US': 'Update',
|
|
@@ -620,6 +618,54 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
|
|
|
620
618
|
});
|
|
621
619
|
});
|
|
622
620
|
|
|
621
|
+
test('selects the Protocol V2 resource archive using the DeviceState identity', async () => {
|
|
622
|
+
const releaseWithResources: IFirmwareReleaseInfo = {
|
|
623
|
+
...release,
|
|
624
|
+
resources: { source: resourceSource },
|
|
625
|
+
};
|
|
626
|
+
const method = new CheckAllFirmwareRelease({
|
|
627
|
+
id: 1,
|
|
628
|
+
payload: {
|
|
629
|
+
method: 'checkAllFirmwareRelease',
|
|
630
|
+
platform: 'desktop',
|
|
631
|
+
protocolV2ForceUpdateTargets: ['resource'],
|
|
632
|
+
},
|
|
633
|
+
});
|
|
634
|
+
method.init();
|
|
635
|
+
method.device = {
|
|
636
|
+
isProtocolV2: () => true,
|
|
637
|
+
features: {
|
|
638
|
+
firmwareVersion: '1.0.0',
|
|
639
|
+
serialNo: 'device-without-model-prefix',
|
|
640
|
+
},
|
|
641
|
+
getDeviceState: jest.fn().mockResolvedValue({
|
|
642
|
+
identity: { deviceType: 'pro2', firmwareType: EFirmwareType.Universal },
|
|
643
|
+
status: { mode: 'normal' },
|
|
644
|
+
versions: currentVersions,
|
|
645
|
+
}),
|
|
646
|
+
} as unknown as CheckAllFirmwareRelease['device'];
|
|
647
|
+
const getLatestReleaseSpy = jest
|
|
648
|
+
.spyOn(DataManager, 'getFirmwareLatestRelease')
|
|
649
|
+
.mockImplementation(features =>
|
|
650
|
+
features.deviceType === 'pro2' ? releaseWithResources : undefined
|
|
651
|
+
);
|
|
652
|
+
|
|
653
|
+
await expect(method.run()).resolves.toMatchObject({
|
|
654
|
+
deviceType: 'pro2',
|
|
655
|
+
resourceArchive: resourceSource,
|
|
656
|
+
targetsToUpdate: expect.arrayContaining(['resource']),
|
|
657
|
+
firmwareUpdatePlan: {
|
|
658
|
+
executor: 'v4',
|
|
659
|
+
deviceModel: 'pro2',
|
|
660
|
+
targetsToUpdate: expect.arrayContaining(['resource']),
|
|
661
|
+
},
|
|
662
|
+
});
|
|
663
|
+
expect(getLatestReleaseSpy).toHaveBeenCalledWith(
|
|
664
|
+
expect.objectContaining({ deviceType: 'pro2' }),
|
|
665
|
+
EFirmwareType.Universal
|
|
666
|
+
);
|
|
667
|
+
});
|
|
668
|
+
|
|
623
669
|
test.each(['resource', 'boot_resources'] as const)(
|
|
624
670
|
'allows an explicitly forced Protocol V2 resource-only target through %s',
|
|
625
671
|
async forceTarget => {
|
|
@@ -16,8 +16,6 @@ jest.mock('../src/data/config', () => ({
|
|
|
16
16
|
const release: IFirmwareReleaseInfo = {
|
|
17
17
|
required: false,
|
|
18
18
|
version: [2, 0, 0],
|
|
19
|
-
url: 'https://example.com/application-p1.okpkg',
|
|
20
|
-
fingerprint: 'release-fingerprint',
|
|
21
19
|
changelog: {
|
|
22
20
|
'zh-CN': '更新',
|
|
23
21
|
'en-US': 'Update',
|
|
@@ -68,6 +66,37 @@ const createDevice = (deviceType: 'pro2' | 'neo') => ({
|
|
|
68
66
|
}),
|
|
69
67
|
});
|
|
70
68
|
|
|
69
|
+
const createFeaturelessDevice = (protocolV2: boolean) => {
|
|
70
|
+
const device = {
|
|
71
|
+
isProtocolV2: jest.fn(() => protocolV2),
|
|
72
|
+
features: undefined,
|
|
73
|
+
getDeviceState: jest.fn(),
|
|
74
|
+
};
|
|
75
|
+
device.getDeviceState.mockImplementation(() => {
|
|
76
|
+
Object.assign(device, {
|
|
77
|
+
features: {
|
|
78
|
+
deviceType: 'pro2',
|
|
79
|
+
firmwareVersion: '1.0.0',
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
return Promise.resolve({
|
|
83
|
+
identity: {
|
|
84
|
+
deviceType: 'pro2',
|
|
85
|
+
firmwareType: EFirmwareType.Universal,
|
|
86
|
+
},
|
|
87
|
+
status: { mode: 'bootloader' },
|
|
88
|
+
versions: {
|
|
89
|
+
firmware: '1.0.0',
|
|
90
|
+
applicationP1: '1.0.0',
|
|
91
|
+
bootloader: '1.0.0',
|
|
92
|
+
board: '1.0.0',
|
|
93
|
+
ble: '1.0.0',
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
return device;
|
|
98
|
+
};
|
|
99
|
+
|
|
71
100
|
describe.each(['pro2', 'neo'] as const)('Protocol V2 release checks for %s', deviceType => {
|
|
72
101
|
afterEach(() => {
|
|
73
102
|
jest.restoreAllMocks();
|
|
@@ -168,12 +197,50 @@ describe.each(['pro2', 'neo'] as const)('Protocol V2 release checks for %s', dev
|
|
|
168
197
|
});
|
|
169
198
|
});
|
|
170
199
|
|
|
171
|
-
test('
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
200
|
+
test('probes Protocol V2 loader state before requiring initialized features', async () => {
|
|
201
|
+
jest.spyOn(DataManager, 'getFirmwareLatestRelease').mockReturnValue(release);
|
|
202
|
+
const firmwareDevice = createFeaturelessDevice(true);
|
|
203
|
+
const bleDevice = createFeaturelessDevice(true);
|
|
204
|
+
const bootloaderDevice = createFeaturelessDevice(true);
|
|
205
|
+
const firmwareMethod = new CheckFirmwareRelease({
|
|
206
|
+
id: 1,
|
|
207
|
+
payload: { method: 'checkFirmwareRelease' },
|
|
208
|
+
});
|
|
209
|
+
const bleMethod = new CheckBLEFirmwareRelease({
|
|
210
|
+
id: 2,
|
|
211
|
+
payload: { method: 'checkBLEFirmwareRelease' },
|
|
212
|
+
});
|
|
213
|
+
const bootloaderMethod = new CheckBootloaderRelease({
|
|
214
|
+
id: 3,
|
|
215
|
+
payload: { method: 'checkBootloaderRelease' },
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
firmwareMethod.device = firmwareDevice as unknown as CheckFirmwareRelease['device'];
|
|
219
|
+
bleMethod.device = bleDevice as unknown as CheckBLEFirmwareRelease['device'];
|
|
220
|
+
bootloaderMethod.device = bootloaderDevice as unknown as CheckBootloaderRelease['device'];
|
|
221
|
+
|
|
222
|
+
await expect(firmwareMethod.run()).resolves.toMatchObject({
|
|
223
|
+
status: 'outdated',
|
|
224
|
+
shouldUpdate: true,
|
|
225
|
+
});
|
|
226
|
+
await expect(bleMethod.run()).resolves.toMatchObject({
|
|
227
|
+
status: 'outdated',
|
|
228
|
+
shouldUpdate: true,
|
|
229
|
+
});
|
|
230
|
+
await expect(bootloaderMethod.run()).resolves.toMatchObject({
|
|
231
|
+
status: 'outdated',
|
|
232
|
+
shouldUpdate: true,
|
|
233
|
+
});
|
|
234
|
+
for (const device of [firmwareDevice, bleDevice, bootloaderDevice]) {
|
|
235
|
+
expect(device.isProtocolV2).toHaveBeenCalled();
|
|
236
|
+
expect(device.getDeviceState).toHaveBeenCalledTimes(1);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
test('keeps featureless Protocol V1 release probes optional', async () => {
|
|
241
|
+
const firmwareDevice = createFeaturelessDevice(false);
|
|
242
|
+
const bleDevice = createFeaturelessDevice(false);
|
|
243
|
+
const bootloaderDevice = createFeaturelessDevice(false);
|
|
177
244
|
const firmwareMethod = new CheckFirmwareRelease({
|
|
178
245
|
id: 1,
|
|
179
246
|
payload: { method: 'checkFirmwareRelease' },
|
|
@@ -187,13 +254,15 @@ test('returns null from optional release probes when device features are unavail
|
|
|
187
254
|
payload: { method: 'checkBootloaderRelease' },
|
|
188
255
|
});
|
|
189
256
|
|
|
190
|
-
firmwareMethod.device =
|
|
191
|
-
bleMethod.device =
|
|
192
|
-
bootloaderMethod.device =
|
|
257
|
+
firmwareMethod.device = firmwareDevice as unknown as CheckFirmwareRelease['device'];
|
|
258
|
+
bleMethod.device = bleDevice as unknown as CheckBLEFirmwareRelease['device'];
|
|
259
|
+
bootloaderMethod.device = bootloaderDevice as unknown as CheckBootloaderRelease['device'];
|
|
193
260
|
|
|
194
261
|
await expect(firmwareMethod.run()).resolves.toBeNull();
|
|
195
262
|
await expect(bleMethod.run()).resolves.toBeNull();
|
|
196
263
|
await expect(bootloaderMethod.run()).resolves.toBeNull();
|
|
197
|
-
|
|
198
|
-
|
|
264
|
+
for (const device of [firmwareDevice, bleDevice, bootloaderDevice]) {
|
|
265
|
+
expect(device.isProtocolV2).toHaveBeenCalled();
|
|
266
|
+
expect(device.getDeviceState).not.toHaveBeenCalled();
|
|
267
|
+
}
|
|
199
268
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
+
import { createProtocolV2LinkDisabledError } from '@onekeyfe/hd-transport';
|
|
2
3
|
|
|
3
4
|
import DeviceConnector from '../src/device/DeviceConnector';
|
|
4
5
|
|
|
@@ -78,4 +79,24 @@ describe('DeviceConnector protocol validation', () => {
|
|
|
78
79
|
'Device protocol mismatch: expected V2, detected V1'
|
|
79
80
|
);
|
|
80
81
|
});
|
|
82
|
+
|
|
83
|
+
it('preserves the Protocol V2 USB-priority failure as public BLE error 723', async () => {
|
|
84
|
+
transportManagerMock.default.getTransport.mockReturnValue({
|
|
85
|
+
acquire: jest
|
|
86
|
+
.fn()
|
|
87
|
+
.mockRejectedValue(
|
|
88
|
+
createProtocolV2LinkDisabledError('Failure_ProcessError', 'link disabled')
|
|
89
|
+
),
|
|
90
|
+
getProtocolType: jest.fn(() => undefined),
|
|
91
|
+
});
|
|
92
|
+
const connector = new DeviceConnector();
|
|
93
|
+
|
|
94
|
+
await expect(connector.acquire('pro2-id', undefined, undefined, 'V2')).rejects.toMatchObject({
|
|
95
|
+
errorCode: HardwareErrorCode.BleUnavailableWhileUsbConnected,
|
|
96
|
+
params: {
|
|
97
|
+
failureCode: 'Failure_ProcessError',
|
|
98
|
+
firmwareMessage: 'link disabled',
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
});
|
|
81
102
|
});
|