@onekeyfe/hd-core 1.2.2-alpha.8 → 1.2.2

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 (81) hide show
  1. package/README.md +1 -1
  2. package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +503 -10
  3. package/__tests__/DeviceCommands.test.ts +254 -1
  4. package/__tests__/core-error-output.test.ts +169 -1
  5. package/__tests__/device-lifecycle-events.test.ts +432 -15
  6. package/__tests__/logBlockEvent.test.ts +45 -122
  7. package/__tests__/open-wallet-session-error-response.test.ts +2 -2
  8. package/__tests__/open-wallet-session.test.ts +94 -363
  9. package/__tests__/protocol-v2.test.ts +132 -2
  10. package/__tests__/public-device-state-api.test.ts +2 -7
  11. package/__tests__/search-devices.test.ts +196 -8
  12. package/__tests__/sol-sign-offchain-message.test.ts +64 -0
  13. package/dist/api/FirmwareUpdateV4.d.ts +1 -0
  14. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  15. package/dist/api/GetFeatures.d.ts.map +1 -1
  16. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  17. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  18. package/dist/api/SearchDevices.d.ts +2 -15
  19. package/dist/api/SearchDevices.d.ts.map +1 -1
  20. package/dist/api/UploadPortfolio.d.ts +1 -0
  21. package/dist/api/UploadPortfolio.d.ts.map +1 -1
  22. package/dist/api/allnetwork/AllNetworkGetAddress.d.ts +2 -0
  23. package/dist/api/allnetwork/AllNetworkGetAddress.d.ts.map +1 -1
  24. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts +7 -1
  25. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
  26. package/dist/api/allnetwork/AllNetworkGetAddressByLoop.d.ts.map +1 -1
  27. package/dist/api/device/DeviceVerify.d.ts.map +1 -1
  28. package/dist/api/solana/SolSignOffchainMessage.d.ts.map +1 -1
  29. package/dist/core/RequestQueue.d.ts +3 -0
  30. package/dist/core/RequestQueue.d.ts.map +1 -1
  31. package/dist/core/index.d.ts +3 -1
  32. package/dist/core/index.d.ts.map +1 -1
  33. package/dist/core/uiPromiseRegistry.d.ts +1 -1
  34. package/dist/data-manager/TransportManager.d.ts +2 -0
  35. package/dist/data-manager/TransportManager.d.ts.map +1 -1
  36. package/dist/device/Device.d.ts +2 -0
  37. package/dist/device/Device.d.ts.map +1 -1
  38. package/dist/device/DeviceCommands.d.ts +5 -4
  39. package/dist/device/DeviceCommands.d.ts.map +1 -1
  40. package/dist/events/logBlockEvent.d.ts.map +1 -1
  41. package/dist/index.d.ts +35 -30
  42. package/dist/index.js +620 -325
  43. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  44. package/dist/types/api/getFeatures.d.ts.map +1 -1
  45. package/dist/types/api/getPassphraseState.d.ts.map +1 -1
  46. package/dist/types/api/openWalletSession.d.ts +1 -10
  47. package/dist/types/api/openWalletSession.d.ts.map +1 -1
  48. package/dist/types/api/protocolV2.d.ts +3 -4
  49. package/dist/types/api/protocolV2.d.ts.map +1 -1
  50. package/dist/types/api/solSignOffchainMessage.d.ts +1 -0
  51. package/dist/types/api/solSignOffchainMessage.d.ts.map +1 -1
  52. package/dist/types/params.d.ts.map +1 -1
  53. package/dist/utils/patch.d.ts +1 -1
  54. package/dist/utils/patch.d.ts.map +1 -1
  55. package/package.json +4 -4
  56. package/src/api/FirmwareUpdateV4.ts +9 -4
  57. package/src/api/GetFeatures.ts +1 -0
  58. package/src/api/GetPassphraseState.ts +1 -0
  59. package/src/api/OpenWalletSession.ts +7 -77
  60. package/src/api/SearchDevices.ts +121 -27
  61. package/src/api/UploadPortfolio.ts +5 -4
  62. package/src/api/allnetwork/AllNetworkGetAddress.ts +79 -45
  63. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +95 -24
  64. package/src/api/allnetwork/AllNetworkGetAddressByLoop.ts +3 -0
  65. package/src/api/device/DeviceVerify.ts +8 -0
  66. package/src/api/solana/SolSignOffchainMessage.ts +44 -4
  67. package/src/core/RequestQueue.ts +36 -1
  68. package/src/core/index.ts +178 -63
  69. package/src/data/messages/messages-protocol-v2.json +49 -33
  70. package/src/data/messages/messages.json +8 -5
  71. package/src/data-manager/TransportManager.ts +14 -3
  72. package/src/device/Device.ts +58 -27
  73. package/src/device/DeviceCommands.ts +29 -2
  74. package/src/events/logBlockEvent.ts +6 -75
  75. package/src/protocols/protocol-v2/walletSession.ts +18 -2
  76. package/src/types/api/getFeatures.ts +2 -1
  77. package/src/types/api/getPassphraseState.ts +2 -5
  78. package/src/types/api/openWalletSession.ts +7 -19
  79. package/src/types/api/protocolV2.ts +3 -4
  80. package/src/types/api/solSignOffchainMessage.ts +2 -0
  81. package/src/types/params.ts +7 -0
@@ -26,12 +26,16 @@ jest.mock('../src/data/config', () => ({
26
26
  const createDevice = ({
27
27
  passphraseProtection = true,
28
28
  unlockedAttachPin = false,
29
+ refreshedUnlocked = true,
30
+ refreshedPassphraseProtection = passphraseProtection,
29
31
  refreshedUnlockedAttachPin = unlockedAttachPin,
30
32
  typedCall = jest.fn(),
31
33
  promptPassphrase = jest.fn(),
32
34
  }: {
33
35
  passphraseProtection?: boolean;
34
36
  unlockedAttachPin?: boolean;
37
+ refreshedUnlocked?: boolean;
38
+ refreshedPassphraseProtection?: boolean;
35
39
  refreshedUnlockedAttachPin?: boolean;
36
40
  typedCall?: jest.Mock;
37
41
  promptPassphrase?: jest.Mock;
@@ -50,11 +54,11 @@ const createDevice = ({
50
54
  return {
51
55
  message: {
52
56
  device_id: 'device-1',
53
- unlocked: true,
57
+ unlocked: refreshedUnlocked,
54
58
  attach_to_pin_enabled: unlockedAttachPin,
55
59
  unlocked_attach_pin: refreshedUnlockedAttachPin,
56
60
  unlocked_by_attach_to_pin: refreshedUnlockedAttachPin,
57
- passphrase_enabled: passphraseProtection,
61
+ passphrase_enabled: refreshedPassphraseProtection,
58
62
  },
59
63
  };
60
64
  }
@@ -95,6 +99,8 @@ const createDevice = ({
95
99
  unlockDevice: jest.fn(),
96
100
  updateProtocolV2Status: jest.fn((status: Record<string, unknown>) => {
97
101
  device.features.unlocked = status.unlocked ?? device.features.unlocked;
102
+ device.features.passphraseProtection =
103
+ status.passphrase_enabled ?? device.features.passphraseProtection;
98
104
  device.features.attachToPinEnabled =
99
105
  status.attach_to_pin_enabled ?? device.features.attachToPinEnabled;
100
106
  device.features.unlockedAttachPin =
@@ -182,6 +188,65 @@ describe('openWalletSession', () => {
182
188
  expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', standardSessionGet);
183
189
  });
184
190
 
191
+ test('refreshes stale wallet status before accepting an only-Main-PIN session', async () => {
192
+ let attachPinSelected = true;
193
+ const typedCall = jest.fn((request: string) => {
194
+ if (request === 'ProtocolInfoRequest') {
195
+ return { message: { version: 2 } };
196
+ }
197
+ if (request === 'DeviceSessionGet') {
198
+ return {
199
+ message: {
200
+ btc_test_address: 'standard-state',
201
+ session_id: 'standard-session',
202
+ },
203
+ };
204
+ }
205
+ if (request === 'DeviceSessionAskPassphrase') {
206
+ return { message: {} };
207
+ }
208
+ throw new Error(`Unexpected request: ${request}`);
209
+ });
210
+ const device = createDevice({
211
+ passphraseProtection: false,
212
+ unlockedAttachPin: false,
213
+ typedCall,
214
+ });
215
+ device.commands.typedCall.mockImplementation((request: string, ...args: unknown[]) => {
216
+ if (request === 'DeviceStatusGet') {
217
+ return {
218
+ message: {
219
+ device_id: 'device-1',
220
+ unlocked: true,
221
+ attach_to_pin_enabled: true,
222
+ unlocked_attach_pin: attachPinSelected,
223
+ unlocked_by_attach_to_pin: attachPinSelected,
224
+ passphrase_enabled: true,
225
+ },
226
+ };
227
+ }
228
+ return typedCall(request, ...args);
229
+ });
230
+ device.unlockDevice.mockImplementation(() => {
231
+ attachPinSelected = false;
232
+ device.features.unlockedAttachPin = false;
233
+ return Promise.resolve(device.features);
234
+ });
235
+
236
+ await expect(
237
+ getProtocolV2WalletSession(device as any, { onlyMainPin: true })
238
+ ).resolves.toMatchObject({
239
+ unlockedAttachPin: false,
240
+ });
241
+
242
+ expect(device.commands.typedCall).toHaveBeenCalledWith('DeviceStatusGet', 'DeviceStatus', {});
243
+ expect(device.unlockDevice).toHaveBeenCalledWith(DeviceSessionPinType.Main, {
244
+ source: 'wallet-session-coordinator',
245
+ reason: 'open-wallet',
246
+ deviceOnly: true,
247
+ });
248
+ });
249
+
185
250
  test('still requires Main PIN when a cached standard session resolves to another wallet', async () => {
186
251
  let sessionGetCount = 0;
187
252
  const typedCall = jest.fn((request: string) => {
@@ -267,8 +332,7 @@ describe('openWalletSession', () => {
267
332
  }
268
333
  throw new Error(`Unexpected request: ${request}`);
269
334
  });
270
- const device = createDevice({ typedCall });
271
- device.features.unlockedAttachPin = true;
335
+ const device = createDevice({ refreshedUnlockedAttachPin: true, typedCall });
272
336
 
273
337
  await getProtocolV2WalletSession(device as any, { onlyMainPin: true });
274
338
 
@@ -918,45 +982,6 @@ describe('openWalletSession', () => {
918
982
  );
919
983
  });
920
984
 
921
- test('uses an explicit wallet binding to resume on Protocol V2', async () => {
922
- const typedCall = jest
923
- .fn()
924
- .mockResolvedValueOnce({ message: { version: 2 } })
925
- .mockResolvedValueOnce({
926
- message: {
927
- btc_test_address: 'hidden-state',
928
- session_id: 'renewed-session',
929
- },
930
- });
931
- const promptPassphrase = jest.fn();
932
- const method = new OpenWalletSession({
933
- payload: {
934
- method: 'openWalletSession',
935
- connectId: 'connect-id',
936
- mode: 'resume-hidden',
937
- deviceId: 'device-1',
938
- passphraseState: 'hidden-state',
939
- },
940
- });
941
- method.init();
942
- deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
943
- method.device = createDevice({ typedCall, promptPassphrase }) as any;
944
-
945
- await expect(method.run()).resolves.toEqual({
946
- protocol: 'V2',
947
- walletType: 'hidden',
948
- deviceId: 'device-1',
949
- passphraseState: 'hidden-state',
950
- resumed: true,
951
- });
952
- expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
953
- session_id: 'known-session',
954
- btc_test_address: 'hidden-state',
955
- ...standardSessionGet,
956
- });
957
- expect(promptPassphrase).not.toHaveBeenCalled();
958
- });
959
-
960
985
  test.each([
961
986
  {
962
987
  mode: 'standard',
@@ -971,12 +996,6 @@ describe('openWalletSession', () => {
971
996
  deviceId: 'device-1',
972
997
  passphraseState: 'hidden-state',
973
998
  },
974
- {
975
- mode: 'resume-hidden',
976
- deviceId: 'device-1',
977
- passphraseState: 'hidden-state',
978
- initSession: false,
979
- },
980
999
  ])('rejects legacy parameters combined with explicit mode: %o', params => {
981
1000
  const method = new OpenWalletSession({
982
1001
  payload: {
@@ -1012,63 +1031,7 @@ describe('openWalletSession', () => {
1012
1031
  }
1013
1032
  );
1014
1033
 
1015
- test('reuses the SDK-managed Protocol V1 hidden-wallet session before validation', async () => {
1016
- const typedCall = jest.fn().mockResolvedValue({
1017
- type: 'PassphraseState',
1018
- message: {
1019
- passphrase_state: 'hidden-state',
1020
- session_id: 'known-session',
1021
- unlocked_attach_pin: false,
1022
- },
1023
- });
1024
- const method = new OpenWalletSession({
1025
- payload: {
1026
- method: 'openWalletSession',
1027
- connectId: 'connect-id',
1028
- mode: 'resume-hidden',
1029
- deviceId: 'device-1',
1030
- passphraseState: 'hidden-state',
1031
- },
1032
- });
1033
- method.init();
1034
- deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
1035
- const device = createDevice({ typedCall });
1036
- device.isProtocolV2 = () => false;
1037
- device.features = {
1038
- ...device.features,
1039
- deviceId: 'device-1',
1040
- unlocked: true,
1041
- sessionId: null,
1042
- };
1043
- device.getCurrentFirmwareVersionString = () => '4.15.0';
1044
- device.getCurrentDeviceType = () => EDeviceType.Pro;
1045
- device.getFeatures = jest.fn();
1046
- method.device = device as any;
1047
-
1048
- await expect(method.run()).resolves.toMatchObject({
1049
- protocol: 'V1',
1050
- walletType: 'hidden',
1051
- passphraseState: 'hidden-state',
1052
- resumed: true,
1053
- });
1054
- expect(device.initialize).toHaveBeenCalledWith({
1055
- deviceId: 'device-1',
1056
- passphraseState: 'hidden-state',
1057
- });
1058
- expect(typedCall).toHaveBeenCalledWith('GetPassphraseState', 'PassphraseState', {
1059
- passphrase_state: 'hidden-state',
1060
- });
1061
- });
1062
-
1063
- test('rejects a Protocol V1 resume when the device returns another hidden wallet', async () => {
1064
- const typedCall = jest.fn().mockResolvedValue({
1065
- type: 'PassphraseState',
1066
- message: {
1067
- passphrase_state: 'other-hidden-state',
1068
- session_id: 'other-session',
1069
- unlocked_attach_pin: false,
1070
- },
1071
- });
1034
+ test('rejects the removed resume-hidden mode', () => {
1072
1035
  const method = new OpenWalletSession({
1073
1036
  payload: {
1074
1037
  method: 'openWalletSession',
@@ -1076,28 +1039,15 @@ describe('openWalletSession', () => {
1076
1039
  mode: 'resume-hidden',
1077
1040
  deviceId: 'device-1',
1078
1041
  passphraseState: 'hidden-state',
1079
- },
1042
+ } as any,
1080
1043
  });
1081
- method.init();
1082
- deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
1083
- const device = createDevice({ typedCall });
1084
- device.isProtocolV2 = () => false;
1085
- device.features = {
1086
- ...device.features,
1087
- deviceId: 'device-1',
1088
- unlocked: true,
1089
- sessionId: null,
1090
- };
1091
- device.getCurrentFirmwareVersionString = () => '4.15.0';
1092
- device.getCurrentDeviceType = () => EDeviceType.Pro;
1093
- device.getFeatures = jest.fn();
1094
- method.device = device as any;
1095
1044
 
1096
- await expect(method.run()).rejects.toMatchObject({
1097
- errorCode: HardwareErrorCode.DeviceCheckPassphraseStateError,
1098
- });
1099
- expect(device.clearInternalState).toHaveBeenCalledTimes(1);
1100
- expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBeUndefined();
1045
+ expect(() => method.init()).toThrow(
1046
+ expect.objectContaining({
1047
+ errorCode: HardwareErrorCode.CallMethodInvalidParameter,
1048
+ message: 'Parameter [mode] must be one of standard or select-hidden.',
1049
+ })
1050
+ );
1101
1051
  });
1102
1052
 
1103
1053
  test('opens the standard wallet without selecting a hidden wallet', async () => {
@@ -1157,7 +1107,7 @@ describe('openWalletSession', () => {
1157
1107
  payload: { method: 'openWalletSession', connectId: 'connect-id', mode: 'standard' },
1158
1108
  });
1159
1109
  method.init();
1160
- const device = createDevice({ typedCall });
1110
+ const device = createDevice({ refreshedUnlocked: false, typedCall });
1161
1111
  device.features.unlocked = false;
1162
1112
  device.getDeviceState = jest
1163
1113
  .fn()
@@ -1257,6 +1207,7 @@ describe('openWalletSession', () => {
1257
1207
  });
1258
1208
 
1259
1209
  test('switches from Attach PIN to Main PIN before opening the standard wallet', async () => {
1210
+ let attachPinSelected = true;
1260
1211
  const typedCall = jest
1261
1212
  .fn()
1262
1213
  .mockResolvedValueOnce({ message: { version: 2 } })
@@ -1273,6 +1224,21 @@ describe('openWalletSession', () => {
1273
1224
  method.init();
1274
1225
  const device = createDevice({ typedCall });
1275
1226
  device.features.unlockedAttachPin = true;
1227
+ device.commands.typedCall.mockImplementation((request: string, ...args: unknown[]) => {
1228
+ if (request === 'DeviceStatusGet') {
1229
+ return {
1230
+ message: {
1231
+ device_id: 'device-1',
1232
+ unlocked: true,
1233
+ attach_to_pin_enabled: true,
1234
+ unlocked_attach_pin: attachPinSelected,
1235
+ unlocked_by_attach_to_pin: attachPinSelected,
1236
+ passphrase_enabled: true,
1237
+ },
1238
+ };
1239
+ }
1240
+ return typedCall(request, ...args);
1241
+ });
1276
1242
  device.getDeviceState = jest
1277
1243
  .fn()
1278
1244
  .mockResolvedValueOnce({
@@ -1292,6 +1258,7 @@ describe('openWalletSession', () => {
1292
1258
  },
1293
1259
  });
1294
1260
  device.unlockDevice = jest.fn().mockImplementation(() => {
1261
+ attachPinSelected = false;
1295
1262
  device.features.unlockedAttachPin = false;
1296
1263
  return Promise.resolve(device.features);
1297
1264
  });
@@ -1801,242 +1768,6 @@ describe('openWalletSession', () => {
1801
1768
  }
1802
1769
  );
1803
1770
 
1804
- test('resumes a known hidden wallet without prompting or device selection', async () => {
1805
- const typedCall = jest
1806
- .fn()
1807
- .mockResolvedValueOnce({ message: { version: 2 } })
1808
- .mockResolvedValueOnce({
1809
- message: {
1810
- btc_test_address: 'hidden-state',
1811
- session_id: 'renewed-session',
1812
- },
1813
- });
1814
- const promptPassphrase = jest.fn();
1815
- const method = new OpenWalletSession({
1816
- payload: {
1817
- method: 'openWalletSession',
1818
- connectId: 'connect-id',
1819
- mode: 'resume-hidden',
1820
- deviceId: 'device-1',
1821
- passphraseState: 'hidden-state',
1822
- },
1823
- });
1824
- method.init();
1825
- deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
1826
- method.device = createDevice({ typedCall, promptPassphrase }) as any;
1827
-
1828
- await expect(method.run()).resolves.toEqual({
1829
- protocol: 'V2',
1830
- walletType: 'hidden',
1831
- deviceId: 'device-1',
1832
- passphraseState: 'hidden-state',
1833
- resumed: true,
1834
- });
1835
- expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
1836
- session_id: 'known-session',
1837
- btc_test_address: 'hidden-state',
1838
- ...standardSessionGet,
1839
- });
1840
- expect(promptPassphrase).not.toHaveBeenCalled();
1841
- });
1842
-
1843
- test('validates a locked Protocol V2 resume binding after deviceId refresh', async () => {
1844
- const typedCall = jest
1845
- .fn()
1846
- .mockResolvedValueOnce({ message: { version: 2 } })
1847
- .mockResolvedValueOnce({
1848
- message: {
1849
- btc_test_address: 'hidden-state',
1850
- session_id: 'renewed-session',
1851
- },
1852
- });
1853
- const method = new OpenWalletSession({
1854
- payload: {
1855
- method: 'openWalletSession',
1856
- connectId: 'connect-id',
1857
- mode: 'resume-hidden',
1858
- deviceId: 'device-1',
1859
- passphraseState: 'hidden-state',
1860
- },
1861
- });
1862
- method.init();
1863
- deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
1864
- const device = createDevice({ typedCall });
1865
- device.features.unlocked = false;
1866
- device.getDeviceState = jest
1867
- .fn()
1868
- .mockResolvedValueOnce({
1869
- identity: { deviceId: undefined },
1870
- status: { unlocked: false, passphraseProtection: true },
1871
- })
1872
- .mockResolvedValueOnce({
1873
- identity: { deviceId: 'device-1' },
1874
- status: {
1875
- unlocked: true,
1876
- passphraseProtection: true,
1877
- unlockedAttachPin: false,
1878
- },
1879
- });
1880
- device.unlockDevice = jest.fn().mockImplementation(() => {
1881
- device.features.unlocked = true;
1882
- return Promise.resolve(device.features);
1883
- });
1884
- method.device = device as any;
1885
-
1886
- await expect(method.run()).resolves.toMatchObject({
1887
- protocol: 'V2',
1888
- walletType: 'hidden',
1889
- deviceId: 'device-1',
1890
- passphraseState: 'hidden-state',
1891
- resumed: true,
1892
- });
1893
- expect(device.unlockDevice).toHaveBeenCalledTimes(1);
1894
- expect(device.getDeviceState).toHaveBeenCalledTimes(2);
1895
- expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
1896
- session_id: 'known-session',
1897
- btc_test_address: 'hidden-state',
1898
- ...standardSessionGet,
1899
- });
1900
- const sessionGetCall = typedCall.mock.calls.findIndex(
1901
- ([requestName]) => requestName === 'DeviceSessionGet'
1902
- );
1903
- expect(device.getDeviceState.mock.invocationCallOrder[1]).toBeLessThan(
1904
- typedCall.mock.invocationCallOrder[sessionGetCall]
1905
- );
1906
- });
1907
-
1908
- test('rejects a Protocol V2 resume when the refreshed deviceId does not match', async () => {
1909
- const typedCall = jest.fn().mockResolvedValue({
1910
- message: {
1911
- btc_test_address: 'hidden-state',
1912
- session_id: 'renewed-session',
1913
- },
1914
- });
1915
- const method = new OpenWalletSession({
1916
- payload: {
1917
- method: 'openWalletSession',
1918
- connectId: 'connect-id',
1919
- mode: 'resume-hidden',
1920
- deviceId: 'device-1',
1921
- passphraseState: 'hidden-state',
1922
- },
1923
- });
1924
- method.init();
1925
- deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
1926
- const device = createDevice({ typedCall });
1927
- device.features.unlocked = false;
1928
- device.getDeviceState = jest
1929
- .fn()
1930
- .mockResolvedValueOnce({
1931
- identity: { deviceId: undefined },
1932
- status: { passphraseProtection: true },
1933
- })
1934
- .mockResolvedValueOnce({
1935
- identity: { deviceId: 'other-device' },
1936
- status: {
1937
- unlocked: true,
1938
- passphraseProtection: true,
1939
- unlockedAttachPin: false,
1940
- },
1941
- });
1942
- device.unlockDevice = jest.fn().mockImplementation(() => {
1943
- device.features.unlocked = true;
1944
- return Promise.resolve(device.features);
1945
- });
1946
- method.device = device as any;
1947
-
1948
- await expect(method.run()).rejects.toMatchObject({
1949
- errorCode: HardwareErrorCode.DeviceCheckDeviceIdError,
1950
- });
1951
- expect(typedCall).not.toHaveBeenCalled();
1952
- expect(device.clearInternalState).not.toHaveBeenCalled();
1953
- expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBeUndefined();
1954
- });
1955
-
1956
- test('reselects the expected hidden wallet when a cached Protocol V2 session is invalid', async () => {
1957
- const typedCall = jest
1958
- .fn()
1959
- .mockResolvedValueOnce({ message: { version: 2 } })
1960
- .mockRejectedValueOnce(
1961
- Object.assign(new Error('Invalid session'), {
1962
- errorCode: HardwareErrorCode.WalletSessionInvalid,
1963
- })
1964
- )
1965
- .mockResolvedValueOnce({ message: {} })
1966
- .mockResolvedValueOnce({
1967
- message: {
1968
- btc_test_address: 'hidden-state',
1969
- session_id: 'renewed-session',
1970
- },
1971
- });
1972
- const promptPassphrase = jest.fn().mockResolvedValue({ passphrase: 'host hidden wallet' });
1973
- const method = new OpenWalletSession({
1974
- payload: {
1975
- method: 'openWalletSession',
1976
- connectId: 'connect-id',
1977
- mode: 'resume-hidden',
1978
- deviceId: 'device-1',
1979
- passphraseState: 'hidden-state',
1980
- },
1981
- });
1982
- method.init();
1983
- deviceWalletSessionStore.set('device-1', 'hidden-state', 'expired-session');
1984
- method.device = createDevice({ typedCall, promptPassphrase }) as any;
1985
-
1986
- await expect(method.run()).resolves.toEqual({
1987
- protocol: 'V2',
1988
- walletType: 'hidden',
1989
- deviceId: 'device-1',
1990
- passphraseState: 'hidden-state',
1991
- resumed: false,
1992
- });
1993
- expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
1994
- session_id: 'expired-session',
1995
- btc_test_address: 'hidden-state',
1996
- ...standardSessionGet,
1997
- });
1998
- expect(promptPassphrase).toHaveBeenCalledTimes(1);
1999
- expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBe('renewed-session');
2000
- });
2001
-
2002
- test('selects the expected hidden wallet when Protocol V2 has no cached session', async () => {
2003
- const typedCall = jest
2004
- .fn()
2005
- .mockResolvedValueOnce({ message: { version: 2 } })
2006
- .mockResolvedValueOnce({
2007
- message: {
2008
- btc_test_address: 'hidden-state',
2009
- session_id: 'new-session',
2010
- },
2011
- });
2012
- const promptPassphrase = jest.fn().mockResolvedValue({ passphrase: 'host hidden wallet' });
2013
- const method = new OpenWalletSession({
2014
- payload: {
2015
- method: 'openWalletSession',
2016
- connectId: 'connect-id',
2017
- mode: 'resume-hidden',
2018
- deviceId: 'device-1',
2019
- passphraseState: 'hidden-state',
2020
- },
2021
- });
2022
- method.init();
2023
- method.device = createDevice({ typedCall, promptPassphrase }) as any;
2024
-
2025
- await expect(method.run()).resolves.toEqual({
2026
- protocol: 'V2',
2027
- walletType: 'hidden',
2028
- deviceId: 'device-1',
2029
- passphraseState: 'hidden-state',
2030
- resumed: false,
2031
- });
2032
- expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
2033
- btc_test_address: 'hidden-state',
2034
- ...standardSessionGet,
2035
- });
2036
- expect(promptPassphrase).not.toHaveBeenCalled();
2037
- expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBe('new-session');
2038
- });
2039
-
2040
1771
  test.each([false, true])(
2041
1772
  'openWalletSession does not thread CommonParams.deriveCardano: %s',
2042
1773
  async deriveCardano => {