@onekeyfe/hd-core 1.2.0-alpha.19 → 1.2.0-alpha.20
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__/AllNetworkGetAddressBase.tracing.test.ts +75 -0
- package/__tests__/DeviceCommands.test.ts +143 -7
- package/__tests__/RequestQueue.test.ts +106 -0
- package/__tests__/UploadPortfolio.test.ts +46 -0
- package/__tests__/core-dispose.test.ts +34 -0
- package/__tests__/core-error-output.test.ts +39 -0
- package/__tests__/device-lifecycle-events.test.ts +117 -0
- package/__tests__/device-pool-state.test.ts +20 -1
- package/__tests__/device-settings.test.ts +184 -6
- package/__tests__/device-state-events.test.ts +1 -2
- package/__tests__/device-state-mapper.test.ts +33 -26
- package/__tests__/device-state-store.test.ts +1 -34
- package/__tests__/device-utils.test.ts +106 -0
- package/__tests__/device-wallet-session-store.test.ts +65 -29
- package/__tests__/deviceSettings.test.ts +21 -12
- package/__tests__/evmLedgerLegacySafety.test.ts +2 -2
- package/__tests__/evmSignTypedData.test.ts +80 -0
- package/__tests__/filesystemValidation.test.ts +53 -0
- package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +402 -0
- package/__tests__/get-device-state.test.ts +77 -41
- package/__tests__/logBlockEvent.test.ts +24 -11
- package/__tests__/networkUtils.test.ts +386 -0
- package/__tests__/open-wallet-session-error-response.test.ts +43 -0
- package/__tests__/open-wallet-session.test.ts +559 -0
- package/__tests__/protocol-v2.test.ts +756 -452
- package/__tests__/public-device-state-api.test.ts +113 -13
- package/__tests__/public-pro2-api-boundary.test.ts +91 -0
- package/__tests__/search-devices.test.ts +43 -0
- package/dist/api/BaseMethod.d.ts +3 -0
- package/dist/api/BaseMethod.d.ts.map +1 -1
- package/dist/api/CheckBootloaderRelease.d.ts.map +1 -1
- package/dist/api/CheckFirmwareRelease.d.ts.map +1 -1
- package/dist/api/ClearSessionCache.d.ts.map +1 -1
- package/dist/api/DirList.d.ts.map +1 -1
- package/dist/api/FileRead.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV2.d.ts +2 -2
- package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +3 -2
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/GetPassphraseState.d.ts.map +1 -1
- package/dist/api/OpenWalletSession.d.ts +14 -0
- package/dist/api/OpenWalletSession.d.ts.map +1 -0
- package/dist/api/PathInfo.d.ts.map +1 -1
- package/dist/api/PromptWebDeviceAccess.d.ts.map +1 -1
- package/dist/api/SearchDevices.d.ts +3 -0
- package/dist/api/SearchDevices.d.ts.map +1 -1
- package/dist/api/UploadPortfolio.d.ts.map +1 -1
- package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
- package/dist/api/device/DeviceChangePin.d.ts.map +1 -1
- package/dist/api/device/DeviceFullyUploadResource.d.ts +1 -2
- package/dist/api/device/DeviceFullyUploadResource.d.ts.map +1 -1
- package/dist/api/device/DeviceSettings.d.ts.map +1 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
- package/dist/api/device/DeviceWipe.d.ts.map +1 -1
- package/dist/api/evm/EVMSignTypedData.d.ts.map +1 -1
- package/dist/api/firmware/getBinary.d.ts +7 -3
- package/dist/api/firmware/getBinary.d.ts.map +1 -1
- package/dist/api/helpers/filesystemValidation.d.ts +3 -0
- package/dist/api/helpers/filesystemValidation.d.ts.map +1 -1
- package/dist/api/helpers/paramsValidator.d.ts +1 -0
- package/dist/api/helpers/paramsValidator.d.ts.map +1 -1
- package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
- package/dist/api/index.d.ts +7 -11
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceSettingsPageShow.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceSettingsSet.d.ts.map +1 -1
- package/dist/api/utils.d.ts.map +1 -1
- package/dist/core/RequestQueue.d.ts +17 -1
- package/dist/core/RequestQueue.d.ts.map +1 -1
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/device/Device.d.ts +6 -5
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts +5 -5
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/device/DevicePool.d.ts +1 -0
- package/dist/device/DevicePool.d.ts.map +1 -1
- package/dist/device/DeviceStateMapper.d.ts +2 -2
- package/dist/device/DeviceStateMapper.d.ts.map +1 -1
- package/dist/device/DeviceStateProjector.d.ts +1 -2
- package/dist/device/DeviceStateProjector.d.ts.map +1 -1
- package/dist/device/DeviceStateStore.d.ts +1 -3
- package/dist/device/DeviceStateStore.d.ts.map +1 -1
- package/dist/device/DeviceWalletSessionStore.d.ts +6 -1
- package/dist/device/DeviceWalletSessionStore.d.ts.map +1 -1
- package/dist/device/cloneDeviceState.d.ts +2 -0
- package/dist/device/cloneDeviceState.d.ts.map +1 -0
- package/dist/deviceProfile/buildDeviceFeatures.d.ts +3 -1
- package/dist/deviceProfile/buildDeviceFeatures.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/index.d.ts +608 -75
- package/dist/index.js +2287 -1706
- package/dist/inject.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/deviceSession.d.ts +7 -0
- package/dist/protocols/protocol-v2/deviceSession.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/features.d.ts +11 -4
- package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/index.d.ts +2 -2
- package/dist/protocols/protocol-v2/index.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts +16 -0
- package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/walletSession.d.ts +8 -3
- package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
- package/dist/types/api/checkAllFirmwareRelease.d.ts +1 -2
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/deviceSettings.d.ts +1 -0
- package/dist/types/api/deviceSettings.d.ts.map +1 -1
- package/dist/types/api/deviceUnlock.d.ts +1 -1
- package/dist/types/api/deviceUnlock.d.ts.map +1 -1
- package/dist/types/api/getFeatures.d.ts.map +1 -1
- package/dist/types/api/getOnekeyFeatures.d.ts.map +1 -1
- package/dist/types/api/getPassphraseState.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +13 -15
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/openWalletSession.d.ts +41 -0
- package/dist/types/api/openWalletSession.d.ts.map +1 -0
- package/dist/types/api/protocolV2.d.ts +6 -11
- package/dist/types/api/protocolV2.d.ts.map +1 -1
- package/dist/types/device.d.ts +2 -9
- package/dist/types/device.d.ts.map +1 -1
- package/dist/utils/assets.d.ts +2 -1
- package/dist/utils/assets.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesCompat.d.ts +13 -0
- package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -0
- package/dist/utils/deviceFeaturesUtils.d.ts +11 -1
- package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
- package/dist/utils/deviceInfoUtils.d.ts +9 -8
- package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
- package/dist/utils/deviceSettings.d.ts +2 -0
- package/dist/utils/deviceSettings.d.ts.map +1 -1
- package/dist/utils/deviceVersionUtils.d.ts +6 -5
- package/dist/utils/deviceVersionUtils.d.ts.map +1 -1
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/networkUtils.d.ts +9 -1
- package/dist/utils/networkUtils.d.ts.map +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/dist/utils/pro2Wallpaper.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/BaseMethod.ts +17 -10
- package/src/api/CheckBootloaderRelease.ts +1 -2
- package/src/api/CheckFirmwareRelease.ts +1 -2
- package/src/api/ClearSessionCache.ts +0 -4
- package/src/api/DirList.ts +5 -3
- package/src/api/DirMake.ts +3 -3
- package/src/api/DirRemove.ts +3 -3
- package/src/api/FileDelete.ts +3 -3
- package/src/api/FileRead.ts +9 -6
- package/src/api/FileWrite.ts +3 -3
- package/src/api/FirmwareUpdate.ts +4 -4
- package/src/api/FirmwareUpdateV2.ts +133 -45
- package/src/api/FirmwareUpdateV3.ts +3 -5
- package/src/api/FirmwareUpdateV4.ts +192 -154
- package/src/api/GetPassphraseState.ts +10 -16
- package/src/api/OpenWalletSession.ts +221 -0
- package/src/api/PathInfo.ts +5 -3
- package/src/api/PromptWebDeviceAccess.ts +2 -3
- package/src/api/SearchDevices.ts +6 -2
- package/src/api/UploadPortfolio.ts +12 -3
- package/src/api/alephium/AlephiumSignTransaction.ts +2 -2
- package/src/api/allnetwork/AllNetworkGetAddressBase.ts +4 -8
- package/src/api/benfen/BenfenGetAddress.ts +1 -1
- package/src/api/btc/BTCGetPublicKey.ts +1 -1
- package/src/api/device/DeviceChangePin.ts +1 -0
- package/src/api/device/DeviceFullyUploadResource.ts +4 -5
- package/src/api/device/DeviceSettings.ts +93 -0
- package/src/api/device/DeviceUpdateBootloader.ts +1 -2
- package/src/api/device/DeviceWipe.ts +1 -0
- package/src/api/evm/EVMSignTypedData.ts +3 -5
- package/src/api/evm/legacyV1/getAddress.ts +2 -2
- package/src/api/evm/legacyV1/getPublicKey.ts +2 -2
- package/src/api/evm/legacyV1/signMessage.ts +2 -2
- package/src/api/evm/legacyV1/signTypedData.ts +2 -2
- package/src/api/evm/legacyV1/signTypedHash.ts +2 -2
- package/src/api/evm/legacyV1/verifyMessage.ts +2 -2
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +3 -3
- package/src/api/firmware/getBinary.ts +8 -3
- package/src/api/helpers/batchGetPublickeys.ts +2 -2
- package/src/api/helpers/filesystemValidation.ts +61 -0
- package/src/api/helpers/paramsValidator.ts +1 -1
- package/src/api/helpers/protocolV2FileWrite.ts +3 -2
- package/src/api/index.ts +9 -12
- package/src/api/nervos/NervosSignTransaction.ts +2 -2
- package/src/api/nexa/NexaSignTransaction.ts +1 -1
- package/src/api/protocol-v2/DeviceFactoryInfoGet.ts +1 -1
- package/src/api/protocol-v2/DeviceFactoryInfoSet.ts +1 -1
- package/src/api/protocol-v2/DeviceFirmwareUpdate.ts +4 -4
- package/src/api/protocol-v2/DeviceGetFirmwareUpdateStatus.ts +6 -5
- package/src/api/protocol-v2/DeviceInfoGet.ts +4 -4
- package/src/api/protocol-v2/DeviceReboot.ts +1 -1
- package/src/api/protocol-v2/DeviceSettingsPageShow.ts +11 -8
- package/src/api/protocol-v2/DeviceSettingsSet.ts +4 -11
- package/src/api/protocol-v2/FilesystemFormat.ts +1 -1
- package/src/api/protocol-v2/FilesystemPermissionFix.ts +1 -1
- package/src/api/protocol-v2/Ping.ts +1 -1
- package/src/api/protocol-v2/ProtocolInfoRequest.ts +1 -1
- package/src/api/utils.ts +1 -3
- package/src/core/RequestQueue.ts +107 -6
- package/src/core/index.ts +91 -46
- package/src/data/messages/messages-protocol-v2.json +25 -79
- package/src/data-manager/DataManager.ts +6 -6
- package/src/device/Device.ts +186 -102
- package/src/device/DeviceCommands.ts +51 -21
- package/src/device/DeviceFeaturesState.ts +4 -4
- package/src/device/DevicePool.ts +17 -3
- package/src/device/DeviceStateMapper.ts +13 -29
- package/src/device/DeviceStateProjector.ts +11 -8
- package/src/device/DeviceStateStore.ts +11 -52
- package/src/device/DeviceWalletSessionStore.ts +31 -4
- package/src/device/cloneDeviceState.ts +39 -0
- package/src/device/deviceIdentity.ts +2 -2
- package/src/deviceProfile/buildDeviceFeatures.ts +29 -88
- package/src/events/logBlockEvent.ts +8 -1
- package/src/inject.ts +14 -24
- package/src/protocols/protocol-v2/deviceSession.ts +24 -0
- package/src/protocols/protocol-v2/features.ts +37 -49
- package/src/protocols/protocol-v2/firmware.ts +1 -1
- package/src/protocols/protocol-v2/index.ts +2 -3
- package/src/protocols/protocol-v2/settingsUnlockPolicy.ts +61 -0
- package/src/protocols/protocol-v2/uiInteraction.ts +4 -3
- package/src/protocols/protocol-v2/walletSession.ts +57 -146
- package/src/types/api/checkAllFirmwareRelease.ts +1 -2
- package/src/types/api/deviceSettings.ts +1 -0
- package/src/types/api/deviceUnlock.ts +1 -1
- package/src/types/api/firmwareUpdate.ts +5 -5
- package/src/types/api/getDeviceState.ts +1 -1
- package/src/types/api/getFeatures.ts +3 -0
- package/src/types/api/getOnekeyFeatures.ts +3 -0
- package/src/types/api/getPassphraseState.ts +6 -0
- package/src/types/api/index.ts +16 -23
- package/src/types/api/openWalletSession.ts +64 -0
- package/src/types/api/protocolV2.ts +36 -18
- package/src/types/device.ts +20 -14
- package/src/types/params.ts +1 -1
- package/src/types/settings.ts +8 -8
- package/src/utils/assets.ts +4 -1
- package/src/utils/deviceFeaturesCompat.ts +173 -0
- package/src/utils/deviceFeaturesUtils.ts +9 -8
- package/src/utils/deviceInfoUtils.ts +26 -64
- package/src/utils/deviceSettings.ts +18 -11
- package/src/utils/deviceVersionUtils.ts +25 -44
- package/src/utils/findDefectiveBatchDevice.ts +3 -3
- package/src/utils/index.ts +2 -5
- package/src/utils/networkUtils.ts +270 -14
- package/src/utils/pro2Wallpaper.ts +11 -13
- package/src/utils/tracing.ts +2 -2
- package/dist/api/internal.d.ts +0 -4
- package/dist/api/internal.d.ts.map +0 -1
- package/dist/api/protocol-v2/DeviceSessionOpen.d.ts +0 -28
- package/dist/api/protocol-v2/DeviceSessionOpen.d.ts.map +0 -1
- package/src/api/internal.ts +0 -9
- package/src/api/protocol-v2/DeviceSessionOpen.ts +0 -100
|
@@ -30,58 +30,55 @@ const createV1Device = (typedCall: jest.Mock) => {
|
|
|
30
30
|
describe('getDeviceState', () => {
|
|
31
31
|
test('does not expose the internal wallet session', async () => {
|
|
32
32
|
const device = createV2Device(jest.fn());
|
|
33
|
-
device.updateState(
|
|
34
|
-
{
|
|
35
|
-
protocol: 'V2',
|
|
36
|
-
session: { sessionId: 'private-session', passphraseState: 'private-state' },
|
|
37
|
-
},
|
|
38
|
-
'initialize'
|
|
39
|
-
);
|
|
33
|
+
device.updateState({ protocol: 'V2' }, 'initialize');
|
|
40
34
|
|
|
41
35
|
const state = await device.getDeviceState();
|
|
42
36
|
|
|
43
37
|
expect(state).not.toHaveProperty('session');
|
|
44
38
|
});
|
|
45
39
|
|
|
46
|
-
test('hydrates Protocol V2
|
|
47
|
-
const typedCall = jest.fn().
|
|
48
|
-
message:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
40
|
+
test('hydrates Protocol V2 with separate DeviceInfoGet and DeviceStatusGet', async () => {
|
|
41
|
+
const typedCall = jest.fn().mockImplementation((requestType: string) => ({
|
|
42
|
+
message:
|
|
43
|
+
requestType === 'DeviceInfoGet'
|
|
44
|
+
? {
|
|
45
|
+
protocol_version: 2,
|
|
46
|
+
hw: { serial_no: 'SERIAL-1' },
|
|
47
|
+
fw: { application: { version: '5.0.0' } },
|
|
48
|
+
}
|
|
49
|
+
: { init_states: true, unlocked: true },
|
|
50
|
+
}));
|
|
54
51
|
const device = createV2Device(typedCall);
|
|
55
52
|
|
|
56
53
|
const state = await device.getDeviceState();
|
|
57
54
|
|
|
58
55
|
expect(state.identity.serialNo).toBe('SERIAL-1');
|
|
59
|
-
expect(typedCall).toHaveBeenCalledTimes(
|
|
56
|
+
expect(typedCall).toHaveBeenCalledTimes(2);
|
|
60
57
|
expect(typedCall.mock.calls[0][0]).toBe('DeviceInfoGet');
|
|
61
58
|
expect(typedCall.mock.calls[0][2]?.targets?.status).not.toBe(true);
|
|
62
|
-
expect(typedCall).
|
|
63
|
-
'DeviceStatusGet',
|
|
64
|
-
expect.anything(),
|
|
65
|
-
expect.anything()
|
|
66
|
-
);
|
|
59
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceStatusGet', 'DeviceStatus', {});
|
|
67
60
|
});
|
|
68
61
|
|
|
69
|
-
test('uses
|
|
70
|
-
const typedCall = jest.fn().
|
|
71
|
-
message:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
62
|
+
test('uses one full DeviceInfoGet plus DeviceStatusGet when firmware refresh initializes state', async () => {
|
|
63
|
+
const typedCall = jest.fn().mockImplementation((requestType: string) => ({
|
|
64
|
+
message:
|
|
65
|
+
requestType === 'DeviceInfoGet'
|
|
66
|
+
? {
|
|
67
|
+
protocol_version: 2,
|
|
68
|
+
hw: { serial_no: 'SERIAL-1' },
|
|
69
|
+
fw: { application: { version: '5.0.0', hash: 'HASH-1' } },
|
|
70
|
+
}
|
|
71
|
+
: { init_states: true, unlocked: true },
|
|
72
|
+
}));
|
|
77
73
|
const device = createV2Device(typedCall);
|
|
78
74
|
|
|
79
75
|
await device.getDeviceState({
|
|
80
76
|
refreshSections: ['identity', 'versions', 'verification'],
|
|
81
77
|
});
|
|
82
78
|
|
|
83
|
-
expect(typedCall).toHaveBeenCalledTimes(
|
|
84
|
-
expect(typedCall).
|
|
79
|
+
expect(typedCall).toHaveBeenCalledTimes(2);
|
|
80
|
+
expect(typedCall).toHaveBeenNthCalledWith(
|
|
81
|
+
1,
|
|
85
82
|
'DeviceInfoGet',
|
|
86
83
|
'DeviceInfo',
|
|
87
84
|
expect.objectContaining({
|
|
@@ -117,16 +114,32 @@ describe('getDeviceState', () => {
|
|
|
117
114
|
});
|
|
118
115
|
|
|
119
116
|
test.each(['bootloader', 'romloader'] as const)(
|
|
120
|
-
'
|
|
117
|
+
'temporarily treats failed DeviceStatusGet with %s metadata as bootloader',
|
|
121
118
|
async mode => {
|
|
122
|
-
const typedCall = jest.fn()
|
|
119
|
+
const typedCall = jest.fn().mockImplementation((requestType: string) => {
|
|
120
|
+
if (requestType === 'DeviceInfoGet') {
|
|
121
|
+
return {
|
|
122
|
+
message: {
|
|
123
|
+
hw: { serial_no: 'SERIAL-1' },
|
|
124
|
+
fw:
|
|
125
|
+
mode === 'romloader'
|
|
126
|
+
? { romloader: { version: '1.0.0' } }
|
|
127
|
+
: { bootloader: { version: '1.0.0' } },
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
throw new Error('DeviceStatusGet unavailable');
|
|
132
|
+
});
|
|
123
133
|
const device = createV2Device(typedCall);
|
|
124
134
|
device.updateState({ protocol: 'V2', status: { mode } }, 'initialize');
|
|
125
135
|
|
|
126
136
|
const state = await device.getDeviceState({ refreshSections: ['status'] });
|
|
127
137
|
|
|
128
|
-
expect(state.status.mode).toBe(
|
|
129
|
-
expect(typedCall
|
|
138
|
+
expect(state.status.mode).toBe('bootloader');
|
|
139
|
+
expect(typedCall.mock.calls.map(call => call[0])).toEqual([
|
|
140
|
+
'DeviceInfoGet',
|
|
141
|
+
'DeviceStatusGet',
|
|
142
|
+
]);
|
|
130
143
|
}
|
|
131
144
|
);
|
|
132
145
|
|
|
@@ -170,6 +183,14 @@ describe('getDeviceState', () => {
|
|
|
170
183
|
|
|
171
184
|
test('refreshes Protocol V2 status before settings in a combined read', async () => {
|
|
172
185
|
const typedCall = jest.fn().mockImplementation((requestType: string) => {
|
|
186
|
+
if (requestType === 'DeviceInfoGet') {
|
|
187
|
+
return {
|
|
188
|
+
message: {
|
|
189
|
+
hw: { serial_no: 'SERIAL-1' },
|
|
190
|
+
fw: { application: { version: '5.0.0' } },
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
173
194
|
if (requestType === 'DeviceStatusGet') {
|
|
174
195
|
return {
|
|
175
196
|
message: { init_states: true, unlocked: false, device_id: 'device-1' },
|
|
@@ -186,6 +207,7 @@ describe('getDeviceState', () => {
|
|
|
186
207
|
const state = await device.getDeviceState({ refreshSections: ['status', 'settings'] });
|
|
187
208
|
|
|
188
209
|
expect(typedCall.mock.calls.map(call => call[0])).toEqual([
|
|
210
|
+
'DeviceInfoGet',
|
|
189
211
|
'DeviceStatusGet',
|
|
190
212
|
'DeviceSettingsGet',
|
|
191
213
|
]);
|
|
@@ -195,6 +217,14 @@ describe('getDeviceState', () => {
|
|
|
195
217
|
|
|
196
218
|
test('keeps the refreshed status when a following settings read fails', async () => {
|
|
197
219
|
const typedCall = jest.fn().mockImplementation((requestType: string) => {
|
|
220
|
+
if (requestType === 'DeviceInfoGet') {
|
|
221
|
+
return {
|
|
222
|
+
message: {
|
|
223
|
+
hw: { serial_no: 'SERIAL-1' },
|
|
224
|
+
fw: { application: { version: '5.0.0' } },
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
}
|
|
198
228
|
if (requestType === 'DeviceStatusGet') {
|
|
199
229
|
return {
|
|
200
230
|
message: { init_states: true, unlocked: false, device_id: 'device-1' },
|
|
@@ -335,12 +365,18 @@ describe('getDeviceState', () => {
|
|
|
335
365
|
});
|
|
336
366
|
|
|
337
367
|
test('reloads Protocol V2 DeviceInfo after a physical reconnect', async () => {
|
|
338
|
-
const typedCall = jest.fn().
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
368
|
+
const typedCall = jest.fn().mockImplementation((requestType: string) => {
|
|
369
|
+
if (requestType === 'DeviceInfoGet') {
|
|
370
|
+
return {
|
|
371
|
+
message: {
|
|
372
|
+
protocol_version: 1,
|
|
373
|
+
hw: { serial_no: 'SERIAL-1' },
|
|
374
|
+
fw: { bootloader: { version: '1.0.0' } },
|
|
375
|
+
se1: {},
|
|
376
|
+
},
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
throw new Error('DeviceStatusGet unavailable in bootloader');
|
|
344
380
|
});
|
|
345
381
|
const device = createV2Device(typedCall);
|
|
346
382
|
device.updateState(
|
|
@@ -31,20 +31,33 @@ describe('getLogBlockLabel', () => {
|
|
|
31
31
|
).toBe('evmSignTypedData');
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
-
it('
|
|
34
|
+
it('keeps existing sensitive UI response blocking', () => {
|
|
35
|
+
expect(getLogBlockLabel({ type: UI_RESPONSE.RECEIVE_PIN })).toBe(UI_RESPONSE.RECEIVE_PIN);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('blocks openWalletSession wallet identifiers in direct and iframe call logging', () => {
|
|
39
|
+
const payload = {
|
|
40
|
+
method: 'openWalletSession',
|
|
41
|
+
mode: 'resume-hidden',
|
|
42
|
+
deviceId: 'device-id',
|
|
43
|
+
passphraseState: 'wallet-identifier',
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
expect(getLogBlockLabel(payload)).toBe('openWalletSession');
|
|
35
47
|
expect(
|
|
36
48
|
getLogBlockLabel({
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
passphrase: 'do-not-log-this',
|
|
41
|
-
},
|
|
42
|
-
},
|
|
49
|
+
event: 'iframe-call',
|
|
50
|
+
type: 'iframe-call',
|
|
51
|
+
payload,
|
|
43
52
|
})
|
|
44
|
-
).toBe('
|
|
53
|
+
).toBe('openWalletSession');
|
|
45
54
|
});
|
|
46
55
|
|
|
47
|
-
it('
|
|
48
|
-
|
|
49
|
-
|
|
56
|
+
it.each(['deviceUploadWallpaper', 'uploadPortfolio', 'fileWrite', 'fileRead'])(
|
|
57
|
+
'blocks binary payload logging for %s',
|
|
58
|
+
method => {
|
|
59
|
+
expect(getLogBlockLabel({ method, data: new Uint8Array(1024) })).toBe(method);
|
|
60
|
+
expect(getLogBlockLabel({ payload: { method, data: new Uint8Array(1024) } })).toBe(method);
|
|
61
|
+
}
|
|
62
|
+
);
|
|
50
63
|
});
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
|
|
3
|
+
import { httpRequest } from '../src/utils/networkUtils';
|
|
4
|
+
|
|
5
|
+
describe('networkUtils httpRequest retry bounds', () => {
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
jest.restoreAllMocks();
|
|
8
|
+
jest.useRealTimers();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('keeps timeout, retries, and cancellation opt-in for existing callers', async () => {
|
|
12
|
+
const requestSpy = jest.spyOn(axios, 'request').mockResolvedValue({
|
|
13
|
+
status: 200,
|
|
14
|
+
data: {
|
|
15
|
+
ok: true,
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
await expect(httpRequest('https://example.com/data.json', 'json')).resolves.toEqual({
|
|
20
|
+
ok: true,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
expect(requestSpy).toHaveBeenCalledTimes(1);
|
|
24
|
+
expect(requestSpy.mock.calls[0][0]).not.toHaveProperty('timeout');
|
|
25
|
+
expect(requestSpy.mock.calls[0][0]).not.toHaveProperty('signal');
|
|
26
|
+
expect(requestSpy.mock.calls[0][0]).not.toHaveProperty('adapter');
|
|
27
|
+
expect(requestSpy.mock.calls[0][0]).not.toHaveProperty('onDownloadProgress');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('passes the per-attempt timeout and stops after the configured retry count', async () => {
|
|
31
|
+
const timeoutError = Object.assign(new Error('timeout'), {
|
|
32
|
+
code: 'ECONNABORTED',
|
|
33
|
+
isAxiosError: true,
|
|
34
|
+
});
|
|
35
|
+
const requestSpy = jest.spyOn(axios, 'request').mockRejectedValue(timeoutError);
|
|
36
|
+
|
|
37
|
+
await expect(
|
|
38
|
+
httpRequest('https://example.com/firmware.bin', 'binary', {
|
|
39
|
+
timeoutMs: 1234,
|
|
40
|
+
maxRetries: 2,
|
|
41
|
+
retryDelayMs: 0,
|
|
42
|
+
})
|
|
43
|
+
).rejects.toBe(timeoutError);
|
|
44
|
+
|
|
45
|
+
expect(requestSpy).toHaveBeenCalledTimes(3);
|
|
46
|
+
expect(requestSpy).toHaveBeenNthCalledWith(
|
|
47
|
+
1,
|
|
48
|
+
expect.objectContaining({
|
|
49
|
+
timeout: 1234,
|
|
50
|
+
})
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('retries a connection deadline and stops at the configured attempt bound', async () => {
|
|
55
|
+
jest.useFakeTimers({ doNotFake: ['performance'] });
|
|
56
|
+
const requestSpy = jest.spyOn(axios, 'request').mockImplementation(
|
|
57
|
+
config =>
|
|
58
|
+
new Promise((_resolve, reject) => {
|
|
59
|
+
config.signal?.addEventListener(
|
|
60
|
+
'abort',
|
|
61
|
+
() => {
|
|
62
|
+
reject(
|
|
63
|
+
Object.assign(new Error('canceled'), {
|
|
64
|
+
__CANCEL__: true,
|
|
65
|
+
code: 'ERR_CANCELED',
|
|
66
|
+
isAxiosError: true,
|
|
67
|
+
})
|
|
68
|
+
);
|
|
69
|
+
},
|
|
70
|
+
{ once: true }
|
|
71
|
+
);
|
|
72
|
+
})
|
|
73
|
+
);
|
|
74
|
+
const requestPromise = httpRequest('https://example.com/firmware.bin', 'binary', {
|
|
75
|
+
connectTimeoutMs: 1_000,
|
|
76
|
+
maxRetries: 1,
|
|
77
|
+
retryDelayMs: 0,
|
|
78
|
+
});
|
|
79
|
+
const rejection = expect(requestPromise).rejects.toMatchObject({
|
|
80
|
+
name: 'HttpRequestPhaseTimeoutError',
|
|
81
|
+
code: 'ECONNECTTIMEDOUT',
|
|
82
|
+
message: expect.stringContaining('connect timeout'),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
await Promise.resolve();
|
|
86
|
+
jest.advanceTimersByTime(1_000);
|
|
87
|
+
await Promise.resolve();
|
|
88
|
+
await Promise.resolve();
|
|
89
|
+
expect(requestSpy).toHaveBeenCalledTimes(2);
|
|
90
|
+
|
|
91
|
+
jest.advanceTimersByTime(1_000);
|
|
92
|
+
|
|
93
|
+
await rejection;
|
|
94
|
+
expect(requestSpy).toHaveBeenCalledTimes(2);
|
|
95
|
+
expect(requestSpy.mock.calls[0][0].adapter).toEqual(['xhr', 'http']);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('restarts the read-idle deadline only when loaded bytes increase', async () => {
|
|
99
|
+
jest.useFakeTimers({ doNotFake: ['performance'] });
|
|
100
|
+
let requestConfig: Parameters<typeof axios.request>[0] | undefined;
|
|
101
|
+
const requestSpy = jest.spyOn(axios, 'request').mockImplementation(
|
|
102
|
+
config =>
|
|
103
|
+
new Promise((_resolve, reject) => {
|
|
104
|
+
requestConfig = config;
|
|
105
|
+
config.signal?.addEventListener(
|
|
106
|
+
'abort',
|
|
107
|
+
() => {
|
|
108
|
+
reject(
|
|
109
|
+
Object.assign(new Error('canceled'), {
|
|
110
|
+
__CANCEL__: true,
|
|
111
|
+
code: 'ERR_CANCELED',
|
|
112
|
+
isAxiosError: true,
|
|
113
|
+
})
|
|
114
|
+
);
|
|
115
|
+
},
|
|
116
|
+
{ once: true }
|
|
117
|
+
);
|
|
118
|
+
})
|
|
119
|
+
);
|
|
120
|
+
const requestPromise = httpRequest('https://example.com/firmware.bin', 'binary', {
|
|
121
|
+
connectTimeoutMs: 1_000,
|
|
122
|
+
readTimeoutMs: 2_000,
|
|
123
|
+
});
|
|
124
|
+
const rejection = expect(requestPromise).rejects.toMatchObject({
|
|
125
|
+
name: 'HttpRequestPhaseTimeoutError',
|
|
126
|
+
code: 'EREADTIMEDOUT',
|
|
127
|
+
message: expect.stringContaining('read timeout'),
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
await Promise.resolve();
|
|
131
|
+
jest.advanceTimersByTime(500);
|
|
132
|
+
requestConfig?.onDownloadProgress?.({
|
|
133
|
+
bytes: 0,
|
|
134
|
+
lengthComputable: false,
|
|
135
|
+
loaded: 0,
|
|
136
|
+
});
|
|
137
|
+
jest.advanceTimersByTime(400);
|
|
138
|
+
requestConfig?.onDownloadProgress?.({
|
|
139
|
+
bytes: 1,
|
|
140
|
+
lengthComputable: false,
|
|
141
|
+
loaded: 1,
|
|
142
|
+
});
|
|
143
|
+
jest.advanceTimersByTime(900);
|
|
144
|
+
requestConfig?.onDownloadProgress?.({
|
|
145
|
+
bytes: 1,
|
|
146
|
+
lengthComputable: false,
|
|
147
|
+
loaded: 2,
|
|
148
|
+
});
|
|
149
|
+
jest.advanceTimersByTime(1_900);
|
|
150
|
+
expect(requestConfig?.signal?.aborted).toBe(false);
|
|
151
|
+
|
|
152
|
+
requestConfig?.onDownloadProgress?.({
|
|
153
|
+
bytes: 0,
|
|
154
|
+
lengthComputable: false,
|
|
155
|
+
loaded: 2,
|
|
156
|
+
});
|
|
157
|
+
jest.advanceTimersByTime(99);
|
|
158
|
+
expect(requestConfig?.signal?.aborted).toBe(false);
|
|
159
|
+
|
|
160
|
+
jest.advanceTimersByTime(1);
|
|
161
|
+
|
|
162
|
+
await rejection;
|
|
163
|
+
expect(requestSpy).toHaveBeenCalledTimes(1);
|
|
164
|
+
expect(requestConfig?.signal?.aborted).toBe(true);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('ignores progress callbacks after the attempt has settled', async () => {
|
|
168
|
+
let requestConfig: Parameters<typeof axios.request>[0] | undefined;
|
|
169
|
+
jest.spyOn(axios, 'request').mockImplementation(config => {
|
|
170
|
+
requestConfig = config;
|
|
171
|
+
return Promise.resolve({
|
|
172
|
+
status: 200,
|
|
173
|
+
data: new ArrayBuffer(4),
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
await httpRequest('https://example.com/firmware.bin', 'binary', {
|
|
178
|
+
connectTimeoutMs: 1_000,
|
|
179
|
+
readTimeoutMs: 2_000,
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
const timeoutSpy = jest.spyOn(global, 'setTimeout');
|
|
183
|
+
requestConfig?.onDownloadProgress?.({
|
|
184
|
+
bytes: 1,
|
|
185
|
+
lengthComputable: false,
|
|
186
|
+
loaded: 1,
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
expect(timeoutSpy).not.toHaveBeenCalled();
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it.each(['ECONNRESET', 'ENOTFOUND', 'ERR_NETWORK', 'ETIMEDOUT'])(
|
|
193
|
+
'retries transient network error %s',
|
|
194
|
+
async code => {
|
|
195
|
+
const networkError = Object.assign(new Error('temporarily unreachable'), {
|
|
196
|
+
code,
|
|
197
|
+
isAxiosError: true,
|
|
198
|
+
});
|
|
199
|
+
const firmwareBinary = new ArrayBuffer(4);
|
|
200
|
+
const requestSpy = jest
|
|
201
|
+
.spyOn(axios, 'request')
|
|
202
|
+
.mockRejectedValueOnce(networkError)
|
|
203
|
+
.mockResolvedValueOnce({
|
|
204
|
+
status: 200,
|
|
205
|
+
data: firmwareBinary,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
await expect(
|
|
209
|
+
httpRequest('https://example.com/firmware.bin', 'binary', {
|
|
210
|
+
maxRetries: 1,
|
|
211
|
+
retryDelayMs: 0,
|
|
212
|
+
})
|
|
213
|
+
).resolves.toBe(firmwareBinary);
|
|
214
|
+
|
|
215
|
+
expect(requestSpy).toHaveBeenCalledTimes(2);
|
|
216
|
+
}
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
it('does not retry a canceled request', async () => {
|
|
220
|
+
const canceledError = Object.assign(new Error('canceled'), {
|
|
221
|
+
__CANCEL__: true,
|
|
222
|
+
code: 'ERR_CANCELED',
|
|
223
|
+
isAxiosError: true,
|
|
224
|
+
});
|
|
225
|
+
const requestSpy = jest.spyOn(axios, 'request').mockRejectedValue(canceledError);
|
|
226
|
+
|
|
227
|
+
await expect(
|
|
228
|
+
httpRequest('https://example.com/firmware.bin', 'binary', {
|
|
229
|
+
maxRetries: 2,
|
|
230
|
+
retryDelayMs: 0,
|
|
231
|
+
})
|
|
232
|
+
).rejects.toBe(canceledError);
|
|
233
|
+
|
|
234
|
+
expect(requestSpy).toHaveBeenCalledTimes(1);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('enforces an overall deadline independently from per-attempt phase deadlines', async () => {
|
|
238
|
+
jest.useFakeTimers({ doNotFake: ['performance'] });
|
|
239
|
+
const requestSpy = jest.spyOn(axios, 'request').mockImplementation(
|
|
240
|
+
() =>
|
|
241
|
+
new Promise(() => {
|
|
242
|
+
// Keep the request pending until the overall deadline aborts it.
|
|
243
|
+
})
|
|
244
|
+
);
|
|
245
|
+
const requestPromise = httpRequest('https://example.com/firmware.bin', 'binary', {
|
|
246
|
+
connectTimeoutMs: 5_000,
|
|
247
|
+
readTimeoutMs: 5_000,
|
|
248
|
+
overallTimeoutMs: 2_500,
|
|
249
|
+
maxRetries: 2,
|
|
250
|
+
retryDelayMs: 0,
|
|
251
|
+
});
|
|
252
|
+
const rejection = expect(requestPromise).rejects.toMatchObject({
|
|
253
|
+
name: 'HttpRequestOverallTimeoutError',
|
|
254
|
+
message: expect.stringContaining('2500ms'),
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
jest.advanceTimersByTime(2_500);
|
|
258
|
+
|
|
259
|
+
await rejection;
|
|
260
|
+
expect(requestSpy).toHaveBeenCalledTimes(1);
|
|
261
|
+
expect(requestSpy.mock.calls[0][0].signal?.aborted).toBe(true);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it('includes retry backoff in the overall deadline', async () => {
|
|
265
|
+
jest.useFakeTimers({ doNotFake: ['performance'] });
|
|
266
|
+
const networkError = Object.assign(new Error('temporarily unreachable'), {
|
|
267
|
+
code: 'ECONNRESET',
|
|
268
|
+
isAxiosError: true,
|
|
269
|
+
});
|
|
270
|
+
const requestSpy = jest.spyOn(axios, 'request').mockRejectedValue(networkError);
|
|
271
|
+
const requestPromise = httpRequest('https://example.com/firmware.bin', 'binary', {
|
|
272
|
+
overallTimeoutMs: 2_500,
|
|
273
|
+
maxRetries: 2,
|
|
274
|
+
retryDelayMs: 5_000,
|
|
275
|
+
});
|
|
276
|
+
const rejection = expect(requestPromise).rejects.toMatchObject({
|
|
277
|
+
name: 'HttpRequestOverallTimeoutError',
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
await Promise.resolve();
|
|
281
|
+
await Promise.resolve();
|
|
282
|
+
await Promise.resolve();
|
|
283
|
+
await Promise.resolve();
|
|
284
|
+
expect(requestSpy).toHaveBeenCalledTimes(1);
|
|
285
|
+
expect(jest.getTimerCount()).toBe(2);
|
|
286
|
+
jest.advanceTimersByTime(2_500);
|
|
287
|
+
|
|
288
|
+
await rejection;
|
|
289
|
+
expect(requestSpy).toHaveBeenCalledTimes(1);
|
|
290
|
+
expect(jest.getTimerCount()).toBe(0);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it('does not start another attempt after an absolute deadline clock jump', async () => {
|
|
294
|
+
jest
|
|
295
|
+
.spyOn(Date, 'now')
|
|
296
|
+
.mockReturnValueOnce(1_000)
|
|
297
|
+
.mockReturnValueOnce(1_000)
|
|
298
|
+
.mockReturnValue(4_000);
|
|
299
|
+
const networkError = Object.assign(new Error('temporarily unreachable'), {
|
|
300
|
+
code: 'ECONNRESET',
|
|
301
|
+
isAxiosError: true,
|
|
302
|
+
});
|
|
303
|
+
const requestSpy = jest.spyOn(axios, 'request').mockRejectedValue(networkError);
|
|
304
|
+
|
|
305
|
+
await expect(
|
|
306
|
+
httpRequest('https://example.com/firmware.bin', 'binary', {
|
|
307
|
+
overallTimeoutMs: 2_500,
|
|
308
|
+
maxRetries: 1,
|
|
309
|
+
retryDelayMs: 0,
|
|
310
|
+
})
|
|
311
|
+
).rejects.toMatchObject({
|
|
312
|
+
name: 'HttpRequestOverallTimeoutError',
|
|
313
|
+
message: expect.stringContaining('2500ms'),
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
expect(requestSpy).toHaveBeenCalledTimes(1);
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it.each([500, 502, 503, 504])(
|
|
320
|
+
'retries transient HTTP %s and returns the next response',
|
|
321
|
+
async status => {
|
|
322
|
+
const serverError = Object.assign(new Error('unavailable'), {
|
|
323
|
+
isAxiosError: true,
|
|
324
|
+
response: {
|
|
325
|
+
status,
|
|
326
|
+
},
|
|
327
|
+
});
|
|
328
|
+
const firmwareBinary = new ArrayBuffer(4);
|
|
329
|
+
const requestSpy = jest
|
|
330
|
+
.spyOn(axios, 'request')
|
|
331
|
+
.mockRejectedValueOnce(serverError)
|
|
332
|
+
.mockResolvedValueOnce({
|
|
333
|
+
status: 200,
|
|
334
|
+
data: firmwareBinary,
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
await expect(
|
|
338
|
+
httpRequest('https://example.com/firmware.bin', 'binary', {
|
|
339
|
+
maxRetries: 1,
|
|
340
|
+
retryDelayMs: 0,
|
|
341
|
+
})
|
|
342
|
+
).resolves.toBe(firmwareBinary);
|
|
343
|
+
|
|
344
|
+
expect(requestSpy).toHaveBeenCalledTimes(2);
|
|
345
|
+
}
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
it.each([404, 501, 505])('does not retry HTTP %s', async status => {
|
|
349
|
+
const responseError = Object.assign(new Error('request failed'), {
|
|
350
|
+
isAxiosError: true,
|
|
351
|
+
response: {
|
|
352
|
+
status,
|
|
353
|
+
},
|
|
354
|
+
});
|
|
355
|
+
const requestSpy = jest.spyOn(axios, 'request').mockRejectedValue(responseError);
|
|
356
|
+
|
|
357
|
+
await expect(
|
|
358
|
+
httpRequest('https://example.com/firmware.bin', 'binary', {
|
|
359
|
+
maxRetries: 2,
|
|
360
|
+
retryDelayMs: 0,
|
|
361
|
+
})
|
|
362
|
+
).rejects.toBe(responseError);
|
|
363
|
+
|
|
364
|
+
expect(requestSpy).toHaveBeenCalledTimes(1);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it.each(['CERT_HAS_EXPIRED', 'DEPTH_ZERO_SELF_SIGNED_CERT', 'ERR_TLS_CERT_ALTNAME_INVALID'])(
|
|
368
|
+
'does not retry TLS/certificate error %s',
|
|
369
|
+
async code => {
|
|
370
|
+
const certificateError = Object.assign(new Error('certificate rejected'), {
|
|
371
|
+
code,
|
|
372
|
+
isAxiosError: true,
|
|
373
|
+
});
|
|
374
|
+
const requestSpy = jest.spyOn(axios, 'request').mockRejectedValue(certificateError);
|
|
375
|
+
|
|
376
|
+
await expect(
|
|
377
|
+
httpRequest('https://example.com/firmware.bin', 'binary', {
|
|
378
|
+
maxRetries: 2,
|
|
379
|
+
retryDelayMs: 0,
|
|
380
|
+
})
|
|
381
|
+
).rejects.toBe(certificateError);
|
|
382
|
+
|
|
383
|
+
expect(requestSpy).toHaveBeenCalledTimes(1);
|
|
384
|
+
}
|
|
385
|
+
);
|
|
386
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
+
|
|
3
|
+
import { initCore } from '../src/core';
|
|
4
|
+
import { IFRAME } from '../src/events';
|
|
5
|
+
|
|
6
|
+
jest.mock('../src/data/config', () => ({
|
|
7
|
+
getSDKVersion: jest.fn(() => '1.0.0-test'),
|
|
8
|
+
DEFAULT_DOMAIN: 'https://jssdk.onekey.so/1.0.0-test/',
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
jest.mock('../src/data-manager/TransportManager', () => ({
|
|
12
|
+
__esModule: true,
|
|
13
|
+
default: {
|
|
14
|
+
configure: jest.fn().mockResolvedValue(undefined),
|
|
15
|
+
getTransport: jest.fn(() => undefined),
|
|
16
|
+
},
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
describe('openWalletSession error response', () => {
|
|
20
|
+
test('returns a structured invalid-parameter response for an incomplete resume request', async () => {
|
|
21
|
+
const core = initCore();
|
|
22
|
+
|
|
23
|
+
const response = await core.handleMessage({
|
|
24
|
+
id: 1,
|
|
25
|
+
event: IFRAME.CALL,
|
|
26
|
+
type: IFRAME.CALL,
|
|
27
|
+
payload: {
|
|
28
|
+
method: 'openWalletSession',
|
|
29
|
+
connectId: 'connect-id',
|
|
30
|
+
mode: 'resume-hidden',
|
|
31
|
+
},
|
|
32
|
+
} as never);
|
|
33
|
+
|
|
34
|
+
expect(response).toMatchObject({
|
|
35
|
+
success: false,
|
|
36
|
+
payload: {
|
|
37
|
+
error: 'Missing required parameter: deviceId',
|
|
38
|
+
code: HardwareErrorCode.CallMethodInvalidParameter,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
await core.dispose();
|
|
42
|
+
});
|
|
43
|
+
});
|