@onekeyfe/hd-core 1.1.27-alpha.30 → 1.1.27-alpha.32
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__/evmSignTransaction.test.ts +1 -1
- package/__tests__/evmSignTypedData.test.ts +1 -1
- package/__tests__/protocol-v2.test.ts +503 -37
- package/dist/api/DirList.d.ts.map +1 -1
- package/dist/api/DirMake.d.ts.map +1 -1
- package/dist/api/DirRemove.d.ts.map +1 -1
- package/dist/api/FileDelete.d.ts.map +1 -1
- package/dist/api/FileRead.d.ts.map +1 -1
- package/dist/api/FileWrite.d.ts.map +1 -1
- package/dist/api/GetPassphraseState.d.ts +6 -1
- package/dist/api/GetPassphraseState.d.ts.map +1 -1
- package/dist/api/PathInfo.d.ts.map +1 -1
- package/dist/api/conflux/ConfluxSignTransaction.d.ts.map +1 -1
- package/dist/api/dynex/DnxGetAddress.d.ts.map +1 -1
- package/dist/api/dynex/DnxSignTransaction.d.ts.map +1 -1
- package/dist/api/helpers/batchGetPublickeys.d.ts.map +1 -1
- package/dist/api/helpers/filesystemValidation.d.ts +7 -0
- package/dist/api/helpers/filesystemValidation.d.ts.map +1 -0
- package/dist/api/index.d.ts +5 -5
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceFirmwareUpdate.d.ts +7 -0
- package/dist/api/protocol-v2/DeviceFirmwareUpdate.d.ts.map +1 -0
- package/dist/api/protocol-v2/DeviceGetDeviceInfo.d.ts +7 -0
- package/dist/api/protocol-v2/DeviceGetDeviceInfo.d.ts.map +1 -0
- package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts +6 -0
- package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts.map +1 -0
- package/dist/api/protocol-v2/DeviceGetOnboardingStatus.d.ts +6 -0
- package/dist/api/protocol-v2/DeviceGetOnboardingStatus.d.ts.map +1 -0
- package/dist/api/protocol-v2/DeviceReboot.d.ts +7 -0
- package/dist/api/protocol-v2/DeviceReboot.d.ts.map +1 -0
- package/dist/api/protocol-v2/helpers.d.ts +19 -19
- package/dist/api/protocol-v2/helpers.d.ts.map +1 -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/MessagesConfig.d.ts +2 -2
- package/dist/data-manager/MessagesConfig.d.ts.map +1 -1
- package/dist/data-manager/TransportManager.d.ts +3 -3
- package/dist/data-manager/TransportManager.d.ts.map +1 -1
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/index.d.ts +37 -27
- package/dist/index.js +385 -236
- package/dist/protocols/protocol-v2/features.d.ts +2 -1
- package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/firmware.d.ts +7 -7
- package/dist/types/api/getPassphraseState.d.ts +10 -1
- package/dist/types/api/getPassphraseState.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +7 -6
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/protocolV2.d.ts +16 -16
- package/dist/types/api/protocolV2.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesUtils.d.ts +5 -3
- package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/DirList.ts +6 -2
- package/src/api/DirMake.ts +2 -1
- package/src/api/DirRemove.ts +2 -1
- package/src/api/FileDelete.ts +2 -1
- package/src/api/FileRead.ts +12 -5
- package/src/api/FileWrite.ts +19 -7
- package/src/api/FirmwareUpdateV4.ts +13 -13
- package/src/api/GetPassphraseState.ts +18 -2
- package/src/api/PathInfo.ts +2 -1
- package/src/api/allnetwork/AllNetworkGetAddressBase.ts +15 -0
- package/src/api/conflux/ConfluxSignTransaction.ts +5 -2
- package/src/api/device/DeviceRebootToBoardloader.ts +4 -4
- package/src/api/device/DeviceRebootToBootloader.ts +4 -4
- package/src/api/dynex/DnxGetAddress.ts +7 -0
- package/src/api/dynex/DnxSignTransaction.ts +7 -0
- package/src/api/evm/EVMGetAddress.ts +1 -1
- package/src/api/evm/EVMGetPublicKey.ts +1 -1
- package/src/api/evm/EVMSignMessage.ts +1 -1
- package/src/api/evm/EVMSignTransaction.ts +1 -1
- package/src/api/evm/EVMSignTypedData.ts +6 -6
- package/src/api/evm/EVMVerifyMessage.ts +1 -1
- package/src/api/helpers/batchGetPublickeys.ts +4 -2
- package/src/api/helpers/filesystemValidation.ts +51 -0
- package/src/api/index.ts +5 -5
- package/src/api/protocol-v2/{DevFirmwareUpdate.ts → DeviceFirmwareUpdate.ts} +5 -4
- package/src/api/protocol-v2/{DevGetDeviceInfo.ts → DeviceGetDeviceInfo.ts} +3 -3
- package/src/api/protocol-v2/{DevGetFirmwareUpdateStatus.ts → DeviceGetFirmwareUpdateStatus.ts} +3 -3
- package/src/api/protocol-v2/{DevGetOnboardingStatus.ts → DeviceGetOnboardingStatus.ts} +3 -3
- package/src/api/protocol-v2/{DevReboot.ts → DeviceReboot.ts} +3 -3
- package/src/api/protocol-v2/helpers.ts +68 -45
- package/src/api/tron/TronSignMessage.ts +1 -1
- package/src/api/xrp/XrpSignTransaction.ts +1 -1
- package/src/core/index.ts +13 -1
- package/src/data/messages/{messages-pro2.json → messages-protocol-v2.json} +67 -63
- package/src/data-manager/DataManager.ts +9 -8
- package/src/data-manager/MessagesConfig.ts +14 -14
- package/src/data-manager/TransportManager.ts +13 -13
- package/src/device/Device.ts +7 -3
- package/src/inject.ts +9 -9
- package/src/protocols/protocol-v2/features.ts +39 -41
- package/src/protocols/protocol-v2/firmware.ts +16 -16
- package/src/types/api/getPassphraseState.ts +15 -2
- package/src/types/api/index.ts +11 -10
- package/src/types/api/protocolV2.ts +27 -27
- package/src/utils/deviceFeaturesUtils.ts +53 -19
- package/dist/api/protocol-v2/DevFirmwareUpdate.d.ts +0 -7
- package/dist/api/protocol-v2/DevFirmwareUpdate.d.ts.map +0 -1
- package/dist/api/protocol-v2/DevGetDeviceInfo.d.ts +0 -7
- package/dist/api/protocol-v2/DevGetDeviceInfo.d.ts.map +0 -1
- package/dist/api/protocol-v2/DevGetFirmwareUpdateStatus.d.ts +0 -6
- package/dist/api/protocol-v2/DevGetFirmwareUpdateStatus.d.ts.map +0 -1
- package/dist/api/protocol-v2/DevGetOnboardingStatus.d.ts +0 -6
- package/dist/api/protocol-v2/DevGetOnboardingStatus.d.ts.map +0 -1
- package/dist/api/protocol-v2/DevReboot.d.ts +0 -7
- package/dist/api/protocol-v2/DevReboot.d.ts.map +0 -1
|
@@ -1,19 +1,31 @@
|
|
|
1
1
|
import JSZip from 'jszip';
|
|
2
|
-
import {
|
|
2
|
+
import { HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
3
|
+
import { DeviceRebootType } from '@onekeyfe/hd-transport';
|
|
3
4
|
|
|
5
|
+
import ConfluxSignTransaction from '../src/api/conflux/ConfluxSignTransaction';
|
|
6
|
+
import DnxGetAddress from '../src/api/dynex/DnxGetAddress';
|
|
7
|
+
import DnxSignTransaction from '../src/api/dynex/DnxSignTransaction';
|
|
8
|
+
import DirList from '../src/api/DirList';
|
|
4
9
|
import FileRead from '../src/api/FileRead';
|
|
5
10
|
import FileWrite from '../src/api/FileWrite';
|
|
6
|
-
import
|
|
7
|
-
import
|
|
11
|
+
import DeviceFirmwareUpdate from '../src/api/protocol-v2/DeviceFirmwareUpdate';
|
|
12
|
+
import DeviceGetOnboardingStatus from '../src/api/protocol-v2/DeviceGetOnboardingStatus';
|
|
8
13
|
import FirmwareUpdateV3 from '../src/api/FirmwareUpdateV3';
|
|
9
14
|
import FirmwareUpdateV4 from '../src/api/FirmwareUpdateV4';
|
|
10
15
|
import GetOnekeyFeatures from '../src/api/GetOnekeyFeatures';
|
|
16
|
+
import { batchGetPublickeys } from '../src/api/helpers/batchGetPublickeys';
|
|
11
17
|
import KaspaGetAddress from '../src/api/kaspa/KaspaGetAddress';
|
|
18
|
+
import TronSignMessage from '../src/api/tron/TronSignMessage';
|
|
19
|
+
import XrpSignTransaction from '../src/api/xrp/XrpSignTransaction';
|
|
12
20
|
import { DataManager } from '../src/data-manager';
|
|
13
21
|
import { Device } from '../src/device/Device';
|
|
14
22
|
import { UI_REQUEST } from '../src/events/ui-request';
|
|
15
23
|
import { getProtocolV2Features, normalizeProtocolV2Features } from '../src/protocols/protocol-v2';
|
|
16
24
|
import { shouldSkipMethodSupportCheck } from '../src/utils';
|
|
25
|
+
import {
|
|
26
|
+
getPassphraseState,
|
|
27
|
+
getPassphraseStateWithRefreshDeviceInfo,
|
|
28
|
+
} from '../src/utils/deviceFeaturesUtils';
|
|
17
29
|
|
|
18
30
|
import type { DeviceCommands } from '../src/device/DeviceCommands';
|
|
19
31
|
|
|
@@ -110,6 +122,113 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
110
122
|
expect(features.ble_enable).toBe(true);
|
|
111
123
|
});
|
|
112
124
|
|
|
125
|
+
test('uses GetPassphraseState payloads compatible with Pro1 passphrase flow', async () => {
|
|
126
|
+
const features = normalizeProtocolV2Features(descriptor as any);
|
|
127
|
+
const typedCall = jest.fn().mockResolvedValue({
|
|
128
|
+
type: 'PassphraseState',
|
|
129
|
+
message: {
|
|
130
|
+
passphrase_state: 'state-1',
|
|
131
|
+
session_id: 'session-1',
|
|
132
|
+
unlocked_attach_pin: false,
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
const commands = { typedCall } as unknown as DeviceCommands;
|
|
136
|
+
|
|
137
|
+
await getPassphraseState(features, commands, {
|
|
138
|
+
expectPassphraseState: 'state-1',
|
|
139
|
+
});
|
|
140
|
+
expect(typedCall).toHaveBeenLastCalledWith('GetPassphraseState', 'PassphraseState', {
|
|
141
|
+
passphrase_state: 'state-1',
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
await getPassphraseState(features, commands, {
|
|
145
|
+
expectPassphraseState: 'state-2',
|
|
146
|
+
allowCreateAttachPin: true,
|
|
147
|
+
});
|
|
148
|
+
expect(typedCall).toHaveBeenLastCalledWith('GetPassphraseState', 'PassphraseState', {
|
|
149
|
+
passphrase_state: 'state-2',
|
|
150
|
+
allow_create_attach_pin: true,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
await getPassphraseState(features, commands, {
|
|
154
|
+
onlyMainPin: true,
|
|
155
|
+
});
|
|
156
|
+
expect(typedCall).toHaveBeenLastCalledWith('GetPassphraseState', 'PassphraseState', {
|
|
157
|
+
_only_main_pin: true,
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test('stores Pro2 passphrase sessions without selecting them implicitly', async () => {
|
|
162
|
+
const device = Device.fromDescriptor({ ...descriptor, protocolType: 'V2' } as any);
|
|
163
|
+
const typedCall = jest.fn().mockResolvedValue({
|
|
164
|
+
type: 'PassphraseState',
|
|
165
|
+
message: {
|
|
166
|
+
passphrase_state: 'state-auto',
|
|
167
|
+
session_id: 'session-auto',
|
|
168
|
+
unlocked_attach_pin: false,
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
(device as any).features = normalizeProtocolV2Features({
|
|
173
|
+
...descriptor,
|
|
174
|
+
protocolType: 'V2',
|
|
175
|
+
} as any);
|
|
176
|
+
(device as any).commands = { typedCall };
|
|
177
|
+
|
|
178
|
+
await expect(getPassphraseStateWithRefreshDeviceInfo(device)).resolves.toMatchObject({
|
|
179
|
+
passphraseState: 'state-auto',
|
|
180
|
+
newSession: 'session-auto',
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
expect(device.passphraseState).toBeUndefined();
|
|
184
|
+
expect(device.features?.passphrase_protection).toBe(true);
|
|
185
|
+
expect(device.features?.session_id).toBe('session-auto');
|
|
186
|
+
expect(device.getInternalState()).toBeUndefined();
|
|
187
|
+
device.passphraseState = 'state-auto';
|
|
188
|
+
expect(device.getInternalState()).toBe('session-auto');
|
|
189
|
+
expect(typedCall).toHaveBeenLastCalledWith('GetPassphraseState', 'PassphraseState', {
|
|
190
|
+
passphrase_state: undefined,
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test('does not mark Pro2 passphrase enabled from a main PIN session alone', async () => {
|
|
195
|
+
const device = Device.fromDescriptor({ ...descriptor, protocolType: 'V2' } as any);
|
|
196
|
+
const typedCall = jest.fn().mockResolvedValue({
|
|
197
|
+
type: 'PassphraseState',
|
|
198
|
+
message: {
|
|
199
|
+
session_id: 'main-pin-session',
|
|
200
|
+
unlocked_attach_pin: false,
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
(device as any).features = normalizeProtocolV2Features(
|
|
205
|
+
{
|
|
206
|
+
...descriptor,
|
|
207
|
+
protocolType: 'V2',
|
|
208
|
+
} as any,
|
|
209
|
+
{
|
|
210
|
+
status: {
|
|
211
|
+
passphrase_protection: false,
|
|
212
|
+
},
|
|
213
|
+
}
|
|
214
|
+
);
|
|
215
|
+
(device as any).commands = { typedCall };
|
|
216
|
+
|
|
217
|
+
await expect(
|
|
218
|
+
getPassphraseStateWithRefreshDeviceInfo(device, { onlyMainPin: true })
|
|
219
|
+
).resolves.toMatchObject({
|
|
220
|
+
passphraseState: undefined,
|
|
221
|
+
newSession: 'main-pin-session',
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
expect(device.features?.passphrase_protection).toBe(false);
|
|
225
|
+
expect(device.features?.session_id).toBe('main-pin-session');
|
|
226
|
+
expect(device.getInternalState()).toBeUndefined();
|
|
227
|
+
expect(typedCall).toHaveBeenLastCalledWith('GetPassphraseState', 'PassphraseState', {
|
|
228
|
+
_only_main_pin: true,
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
|
|
113
232
|
test('marks fallback features as unavailable when DeviceInfo is missing', () => {
|
|
114
233
|
const features = normalizeProtocolV2Features(descriptor as any);
|
|
115
234
|
|
|
@@ -131,10 +250,45 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
131
250
|
expect(shouldSkipMethodSupportCheck(features)).toBe(true);
|
|
132
251
|
});
|
|
133
252
|
|
|
134
|
-
test('initializes Protocol V2 features
|
|
253
|
+
test('initializes Protocol V2 features from DeviceGetDeviceInfo after Ping', async () => {
|
|
254
|
+
const commands = {
|
|
255
|
+
typedCall: jest
|
|
256
|
+
.fn()
|
|
257
|
+
.mockResolvedValueOnce({ type: 'Success', message: { message: 'pong' } })
|
|
258
|
+
.mockResolvedValueOnce({
|
|
259
|
+
type: 'DeviceInfo',
|
|
260
|
+
message: {
|
|
261
|
+
hw: { serial_no: 'PR2SERIAL' },
|
|
262
|
+
status: {
|
|
263
|
+
init_states: true,
|
|
264
|
+
passphrase_protection: true,
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
}),
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
const features = await getProtocolV2Features({
|
|
271
|
+
commands: commands as unknown as DeviceCommands,
|
|
272
|
+
descriptor: descriptor as any,
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
expect(features.device_id).toBe('PR2SERIAL');
|
|
276
|
+
expect(features.initialized).toBe(true);
|
|
277
|
+
expect(features.passphrase_protection).toBe(true);
|
|
278
|
+
expect(commands.typedCall).toHaveBeenNthCalledWith(1, 'Ping', 'Success', { message: 'init' });
|
|
279
|
+
expect(commands.typedCall).toHaveBeenNthCalledWith(2, 'DeviceGetDeviceInfo', 'DeviceInfo', {
|
|
280
|
+
targets: expect.objectContaining({ status: true }),
|
|
281
|
+
types: expect.objectContaining({ specific: true }),
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
test('falls back to descriptor features when Protocol V2 DeviceGetDeviceInfo fails', async () => {
|
|
135
286
|
const onDeviceInfoError = jest.fn();
|
|
136
287
|
const commands = {
|
|
137
|
-
typedCall: jest
|
|
288
|
+
typedCall: jest
|
|
289
|
+
.fn()
|
|
290
|
+
.mockResolvedValueOnce({ type: 'Success', message: { message: 'pong' } })
|
|
291
|
+
.mockRejectedValueOnce(new Error('DeviceInfo not supported')),
|
|
138
292
|
};
|
|
139
293
|
|
|
140
294
|
const features = await getProtocolV2Features({
|
|
@@ -144,9 +298,8 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
144
298
|
});
|
|
145
299
|
|
|
146
300
|
expect(features.device_id).toBe('usb-path');
|
|
147
|
-
expect(
|
|
148
|
-
expect(
|
|
149
|
-
expect(onDeviceInfoError).not.toHaveBeenCalled();
|
|
301
|
+
expect(features.passphrase_protection).toBeNull();
|
|
302
|
+
expect(onDeviceInfoError).toHaveBeenCalledWith(expect.any(Error));
|
|
150
303
|
});
|
|
151
304
|
|
|
152
305
|
test('does not block method-level legacy version checks on Protocol V2', async () => {
|
|
@@ -182,6 +335,35 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
182
335
|
expect(typedCall).toHaveBeenCalledWith('KaspaGetAddress', 'KaspaAddress', expect.any(Object));
|
|
183
336
|
});
|
|
184
337
|
|
|
338
|
+
test('does not block legacy batch public key support checks on Protocol V2', async () => {
|
|
339
|
+
const paths = [{ address_n: [0x8000002c, 0x80000000, 0x80000000] }] as any;
|
|
340
|
+
const typedCall = jest.fn().mockResolvedValue({
|
|
341
|
+
type: 'EcdsaPublicKeys',
|
|
342
|
+
message: {
|
|
343
|
+
root_fingerprint: 123,
|
|
344
|
+
public_keys: [],
|
|
345
|
+
hd_nodes: [{}],
|
|
346
|
+
},
|
|
347
|
+
});
|
|
348
|
+
const device = {
|
|
349
|
+
originalDescriptor: { protocolType: 'V2' },
|
|
350
|
+
features: normalizeProtocolV2Features({ ...descriptor, protocolType: 'V2' } as any),
|
|
351
|
+
commands: { typedCall },
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
await expect(
|
|
355
|
+
batchGetPublickeys(device as any, paths, 'secp256k1', 0, { includeNode: true })
|
|
356
|
+
).resolves.toMatchObject({
|
|
357
|
+
root_fingerprint: 123,
|
|
358
|
+
hd_nodes: [{}],
|
|
359
|
+
});
|
|
360
|
+
expect(typedCall).toHaveBeenCalledWith('BatchGetPublickeys', 'EcdsaPublicKeys', {
|
|
361
|
+
paths,
|
|
362
|
+
ecdsa_curve_name: 'secp256k1',
|
|
363
|
+
include_node: true,
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
|
|
185
367
|
test('returns Protocol V2 oneKey fields without calling legacy OnekeyGetFeatures', async () => {
|
|
186
368
|
const method = new GetOnekeyFeatures({
|
|
187
369
|
id: 1,
|
|
@@ -224,15 +406,25 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
224
406
|
} as any);
|
|
225
407
|
const typedCall = jest
|
|
226
408
|
.fn()
|
|
227
|
-
.mockResolvedValueOnce({ type: 'Success', message: { message: 'init' } })
|
|
409
|
+
.mockResolvedValueOnce({ type: 'Success', message: { message: 'init' } })
|
|
410
|
+
.mockResolvedValueOnce({
|
|
411
|
+
type: 'DeviceInfo',
|
|
412
|
+
message: {
|
|
413
|
+
hw: { serial_no: 'PR2SERIAL' },
|
|
414
|
+
status: {
|
|
415
|
+
passphrase_protection: true,
|
|
416
|
+
},
|
|
417
|
+
},
|
|
418
|
+
});
|
|
228
419
|
|
|
229
420
|
(device as any).commands = { typedCall };
|
|
230
421
|
|
|
231
422
|
await device.initialize();
|
|
232
423
|
await device.initialize();
|
|
233
424
|
|
|
234
|
-
expect(device.features?.device_id).toBe('
|
|
235
|
-
expect(
|
|
425
|
+
expect(device.features?.device_id).toBe('PR2SERIAL');
|
|
426
|
+
expect(device.features?.passphrase_protection).toBe(true);
|
|
427
|
+
expect(typedCall).toHaveBeenCalledTimes(2);
|
|
236
428
|
expect(typedCall).toHaveBeenNthCalledWith(
|
|
237
429
|
1,
|
|
238
430
|
'Ping',
|
|
@@ -242,6 +434,139 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
242
434
|
timeoutMs: 10000,
|
|
243
435
|
}
|
|
244
436
|
);
|
|
437
|
+
expect(typedCall).toHaveBeenNthCalledWith(
|
|
438
|
+
2,
|
|
439
|
+
'DeviceGetDeviceInfo',
|
|
440
|
+
'DeviceInfo',
|
|
441
|
+
{
|
|
442
|
+
targets: expect.objectContaining({ status: true }),
|
|
443
|
+
types: expect.objectContaining({ specific: true }),
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
timeoutMs: 10000,
|
|
447
|
+
}
|
|
448
|
+
);
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
describe('API compatibility handling', () => {
|
|
453
|
+
test('returns a typed unsupported error for Tron sign message V1 before device binding', () => {
|
|
454
|
+
const method = new TronSignMessage({
|
|
455
|
+
id: 1,
|
|
456
|
+
payload: {
|
|
457
|
+
method: 'tronSignMessage',
|
|
458
|
+
path: "m/44'/195'/0'/0/0",
|
|
459
|
+
messageHex: '0x1234',
|
|
460
|
+
messageType: 'V1',
|
|
461
|
+
},
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
expect(() => method.init()).toThrow(
|
|
465
|
+
expect.objectContaining({
|
|
466
|
+
errorCode: HardwareErrorCode.DeviceNotSupportMethod,
|
|
467
|
+
})
|
|
468
|
+
);
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
test('accepts string XRP payment amount values', () => {
|
|
472
|
+
const method = new XrpSignTransaction({
|
|
473
|
+
id: 1,
|
|
474
|
+
payload: {
|
|
475
|
+
method: 'xrpSignTransaction',
|
|
476
|
+
path: "m/44'/144'/0'/0/0",
|
|
477
|
+
transaction: {
|
|
478
|
+
fee: '100000',
|
|
479
|
+
flags: 2147483648,
|
|
480
|
+
sequence: 25,
|
|
481
|
+
maxLedgerVersion: 8820051,
|
|
482
|
+
payment: {
|
|
483
|
+
amount: '100000000',
|
|
484
|
+
destination: 'rBKz5MC2iXdoS3XgnNSYmF69K1Yo4NS3Ws',
|
|
485
|
+
},
|
|
486
|
+
},
|
|
487
|
+
},
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
expect(() => method.init()).not.toThrow();
|
|
491
|
+
expect(method.params.payment?.amount).toBe('100000000');
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
test('accepts Conflux base32 recipient addresses without hex formatting them', () => {
|
|
495
|
+
const to = 'cfx:aak2rra2njvd77ezwjvx04kkds9fzagfe6ku8scz91';
|
|
496
|
+
const method = new ConfluxSignTransaction({
|
|
497
|
+
id: 1,
|
|
498
|
+
payload: {
|
|
499
|
+
method: 'confluxSignTransaction',
|
|
500
|
+
path: "m/44'/503'/0'/0/0",
|
|
501
|
+
transaction: {
|
|
502
|
+
to,
|
|
503
|
+
value: '0x0',
|
|
504
|
+
data: '0x',
|
|
505
|
+
chainId: 1,
|
|
506
|
+
nonce: '0x00',
|
|
507
|
+
epochHeight: '0x00',
|
|
508
|
+
gasLimit: '0x5208',
|
|
509
|
+
storageLimit: '0x5208',
|
|
510
|
+
gasPrice: '0xbebc200',
|
|
511
|
+
},
|
|
512
|
+
},
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
expect(() => method.init()).not.toThrow();
|
|
516
|
+
expect(method.formattedTx?.to).toBe(to);
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
test('returns a typed unsupported error for Dynex signing on Protocol V2', async () => {
|
|
520
|
+
const method = new DnxSignTransaction({
|
|
521
|
+
id: 1,
|
|
522
|
+
payload: {
|
|
523
|
+
method: 'dnxSignTransaction',
|
|
524
|
+
path: "m/44'/29538'/0'/0/0",
|
|
525
|
+
inputs: [
|
|
526
|
+
{
|
|
527
|
+
prevIndex: 1,
|
|
528
|
+
globalIndex: 1,
|
|
529
|
+
txPubkey: '00',
|
|
530
|
+
prevOutPubkey: '00',
|
|
531
|
+
amount: '1',
|
|
532
|
+
},
|
|
533
|
+
],
|
|
534
|
+
toAddress: 'dnx-address',
|
|
535
|
+
amount: '1',
|
|
536
|
+
fee: '1',
|
|
537
|
+
},
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
method.init();
|
|
541
|
+
(method as any).device = {
|
|
542
|
+
originalDescriptor: { protocolType: 'V2' },
|
|
543
|
+
features: normalizeProtocolV2Features({ ...descriptor, protocolType: 'V2' } as any),
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
await expect(method.run()).rejects.toMatchObject({
|
|
547
|
+
errorCode: HardwareErrorCode.DeviceNotSupportMethod,
|
|
548
|
+
});
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
test('returns a typed unsupported error for Dynex address on Protocol V2', async () => {
|
|
552
|
+
const method = new DnxGetAddress({
|
|
553
|
+
id: 1,
|
|
554
|
+
payload: {
|
|
555
|
+
method: 'dnxGetAddress',
|
|
556
|
+
path: "m/44'/29538'/0'/0/0",
|
|
557
|
+
showOnOneKey: false,
|
|
558
|
+
},
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
method.init();
|
|
562
|
+
(method as any).device = {
|
|
563
|
+
originalDescriptor: { protocolType: 'V2' },
|
|
564
|
+
features: normalizeProtocolV2Features({ ...descriptor, protocolType: 'V2' } as any),
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
await expect(method.run()).rejects.toMatchObject({
|
|
568
|
+
errorCode: HardwareErrorCode.DeviceNotSupportMethod,
|
|
569
|
+
});
|
|
245
570
|
});
|
|
246
571
|
});
|
|
247
572
|
|
|
@@ -272,6 +597,9 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
272
597
|
if (name === 'Ping') {
|
|
273
598
|
return Promise.resolve({ type: 'Success', message: { message: 'init' } });
|
|
274
599
|
}
|
|
600
|
+
if (name === 'DeviceGetDeviceInfo') {
|
|
601
|
+
return Promise.resolve({ type: 'DeviceInfo', message: {} });
|
|
602
|
+
}
|
|
275
603
|
return Promise.reject(new Error(`unexpected call ${name}`));
|
|
276
604
|
});
|
|
277
605
|
const commands = { typedCall };
|
|
@@ -294,7 +622,17 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
294
622
|
{ message: 'init' },
|
|
295
623
|
{ timeoutMs: 5000 }
|
|
296
624
|
);
|
|
297
|
-
expect(typedCall).
|
|
625
|
+
expect(typedCall).toHaveBeenNthCalledWith(
|
|
626
|
+
2,
|
|
627
|
+
'DeviceGetDeviceInfo',
|
|
628
|
+
'DeviceInfo',
|
|
629
|
+
{
|
|
630
|
+
targets: expect.objectContaining({ status: true }),
|
|
631
|
+
types: expect.objectContaining({ specific: true }),
|
|
632
|
+
},
|
|
633
|
+
{ timeoutMs: 5000 }
|
|
634
|
+
);
|
|
635
|
+
expect(typedCall).toHaveBeenCalledTimes(2);
|
|
298
636
|
expect(typedCall).not.toHaveBeenCalledWith('Initialize', 'Features', {});
|
|
299
637
|
expect(versions).toEqual({
|
|
300
638
|
bootloaderVersion: '0.0.0',
|
|
@@ -346,7 +684,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
346
684
|
],
|
|
347
685
|
bootloaderBinary: null,
|
|
348
686
|
});
|
|
349
|
-
expect((method as any).protocolV2Reboot).not.toHaveBeenCalledWith(
|
|
687
|
+
expect((method as any).protocolV2Reboot).not.toHaveBeenCalledWith(DeviceRebootType.Bootloader);
|
|
350
688
|
expect(method.postTipMessage).not.toHaveBeenCalledWith('AutoRebootToBootloader');
|
|
351
689
|
});
|
|
352
690
|
|
|
@@ -365,7 +703,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
365
703
|
await (method as any).exitProtocolV2BootloaderToNormal();
|
|
366
704
|
|
|
367
705
|
expect(method.postTipMessage).toHaveBeenCalledWith('SwitchFirmwareReconnectDevice');
|
|
368
|
-
expect((method as any).protocolV2Reboot).toHaveBeenCalledWith(
|
|
706
|
+
expect((method as any).protocolV2Reboot).toHaveBeenCalledWith(DeviceRebootType.Normal);
|
|
369
707
|
});
|
|
370
708
|
|
|
371
709
|
test('treats iOS BLE RxError 6 during Protocol V2 reboot as expected disconnect', async () => {
|
|
@@ -385,7 +723,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
385
723
|
getCommands: () => ({ typedCall }),
|
|
386
724
|
};
|
|
387
725
|
|
|
388
|
-
await expect((method as any).protocolV2Reboot(
|
|
726
|
+
await expect((method as any).protocolV2Reboot(DeviceRebootType.Normal)).resolves.toEqual({
|
|
389
727
|
message: 'Device rebooted successfully',
|
|
390
728
|
});
|
|
391
729
|
});
|
|
@@ -405,7 +743,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
405
743
|
getCommands: () => ({ typedCall }),
|
|
406
744
|
};
|
|
407
745
|
|
|
408
|
-
await expect((method as any).protocolV2Reboot(
|
|
746
|
+
await expect((method as any).protocolV2Reboot(DeviceRebootType.Normal)).resolves.toEqual({
|
|
409
747
|
message: 'Device rebooted successfully',
|
|
410
748
|
});
|
|
411
749
|
});
|
|
@@ -425,7 +763,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
425
763
|
)
|
|
426
764
|
)
|
|
427
765
|
.mockResolvedValueOnce({
|
|
428
|
-
type: '
|
|
766
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
429
767
|
message: {
|
|
430
768
|
targets: [{ target_id: 2, status: 0 }],
|
|
431
769
|
},
|
|
@@ -446,7 +784,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
446
784
|
expect(typedCall).toHaveBeenCalledTimes(2);
|
|
447
785
|
});
|
|
448
786
|
|
|
449
|
-
test('passes resource, bootloader, BLE, SE and app files to
|
|
787
|
+
test('passes resource, bootloader, BLE, SE and app files to DeviceFirmwareUpdate targets', async () => {
|
|
450
788
|
const resourceZip = new JSZip();
|
|
451
789
|
resourceZip.file('icons/home.png', new Uint8Array([1, 2, 3]));
|
|
452
790
|
const resourceBinary = await resourceZip.generateAsync({ type: 'arraybuffer' });
|
|
@@ -499,10 +837,10 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
499
837
|
expect((method as any).protocolV2StartFirmwareUpdate).toHaveBeenCalledWith({
|
|
500
838
|
targets: [
|
|
501
839
|
{ target_id: 10, path: 'vol1:res/' },
|
|
502
|
-
{ target_id:
|
|
503
|
-
{ target_id:
|
|
504
|
-
{ target_id:
|
|
505
|
-
{ target_id:
|
|
840
|
+
{ target_id: 2, path: 'vol1:bootloader.bin' },
|
|
841
|
+
{ target_id: 5, path: 'vol1:ble-firmware.bin' },
|
|
842
|
+
{ target_id: 6, path: 'vol1:se1-firmware.bin' },
|
|
843
|
+
{ target_id: 3, path: 'vol1:firmware.bin' },
|
|
506
844
|
],
|
|
507
845
|
});
|
|
508
846
|
expect((method as any).waitForProtocolV2FirmwareUpdateComplete).toHaveBeenCalled();
|
|
@@ -621,10 +959,10 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
621
959
|
});
|
|
622
960
|
|
|
623
961
|
const callOptions = typedCall.mock.calls[0][3];
|
|
624
|
-
expect(typedCall.mock.calls[0][1]).toEqual(['Success', '
|
|
625
|
-
expect(callOptions.intermediateTypes).toEqual(['
|
|
962
|
+
expect(typedCall.mock.calls[0][1]).toEqual(['Success', 'DeviceFirmwareUpdateStatus']);
|
|
963
|
+
expect(callOptions.intermediateTypes).toEqual(['DeviceFirmwareInstallProgress']);
|
|
626
964
|
callOptions.onIntermediateResponse({
|
|
627
|
-
type: '
|
|
965
|
+
type: 'DeviceFirmwareInstallProgress',
|
|
628
966
|
message: { target_id: 0, progress: 42 },
|
|
629
967
|
});
|
|
630
968
|
|
|
@@ -639,7 +977,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
639
977
|
},
|
|
640
978
|
});
|
|
641
979
|
const typedCall = jest.fn().mockResolvedValue({
|
|
642
|
-
type: '
|
|
980
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
643
981
|
message: { targets: [{ target_id: 0, status: 1 }] },
|
|
644
982
|
});
|
|
645
983
|
|
|
@@ -653,24 +991,25 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
653
991
|
targets: [{ target_id: 0, path: 'vol1:firmware.bin' }],
|
|
654
992
|
});
|
|
655
993
|
|
|
656
|
-
expect(typedCall.mock.calls[0][1]).toEqual(['Success', '
|
|
994
|
+
expect(typedCall.mock.calls[0][1]).toEqual(['Success', 'DeviceFirmwareUpdateStatus']);
|
|
657
995
|
expect(method.postTipMessage).toHaveBeenCalledWith('FirmwareUpdating');
|
|
658
996
|
});
|
|
659
997
|
});
|
|
660
998
|
|
|
661
999
|
describe('Protocol V2 firmware update method', () => {
|
|
662
|
-
test('returns
|
|
663
|
-
const method = new
|
|
1000
|
+
test('returns DeviceFirmwareUpdateStatus from low-level update trigger', async () => {
|
|
1001
|
+
const method = new DeviceFirmwareUpdate({
|
|
664
1002
|
id: 1,
|
|
665
1003
|
payload: {
|
|
666
|
-
method: '
|
|
1004
|
+
method: 'deviceFirmwareUpdate',
|
|
1005
|
+
targetId: 3,
|
|
667
1006
|
path: 'vol0:firmware.bin',
|
|
668
1007
|
},
|
|
669
1008
|
});
|
|
670
1009
|
method.init();
|
|
671
1010
|
|
|
672
1011
|
const typedCall = jest.fn().mockResolvedValue({
|
|
673
|
-
type: '
|
|
1012
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
674
1013
|
message: { targets: [{ target_id: 0, status: 1 }] },
|
|
675
1014
|
});
|
|
676
1015
|
|
|
@@ -681,22 +1020,71 @@ describe('Protocol V2 firmware update method', () => {
|
|
|
681
1020
|
await expect(method.run()).resolves.toEqual({
|
|
682
1021
|
targets: [{ target_id: 0, status: 1 }],
|
|
683
1022
|
});
|
|
684
|
-
expect(typedCall.mock.calls[0][1]).toEqual(['Success', '
|
|
1023
|
+
expect(typedCall.mock.calls[0][1]).toEqual(['Success', 'DeviceFirmwareUpdateStatus']);
|
|
1024
|
+
expect(typedCall.mock.calls[0][2]).toEqual({
|
|
1025
|
+
targets: [{ target_id: 3, path: 'vol0:firmware.bin' }],
|
|
1026
|
+
});
|
|
1027
|
+
});
|
|
1028
|
+
|
|
1029
|
+
test('rejects missing or invalid firmware targets before transport call', async () => {
|
|
1030
|
+
const typedCall = jest.fn();
|
|
1031
|
+
const method = new DeviceFirmwareUpdate({
|
|
1032
|
+
id: 1,
|
|
1033
|
+
payload: {
|
|
1034
|
+
method: 'deviceFirmwareUpdate',
|
|
1035
|
+
path: 'vol0:firmware.bin',
|
|
1036
|
+
},
|
|
1037
|
+
});
|
|
1038
|
+
method.init();
|
|
1039
|
+
(method as any).device = {
|
|
1040
|
+
commands: { typedCall },
|
|
1041
|
+
};
|
|
1042
|
+
|
|
1043
|
+
await expect(method.run()).rejects.toMatchObject({
|
|
1044
|
+
errorCode: HardwareErrorCode.CallMethodInvalidParameter,
|
|
1045
|
+
});
|
|
1046
|
+
expect(typedCall).not.toHaveBeenCalled();
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
test('accepts targetId alias inside firmware targets', async () => {
|
|
1050
|
+
const typedCall = jest.fn().mockResolvedValue({ message: {} });
|
|
1051
|
+
const method = new DeviceFirmwareUpdate({
|
|
1052
|
+
id: 1,
|
|
1053
|
+
payload: {
|
|
1054
|
+
method: 'deviceFirmwareUpdate',
|
|
1055
|
+
targets: [
|
|
1056
|
+
{
|
|
1057
|
+
target_id: undefined,
|
|
1058
|
+
targetId: 3,
|
|
1059
|
+
path: 'vol0:firmware.bin',
|
|
1060
|
+
},
|
|
1061
|
+
],
|
|
1062
|
+
} as any,
|
|
1063
|
+
});
|
|
1064
|
+
method.init();
|
|
1065
|
+
(method as any).device = {
|
|
1066
|
+
commands: { typedCall },
|
|
1067
|
+
};
|
|
1068
|
+
|
|
1069
|
+
await method.run();
|
|
1070
|
+
expect(typedCall.mock.calls[0][2]).toEqual({
|
|
1071
|
+
targets: [{ target_id: 3, path: 'vol0:firmware.bin' }],
|
|
1072
|
+
});
|
|
685
1073
|
});
|
|
686
1074
|
});
|
|
687
1075
|
|
|
688
1076
|
describe('Protocol V2 onboarding status method', () => {
|
|
689
|
-
test('returns
|
|
690
|
-
const method = new
|
|
1077
|
+
test('returns DeviceOnboardingStatus from low-level status query', async () => {
|
|
1078
|
+
const method = new DeviceGetOnboardingStatus({
|
|
691
1079
|
id: 1,
|
|
692
1080
|
payload: {
|
|
693
|
-
method: '
|
|
1081
|
+
method: 'deviceGetOnboardingStatus',
|
|
694
1082
|
},
|
|
695
1083
|
});
|
|
696
1084
|
method.init();
|
|
697
1085
|
|
|
698
1086
|
const typedCall = jest.fn().mockResolvedValue({
|
|
699
|
-
type: '
|
|
1087
|
+
type: 'DeviceOnboardingStatus',
|
|
700
1088
|
message: {
|
|
701
1089
|
page_index: 2,
|
|
702
1090
|
page_count: 5,
|
|
@@ -713,11 +1101,45 @@ describe('Protocol V2 onboarding status method', () => {
|
|
|
713
1101
|
page_count: 5,
|
|
714
1102
|
page_name: 'backup',
|
|
715
1103
|
});
|
|
716
|
-
expect(typedCall).toHaveBeenCalledWith(
|
|
1104
|
+
expect(typedCall).toHaveBeenCalledWith(
|
|
1105
|
+
'DeviceGetOnboardingStatus',
|
|
1106
|
+
'DeviceOnboardingStatus',
|
|
1107
|
+
{}
|
|
1108
|
+
);
|
|
717
1109
|
});
|
|
718
1110
|
});
|
|
719
1111
|
|
|
720
1112
|
describe('Protocol V2 file write method', () => {
|
|
1113
|
+
test('rejects invalid write parameters before transport call', () => {
|
|
1114
|
+
expect(() => {
|
|
1115
|
+
const method = new FileWrite({
|
|
1116
|
+
id: 1,
|
|
1117
|
+
payload: {
|
|
1118
|
+
method: 'fileWrite',
|
|
1119
|
+
path: 'vol1:test.bin',
|
|
1120
|
+
offset: -1,
|
|
1121
|
+
data: new Uint8Array([1]),
|
|
1122
|
+
},
|
|
1123
|
+
});
|
|
1124
|
+
method.init();
|
|
1125
|
+
}).toThrow(
|
|
1126
|
+
expect.objectContaining({ errorCode: HardwareErrorCode.CallMethodInvalidParameter })
|
|
1127
|
+
);
|
|
1128
|
+
|
|
1129
|
+
expect(() => {
|
|
1130
|
+
const method = new FileWrite({
|
|
1131
|
+
id: 1,
|
|
1132
|
+
payload: {
|
|
1133
|
+
method: 'fileWrite',
|
|
1134
|
+
path: 'vol1:test.bin',
|
|
1135
|
+
} as any,
|
|
1136
|
+
});
|
|
1137
|
+
method.init();
|
|
1138
|
+
}).toThrow(
|
|
1139
|
+
expect.objectContaining({ errorCode: HardwareErrorCode.CallMethodInvalidParameter })
|
|
1140
|
+
);
|
|
1141
|
+
});
|
|
1142
|
+
|
|
721
1143
|
test('uses demo-aligned overwrite and append defaults', async () => {
|
|
722
1144
|
const typedCall = jest.fn().mockResolvedValue({ message: { processed_byte: 1 } });
|
|
723
1145
|
const method = new FileWrite({
|
|
@@ -860,6 +1282,50 @@ describe('Protocol V2 file write method', () => {
|
|
|
860
1282
|
});
|
|
861
1283
|
|
|
862
1284
|
describe('Protocol V2 file read method', () => {
|
|
1285
|
+
test('rejects invalid read and directory parameters before transport call', () => {
|
|
1286
|
+
expect(() => {
|
|
1287
|
+
const method = new FileRead({
|
|
1288
|
+
id: 1,
|
|
1289
|
+
payload: {
|
|
1290
|
+
method: 'fileRead',
|
|
1291
|
+
path: '',
|
|
1292
|
+
offset: 0,
|
|
1293
|
+
},
|
|
1294
|
+
});
|
|
1295
|
+
method.init();
|
|
1296
|
+
}).toThrow(
|
|
1297
|
+
expect.objectContaining({ errorCode: HardwareErrorCode.CallMethodInvalidParameter })
|
|
1298
|
+
);
|
|
1299
|
+
|
|
1300
|
+
expect(() => {
|
|
1301
|
+
const method = new FileRead({
|
|
1302
|
+
id: 1,
|
|
1303
|
+
payload: {
|
|
1304
|
+
method: 'fileRead',
|
|
1305
|
+
path: 'vol1:test.bin',
|
|
1306
|
+
totalSize: -1,
|
|
1307
|
+
},
|
|
1308
|
+
});
|
|
1309
|
+
method.init();
|
|
1310
|
+
}).toThrow(
|
|
1311
|
+
expect.objectContaining({ errorCode: HardwareErrorCode.CallMethodInvalidParameter })
|
|
1312
|
+
);
|
|
1313
|
+
|
|
1314
|
+
expect(() => {
|
|
1315
|
+
const method = new DirList({
|
|
1316
|
+
id: 1,
|
|
1317
|
+
payload: {
|
|
1318
|
+
method: 'dirList',
|
|
1319
|
+
path: 'vol1:',
|
|
1320
|
+
depth: -1,
|
|
1321
|
+
},
|
|
1322
|
+
});
|
|
1323
|
+
method.init();
|
|
1324
|
+
}).toThrow(
|
|
1325
|
+
expect.objectContaining({ errorCode: HardwareErrorCode.CallMethodInvalidParameter })
|
|
1326
|
+
);
|
|
1327
|
+
});
|
|
1328
|
+
|
|
863
1329
|
test('reads full file in chunks when read length is 0', async () => {
|
|
864
1330
|
const firstChunk = new Uint8Array(64).fill(1);
|
|
865
1331
|
const typedCall = jest
|