@onekeyfe/hd-core 1.2.0-alpha.22 → 1.2.0-alpha.24
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__/DeviceCommands.test.ts +43 -8
- package/__tests__/connectSettings.test.ts +5 -47
- package/__tests__/device-lifecycle-events.test.ts +59 -0
- package/__tests__/device-settings.test.ts +1 -1
- package/__tests__/device-wallet-session-store.test.ts +41 -0
- package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +30 -39
- package/__tests__/logBlockEvent.test.ts +17 -0
- package/__tests__/open-wallet-session.test.ts +233 -111
- package/__tests__/protocol-v2-ping.test.ts +28 -0
- package/__tests__/protocol-v2.test.ts +513 -313
- package/__tests__/public-pro2-api-boundary.test.ts +22 -0
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV2.d.ts +0 -11
- package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts +3 -7
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +5 -21
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/GetPassphraseState.d.ts.map +1 -1
- package/dist/api/OpenWalletSession.d.ts +1 -8
- package/dist/api/OpenWalletSession.d.ts.map +1 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts +1 -5
- package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
- package/dist/api/device/DeviceWipe.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +0 -7
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
- package/dist/api/firmware/getBinary.d.ts +0 -7
- package/dist/api/firmware/getBinary.d.ts.map +1 -1
- package/dist/api/firmware/updateBootloader.d.ts +0 -2
- package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/uploadFirmware.d.ts +1 -9
- package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/protocol-v2/Ping.d.ts +2 -0
- package/dist/api/protocol-v2/Ping.d.ts.map +1 -1
- package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/data-manager/DataManager.d.ts +0 -1
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/data-manager/connectSettings.d.ts.map +1 -1
- package/dist/device/Device.d.ts +3 -2
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/events/device.d.ts +1 -0
- package/dist/events/device.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/events/ui-request.d.ts +1 -0
- package/dist/events/ui-request.d.ts.map +1 -1
- package/dist/index.d.ts +98 -278
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +876 -2647
- package/dist/inject.d.ts.map +1 -1
- package/dist/lowLevelInject.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockRetry.d.ts +2 -3
- package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/walletSession.d.ts +12 -0
- package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
- package/dist/topLevelInject.d.ts.map +1 -1
- package/dist/types/api/checkAllFirmwareRelease.d.ts +0 -3
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/deviceUpdateBootloader.d.ts +0 -6
- package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
- package/dist/types/api/export.d.ts +1 -4
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdate.d.ts +0 -69
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/dist/types/api/getPassphraseState.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +4 -10
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/openWalletSession.d.ts +0 -12
- package/dist/types/api/openWalletSession.d.ts.map +1 -1
- package/dist/types/api/protocolV2.d.ts +4 -0
- package/dist/types/api/protocolV2.d.ts.map +1 -1
- package/dist/types/settings.d.ts +0 -13
- package/dist/types/settings.d.ts.map +1 -1
- package/dist/utils/deviceInfoUtils.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/CheckAllFirmwareRelease.ts +3 -16
- package/src/api/FirmwareUpdateV2.ts +119 -284
- package/src/api/FirmwareUpdateV3.ts +55 -248
- package/src/api/FirmwareUpdateV4.ts +293 -751
- package/src/api/GetPassphraseState.ts +11 -5
- package/src/api/OpenWalletSession.ts +23 -86
- package/src/api/device/DeviceUpdateBootloader.ts +6 -114
- package/src/api/device/DeviceWipe.ts +2 -0
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +0 -50
- package/src/api/firmware/updateBootloader.ts +4 -19
- package/src/api/firmware/uploadFirmware.ts +22 -140
- package/src/api/index.ts +1 -0
- package/src/api/protocol-v2/Ping.ts +32 -1
- package/src/core/index.ts +40 -7
- package/src/data/messages/messages-protocol-v2.json +49 -56
- package/src/data-manager/DataManager.ts +33 -33
- package/src/data-manager/connectSettings.ts +0 -11
- package/src/device/Device.ts +29 -8
- package/src/device/DeviceCommands.ts +43 -151
- package/src/events/device.ts +1 -0
- package/src/events/logBlockEvent.ts +1 -15
- package/src/events/ui-request.ts +1 -0
- package/src/index.ts +0 -5
- package/src/inject.ts +4 -22
- package/src/lowLevelInject.ts +1 -5
- package/src/protocols/protocol-v2/deviceSession.ts +1 -1
- package/src/protocols/protocol-v2/settingsUnlockPolicy.ts +0 -1
- package/src/protocols/protocol-v2/unlockRetry.ts +20 -3
- package/src/protocols/protocol-v2/walletSession.ts +57 -18
- package/src/topLevelInject.ts +1 -5
- package/src/types/api/checkAllFirmwareRelease.ts +0 -3
- package/src/types/api/deviceUpdateBootloader.ts +0 -6
- package/src/types/api/export.ts +0 -18
- package/src/types/api/firmwareUpdate.ts +0 -76
- package/src/types/api/getPassphraseState.ts +4 -3
- package/src/types/api/index.ts +3 -14
- package/src/types/api/openWalletSession.ts +0 -19
- package/src/types/api/protocolV2.ts +10 -0
- package/src/types/settings.ts +0 -13
- package/src/utils/deviceInfoUtils.ts +2 -3
- package/__tests__/firmware-update/firmware-artifact-source.test.ts +0 -119
- package/__tests__/firmware-update/firmware-host-binding.test.ts +0 -70
- package/__tests__/firmware-update/firmware-update-capabilities.test.ts +0 -13
- package/__tests__/firmware-update/firmware-update-plan.test.ts +0 -326
- package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +0 -200
- package/__tests__/firmware-update/firmware-upload-source.test.ts +0 -70
- package/dist/api/firmware/FirmwareArtifactSource.d.ts +0 -26
- package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareHostBinding.d.ts +0 -6
- package/dist/api/firmware/FirmwareHostBinding.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +0 -3
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +0 -24
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +0 -25
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdateCapabilities.d.ts +0 -9
- package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdatePlan.d.ts +0 -27
- package/dist/types/api/firmwareUpdatePlan.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +0 -42
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +0 -1
- package/src/api/firmware/FirmwareArtifactSource.ts +0 -278
- package/src/api/firmware/FirmwareHostBinding.ts +0 -100
- package/src/api/firmware/FirmwareUpdateCapabilities.ts +0 -9
- package/src/api/firmware/FirmwareUpdatePlan.ts +0 -621
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +0 -378
- package/src/types/api/firmwareUpdateCapabilities.ts +0 -9
- package/src/types/api/firmwareUpdatePlan.ts +0 -36
- package/src/types/api/firmwareUpdatePreparedPlan.ts +0 -53
|
@@ -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,54 @@ describe('openWalletSession', () => {
|
|
|
59
60
|
deviceWalletSessionStore.clear();
|
|
60
61
|
});
|
|
61
62
|
|
|
62
|
-
test(
|
|
63
|
+
test.each([{ useEmptyPassphrase: true }, { initSession: true }, {}])(
|
|
64
|
+
'requires the explicit mode in the new public API: %p',
|
|
65
|
+
legacyParams => {
|
|
66
|
+
const method = new OpenWalletSession({
|
|
67
|
+
payload: {
|
|
68
|
+
method: 'openWalletSession',
|
|
69
|
+
connectId: 'connect-id',
|
|
70
|
+
...legacyParams,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
expect(() => method.init()).toThrow('Parameter [mode] is required');
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
test('keeps the legacy getPassphraseState App flow working on Protocol V2', async () => {
|
|
79
|
+
const typedCall = jest
|
|
80
|
+
.fn()
|
|
81
|
+
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
82
|
+
.mockResolvedValueOnce({ message: { message: 'passphrase prepared' } })
|
|
83
|
+
.mockResolvedValueOnce({
|
|
84
|
+
message: {
|
|
85
|
+
btc_test_address: 'pro2-wallet-state',
|
|
86
|
+
session_id: 'pro2-wallet-session',
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
const promptPassphrase = jest.fn().mockResolvedValue({ passphraseOnDevice: true });
|
|
63
90
|
const method = new GetPassphraseState({
|
|
64
|
-
payload: {
|
|
91
|
+
payload: {
|
|
92
|
+
method: 'getPassphraseState',
|
|
93
|
+
connectId: 'connect-id',
|
|
94
|
+
initSession: true,
|
|
95
|
+
useEmptyPassphrase: false,
|
|
96
|
+
},
|
|
65
97
|
});
|
|
66
|
-
method.device = createDevice() as any;
|
|
98
|
+
method.device = createDevice({ typedCall, promptPassphrase }) as any;
|
|
67
99
|
|
|
68
|
-
await expect(method.run()).
|
|
69
|
-
|
|
70
|
-
|
|
100
|
+
await expect(method.run()).resolves.toBe('pro2-wallet-state');
|
|
101
|
+
expect(promptPassphrase).toHaveBeenCalledWith(
|
|
102
|
+
{
|
|
103
|
+
existsAttachPinUser: false,
|
|
104
|
+
source: 'wallet-session-coordinator',
|
|
105
|
+
reason: 'open-wallet',
|
|
106
|
+
},
|
|
107
|
+
{ cancelDeviceOnReject: false }
|
|
108
|
+
);
|
|
109
|
+
expect(typedCall).toHaveBeenNthCalledWith(2, 'DeviceSessionAskPassphrase', 'Success', {});
|
|
110
|
+
expect(typedCall).toHaveBeenNthCalledWith(3, 'DeviceSessionGet', 'DeviceSession', {});
|
|
71
111
|
});
|
|
72
112
|
|
|
73
113
|
test('keeps Legacy Protocol V1 getPassphraseState parameterless', async () => {
|
|
@@ -122,9 +162,7 @@ describe('openWalletSession', () => {
|
|
|
122
162
|
payload: {
|
|
123
163
|
method: 'openWalletSession',
|
|
124
164
|
connectId: 'connect-id',
|
|
125
|
-
|
|
126
|
-
initSession: true,
|
|
127
|
-
passphraseState: 'stale-hidden-state',
|
|
165
|
+
mode: 'standard',
|
|
128
166
|
},
|
|
129
167
|
});
|
|
130
168
|
method.init();
|
|
@@ -153,19 +191,27 @@ describe('openWalletSession', () => {
|
|
|
153
191
|
expect(typedCall).toHaveBeenCalledWith('GetPassphraseState', 'PassphraseState', {
|
|
154
192
|
passphrase_state: undefined,
|
|
155
193
|
});
|
|
156
|
-
expect(device.clearInternalState).toHaveBeenCalled();
|
|
194
|
+
expect(device.clearInternalState).not.toHaveBeenCalled();
|
|
157
195
|
});
|
|
158
196
|
|
|
159
|
-
test('uses the
|
|
160
|
-
const typedCall = jest
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
197
|
+
test('uses the explicit mode to select a hidden wallet on Protocol V2', async () => {
|
|
198
|
+
const typedCall = jest
|
|
199
|
+
.fn()
|
|
200
|
+
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
201
|
+
.mockResolvedValueOnce({ message: { message: 'passphrase prepared' } })
|
|
202
|
+
.mockResolvedValueOnce({
|
|
203
|
+
message: {
|
|
204
|
+
btc_test_address: 'hidden-state',
|
|
205
|
+
session_id: 'hidden-session',
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
const promptPassphrase = jest.fn().mockResolvedValue({ passphraseOnDevice: true });
|
|
167
209
|
const method = new OpenWalletSession({
|
|
168
|
-
payload: {
|
|
210
|
+
payload: {
|
|
211
|
+
method: 'openWalletSession',
|
|
212
|
+
connectId: 'connect-id',
|
|
213
|
+
mode: 'select-hidden',
|
|
214
|
+
},
|
|
169
215
|
});
|
|
170
216
|
method.init();
|
|
171
217
|
method.device = createDevice({ typedCall, promptPassphrase }) as any;
|
|
@@ -175,24 +221,32 @@ describe('openWalletSession', () => {
|
|
|
175
221
|
walletType: 'hidden',
|
|
176
222
|
passphraseState: 'hidden-state',
|
|
177
223
|
});
|
|
224
|
+
expect(promptPassphrase).toHaveBeenCalled();
|
|
225
|
+
expect(typedCall).toHaveBeenNthCalledWith(2, 'DeviceSessionAskPassphrase', 'Success', {});
|
|
226
|
+
expect(typedCall).toHaveBeenNthCalledWith(3, 'DeviceSessionGet', 'DeviceSession', {});
|
|
178
227
|
});
|
|
179
228
|
|
|
180
229
|
test('classifies the selected Pro2 wallet from the post-unlock device state', async () => {
|
|
181
230
|
const typedCall = jest
|
|
182
231
|
.fn()
|
|
183
232
|
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
233
|
+
.mockResolvedValueOnce({ message: { message: 'passphrase prepared' } })
|
|
184
234
|
.mockResolvedValueOnce({
|
|
185
235
|
message: {
|
|
186
236
|
btc_test_address: 'hidden-state-after-unlock',
|
|
187
237
|
session_id: 'hidden-session-after-unlock',
|
|
188
238
|
},
|
|
189
239
|
});
|
|
190
|
-
const promptPassphrase = jest.fn().mockResolvedValue({
|
|
240
|
+
const promptPassphrase = jest.fn().mockResolvedValue({ passphraseOnDevice: true });
|
|
191
241
|
const method = new OpenWalletSession({
|
|
192
242
|
payload: { method: 'openWalletSession', connectId: 'connect-id', mode: 'select-hidden' },
|
|
193
243
|
});
|
|
194
244
|
method.init();
|
|
195
|
-
const device = createDevice({
|
|
245
|
+
const device = createDevice({
|
|
246
|
+
passphraseProtection: false,
|
|
247
|
+
typedCall,
|
|
248
|
+
promptPassphrase,
|
|
249
|
+
});
|
|
196
250
|
device.features.unlocked = false;
|
|
197
251
|
device.getCurrentPassphraseProtection = () => device.features.passphraseProtection;
|
|
198
252
|
device.unlockDevice = jest.fn().mockImplementation(() => {
|
|
@@ -210,29 +264,30 @@ describe('openWalletSession', () => {
|
|
|
210
264
|
sessionId: 'hidden-session-after-unlock',
|
|
211
265
|
resumed: false,
|
|
212
266
|
});
|
|
213
|
-
expect(device.unlockDevice).
|
|
267
|
+
expect(device.unlockDevice).toHaveBeenCalledWith(DeviceSessionPinType.Main);
|
|
214
268
|
expect(promptPassphrase).toHaveBeenCalledTimes(1);
|
|
215
269
|
});
|
|
216
270
|
|
|
217
|
-
test('
|
|
218
|
-
const typedCall = jest
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
271
|
+
test('select-hidden starts a fresh hidden-wallet session on Protocol V2', async () => {
|
|
272
|
+
const typedCall = jest
|
|
273
|
+
.fn()
|
|
274
|
+
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
275
|
+
.mockResolvedValueOnce({ message: { message: 'passphrase prepared' } })
|
|
276
|
+
.mockResolvedValueOnce({
|
|
277
|
+
message: {
|
|
278
|
+
btc_test_address: 'new-hidden-state',
|
|
279
|
+
session_id: 'new-hidden-session',
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
const promptPassphrase = jest.fn().mockResolvedValue({ passphraseOnDevice: true });
|
|
225
283
|
const method = new OpenWalletSession({
|
|
226
284
|
payload: {
|
|
227
285
|
method: 'openWalletSession',
|
|
228
286
|
connectId: 'connect-id',
|
|
229
|
-
|
|
230
|
-
deviceId: 'device-1',
|
|
231
|
-
passphraseState: 'stale-hidden-state',
|
|
287
|
+
mode: 'select-hidden',
|
|
232
288
|
},
|
|
233
289
|
});
|
|
234
290
|
method.init();
|
|
235
|
-
deviceWalletSessionStore.set('device-1', 'stale-hidden-state', 'stale-hidden-session');
|
|
236
291
|
method.device = createDevice({ typedCall, promptPassphrase }) as any;
|
|
237
292
|
|
|
238
293
|
await expect(method.run()).resolves.toEqual({
|
|
@@ -246,29 +301,29 @@ describe('openWalletSession', () => {
|
|
|
246
301
|
expect(typedCall).toHaveBeenCalledWith('ProtocolInfoRequest', 'ProtocolInfo', {
|
|
247
302
|
eventless_wallet_session: true,
|
|
248
303
|
});
|
|
249
|
-
expect(typedCall).toHaveBeenCalledWith('
|
|
250
|
-
|
|
251
|
-
});
|
|
304
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {});
|
|
305
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {});
|
|
252
306
|
expect(promptPassphrase).toHaveBeenCalled();
|
|
253
|
-
expect(deviceWalletSessionStore.get('device-1', 'stale-hidden-state')).toBeUndefined();
|
|
254
307
|
expect(deviceWalletSessionStore.get('device-1', 'new-hidden-state')).toBe('new-hidden-session');
|
|
255
308
|
});
|
|
256
309
|
|
|
257
|
-
test('does not clear another device wallet
|
|
258
|
-
const typedCall = jest
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
310
|
+
test('select-hidden does not clear another device wallet', async () => {
|
|
311
|
+
const typedCall = jest
|
|
312
|
+
.fn()
|
|
313
|
+
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
314
|
+
.mockResolvedValueOnce({ message: { message: 'passphrase prepared' } })
|
|
315
|
+
.mockResolvedValueOnce({
|
|
316
|
+
message: {
|
|
317
|
+
btc_test_address: 'current-device-state',
|
|
318
|
+
session_id: 'current-device-session',
|
|
319
|
+
},
|
|
320
|
+
});
|
|
321
|
+
const promptPassphrase = jest.fn().mockResolvedValue({ passphraseOnDevice: true });
|
|
265
322
|
const method = new OpenWalletSession({
|
|
266
323
|
payload: {
|
|
267
324
|
method: 'openWalletSession',
|
|
268
325
|
connectId: 'connect-id',
|
|
269
|
-
|
|
270
|
-
deviceId: 'other-device',
|
|
271
|
-
passphraseState: 'other-device-state',
|
|
326
|
+
mode: 'select-hidden',
|
|
272
327
|
},
|
|
273
328
|
});
|
|
274
329
|
method.init();
|
|
@@ -285,19 +340,22 @@ describe('openWalletSession', () => {
|
|
|
285
340
|
);
|
|
286
341
|
});
|
|
287
342
|
|
|
288
|
-
test('uses
|
|
289
|
-
const typedCall = jest
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
343
|
+
test('uses an explicit wallet binding to resume on Protocol V2', async () => {
|
|
344
|
+
const typedCall = jest
|
|
345
|
+
.fn()
|
|
346
|
+
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
347
|
+
.mockResolvedValueOnce({
|
|
348
|
+
message: {
|
|
349
|
+
btc_test_address: 'hidden-state',
|
|
350
|
+
session_id: 'renewed-session',
|
|
351
|
+
},
|
|
352
|
+
});
|
|
295
353
|
const promptPassphrase = jest.fn();
|
|
296
354
|
const method = new OpenWalletSession({
|
|
297
355
|
payload: {
|
|
298
356
|
method: 'openWalletSession',
|
|
299
357
|
connectId: 'connect-id',
|
|
300
|
-
|
|
358
|
+
mode: 'resume-hidden',
|
|
301
359
|
deviceId: 'device-1',
|
|
302
360
|
passphraseState: 'hidden-state',
|
|
303
361
|
},
|
|
@@ -314,8 +372,8 @@ describe('openWalletSession', () => {
|
|
|
314
372
|
sessionId: 'renewed-session',
|
|
315
373
|
resumed: true,
|
|
316
374
|
});
|
|
317
|
-
expect(typedCall).toHaveBeenCalledWith('
|
|
318
|
-
|
|
375
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
376
|
+
session_id: 'known-session',
|
|
319
377
|
});
|
|
320
378
|
expect(promptPassphrase).not.toHaveBeenCalled();
|
|
321
379
|
});
|
|
@@ -357,7 +415,7 @@ describe('openWalletSession', () => {
|
|
|
357
415
|
});
|
|
358
416
|
|
|
359
417
|
test.each([{ initSession: 'true' }, { useEmptyPassphrase: 'false' }])(
|
|
360
|
-
'rejects
|
|
418
|
+
'rejects legacy flags without an explicit mode: %o',
|
|
361
419
|
params => {
|
|
362
420
|
const method = new OpenWalletSession({
|
|
363
421
|
payload: {
|
|
@@ -485,12 +543,15 @@ describe('openWalletSession', () => {
|
|
|
485
543
|
});
|
|
486
544
|
|
|
487
545
|
test('rejects a standard-wallet request when Protocol V2 is unlocked by Attach PIN', async () => {
|
|
488
|
-
const typedCall = jest
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
546
|
+
const typedCall = jest
|
|
547
|
+
.fn()
|
|
548
|
+
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
549
|
+
.mockResolvedValueOnce({
|
|
550
|
+
message: {
|
|
551
|
+
btc_test_address: 'attach-wallet-state',
|
|
552
|
+
session_id: 'attach-wallet-session',
|
|
553
|
+
},
|
|
554
|
+
});
|
|
494
555
|
const method = new OpenWalletSession({
|
|
495
556
|
payload: { method: 'openWalletSession', connectId: 'connect-id', mode: 'standard' },
|
|
496
557
|
});
|
|
@@ -507,13 +568,17 @@ describe('openWalletSession', () => {
|
|
|
507
568
|
});
|
|
508
569
|
|
|
509
570
|
test('selects a hidden wallet and returns the CLI compatibility session', async () => {
|
|
510
|
-
const typedCall = jest
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
571
|
+
const typedCall = jest
|
|
572
|
+
.fn()
|
|
573
|
+
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
574
|
+
.mockResolvedValueOnce({ message: { message: 'passphrase prepared' } })
|
|
575
|
+
.mockResolvedValueOnce({
|
|
576
|
+
message: {
|
|
577
|
+
btc_test_address: 'hidden-state',
|
|
578
|
+
session_id: 'hidden-session',
|
|
579
|
+
},
|
|
580
|
+
});
|
|
581
|
+
const promptPassphrase = jest.fn().mockResolvedValue({ passphraseOnDevice: true });
|
|
517
582
|
const method = new OpenWalletSession({
|
|
518
583
|
payload: { method: 'openWalletSession', connectId: 'connect-id', mode: 'select-hidden' },
|
|
519
584
|
});
|
|
@@ -530,18 +595,21 @@ describe('openWalletSession', () => {
|
|
|
530
595
|
sessionId: 'hidden-session',
|
|
531
596
|
resumed: false,
|
|
532
597
|
});
|
|
533
|
-
expect(typedCall).toHaveBeenCalledWith('
|
|
534
|
-
|
|
535
|
-
});
|
|
598
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {});
|
|
599
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {});
|
|
536
600
|
expect(promptPassphrase).toHaveBeenCalled();
|
|
537
601
|
expect(device.passphraseState).toBeUndefined();
|
|
538
602
|
expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBe('hidden-session');
|
|
539
603
|
});
|
|
540
604
|
|
|
541
|
-
test('selects on-device passphrase entry
|
|
542
|
-
const typedCall = jest
|
|
543
|
-
|
|
544
|
-
|
|
605
|
+
test('selects on-device passphrase entry before getting the prepared session', async () => {
|
|
606
|
+
const typedCall = jest
|
|
607
|
+
.fn()
|
|
608
|
+
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
609
|
+
.mockResolvedValueOnce({ message: { message: 'passphrase prepared' } })
|
|
610
|
+
.mockResolvedValueOnce({
|
|
611
|
+
message: { btc_test_address: 'device-state', session_id: 'device-session' },
|
|
612
|
+
});
|
|
545
613
|
const promptPassphrase = jest.fn().mockResolvedValue({ passphraseOnDevice: true });
|
|
546
614
|
const method = new OpenWalletSession({
|
|
547
615
|
payload: { method: 'openWalletSession', connectId: 'connect-id', mode: 'select-hidden' },
|
|
@@ -553,15 +621,56 @@ describe('openWalletSession', () => {
|
|
|
553
621
|
walletType: 'hidden',
|
|
554
622
|
passphraseState: 'device-state',
|
|
555
623
|
});
|
|
556
|
-
expect(typedCall).toHaveBeenCalledWith('
|
|
557
|
-
|
|
624
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {});
|
|
625
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {});
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
test('forwards a host passphrase to Pro2 firmware', async () => {
|
|
629
|
+
const typedCall = jest
|
|
630
|
+
.fn()
|
|
631
|
+
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
632
|
+
.mockResolvedValueOnce({ message: { message: 'passphrase prepared' } })
|
|
633
|
+
.mockResolvedValueOnce({
|
|
634
|
+
message: { btc_test_address: 'host-state', session_id: 'host-session' },
|
|
635
|
+
});
|
|
636
|
+
const promptPassphrase = jest.fn().mockResolvedValue({ passphrase: 'host hidden wallet' });
|
|
637
|
+
const method = new OpenWalletSession({
|
|
638
|
+
payload: {
|
|
639
|
+
method: 'openWalletSession',
|
|
640
|
+
connectId: 'connect-id',
|
|
641
|
+
mode: 'select-hidden',
|
|
642
|
+
},
|
|
643
|
+
});
|
|
644
|
+
method.init();
|
|
645
|
+
method.device = createDevice({
|
|
646
|
+
typedCall,
|
|
647
|
+
promptPassphrase,
|
|
648
|
+
}) as any;
|
|
649
|
+
|
|
650
|
+
await expect(method.run()).resolves.toMatchObject({
|
|
651
|
+
walletType: 'hidden',
|
|
652
|
+
passphraseState: 'host-state',
|
|
653
|
+
});
|
|
654
|
+
expect(promptPassphrase).toHaveBeenCalledWith(
|
|
655
|
+
{
|
|
656
|
+
existsAttachPinUser: false,
|
|
657
|
+
source: 'wallet-session-coordinator',
|
|
658
|
+
reason: 'open-wallet',
|
|
659
|
+
},
|
|
660
|
+
{ cancelDeviceOnReject: false }
|
|
661
|
+
);
|
|
662
|
+
expect(typedCall).toHaveBeenNthCalledWith(2, 'DeviceSessionAskPassphrase', 'Success', {
|
|
663
|
+
passphrase: 'host hidden wallet',
|
|
558
664
|
});
|
|
559
665
|
});
|
|
560
666
|
|
|
561
667
|
test('selects Attach PIN only when the device reports an existing binding', async () => {
|
|
562
|
-
const typedCall = jest
|
|
563
|
-
|
|
564
|
-
|
|
668
|
+
const typedCall = jest
|
|
669
|
+
.fn()
|
|
670
|
+
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
671
|
+
.mockResolvedValueOnce({
|
|
672
|
+
message: { btc_test_address: 'attach-state', session_id: 'attach-session' },
|
|
673
|
+
});
|
|
565
674
|
const promptPassphrase = jest.fn().mockResolvedValue({ attachPinOnDevice: true });
|
|
566
675
|
const method = new OpenWalletSession({
|
|
567
676
|
payload: { method: 'openWalletSession', connectId: 'connect-id', mode: 'select-hidden' },
|
|
@@ -576,12 +685,15 @@ describe('openWalletSession', () => {
|
|
|
576
685
|
passphraseState: 'attach-state',
|
|
577
686
|
});
|
|
578
687
|
expect(promptPassphrase).toHaveBeenCalledWith(
|
|
579
|
-
|
|
688
|
+
{
|
|
689
|
+
existsAttachPinUser: true,
|
|
690
|
+
source: 'wallet-session-coordinator',
|
|
691
|
+
reason: 'open-wallet',
|
|
692
|
+
},
|
|
580
693
|
{ cancelDeviceOnReject: false }
|
|
581
694
|
);
|
|
582
|
-
expect(
|
|
583
|
-
|
|
584
|
-
});
|
|
695
|
+
expect(device.unlockDevice).toHaveBeenCalledWith(DeviceSessionPinType.AttachToPin);
|
|
696
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {});
|
|
585
697
|
});
|
|
586
698
|
|
|
587
699
|
test.each([
|
|
@@ -596,8 +708,12 @@ describe('openWalletSession', () => {
|
|
|
596
708
|
])(
|
|
597
709
|
'rejects an incomplete Protocol V2 hidden-wallet response missing $missingField',
|
|
598
710
|
async ({ message }) => {
|
|
599
|
-
const typedCall = jest
|
|
600
|
-
|
|
711
|
+
const typedCall = jest
|
|
712
|
+
.fn()
|
|
713
|
+
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
714
|
+
.mockResolvedValueOnce({ message: { message: 'passphrase prepared' } })
|
|
715
|
+
.mockResolvedValueOnce({ message });
|
|
716
|
+
const promptPassphrase = jest.fn().mockResolvedValue({ passphraseOnDevice: true });
|
|
601
717
|
const method = new OpenWalletSession({
|
|
602
718
|
payload: { method: 'openWalletSession', connectId: 'connect-id', mode: 'select-hidden' },
|
|
603
719
|
});
|
|
@@ -607,7 +723,7 @@ describe('openWalletSession', () => {
|
|
|
607
723
|
|
|
608
724
|
await expect(method.run()).rejects.toMatchObject({
|
|
609
725
|
errorCode: HardwareErrorCode.RuntimeError,
|
|
610
|
-
message: '
|
|
726
|
+
message: 'DeviceSessionGet returned an incomplete DeviceSession response.',
|
|
611
727
|
});
|
|
612
728
|
expect(device.clearInternalState).toHaveBeenCalled();
|
|
613
729
|
expect(device.updateInternalState).not.toHaveBeenCalled();
|
|
@@ -615,12 +731,15 @@ describe('openWalletSession', () => {
|
|
|
615
731
|
);
|
|
616
732
|
|
|
617
733
|
test('resumes a known hidden wallet without prompting or device selection', async () => {
|
|
618
|
-
const typedCall = jest
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
734
|
+
const typedCall = jest
|
|
735
|
+
.fn()
|
|
736
|
+
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
737
|
+
.mockResolvedValueOnce({
|
|
738
|
+
message: {
|
|
739
|
+
btc_test_address: 'hidden-state',
|
|
740
|
+
session_id: 'renewed-session',
|
|
741
|
+
},
|
|
742
|
+
});
|
|
624
743
|
const promptPassphrase = jest.fn();
|
|
625
744
|
const method = new OpenWalletSession({
|
|
626
745
|
payload: {
|
|
@@ -643,19 +762,22 @@ describe('openWalletSession', () => {
|
|
|
643
762
|
sessionId: 'renewed-session',
|
|
644
763
|
resumed: true,
|
|
645
764
|
});
|
|
646
|
-
expect(typedCall).toHaveBeenCalledWith('
|
|
647
|
-
|
|
765
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
766
|
+
session_id: 'known-session',
|
|
648
767
|
});
|
|
649
768
|
expect(promptPassphrase).not.toHaveBeenCalled();
|
|
650
769
|
});
|
|
651
770
|
|
|
652
771
|
test('validates a locked Protocol V2 resume binding after deviceId refresh', async () => {
|
|
653
|
-
const typedCall = jest
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
772
|
+
const typedCall = jest
|
|
773
|
+
.fn()
|
|
774
|
+
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
775
|
+
.mockResolvedValueOnce({
|
|
776
|
+
message: {
|
|
777
|
+
btc_test_address: 'hidden-state',
|
|
778
|
+
session_id: 'renewed-session',
|
|
779
|
+
},
|
|
780
|
+
});
|
|
659
781
|
const method = new OpenWalletSession({
|
|
660
782
|
payload: {
|
|
661
783
|
method: 'openWalletSession',
|
|
@@ -694,14 +816,14 @@ describe('openWalletSession', () => {
|
|
|
694
816
|
});
|
|
695
817
|
expect(device.unlockDevice).toHaveBeenCalledTimes(1);
|
|
696
818
|
expect(device.getDeviceState).toHaveBeenCalledTimes(2);
|
|
697
|
-
expect(typedCall).toHaveBeenCalledWith('
|
|
698
|
-
|
|
819
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
|
|
820
|
+
session_id: 'known-session',
|
|
699
821
|
});
|
|
700
|
-
const
|
|
701
|
-
([requestName]) => requestName === '
|
|
822
|
+
const sessionGetCall = typedCall.mock.calls.findIndex(
|
|
823
|
+
([requestName]) => requestName === 'DeviceSessionGet'
|
|
702
824
|
);
|
|
703
825
|
expect(device.getDeviceState.mock.invocationCallOrder[1]).toBeLessThan(
|
|
704
|
-
typedCall.mock.invocationCallOrder[
|
|
826
|
+
typedCall.mock.invocationCallOrder[sessionGetCall]
|
|
705
827
|
);
|
|
706
828
|
});
|
|
707
829
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { validateProtocolV2PingMessage } from '../src/api/protocol-v2/Ping';
|
|
2
|
+
|
|
3
|
+
jest.mock('../src/data/config', () => ({
|
|
4
|
+
DEFAULT_DOMAIN: 'https://example.com/',
|
|
5
|
+
getSDKVersion: () => '0.0.0-test',
|
|
6
|
+
}));
|
|
7
|
+
|
|
8
|
+
describe('Protocol V2 diagnostic Ping validation', () => {
|
|
9
|
+
test('accepts messages up to the firmware UTF-8 byte limit', () => {
|
|
10
|
+
expect(validateProtocolV2PingMessage('x'.repeat(63))).toBe('x'.repeat(63));
|
|
11
|
+
expect(validateProtocolV2PingMessage('测'.repeat(21))).toBe('测'.repeat(21));
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test('rejects messages larger than the firmware UTF-8 byte limit', () => {
|
|
15
|
+
expect(() => validateProtocolV2PingMessage('x'.repeat(64))).toThrow(
|
|
16
|
+
'Protocol V2 Ping message must not exceed 63 UTF-8 bytes.'
|
|
17
|
+
);
|
|
18
|
+
expect(() => validateProtocolV2PingMessage('测'.repeat(22))).toThrow(
|
|
19
|
+
'Protocol V2 Ping message must not exceed 63 UTF-8 bytes.'
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('rejects non-string messages at the runtime API boundary', () => {
|
|
24
|
+
expect(() => validateProtocolV2PingMessage(64)).toThrow(
|
|
25
|
+
'Protocol V2 Ping message must be a string.'
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
});
|