@onekeyfe/hd-core 1.2.0-alpha.20 → 1.2.0-alpha.22
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 +87 -2
- package/__tests__/connectSettings.test.ts +47 -5
- package/__tests__/device-identity.test.ts +24 -2
- package/__tests__/device-lifecycle-events.test.ts +1 -1
- package/__tests__/device-settings.test.ts +111 -6
- package/__tests__/device-state-events.test.ts +3 -3
- package/__tests__/device-state-mapper.test.ts +15 -3
- package/__tests__/device-state-store.test.ts +1 -1
- package/__tests__/device-wallet-session-store.test.ts +111 -7
- package/__tests__/deviceSettings.test.ts +55 -15
- package/__tests__/evmLedgerLegacySafety.test.ts +6 -5
- package/__tests__/firmware-update/firmware-artifact-source.test.ts +119 -0
- package/__tests__/firmware-update/firmware-host-binding.test.ts +70 -0
- package/__tests__/firmware-update/firmware-update-capabilities.test.ts +13 -0
- package/__tests__/firmware-update/firmware-update-plan.test.ts +326 -0
- package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +200 -0
- package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +39 -30
- package/__tests__/firmware-update/firmware-upload-source.test.ts +70 -0
- package/__tests__/get-device-state.test.ts +7 -0
- package/__tests__/open-wallet-session.test.ts +253 -13
- package/__tests__/pro2Wallpaper.test.ts +7 -18
- package/__tests__/protocol-v2-unlock-policy.test.ts +45 -0
- package/__tests__/protocol-v2.test.ts +439 -282
- package/__tests__/public-device-state-api.test.ts +79 -68
- package/__tests__/public-pro2-api-boundary.test.ts +22 -29
- package/dist/api/BaseMethod.d.ts +2 -4
- package/dist/api/BaseMethod.d.ts.map +1 -1
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/ClearSessionCache.d.ts.map +1 -1
- package/dist/api/FirmwareUpdate.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV2.d.ts +11 -0
- package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts +7 -3
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +29 -10
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/OpenWalletSession.d.ts.map +1 -1
- package/dist/api/UploadPortfolio.d.ts +0 -1
- package/dist/api/UploadPortfolio.d.ts.map +1 -1
- package/dist/api/conflux/ConfluxGetAddress.d.ts +1 -0
- package/dist/api/conflux/ConfluxGetAddress.d.ts.map +1 -1
- package/dist/api/conflux/ConfluxSignMessage.d.ts +1 -0
- package/dist/api/conflux/ConfluxSignMessage.d.ts.map +1 -1
- package/dist/api/conflux/ConfluxSignMessageCIP23.d.ts +1 -0
- package/dist/api/conflux/ConfluxSignMessageCIP23.d.ts.map +1 -1
- package/dist/api/conflux/ConfluxSignTransaction.d.ts +1 -0
- package/dist/api/conflux/ConfluxSignTransaction.d.ts.map +1 -1
- package/dist/api/device/DeviceSettings.d.ts.map +1 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts +5 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareArtifactSource.d.ts +26 -0
- package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareHostBinding.d.ts +6 -0
- package/dist/api/firmware/FirmwareHostBinding.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +7 -0
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +3 -0
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +24 -0
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +25 -0
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -0
- package/dist/api/firmware/getBinary.d.ts +7 -0
- package/dist/api/firmware/getBinary.d.ts.map +1 -1
- package/dist/api/firmware/updateBootloader.d.ts +2 -0
- package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/uploadFirmware.d.ts +9 -1
- package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
- package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
- package/dist/api/index.d.ts +0 -20
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/nexa/NexaSignTransaction.d.ts +1 -0
- package/dist/api/nexa/NexaSignTransaction.d.ts.map +1 -1
- package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
- package/dist/core/RequestQueue.d.ts +1 -19
- package/dist/core/RequestQueue.d.ts.map +1 -1
- package/dist/core/index.d.ts +0 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/data-manager/DataManager.d.ts +1 -0
- 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 +1 -1
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/device/DeviceFeaturesState.d.ts +0 -1
- package/dist/device/DeviceFeaturesState.d.ts.map +1 -1
- package/dist/device/DeviceStateMapper.d.ts.map +1 -1
- package/dist/device/DeviceStateProjector.d.ts.map +1 -1
- package/dist/deviceProfile/buildDeviceFeatures.d.ts.map +1 -1
- package/dist/events/call.d.ts +0 -7
- package/dist/events/call.d.ts.map +1 -1
- package/dist/events/core.d.ts +2 -2
- package/dist/events/core.d.ts.map +1 -1
- package/dist/events/iframe.d.ts +0 -1
- package/dist/events/iframe.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/index.d.ts +320 -277
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3210 -1856
- package/dist/inject.d.ts +2 -3
- package/dist/inject.d.ts.map +1 -1
- package/dist/lowLevelInject.d.ts +1 -2
- package/dist/lowLevelInject.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockPolicy.d.ts +4 -0
- package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +1 -1
- 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 +3 -0
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/deviceSettings.d.ts +2 -2
- package/dist/types/api/deviceSettings.d.ts.map +1 -1
- package/dist/types/api/deviceUpdateBootloader.d.ts +6 -0
- package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
- package/dist/types/api/export.d.ts +4 -1
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdate.d.ts +69 -0
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdateCapabilities.d.ts +9 -0
- package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +1 -0
- package/dist/types/api/firmwareUpdatePlan.d.ts +27 -0
- package/dist/types/api/firmwareUpdatePlan.d.ts.map +1 -0
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +42 -0
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +1 -0
- package/dist/types/api/index.d.ts +10 -23
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/openWalletSession.d.ts +1 -0
- package/dist/types/api/openWalletSession.d.ts.map +1 -1
- package/dist/types/api/protocolV2.d.ts +3 -84
- package/dist/types/api/protocolV2.d.ts.map +1 -1
- package/dist/types/api/sessionCache.d.ts +4 -1
- package/dist/types/api/sessionCache.d.ts.map +1 -1
- package/dist/types/device.d.ts +4 -4
- package/dist/types/device.d.ts.map +1 -1
- package/dist/types/settings.d.ts +13 -0
- package/dist/types/settings.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
- package/dist/utils/deviceSettings.d.ts +36 -7
- package/dist/utils/deviceSettings.d.ts.map +1 -1
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/BaseMethod.ts +11 -12
- package/src/api/CheckAllFirmwareRelease.ts +16 -3
- package/src/api/ClearSessionCache.ts +4 -0
- package/src/api/FirmwareUpdate.ts +8 -1
- package/src/api/FirmwareUpdateV2.ts +284 -119
- package/src/api/FirmwareUpdateV3.ts +248 -55
- package/src/api/FirmwareUpdateV4.ts +816 -328
- package/src/api/OpenWalletSession.ts +74 -25
- package/src/api/UploadPortfolio.ts +3 -13
- package/src/api/conflux/ConfluxGetAddress.ts +2 -0
- package/src/api/conflux/ConfluxSignMessage.ts +2 -0
- package/src/api/conflux/ConfluxSignMessageCIP23.ts +2 -0
- package/src/api/conflux/ConfluxSignTransaction.ts +2 -0
- package/src/api/device/DeviceChangePin.ts +1 -1
- package/src/api/device/DeviceSettings.ts +66 -5
- package/src/api/device/DeviceUpdateBootloader.ts +114 -6
- package/src/api/device/DeviceWipe.ts +1 -1
- package/src/api/firmware/FirmwareArtifactSource.ts +278 -0
- package/src/api/firmware/FirmwareHostBinding.ts +100 -0
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +50 -0
- package/src/api/firmware/FirmwareUpdateCapabilities.ts +9 -0
- package/src/api/firmware/FirmwareUpdatePlan.ts +621 -0
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +378 -0
- package/src/api/firmware/updateBootloader.ts +19 -4
- package/src/api/firmware/uploadFirmware.ts +140 -22
- package/src/api/helpers/protocolV2FileWrite.ts +6 -0
- package/src/api/index.ts +0 -21
- package/src/api/nexa/NexaSignTransaction.ts +2 -0
- package/src/api/protocol-v2/DeviceUploadWallpaper.ts +1 -1
- package/src/core/RequestQueue.ts +4 -123
- package/src/core/index.ts +25 -31
- package/src/data/messages/messages-protocol-v2.json +77 -4
- package/src/data-manager/DataManager.ts +33 -33
- package/src/data-manager/connectSettings.ts +11 -0
- package/src/device/Device.ts +51 -61
- package/src/device/DeviceCommands.ts +58 -14
- package/src/device/DeviceFeaturesState.ts +0 -9
- package/src/device/DeviceStateMapper.ts +26 -8
- package/src/device/DeviceStateProjector.ts +7 -1
- package/src/deviceProfile/buildDeviceFeatures.ts +2 -1
- package/src/events/call.ts +0 -6
- package/src/events/core.ts +0 -2
- package/src/events/iframe.ts +0 -1
- package/src/events/logBlockEvent.ts +1 -0
- package/src/index.ts +5 -4
- package/src/inject.ts +22 -35
- package/src/lowLevelInject.ts +5 -4
- package/src/protocols/protocol-v2/deviceSession.ts +1 -1
- package/src/protocols/protocol-v2/settingsUnlockPolicy.ts +2 -2
- package/src/protocols/protocol-v2/unlockPolicy.ts +105 -0
- package/src/protocols/protocol-v2/unlockRetry.ts +1 -3
- package/src/protocols/protocol-v2/walletSession.ts +68 -12
- package/src/topLevelInject.ts +5 -3
- package/src/types/api/checkAllFirmwareRelease.ts +3 -0
- package/src/types/api/deviceSettings.ts +17 -2
- package/src/types/api/deviceUpdateBootloader.ts +6 -0
- package/src/types/api/export.ts +18 -0
- package/src/types/api/firmwareUpdate.ts +76 -0
- package/src/types/api/firmwareUpdateCapabilities.ts +9 -0
- package/src/types/api/firmwareUpdatePlan.ts +36 -0
- package/src/types/api/firmwareUpdatePreparedPlan.ts +53 -0
- package/src/types/api/index.ts +14 -41
- package/src/types/api/openWalletSession.ts +2 -0
- package/src/types/api/protocolV2.ts +3 -187
- package/src/types/api/sessionCache.ts +9 -4
- package/src/types/device.ts +5 -3
- package/src/types/settings.ts +13 -0
- package/src/utils/deviceFeaturesUtils.ts +5 -1
- package/src/utils/deviceSettings.ts +130 -56
- package/src/utils/index.ts +18 -1
- package/__tests__/RequestQueue.test.ts +0 -140
- package/__tests__/UploadPortfolio.test.ts +0 -46
- package/dist/api/protocol-v2/DeviceSettingsGet.d.ts +0 -6
- package/dist/api/protocol-v2/DeviceSettingsGet.d.ts.map +0 -1
- package/dist/api/protocol-v2/DeviceSettingsPageShow.d.ts +0 -16
- package/dist/api/protocol-v2/DeviceSettingsPageShow.d.ts.map +0 -1
- package/dist/api/protocol-v2/DeviceSettingsSet.d.ts +0 -12
- package/dist/api/protocol-v2/DeviceSettingsSet.d.ts.map +0 -1
- package/src/api/protocol-v2/DeviceSettingsGet.ts +0 -18
- package/src/api/protocol-v2/DeviceSettingsPageShow.ts +0 -70
- package/src/api/protocol-v2/DeviceSettingsSet.ts +0 -44
|
@@ -19,7 +19,7 @@ const createCommands = () => {
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
describe('DeviceCommands failure mapping', () => {
|
|
22
|
-
it('does not log
|
|
22
|
+
it('does not log DeviceSessionOpen 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
|
-
'
|
|
36
|
+
'DeviceSessionOpen'
|
|
37
37
|
)
|
|
38
38
|
).resolves.toMatchObject({ type: 'DeviceSession' });
|
|
39
39
|
|
|
@@ -41,6 +41,68 @@ 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 () => {
|
|
45
|
+
const commands = createCommands();
|
|
46
|
+
|
|
47
|
+
await expect(
|
|
48
|
+
commands._filterCommonTypes(
|
|
49
|
+
{
|
|
50
|
+
type: 'Failure',
|
|
51
|
+
message: {
|
|
52
|
+
code: 'Failure_ProcessError',
|
|
53
|
+
subcode: 2,
|
|
54
|
+
message: 'Invalid session',
|
|
55
|
+
},
|
|
56
|
+
} as any,
|
|
57
|
+
'DeviceSessionOpen'
|
|
58
|
+
)
|
|
59
|
+
).rejects.toMatchObject({
|
|
60
|
+
errorCode: HardwareErrorCode.WalletSessionInvalid,
|
|
61
|
+
params: {
|
|
62
|
+
failureCode: 'Failure_ProcessError',
|
|
63
|
+
subcode: 2,
|
|
64
|
+
firmwareMessage: 'Invalid session',
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('maps DeviceSessionOpen user cancellation to ActionCancelled', async () => {
|
|
70
|
+
const commands = createCommands();
|
|
71
|
+
|
|
72
|
+
await expect(
|
|
73
|
+
commands._filterCommonTypes(
|
|
74
|
+
{
|
|
75
|
+
type: 'Failure',
|
|
76
|
+
message: {
|
|
77
|
+
code: 'Failure_ProcessError',
|
|
78
|
+
subcode: 1,
|
|
79
|
+
message: 'Cancelled on device',
|
|
80
|
+
},
|
|
81
|
+
} as any,
|
|
82
|
+
'DeviceSessionOpen'
|
|
83
|
+
)
|
|
84
|
+
).rejects.toMatchObject({
|
|
85
|
+
errorCode: HardwareErrorCode.ActionCancelled,
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it.each([
|
|
90
|
+
[3, HardwareErrorCode.DeviceCheckUnlockTypeError],
|
|
91
|
+
[4, HardwareErrorCode.DeviceNotOpenedPassphrase],
|
|
92
|
+
])('maps DeviceSessionOpen subcode %s to its canonical wallet error', async (subcode, code) => {
|
|
93
|
+
const commands = createCommands();
|
|
94
|
+
|
|
95
|
+
await expect(
|
|
96
|
+
commands._filterCommonTypes(
|
|
97
|
+
{
|
|
98
|
+
type: 'Failure',
|
|
99
|
+
message: { code: 'Failure_ProcessError', subcode, message: 'Session selection failed' },
|
|
100
|
+
} as any,
|
|
101
|
+
'DeviceSessionOpen'
|
|
102
|
+
)
|
|
103
|
+
).rejects.toMatchObject({ errorCode: code });
|
|
104
|
+
});
|
|
105
|
+
|
|
44
106
|
it('rejects the Pro2 bootloader DeviceStatusGet unsupported response', async () => {
|
|
45
107
|
const commands = createCommands();
|
|
46
108
|
|
|
@@ -382,3 +444,26 @@ describe('DeviceCommands Protocol V2 interactive response compatibility', () =>
|
|
|
382
444
|
});
|
|
383
445
|
});
|
|
384
446
|
});
|
|
447
|
+
|
|
448
|
+
describe('DeviceCommands cancellation', () => {
|
|
449
|
+
it('stops waiting after the bounded cancellation timeout', async () => {
|
|
450
|
+
jest.useFakeTimers({ doNotFake: ['performance'] });
|
|
451
|
+
try {
|
|
452
|
+
const commands = createCommands();
|
|
453
|
+
commands.disposed = false;
|
|
454
|
+
commands.callPromise = new Promise(() => {});
|
|
455
|
+
const dispose = jest.fn().mockResolvedValue(undefined);
|
|
456
|
+
commands.dispose = dispose;
|
|
457
|
+
|
|
458
|
+
const cancellation = commands.cancel();
|
|
459
|
+
jest.advanceTimersByTime(10_000);
|
|
460
|
+
await Promise.resolve();
|
|
461
|
+
|
|
462
|
+
await expect(cancellation).resolves.toBeUndefined();
|
|
463
|
+
expect(dispose).toHaveBeenCalledWith(true);
|
|
464
|
+
expect(commands.callPromise).toBeUndefined();
|
|
465
|
+
} finally {
|
|
466
|
+
jest.useRealTimers();
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
});
|
|
@@ -1,19 +1,61 @@
|
|
|
1
|
+
import DataManager from '../src/data-manager/DataManager';
|
|
1
2
|
import { parseConnectSettings } from '../src/data-manager/connectSettings';
|
|
2
3
|
|
|
4
|
+
import type { RemoteConfigResponse } from '../src/types';
|
|
5
|
+
|
|
6
|
+
jest.mock('axios', () => ({
|
|
7
|
+
get: jest.fn(),
|
|
8
|
+
}));
|
|
9
|
+
|
|
3
10
|
jest.mock('../src/data/config', () => ({
|
|
4
11
|
getSDKVersion: jest.fn(() => '1.0.0'),
|
|
5
12
|
DEFAULT_DOMAIN: 'https://jssdk.onekey.so/1.0.0/',
|
|
6
13
|
}));
|
|
7
14
|
|
|
15
|
+
const mockAxiosGet: jest.Mock = jest.requireMock('axios').get;
|
|
16
|
+
|
|
8
17
|
describe('parseConnectSettings', () => {
|
|
9
|
-
|
|
10
|
-
|
|
18
|
+
const preloadedConfig = {
|
|
19
|
+
bridge: {},
|
|
20
|
+
classic: { firmware: [], ble: [] },
|
|
21
|
+
classic1s: { firmware: [], ble: [] },
|
|
22
|
+
classicpure: { firmware: [], ble: [] },
|
|
23
|
+
mini: { firmware: [], ble: [] },
|
|
24
|
+
touch: { firmware: [], ble: [] },
|
|
25
|
+
pro: { firmware: [], ble: [] },
|
|
26
|
+
pro2: { firmware: [], ble: [] },
|
|
27
|
+
} as unknown as RemoteConfigResponse;
|
|
28
|
+
|
|
29
|
+
it('keeps a serializable preloaded config in parsed settings', () => {
|
|
30
|
+
const settings = parseConnectSettings({
|
|
31
|
+
firmwareManifestMode: 'sdk-managed',
|
|
32
|
+
preloadedConfig,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
expect(settings.firmwareManifestMode).toBe('sdk-managed');
|
|
36
|
+
expect(settings.preloadedConfig).toBe(preloadedConfig);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('uses the preloaded config before the SDK network client', async () => {
|
|
40
|
+
const settings = parseConnectSettings({
|
|
41
|
+
firmwareManifestMode: 'sdk-managed',
|
|
42
|
+
preloadedConfig,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
await DataManager.load(settings);
|
|
46
|
+
|
|
47
|
+
expect(mockAxiosGet).not.toHaveBeenCalled();
|
|
48
|
+
expect(DataManager.deviceMap.classic).toEqual({ firmware: [], ble: [] });
|
|
49
|
+
});
|
|
11
50
|
|
|
51
|
+
it('fails closed without a preloaded config in external-only mode', async () => {
|
|
12
52
|
const settings = parseConnectSettings({
|
|
13
|
-
|
|
14
|
-
configFetcher,
|
|
53
|
+
firmwareManifestMode: 'external-only',
|
|
15
54
|
});
|
|
16
55
|
|
|
17
|
-
expect(settings
|
|
56
|
+
await expect(DataManager.load(settings)).rejects.toThrow(
|
|
57
|
+
'External firmware config snapshot is required'
|
|
58
|
+
);
|
|
59
|
+
expect(mockAxiosGet).not.toHaveBeenCalled();
|
|
18
60
|
});
|
|
19
61
|
});
|
|
@@ -1,13 +1,35 @@
|
|
|
1
1
|
import { checkLiveDeviceId } from '../src/device/deviceIdentity';
|
|
2
|
+
import ConfluxGetAddress from '../src/api/conflux/ConfluxGetAddress';
|
|
3
|
+
import ConfluxSignMessage from '../src/api/conflux/ConfluxSignMessage';
|
|
4
|
+
import ConfluxSignMessageCIP23 from '../src/api/conflux/ConfluxSignMessageCIP23';
|
|
5
|
+
import ConfluxSignTransaction from '../src/api/conflux/ConfluxSignTransaction';
|
|
6
|
+
import NexaSignTransaction from '../src/api/nexa/NexaSignTransaction';
|
|
7
|
+
|
|
8
|
+
jest.mock('../src/data/config', () => ({
|
|
9
|
+
getSDKVersion: jest.fn(() => '1.0.0'),
|
|
10
|
+
DEFAULT_DOMAIN: 'https://jssdk.onekey.so/1.0.0/',
|
|
11
|
+
}));
|
|
2
12
|
|
|
3
13
|
describe('live device identity', () => {
|
|
14
|
+
test.each([
|
|
15
|
+
['confluxGetAddress', ConfluxGetAddress],
|
|
16
|
+
['confluxSignMessage', ConfluxSignMessage],
|
|
17
|
+
['confluxSignMessageCIP23', ConfluxSignMessageCIP23],
|
|
18
|
+
['confluxSignTransaction', ConfluxSignTransaction],
|
|
19
|
+
['nexaSignTransaction', NexaSignTransaction],
|
|
20
|
+
])('%s requires a live device id check', (methodName, Method) => {
|
|
21
|
+
const method = new Method({ payload: { method: methodName } });
|
|
22
|
+
|
|
23
|
+
expect(method.checkDeviceId).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
|
|
4
26
|
test('refreshes Protocol V2 status before comparing the expected device id', async () => {
|
|
5
27
|
let currentDeviceId = 'OLD_DEVICE_ID';
|
|
6
28
|
const device = {
|
|
7
29
|
isProtocolV2: () => true,
|
|
8
|
-
getDeviceState: jest.fn().mockImplementation(
|
|
30
|
+
getDeviceState: jest.fn().mockImplementation(() => {
|
|
9
31
|
currentDeviceId = 'NEW_DEVICE_ID';
|
|
10
|
-
return { identity: { deviceId: currentDeviceId } };
|
|
32
|
+
return Promise.resolve({ identity: { deviceId: currentDeviceId } });
|
|
11
33
|
}),
|
|
12
34
|
checkDeviceId: jest.fn((expected: string) => currentDeviceId === expected),
|
|
13
35
|
};
|
|
@@ -83,7 +83,7 @@ describe('public device lifecycle events', () => {
|
|
|
83
83
|
const internalDevice = createInitializedDevice(protocol);
|
|
84
84
|
|
|
85
85
|
DevicePool.emitter.emit(DEVICE.CONNECT, internalDevice);
|
|
86
|
-
internalDevice.updateState({ identity: { label: 'Updated label' } }, '
|
|
86
|
+
internalDevice.updateState({ identity: { label: 'Updated label' } }, 'settings-write');
|
|
87
87
|
DevicePool.emitter.emit(DEVICE.DISCONNECT, internalDevice);
|
|
88
88
|
|
|
89
89
|
const connectMessage = messages.find(message => message.type === DEVICE.CONNECT);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
1
|
+
import { EDeviceType, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
2
|
import { DeviceSettingsPage } from '@onekeyfe/hd-transport';
|
|
3
3
|
|
|
4
4
|
import DeviceSettings from '../src/api/device/DeviceSettings';
|
|
@@ -24,6 +24,7 @@ function createDevice({ protocol }: { protocol: 'V1' | 'V2' }) {
|
|
|
24
24
|
device: {
|
|
25
25
|
features,
|
|
26
26
|
isProtocolV2: () => protocol === 'V2',
|
|
27
|
+
getCurrentDeviceType: () => (protocol === 'V2' ? EDeviceType.Pro2 : EDeviceType.Pro),
|
|
27
28
|
commands: { typedCall },
|
|
28
29
|
updateState,
|
|
29
30
|
getDeviceState,
|
|
@@ -69,7 +70,7 @@ describe('DeviceSettings protocol routing', () => {
|
|
|
69
70
|
|
|
70
71
|
method.init();
|
|
71
72
|
|
|
72
|
-
expect(method.unlockPolicy).toBe('
|
|
73
|
+
expect(method.unlockPolicy).toBe('unlock-before-run');
|
|
73
74
|
});
|
|
74
75
|
|
|
75
76
|
it('uses ApplySettings and commits the confirmed patch for Protocol V1', async () => {
|
|
@@ -80,6 +81,7 @@ describe('DeviceSettings protocol routing', () => {
|
|
|
80
81
|
method: 'deviceSettings',
|
|
81
82
|
label: 'Shared Label',
|
|
82
83
|
language: 'ja',
|
|
84
|
+
bluetoothEnabled: true,
|
|
83
85
|
},
|
|
84
86
|
});
|
|
85
87
|
method.init();
|
|
@@ -98,14 +100,15 @@ describe('DeviceSettings protocol routing', () => {
|
|
|
98
100
|
safety_checks: undefined,
|
|
99
101
|
experimental_features: undefined,
|
|
100
102
|
auto_shutdown_delay_ms: undefined,
|
|
103
|
+
use_ble: true,
|
|
101
104
|
haptic_feedback: undefined,
|
|
102
105
|
});
|
|
103
106
|
expect(updateState).toHaveBeenCalledWith(
|
|
104
107
|
{
|
|
105
108
|
identity: { label: 'Shared Label' },
|
|
106
|
-
settings: { language: 'ja' },
|
|
109
|
+
settings: { language: 'ja', bleEnabled: true },
|
|
107
110
|
},
|
|
108
|
-
'
|
|
111
|
+
'settings-write'
|
|
109
112
|
);
|
|
110
113
|
});
|
|
111
114
|
|
|
@@ -119,6 +122,7 @@ describe('DeviceSettings protocol routing', () => {
|
|
|
119
122
|
language: 'ja',
|
|
120
123
|
autoLockDelayMs: 60_000,
|
|
121
124
|
hapticFeedback: true,
|
|
125
|
+
bluetoothEnabled: true,
|
|
122
126
|
},
|
|
123
127
|
});
|
|
124
128
|
method.init();
|
|
@@ -129,6 +133,7 @@ describe('DeviceSettings protocol routing', () => {
|
|
|
129
133
|
settings: {
|
|
130
134
|
label: 'Shared Label',
|
|
131
135
|
language: 'ja-Jpan-JP',
|
|
136
|
+
bt_enable: true,
|
|
132
137
|
autolock_delay_ms: 60_000,
|
|
133
138
|
haptic_feedback: true,
|
|
134
139
|
},
|
|
@@ -137,12 +142,13 @@ describe('DeviceSettings protocol routing', () => {
|
|
|
137
142
|
{
|
|
138
143
|
identity: { label: 'Shared Label' },
|
|
139
144
|
settings: {
|
|
140
|
-
language: 'ja
|
|
145
|
+
language: 'ja',
|
|
146
|
+
bleEnabled: true,
|
|
141
147
|
autoLockDelayMs: 60_000,
|
|
142
148
|
hapticFeedback: true,
|
|
143
149
|
},
|
|
144
150
|
},
|
|
145
|
-
'
|
|
151
|
+
'settings-write'
|
|
146
152
|
);
|
|
147
153
|
expect(typedCall.mock.calls.map(call => call[0])).not.toEqual(
|
|
148
154
|
expect.arrayContaining(['DeviceInfoGet', 'DeviceStatusGet', 'DeviceSettingsGet'])
|
|
@@ -283,4 +289,103 @@ describe('DeviceSettings protocol routing', () => {
|
|
|
283
289
|
});
|
|
284
290
|
expect(typedCall).not.toHaveBeenCalled();
|
|
285
291
|
});
|
|
292
|
+
|
|
293
|
+
it('rejects Protocol V1-only settings on Protocol V2 without partially applying the request', async () => {
|
|
294
|
+
const { device, typedCall } = createDevice({ protocol: 'V2' });
|
|
295
|
+
const method = new DeviceSettings({
|
|
296
|
+
id: 9,
|
|
297
|
+
payload: {
|
|
298
|
+
method: 'deviceSettings',
|
|
299
|
+
label: 'Must not be partially applied',
|
|
300
|
+
safetyChecks: 0,
|
|
301
|
+
},
|
|
302
|
+
});
|
|
303
|
+
method.init();
|
|
304
|
+
(method as any).device = device;
|
|
305
|
+
|
|
306
|
+
await expect(method.run()).rejects.toMatchObject({
|
|
307
|
+
errorCode: HardwareErrorCode.CallMethodInvalidParameter,
|
|
308
|
+
message: 'Protocol V2 does not support settings: safetyChecks.',
|
|
309
|
+
});
|
|
310
|
+
expect(typedCall).not.toHaveBeenCalled();
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it('rejects Protocol V2-only settings on Protocol V1 without partially applying the request', async () => {
|
|
314
|
+
const { device, typedCall } = createDevice({ protocol: 'V1' });
|
|
315
|
+
const method = new DeviceSettings({
|
|
316
|
+
id: 10,
|
|
317
|
+
payload: {
|
|
318
|
+
method: 'deviceSettings',
|
|
319
|
+
label: 'Must not be partially applied',
|
|
320
|
+
brightness: 80,
|
|
321
|
+
},
|
|
322
|
+
});
|
|
323
|
+
method.init();
|
|
324
|
+
(method as any).device = device;
|
|
325
|
+
|
|
326
|
+
await expect(method.run()).rejects.toMatchObject({
|
|
327
|
+
errorCode: HardwareErrorCode.CallMethodInvalidParameter,
|
|
328
|
+
message: 'Protocol V1 does not support settings: brightness.',
|
|
329
|
+
});
|
|
330
|
+
expect(typedCall).not.toHaveBeenCalled();
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it('accepts the Protocol V2 never timeout wire value', async () => {
|
|
334
|
+
const { device, typedCall } = createDevice({ protocol: 'V2' });
|
|
335
|
+
const method = new DeviceSettings({
|
|
336
|
+
id: 11,
|
|
337
|
+
payload: {
|
|
338
|
+
method: 'deviceSettings',
|
|
339
|
+
autoLockDelayMs: 0x10000000,
|
|
340
|
+
autoShutdownDelayMs: 0x10000000,
|
|
341
|
+
},
|
|
342
|
+
});
|
|
343
|
+
method.init();
|
|
344
|
+
(method as any).device = device;
|
|
345
|
+
|
|
346
|
+
await method.run();
|
|
347
|
+
|
|
348
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSettingsSet', 'Success', {
|
|
349
|
+
settings: {
|
|
350
|
+
autolock_delay_ms: 0x10000000,
|
|
351
|
+
autoshutdown_delay_ms: 0x10000000,
|
|
352
|
+
},
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it('rejects unsupported Protocol V2 timeout values before sending a command', async () => {
|
|
357
|
+
const { device, typedCall } = createDevice({ protocol: 'V2' });
|
|
358
|
+
const method = new DeviceSettings({
|
|
359
|
+
id: 12,
|
|
360
|
+
payload: {
|
|
361
|
+
method: 'deviceSettings',
|
|
362
|
+
autoLockDelayMs: 0,
|
|
363
|
+
},
|
|
364
|
+
});
|
|
365
|
+
method.init();
|
|
366
|
+
(method as any).device = device;
|
|
367
|
+
|
|
368
|
+
await expect(method.run()).rejects.toMatchObject({
|
|
369
|
+
errorCode: HardwareErrorCode.CallMethodInvalidParameter,
|
|
370
|
+
});
|
|
371
|
+
expect(typedCall).not.toHaveBeenCalled();
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it('rejects unknown Protocol V1 safety check levels before sending a command', async () => {
|
|
375
|
+
const { device, typedCall } = createDevice({ protocol: 'V1' });
|
|
376
|
+
const method = new DeviceSettings({
|
|
377
|
+
id: 13,
|
|
378
|
+
payload: {
|
|
379
|
+
method: 'deviceSettings',
|
|
380
|
+
safetyChecks: 3,
|
|
381
|
+
},
|
|
382
|
+
} as never);
|
|
383
|
+
method.init();
|
|
384
|
+
(method as any).device = device;
|
|
385
|
+
|
|
386
|
+
await expect(method.run()).rejects.toMatchObject({
|
|
387
|
+
errorCode: HardwareErrorCode.CallMethodInvalidParameter,
|
|
388
|
+
});
|
|
389
|
+
expect(typedCall).not.toHaveBeenCalled();
|
|
390
|
+
});
|
|
286
391
|
});
|
|
@@ -27,7 +27,7 @@ describe('Device state events', () => {
|
|
|
27
27
|
protocolV2DeviceInfo: { protocol_version: 2 },
|
|
28
28
|
},
|
|
29
29
|
},
|
|
30
|
-
'
|
|
30
|
+
'settings-write'
|
|
31
31
|
);
|
|
32
32
|
|
|
33
33
|
expect(state?.identity.label).toBe('Renamed');
|
|
@@ -36,7 +36,7 @@ describe('Device state events', () => {
|
|
|
36
36
|
expect.objectContaining({
|
|
37
37
|
state: expect.objectContaining({ revision: 1 }),
|
|
38
38
|
revision: 1,
|
|
39
|
-
source: '
|
|
39
|
+
source: 'settings-write',
|
|
40
40
|
})
|
|
41
41
|
);
|
|
42
42
|
expect(onFeatures).not.toHaveBeenCalled();
|
|
@@ -96,7 +96,7 @@ describe('Device state events', () => {
|
|
|
96
96
|
protocol: 'V1',
|
|
97
97
|
identity: { label: 'Legacy' },
|
|
98
98
|
},
|
|
99
|
-
'
|
|
99
|
+
'settings-write'
|
|
100
100
|
);
|
|
101
101
|
|
|
102
102
|
expect(onFeatures).toHaveBeenCalledWith(device, expect.objectContaining({ label: 'Legacy' }));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EDeviceType, EFirmwareType } from '@onekeyfe/hd-shared';
|
|
2
2
|
|
|
3
|
+
import { Enum_SafetyCheckLevel } from '@onekeyfe/hd-transport';
|
|
3
4
|
import {
|
|
4
5
|
mapApplySettingsToState,
|
|
5
6
|
mapDeviceSettingsToState,
|
|
@@ -208,22 +209,33 @@ describe('DeviceStateMapper', () => {
|
|
|
208
209
|
|
|
209
210
|
test('maps common settings into identity, status and settings sections', () => {
|
|
210
211
|
expect(
|
|
211
|
-
mapApplySettingsToState({
|
|
212
|
+
mapApplySettingsToState({
|
|
213
|
+
label: 'Renamed',
|
|
214
|
+
use_passphrase: true,
|
|
215
|
+
haptic_feedback: false,
|
|
216
|
+
use_ble: true,
|
|
217
|
+
safety_checks: 'Strict',
|
|
218
|
+
})
|
|
212
219
|
).toEqual({
|
|
213
220
|
identity: { label: 'Renamed' },
|
|
214
221
|
status: { passphraseProtection: true },
|
|
215
|
-
settings: {
|
|
222
|
+
settings: {
|
|
223
|
+
hapticFeedback: false,
|
|
224
|
+
bleEnabled: true,
|
|
225
|
+
safetyChecks: Enum_SafetyCheckLevel.Strict,
|
|
226
|
+
},
|
|
216
227
|
});
|
|
217
228
|
|
|
218
229
|
expect(
|
|
219
230
|
mapDeviceSettingsToState({
|
|
220
231
|
label: 'Pro2',
|
|
232
|
+
language: 'en-Latn-US',
|
|
221
233
|
brightness: 80,
|
|
222
234
|
autolock_delay_ms: 30_000,
|
|
223
235
|
} as DeviceSettings)
|
|
224
236
|
).toEqual({
|
|
225
237
|
identity: { label: 'Pro2' },
|
|
226
|
-
settings: { brightness: 80, autoLockDelayMs: 30_000 },
|
|
238
|
+
settings: { language: 'en', brightness: 80, autoLockDelayMs: 30_000 },
|
|
227
239
|
});
|
|
228
240
|
});
|
|
229
241
|
});
|
|
@@ -14,7 +14,7 @@ describe('DeviceStateStore', () => {
|
|
|
14
14
|
store.update({ identity: { bleName: 'Pro2 1234', label: null } }, 'initialize');
|
|
15
15
|
const result = store.update(
|
|
16
16
|
{ identity: { label: 'My Wallet', bleName: undefined } },
|
|
17
|
-
'
|
|
17
|
+
'settings-write'
|
|
18
18
|
);
|
|
19
19
|
|
|
20
20
|
expect(result.state.identity).toMatchObject({
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
+
|
|
1
3
|
import ClearSessionCache from '../src/api/ClearSessionCache';
|
|
2
4
|
import {
|
|
3
5
|
DeviceWalletSessionStore,
|
|
@@ -5,6 +7,7 @@ import {
|
|
|
5
7
|
} from '../src/device/DeviceWalletSessionStore';
|
|
6
8
|
import { Device } from '../src/device/Device';
|
|
7
9
|
import { createCoreApi } from '../src/inject';
|
|
10
|
+
import TransportManager from '../src/data-manager/TransportManager';
|
|
8
11
|
|
|
9
12
|
jest.mock('../src/data/config', () => ({
|
|
10
13
|
getSDKVersion: jest.fn(() => '1.0.0'),
|
|
@@ -116,7 +119,19 @@ describe('ClearSessionCache', () => {
|
|
|
116
119
|
expect(deviceWalletSessionStore.get('device-2', 'hidden-a')).toBe('session-b');
|
|
117
120
|
});
|
|
118
121
|
|
|
119
|
-
test('
|
|
122
|
+
test('rejects passphraseState without a deviceId instead of clearing every device', () => {
|
|
123
|
+
deviceWalletSessionStore.set('device-1', 'hidden-a', 'session-a');
|
|
124
|
+
deviceWalletSessionStore.set('device-2', 'hidden-a', 'session-b');
|
|
125
|
+
const method = new ClearSessionCache({
|
|
126
|
+
payload: { method: 'clearSessionCache', passphraseState: 'hidden-a' },
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
expect(() => method.init()).toThrow('Parameter [deviceId] is required with [passphraseState].');
|
|
130
|
+
expect(deviceWalletSessionStore.get('device-1', 'hidden-a')).toBe('session-a');
|
|
131
|
+
expect(deviceWalletSessionStore.get('device-2', 'hidden-a')).toBe('session-b');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('keeps wallet sessions internal instead of projecting them through Features', async () => {
|
|
120
135
|
const device = Device.fromDescriptor({ id: 'one', path: 'one' } as never);
|
|
121
136
|
device.features = {
|
|
122
137
|
protocol: 'V1',
|
|
@@ -133,11 +148,14 @@ describe('ClearSessionCache', () => {
|
|
|
133
148
|
} as never;
|
|
134
149
|
|
|
135
150
|
expect(device.state).not.toHaveProperty('session');
|
|
151
|
+
expect(device.getInternalState()).toBe('session-a');
|
|
136
152
|
expect(device.features).toMatchObject({
|
|
137
|
-
sessionId:
|
|
138
|
-
session_id:
|
|
139
|
-
passphraseState: 'hidden-a',
|
|
153
|
+
sessionId: null,
|
|
154
|
+
session_id: null,
|
|
140
155
|
});
|
|
156
|
+
expect(device.features).not.toHaveProperty('passphraseState');
|
|
157
|
+
expect(device.features?.raw?.protocolV1Features).not.toHaveProperty('sessionId');
|
|
158
|
+
expect(device.features?.raw?.protocolV1Features).not.toHaveProperty('session_id');
|
|
141
159
|
|
|
142
160
|
const method = new ClearSessionCache({
|
|
143
161
|
payload: {
|
|
@@ -151,10 +169,20 @@ describe('ClearSessionCache', () => {
|
|
|
151
169
|
|
|
152
170
|
expect(device.features?.sessionId).toBeNull();
|
|
153
171
|
expect(device.features?.session_id).toBeNull();
|
|
154
|
-
expect(device.state?.raw?.protocolV1Features).
|
|
172
|
+
expect(device.state?.raw?.protocolV1Features).not.toHaveProperty('sessionId');
|
|
173
|
+
expect(device.state?.raw?.protocolV1Features).not.toHaveProperty('session_id');
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test('uses only the transport path as the temporary Protocol V2 cache key', () => {
|
|
177
|
+
const device = Device.fromDescriptor({ id: 'descriptor-id' } as never);
|
|
178
|
+
device.features = {
|
|
179
|
+
protocol: 'V2',
|
|
180
|
+
passphraseState: 'hidden-a',
|
|
155
181
|
sessionId: 'session-a',
|
|
156
|
-
|
|
157
|
-
|
|
182
|
+
} as never;
|
|
183
|
+
|
|
184
|
+
expect(device.getInternalState()).toBeUndefined();
|
|
185
|
+
expect(deviceWalletSessionStore.get('descriptor-id', 'hidden-a')).toBeUndefined();
|
|
158
186
|
});
|
|
159
187
|
|
|
160
188
|
test('clears one wallet without using a device', async () => {
|
|
@@ -211,3 +239,79 @@ describe('ClearSessionCache', () => {
|
|
|
211
239
|
});
|
|
212
240
|
});
|
|
213
241
|
});
|
|
242
|
+
|
|
243
|
+
describe('Protocol V1 wallet identity initialization', () => {
|
|
244
|
+
beforeEach(() => {
|
|
245
|
+
deviceWalletSessionStore.clear();
|
|
246
|
+
jest.restoreAllMocks();
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
test('verifies the live device id before sending a cached wallet session', async () => {
|
|
250
|
+
const device = Device.fromDescriptor({ id: 'connect-b', path: 'connect-b' } as never);
|
|
251
|
+
device.features = {
|
|
252
|
+
protocol: 'V1',
|
|
253
|
+
deviceId: 'cached-device-a',
|
|
254
|
+
unlocked: true,
|
|
255
|
+
passphraseProtection: true,
|
|
256
|
+
} as never;
|
|
257
|
+
deviceWalletSessionStore.set('cached-device-a', 'hidden-a', 'session-a');
|
|
258
|
+
const typedCall = jest.fn().mockResolvedValue({
|
|
259
|
+
type: 'Features',
|
|
260
|
+
message: { device_id: 'live-device-b' },
|
|
261
|
+
});
|
|
262
|
+
device.commands = { typedCall } as never;
|
|
263
|
+
jest.spyOn(TransportManager, 'reconfigure').mockResolvedValue(undefined);
|
|
264
|
+
|
|
265
|
+
await expect(
|
|
266
|
+
device.initialize({ deviceId: 'cached-device-a', passphraseState: 'hidden-a' })
|
|
267
|
+
).rejects.toMatchObject({ errorCode: HardwareErrorCode.DeviceCheckDeviceIdError });
|
|
268
|
+
expect(typedCall).toHaveBeenCalledTimes(1);
|
|
269
|
+
expect(typedCall).toHaveBeenCalledWith(
|
|
270
|
+
'Initialize',
|
|
271
|
+
'Features',
|
|
272
|
+
expect.not.objectContaining({ session_id: 'session-a' }),
|
|
273
|
+
expect.any(Object)
|
|
274
|
+
);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
test('resumes a cached V1 wallet only after the live device id matches', async () => {
|
|
278
|
+
const device = Device.fromDescriptor({ id: 'connect-a', path: 'connect-a' } as never);
|
|
279
|
+
device.features = {
|
|
280
|
+
protocol: 'V1',
|
|
281
|
+
deviceId: 'device-a',
|
|
282
|
+
unlocked: true,
|
|
283
|
+
passphraseProtection: true,
|
|
284
|
+
} as never;
|
|
285
|
+
deviceWalletSessionStore.set('device-a', 'hidden-a', 'session-a');
|
|
286
|
+
const typedCall = jest
|
|
287
|
+
.fn()
|
|
288
|
+
.mockResolvedValueOnce({ type: 'Features', message: { device_id: 'device-a' } })
|
|
289
|
+
.mockResolvedValueOnce({
|
|
290
|
+
type: 'Features',
|
|
291
|
+
message: { device_id: 'device-a', session_id: 'session-a' },
|
|
292
|
+
});
|
|
293
|
+
device.commands = { typedCall } as never;
|
|
294
|
+
jest.spyOn(TransportManager, 'reconfigure').mockResolvedValue(undefined);
|
|
295
|
+
|
|
296
|
+
await device.initialize({ deviceId: 'device-a', passphraseState: 'hidden-a' });
|
|
297
|
+
|
|
298
|
+
expect(typedCall).toHaveBeenCalledTimes(2);
|
|
299
|
+
expect(typedCall).toHaveBeenNthCalledWith(
|
|
300
|
+
1,
|
|
301
|
+
'Initialize',
|
|
302
|
+
'Features',
|
|
303
|
+
expect.not.objectContaining({ session_id: 'session-a' }),
|
|
304
|
+
expect.any(Object)
|
|
305
|
+
);
|
|
306
|
+
expect(typedCall).toHaveBeenNthCalledWith(
|
|
307
|
+
2,
|
|
308
|
+
'Initialize',
|
|
309
|
+
'Features',
|
|
310
|
+
expect.objectContaining({
|
|
311
|
+
session_id: 'session-a',
|
|
312
|
+
passphrase_state: 'hidden-a',
|
|
313
|
+
}),
|
|
314
|
+
expect.any(Object)
|
|
315
|
+
);
|
|
316
|
+
});
|
|
317
|
+
});
|