@onekeyfe/hd-core 1.2.0-alpha.22 → 1.2.0-alpha.23

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.
Files changed (61) hide show
  1. package/__tests__/DeviceCommands.test.ts +8 -8
  2. package/__tests__/device-settings.test.ts +1 -1
  3. package/__tests__/device-wallet-session-store.test.ts +41 -0
  4. package/__tests__/firmware-update/check-all-firmware-release.test.ts +86 -0
  5. package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +13 -0
  6. package/__tests__/logBlockEvent.test.ts +17 -0
  7. package/__tests__/open-wallet-session.test.ts +90 -31
  8. package/__tests__/protocol-v2.test.ts +301 -63
  9. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  10. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  11. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  12. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  13. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  14. package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
  15. package/dist/api/device/DeviceWipe.d.ts.map +1 -1
  16. package/dist/api/firmware/FirmwareArtifactSource.d.ts +0 -1
  17. package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +1 -1
  18. package/dist/api/firmware/FirmwareUpdatePlan.d.ts +0 -1
  19. package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -1
  20. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +6 -1
  21. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -1
  22. package/dist/core/index.d.ts.map +1 -1
  23. package/dist/device/Device.d.ts +3 -2
  24. package/dist/device/Device.d.ts.map +1 -1
  25. package/dist/device/DeviceCommands.d.ts.map +1 -1
  26. package/dist/events/device.d.ts +1 -0
  27. package/dist/events/device.d.ts.map +1 -1
  28. package/dist/events/logBlockEvent.d.ts.map +1 -1
  29. package/dist/events/ui-request.d.ts +1 -0
  30. package/dist/events/ui-request.d.ts.map +1 -1
  31. package/dist/index.d.ts +10 -6
  32. package/dist/index.js +157 -268
  33. package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts.map +1 -1
  34. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  35. package/dist/types/api/getPassphraseState.d.ts.map +1 -1
  36. package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
  37. package/dist/utils/patch.d.ts +1 -1
  38. package/dist/utils/patch.d.ts.map +1 -1
  39. package/package.json +4 -4
  40. package/src/api/CheckAllFirmwareRelease.ts +15 -8
  41. package/src/api/FirmwareUpdateV2.ts +8 -1
  42. package/src/api/FirmwareUpdateV3.ts +8 -0
  43. package/src/api/FirmwareUpdateV4.ts +21 -19
  44. package/src/api/GetPassphraseState.ts +11 -5
  45. package/src/api/device/DeviceUpdateBootloader.ts +9 -1
  46. package/src/api/device/DeviceWipe.ts +2 -0
  47. package/src/api/firmware/FirmwareArtifactSource.ts +1 -1
  48. package/src/api/firmware/FirmwareUpdatePlan.ts +1 -1
  49. package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +15 -1
  50. package/src/core/index.ts +1 -0
  51. package/src/data/messages/messages-protocol-v2.json +18 -57
  52. package/src/device/Device.ts +30 -7
  53. package/src/device/DeviceCommands.ts +24 -151
  54. package/src/events/device.ts +1 -0
  55. package/src/events/logBlockEvent.ts +1 -15
  56. package/src/events/ui-request.ts +1 -0
  57. package/src/protocols/protocol-v2/deviceSession.ts +1 -1
  58. package/src/protocols/protocol-v2/settingsUnlockPolicy.ts +0 -1
  59. package/src/protocols/protocol-v2/walletSession.ts +41 -20
  60. package/src/types/api/getPassphraseState.ts +4 -3
  61. package/src/utils/deviceInfoUtils.ts +3 -16
@@ -19,7 +19,7 @@ const createCommands = () => {
19
19
  };
20
20
 
21
21
  describe('DeviceCommands failure mapping', () => {
22
- it('does not log DeviceSessionOpen response secrets', async () => {
22
+ it('does not log DeviceSessionGet response secrets', async () => {
23
23
  const commands = createCommands();
24
24
  const log = getLogger(LoggerNames.DeviceCommands);
25
25
  log.messages.length = 0;
@@ -33,7 +33,7 @@ describe('DeviceCommands failure mapping', () => {
33
33
  btc_test_address: 'secret-wallet-address',
34
34
  },
35
35
  } as any,
36
- 'DeviceSessionOpen'
36
+ 'DeviceSessionGet'
37
37
  )
38
38
  ).resolves.toMatchObject({ type: 'DeviceSession' });
39
39
 
@@ -41,7 +41,7 @@ describe('DeviceCommands failure mapping', () => {
41
41
  expect(JSON.stringify(log.messages)).not.toContain('secret-wallet-address');
42
42
  });
43
43
 
44
- it('maps an invalid DeviceSessionOpen resume to WalletSessionInvalid', async () => {
44
+ it('maps an invalid DeviceSessionGet resume to WalletSessionInvalid', async () => {
45
45
  const commands = createCommands();
46
46
 
47
47
  await expect(
@@ -54,7 +54,7 @@ describe('DeviceCommands failure mapping', () => {
54
54
  message: 'Invalid session',
55
55
  },
56
56
  } as any,
57
- 'DeviceSessionOpen'
57
+ 'DeviceSessionGet'
58
58
  )
59
59
  ).rejects.toMatchObject({
60
60
  errorCode: HardwareErrorCode.WalletSessionInvalid,
@@ -66,7 +66,7 @@ describe('DeviceCommands failure mapping', () => {
66
66
  });
67
67
  });
68
68
 
69
- it('maps DeviceSessionOpen user cancellation to ActionCancelled', async () => {
69
+ it('maps wallet-session user cancellation to ActionCancelled', async () => {
70
70
  const commands = createCommands();
71
71
 
72
72
  await expect(
@@ -79,7 +79,7 @@ describe('DeviceCommands failure mapping', () => {
79
79
  message: 'Cancelled on device',
80
80
  },
81
81
  } as any,
82
- 'DeviceSessionOpen'
82
+ 'DeviceSessionAskPassphrase'
83
83
  )
84
84
  ).rejects.toMatchObject({
85
85
  errorCode: HardwareErrorCode.ActionCancelled,
@@ -89,7 +89,7 @@ describe('DeviceCommands failure mapping', () => {
89
89
  it.each([
90
90
  [3, HardwareErrorCode.DeviceCheckUnlockTypeError],
91
91
  [4, HardwareErrorCode.DeviceNotOpenedPassphrase],
92
- ])('maps DeviceSessionOpen subcode %s to its canonical wallet error', async (subcode, code) => {
92
+ ])('maps wallet-session subcode %s to its canonical wallet error', async (subcode, code) => {
93
93
  const commands = createCommands();
94
94
 
95
95
  await expect(
@@ -98,7 +98,7 @@ describe('DeviceCommands failure mapping', () => {
98
98
  type: 'Failure',
99
99
  message: { code: 'Failure_ProcessError', subcode, message: 'Session selection failed' },
100
100
  } as any,
101
- 'DeviceSessionOpen'
101
+ 'DeviceSessionAskPin'
102
102
  )
103
103
  ).rejects.toMatchObject({ errorCode: code });
104
104
  });
@@ -37,7 +37,6 @@ function createDevice({ protocol }: { protocol: 'V1' | 'V2' }) {
37
37
 
38
38
  describe('DeviceSettings protocol routing', () => {
39
39
  it.each([
40
- ['label', { label: 'Shared Label' }],
41
40
  ['language', { language: 'ja-JP' }],
42
41
  ['brightness', { brightness: 80 }],
43
42
  ['haptic feedback', { hapticFeedback: true }],
@@ -56,6 +55,7 @@ describe('DeviceSettings protocol routing', () => {
56
55
  });
57
56
 
58
57
  it.each([
58
+ ['label', { label: 'Shared Label' }],
59
59
  ['auto lock', { autoLockDelayMs: 60_000 }],
60
60
  ['auto shutdown', { autoShutdownDelayMs: 120_000 }],
61
61
  ['mixed settings', { brightness: 80, autoLockDelayMs: 60_000 }],
@@ -1,6 +1,7 @@
1
1
  import { HardwareErrorCode } from '@onekeyfe/hd-shared';
2
2
 
3
3
  import ClearSessionCache from '../src/api/ClearSessionCache';
4
+ import DeviceWipe from '../src/api/device/DeviceWipe';
4
5
  import {
5
6
  DeviceWalletSessionStore,
6
7
  deviceWalletSessionStore,
@@ -96,6 +97,46 @@ describe('DeviceWalletSessionStore', () => {
96
97
  });
97
98
  });
98
99
 
100
+ describe('Device wipe lifecycle invalidation', () => {
101
+ beforeEach(() => {
102
+ deviceWalletSessionStore.clear();
103
+ });
104
+
105
+ test('clears the old Protocol V2 identity and wallet sessions after wipe succeeds', async () => {
106
+ const device = Device.fromDescriptor({
107
+ id: 'pro2-descriptor',
108
+ path: 'pro2-path',
109
+ protocolType: 'V2',
110
+ } as never);
111
+ device.features = {
112
+ protocol: 'V2',
113
+ deviceId: 'old-device-id',
114
+ unlocked: true,
115
+ passphraseProtection: true,
116
+ } as never;
117
+ device.passphraseState = 'hidden-a';
118
+ deviceWalletSessionStore.set('old-device-id', 'hidden-a', 'old-session');
119
+ deviceWalletSessionStore.set('pro2-path', 'hidden-a', 'temporary-session');
120
+ device.markPreInitialized({ passphraseState: 'hidden-a' });
121
+ device.commands = {
122
+ typedCall: jest.fn().mockResolvedValue({ message: { message: 'accepted' } }),
123
+ } as never;
124
+
125
+ const method = new DeviceWipe({ id: 1, payload: { method: 'deviceWipe' } });
126
+ method.init();
127
+ (method as any).device = device;
128
+
129
+ await expect(method.run()).resolves.toEqual({ message: 'accepted' });
130
+
131
+ expect(device.features).toBeUndefined();
132
+ expect(device.passphraseState).toBeUndefined();
133
+ expect(device.needReloadDevice).toBe(true);
134
+ expect(device.isPreInitializedValid(60_000)).toBe(false);
135
+ expect(deviceWalletSessionStore.get('old-device-id', 'hidden-a')).toBeUndefined();
136
+ expect(deviceWalletSessionStore.get('pro2-path', 'hidden-a')).toBeUndefined();
137
+ });
138
+ });
139
+
99
140
  describe('ClearSessionCache', () => {
100
141
  beforeEach(() => {
101
142
  deviceWalletSessionStore.clear();
@@ -0,0 +1,86 @@
1
+ import { EDeviceType, EFirmwareType } from '@onekeyfe/hd-shared';
2
+
3
+ import CheckAllFirmwareRelease from '../../src/api/CheckAllFirmwareRelease';
4
+ import { buildFirmwareUpdatePlan } from '../../src/api/firmware/FirmwareUpdatePlan';
5
+ import {
6
+ getBleFirmwareReleaseInfo,
7
+ getBootloaderReleaseInfo,
8
+ getFirmwareReleaseInfo,
9
+ } from '../../src/api/firmware/releaseHelper';
10
+
11
+ jest.mock('../../src/data/config', () => ({
12
+ getSDKVersion: jest.fn(() => '1.0.0'),
13
+ DEFAULT_DOMAIN: 'https://jssdk.onekey.so/1.0.0/',
14
+ }));
15
+
16
+ jest.mock('../../src/api/firmware/FirmwareUpdatePlan', () => ({
17
+ buildFirmwareUpdatePlan: jest.fn(),
18
+ }));
19
+
20
+ jest.mock('../../src/api/firmware/releaseHelper', () => ({
21
+ getBleFirmwareReleaseInfo: jest.fn(),
22
+ getBootloaderReleaseInfo: jest.fn(),
23
+ getFirmwareReleaseInfo: jest.fn(),
24
+ }));
25
+
26
+ const mockBuildFirmwareUpdatePlan = buildFirmwareUpdatePlan as jest.MockedFunction<
27
+ typeof buildFirmwareUpdatePlan
28
+ >;
29
+ const mockGetBleFirmwareReleaseInfo = getBleFirmwareReleaseInfo as jest.MockedFunction<
30
+ typeof getBleFirmwareReleaseInfo
31
+ >;
32
+ const mockGetBootloaderReleaseInfo = getBootloaderReleaseInfo as jest.MockedFunction<
33
+ typeof getBootloaderReleaseInfo
34
+ >;
35
+ const mockGetFirmwareReleaseInfo = getFirmwareReleaseInfo as jest.MockedFunction<
36
+ typeof getFirmwareReleaseInfo
37
+ >;
38
+
39
+ describe('CheckAllFirmwareRelease', () => {
40
+ test('keeps release information available when an optional Plan cannot be built', async () => {
41
+ const firmware = {
42
+ status: 'outdated' as const,
43
+ release: {
44
+ url: 'https://firmware.onekey.so/classic/firmware.bin',
45
+ version: [3, 0, 0],
46
+ },
47
+ };
48
+ const noUpdate = {
49
+ status: 'valid' as const,
50
+ release: undefined,
51
+ };
52
+ mockGetFirmwareReleaseInfo.mockReturnValue(firmware);
53
+ mockGetBootloaderReleaseInfo.mockReturnValue(noUpdate);
54
+ mockGetBleFirmwareReleaseInfo.mockReturnValue(noUpdate);
55
+ mockBuildFirmwareUpdatePlan.mockImplementation(() => {
56
+ throw new Error('FirmwarePlanInvalid');
57
+ });
58
+
59
+ const method = new CheckAllFirmwareRelease({
60
+ id: 1,
61
+ payload: {
62
+ method: 'checkAllFirmwareRelease',
63
+ platform: 'native',
64
+ },
65
+ });
66
+ method.init();
67
+ method.device = {
68
+ features: {
69
+ deviceType: EDeviceType.Classic1s,
70
+ serialNo: '',
71
+ firmwareType: EFirmwareType.Universal,
72
+ firmwareVersion: '1.0.0',
73
+ bootloaderVersion: '1.0.0',
74
+ },
75
+ } as typeof method.device;
76
+
77
+ await expect(method.run()).resolves.toEqual(
78
+ expect.objectContaining({
79
+ firmware,
80
+ bootloader: noUpdate,
81
+ ble: noUpdate,
82
+ firmwareUpdatePlan: undefined,
83
+ })
84
+ );
85
+ });
86
+ });
@@ -2,6 +2,7 @@ import { EDeviceType, EFirmwareType } from '@onekeyfe/hd-shared';
2
2
 
3
3
  import { buildFirmwareUpdatePlan } from '../../src/api/firmware/FirmwareUpdatePlan';
4
4
  import {
5
+ assertFirmwareUpdatePreparedPlanDeviceIdentity,
5
6
  assertFirmwareUpdatePreparedPlanBinding,
6
7
  prepareFirmwareUpdatePlan,
7
8
  validateFirmwareUpdatePreparedPlan,
@@ -76,6 +77,18 @@ describe('FirmwareUpdatePreparedPlan', () => {
76
77
  expect(prepared.preparedPlanDigest).toMatch(/^[a-f0-9]{64}$/u);
77
78
  expect(JSON.stringify(prepared)).not.toContain('https://');
78
79
  expect(validateFirmwareUpdatePreparedPlan(prepared)).toEqual(prepared);
80
+ expect(
81
+ assertFirmwareUpdatePreparedPlanDeviceIdentity({
82
+ preparedPlan: prepared,
83
+ deviceIdentity: plan.deviceIdentity,
84
+ })
85
+ ).toEqual(prepared);
86
+ expect(() =>
87
+ assertFirmwareUpdatePreparedPlanDeviceIdentity({
88
+ preparedPlan: prepared,
89
+ deviceIdentity: 'different-device-id',
90
+ })
91
+ ).toThrow();
79
92
  expect(
80
93
  assertFirmwareUpdatePreparedPlanBinding({
81
94
  preparedPlan: prepared,
@@ -60,4 +60,21 @@ describe('getLogBlockLabel', () => {
60
60
  expect(getLogBlockLabel({ payload: { method, data: new Uint8Array(1024) } })).toBe(method);
61
61
  }
62
62
  );
63
+
64
+ it.each(['evmSignMessage', 'btcSignMessage', 'evmSignTransaction'])(
65
+ 'blocks request and response payload logging for every API method including %s',
66
+ method => {
67
+ expect(getLogBlockLabel({ method, message: 'sensitive signing payload' })).toBe(method);
68
+ expect(
69
+ getLogBlockLabel({
70
+ event: 'iframe-call',
71
+ payload: { method, message: 'sensitive signing payload' },
72
+ })
73
+ ).toBe(method);
74
+ }
75
+ );
76
+
77
+ it('does not classify events without an API method as method calls', () => {
78
+ expect(getLogBlockLabel({ event: 'DEVICE_EVENT', type: 'device-connect' })).toBeUndefined();
79
+ });
63
80
  });
@@ -1,4 +1,5 @@
1
1
  import { EDeviceType, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
+ import { DeviceSessionPinType } from '@onekeyfe/hd-transport';
2
3
 
3
4
  import GetPassphraseState from '../src/api/GetPassphraseState';
4
5
  import OpenWalletSession from '../src/api/OpenWalletSession';
@@ -59,15 +60,42 @@ describe('openWalletSession', () => {
59
60
  deviceWalletSessionStore.clear();
60
61
  });
61
62
 
62
- test('keeps getPassphraseState unsupported on Protocol V2', async () => {
63
+ test('keeps the legacy getPassphraseState App flow working on Protocol V2', async () => {
64
+ const typedCall = jest
65
+ .fn()
66
+ .mockResolvedValueOnce({ message: { eventless_wallet_session: true } })
67
+ .mockResolvedValueOnce({ message: { message: 'passphrase prepared' } })
68
+ .mockResolvedValueOnce({
69
+ message: {
70
+ btc_test_address: 'pro2-wallet-state',
71
+ session_id: 'pro2-wallet-session',
72
+ },
73
+ });
74
+ const promptPassphrase = jest.fn().mockResolvedValue({ passphrase: 'legacy app secret' });
63
75
  const method = new GetPassphraseState({
64
- payload: { method: 'getPassphraseState', connectId: 'connect-id' },
76
+ payload: {
77
+ method: 'getPassphraseState',
78
+ connectId: 'connect-id',
79
+ initSession: true,
80
+ useEmptyPassphrase: false,
81
+ },
65
82
  });
66
- method.device = createDevice() as any;
83
+ method.device = createDevice({ typedCall, promptPassphrase }) as any;
67
84
 
68
- await expect(method.run()).rejects.toMatchObject({
69
- errorCode: HardwareErrorCode.DeviceNotSupportMethod,
70
- });
85
+ await expect(method.run()).resolves.toBe('pro2-wallet-state');
86
+ expect(promptPassphrase).toHaveBeenCalledWith(
87
+ expect.objectContaining({ deviceOnly: true }),
88
+ expect.anything()
89
+ );
90
+ expect(typedCall).toHaveBeenNthCalledWith(
91
+ 2,
92
+ 'DeviceSessionAskPassphrase',
93
+ 'Success',
94
+ {},
95
+ { timeoutMs: 120_000 }
96
+ );
97
+ expect(typedCall).toHaveBeenNthCalledWith(3, 'DeviceSessionGet', 'DeviceSession', {});
98
+ expect(JSON.stringify(typedCall.mock.calls)).not.toContain('legacy app secret');
71
99
  });
72
100
 
73
101
  test('keeps Legacy Protocol V1 getPassphraseState parameterless', async () => {
@@ -175,12 +203,26 @@ describe('openWalletSession', () => {
175
203
  walletType: 'hidden',
176
204
  passphraseState: 'hidden-state',
177
205
  });
206
+ expect(promptPassphrase).toHaveBeenCalledWith(
207
+ expect.objectContaining({ deviceOnly: true }),
208
+ expect.anything()
209
+ );
210
+ expect(typedCall).toHaveBeenNthCalledWith(
211
+ 2,
212
+ 'DeviceSessionAskPassphrase',
213
+ 'Success',
214
+ {},
215
+ { timeoutMs: 120_000 }
216
+ );
217
+ expect(typedCall).toHaveBeenNthCalledWith(3, 'DeviceSessionGet', 'DeviceSession', {});
218
+ expect(JSON.stringify(typedCall.mock.calls)).not.toContain('hidden secret');
178
219
  });
179
220
 
180
221
  test('classifies the selected Pro2 wallet from the post-unlock device state', async () => {
181
222
  const typedCall = jest
182
223
  .fn()
183
224
  .mockResolvedValueOnce({ message: { version: 2 } })
225
+ .mockResolvedValueOnce({ message: { message: 'passphrase prepared' } })
184
226
  .mockResolvedValueOnce({
185
227
  message: {
186
228
  btc_test_address: 'hidden-state-after-unlock',
@@ -210,7 +252,7 @@ describe('openWalletSession', () => {
210
252
  sessionId: 'hidden-session-after-unlock',
211
253
  resumed: false,
212
254
  });
213
- expect(device.unlockDevice).toHaveBeenCalledTimes(1);
255
+ expect(device.unlockDevice).toHaveBeenCalledWith(DeviceSessionPinType.Main);
214
256
  expect(promptPassphrase).toHaveBeenCalledTimes(1);
215
257
  });
216
258
 
@@ -246,9 +288,15 @@ describe('openWalletSession', () => {
246
288
  expect(typedCall).toHaveBeenCalledWith('ProtocolInfoRequest', 'ProtocolInfo', {
247
289
  eventless_wallet_session: true,
248
290
  });
249
- expect(typedCall).toHaveBeenCalledWith('DeviceSessionOpen', 'DeviceSession', {
250
- select: { host_passphrase: { passphrase: 'new hidden secret' } },
251
- });
291
+ expect(typedCall).toHaveBeenCalledWith(
292
+ 'DeviceSessionAskPassphrase',
293
+ 'Success',
294
+ {},
295
+ {
296
+ timeoutMs: 120_000,
297
+ }
298
+ );
299
+ expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {});
252
300
  expect(promptPassphrase).toHaveBeenCalled();
253
301
  expect(deviceWalletSessionStore.get('device-1', 'stale-hidden-state')).toBeUndefined();
254
302
  expect(deviceWalletSessionStore.get('device-1', 'new-hidden-state')).toBe('new-hidden-session');
@@ -314,8 +362,8 @@ describe('openWalletSession', () => {
314
362
  sessionId: 'renewed-session',
315
363
  resumed: true,
316
364
  });
317
- expect(typedCall).toHaveBeenCalledWith('DeviceSessionOpen', 'DeviceSession', {
318
- resume: { session_id: 'known-session' },
365
+ expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
366
+ session_id: 'known-session',
319
367
  });
320
368
  expect(promptPassphrase).not.toHaveBeenCalled();
321
369
  });
@@ -530,15 +578,21 @@ describe('openWalletSession', () => {
530
578
  sessionId: 'hidden-session',
531
579
  resumed: false,
532
580
  });
533
- expect(typedCall).toHaveBeenCalledWith('DeviceSessionOpen', 'DeviceSession', {
534
- select: { host_passphrase: { passphrase: 'hidden secret' } },
535
- });
581
+ expect(typedCall).toHaveBeenCalledWith(
582
+ 'DeviceSessionAskPassphrase',
583
+ 'Success',
584
+ {},
585
+ {
586
+ timeoutMs: 120_000,
587
+ }
588
+ );
589
+ expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {});
536
590
  expect(promptPassphrase).toHaveBeenCalled();
537
591
  expect(device.passphraseState).toBeUndefined();
538
592
  expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBe('hidden-session');
539
593
  });
540
594
 
541
- test('selects on-device passphrase entry through DeviceSessionOpen', async () => {
595
+ test('selects on-device passphrase entry before getting the prepared session', async () => {
542
596
  const typedCall = jest.fn().mockResolvedValue({
543
597
  message: { btc_test_address: 'device-state', session_id: 'device-session' },
544
598
  });
@@ -553,9 +607,15 @@ describe('openWalletSession', () => {
553
607
  walletType: 'hidden',
554
608
  passphraseState: 'device-state',
555
609
  });
556
- expect(typedCall).toHaveBeenCalledWith('DeviceSessionOpen', 'DeviceSession', {
557
- select: { passphrase_on_device: {} },
558
- });
610
+ expect(typedCall).toHaveBeenCalledWith(
611
+ 'DeviceSessionAskPassphrase',
612
+ 'Success',
613
+ {},
614
+ {
615
+ timeoutMs: 120_000,
616
+ }
617
+ );
618
+ expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {});
559
619
  });
560
620
 
561
621
  test('selects Attach PIN only when the device reports an existing binding', async () => {
@@ -576,12 +636,11 @@ describe('openWalletSession', () => {
576
636
  passphraseState: 'attach-state',
577
637
  });
578
638
  expect(promptPassphrase).toHaveBeenCalledWith(
579
- expect.objectContaining({ existsAttachPinUser: true }),
639
+ expect.objectContaining({ existsAttachPinUser: true, deviceOnly: true }),
580
640
  { cancelDeviceOnReject: false }
581
641
  );
582
- expect(typedCall).toHaveBeenCalledWith('DeviceSessionOpen', 'DeviceSession', {
583
- select: { attach_pin_on_device: {} },
584
- });
642
+ expect(device.unlockDevice).toHaveBeenCalledWith(DeviceSessionPinType.AttachToPin);
643
+ expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {});
585
644
  });
586
645
 
587
646
  test.each([
@@ -607,7 +666,7 @@ describe('openWalletSession', () => {
607
666
 
608
667
  await expect(method.run()).rejects.toMatchObject({
609
668
  errorCode: HardwareErrorCode.RuntimeError,
610
- message: 'DeviceSessionOpen returned an incomplete DeviceSession response.',
669
+ message: 'DeviceSessionGet returned an incomplete DeviceSession response.',
611
670
  });
612
671
  expect(device.clearInternalState).toHaveBeenCalled();
613
672
  expect(device.updateInternalState).not.toHaveBeenCalled();
@@ -643,8 +702,8 @@ describe('openWalletSession', () => {
643
702
  sessionId: 'renewed-session',
644
703
  resumed: true,
645
704
  });
646
- expect(typedCall).toHaveBeenCalledWith('DeviceSessionOpen', 'DeviceSession', {
647
- resume: { session_id: 'known-session' },
705
+ expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
706
+ session_id: 'known-session',
648
707
  });
649
708
  expect(promptPassphrase).not.toHaveBeenCalled();
650
709
  });
@@ -694,14 +753,14 @@ describe('openWalletSession', () => {
694
753
  });
695
754
  expect(device.unlockDevice).toHaveBeenCalledTimes(1);
696
755
  expect(device.getDeviceState).toHaveBeenCalledTimes(2);
697
- expect(typedCall).toHaveBeenCalledWith('DeviceSessionOpen', 'DeviceSession', {
698
- resume: { session_id: 'known-session' },
756
+ expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
757
+ session_id: 'known-session',
699
758
  });
700
- const sessionOpenCall = typedCall.mock.calls.findIndex(
701
- ([requestName]) => requestName === 'DeviceSessionOpen'
759
+ const sessionGetCall = typedCall.mock.calls.findIndex(
760
+ ([requestName]) => requestName === 'DeviceSessionGet'
702
761
  );
703
762
  expect(device.getDeviceState.mock.invocationCallOrder[1]).toBeLessThan(
704
- typedCall.mock.invocationCallOrder[sessionOpenCall]
763
+ typedCall.mock.invocationCallOrder[sessionGetCall]
705
764
  );
706
765
  });
707
766