@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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
1
|
+
import { EFirmwareType, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
2
|
import { DeviceRebootType, DeviceSettingsPage } from '@onekeyfe/hd-transport';
|
|
3
3
|
|
|
4
4
|
import * as firmwareBinaryApi from '../src/api/firmware/getBinary';
|
|
@@ -21,9 +21,6 @@ import DeviceLock from '../src/api/device/DeviceLock';
|
|
|
21
21
|
import DeviceSettings from '../src/api/device/DeviceSettings';
|
|
22
22
|
import DeviceUnlock from '../src/api/device/DeviceUnlock';
|
|
23
23
|
import DeviceWipe from '../src/api/device/DeviceWipe';
|
|
24
|
-
import DeviceSettingsGet from '../src/api/protocol-v2/DeviceSettingsGet';
|
|
25
|
-
import DeviceSettingsPageShow from '../src/api/protocol-v2/DeviceSettingsPageShow';
|
|
26
|
-
import DeviceSettingsSet from '../src/api/protocol-v2/DeviceSettingsSet';
|
|
27
24
|
import DeviceUploadWallpaper from '../src/api/protocol-v2/DeviceUploadWallpaper';
|
|
28
25
|
import DeviceStatusGet from '../src/api/protocol-v2/DeviceStatusGet';
|
|
29
26
|
import FilesystemFormat from '../src/api/protocol-v2/FilesystemFormat';
|
|
@@ -86,6 +83,7 @@ import {
|
|
|
86
83
|
isMethodVersionRangeUnsupported,
|
|
87
84
|
} from '../src/utils';
|
|
88
85
|
import { getDeviceFirmwareVersion } from '../src/utils/deviceVersionUtils';
|
|
86
|
+
import { openFirmwareByteSource } from '../src/api/firmware/FirmwareArtifactSource';
|
|
89
87
|
import {
|
|
90
88
|
getPassphraseState,
|
|
91
89
|
getPassphraseStateWithRefreshDeviceInfo,
|
|
@@ -125,7 +123,7 @@ describe('DeviceUploadWallpaper', () => {
|
|
|
125
123
|
const result = await method.run();
|
|
126
124
|
|
|
127
125
|
expect(method.requireProtocolV2).toBe(true);
|
|
128
|
-
expect(method.unlockPolicy).toBe('
|
|
126
|
+
expect(method.unlockPolicy).toBe('unlock-before-run');
|
|
129
127
|
expect(typedCall).toHaveBeenNthCalledWith(1, 'FilesystemDirMake', 'Success', {
|
|
130
128
|
path: 'vol1:/wallpapers',
|
|
131
129
|
});
|
|
@@ -214,9 +212,8 @@ describe('UploadPortfolio', () => {
|
|
|
214
212
|
method.init();
|
|
215
213
|
const result = await method.run();
|
|
216
214
|
|
|
217
|
-
expect(method.unlockPolicy).toBe('
|
|
215
|
+
expect(method.unlockPolicy).toBe('unlock-before-run');
|
|
218
216
|
expect(method.protocolV2UiMode).toBe('none');
|
|
219
|
-
expect(method.executionPriority).toBe('background');
|
|
220
217
|
expect(method.protocolV2UiInteraction).toBeUndefined();
|
|
221
218
|
expect(method.payload.emitProgress).toBe(false);
|
|
222
219
|
expect(typedCall).toHaveBeenNthCalledWith(
|
|
@@ -234,15 +231,9 @@ describe('UploadPortfolio', () => {
|
|
|
234
231
|
append: false,
|
|
235
232
|
ui_percentage: 100,
|
|
236
233
|
},
|
|
237
|
-
{ timeoutMs:
|
|
238
|
-
);
|
|
239
|
-
expect(typedCall).toHaveBeenNthCalledWith(
|
|
240
|
-
2,
|
|
241
|
-
'PortfolioUpdate',
|
|
242
|
-
'Success',
|
|
243
|
-
{},
|
|
244
|
-
{ timeoutMs: 5_000 }
|
|
234
|
+
{ timeoutMs: undefined }
|
|
245
235
|
);
|
|
236
|
+
expect(typedCall).toHaveBeenNthCalledWith(2, 'PortfolioUpdate', 'Success', {});
|
|
246
237
|
expect(method.postMessage).not.toHaveBeenCalled();
|
|
247
238
|
expect(result).toMatchObject({
|
|
248
239
|
path: 'vol1:/portfolio/portfolio.okpkg.pending',
|
|
@@ -280,7 +271,6 @@ describe('UploadPortfolio', () => {
|
|
|
280
271
|
payload: {
|
|
281
272
|
method: 'uploadPortfolio',
|
|
282
273
|
packageBytes,
|
|
283
|
-
operationId: 'portfolio-1',
|
|
284
274
|
},
|
|
285
275
|
});
|
|
286
276
|
method.abortSignal = abortController.signal;
|
|
@@ -722,7 +712,9 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
722
712
|
unlockedAttachPin: false,
|
|
723
713
|
resumed: false,
|
|
724
714
|
});
|
|
725
|
-
expect(typedCall).
|
|
715
|
+
expect(typedCall).toHaveBeenCalledWith('ProtocolInfoRequest', 'ProtocolInfo', {
|
|
716
|
+
eventless_wallet_session: true,
|
|
717
|
+
});
|
|
726
718
|
expect(device.getInternalState()).toBeUndefined();
|
|
727
719
|
});
|
|
728
720
|
|
|
@@ -732,7 +724,13 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
732
724
|
{ ...descriptor, protocolType: 'V2' } as any,
|
|
733
725
|
{ status: { passphrase_enabled: false, unlocked: true } }
|
|
734
726
|
);
|
|
735
|
-
const typedCall = jest.fn()
|
|
727
|
+
const typedCall = jest.fn().mockResolvedValue({
|
|
728
|
+
type: 'DeviceSession',
|
|
729
|
+
message: {
|
|
730
|
+
btc_test_address: 'main-wallet-state',
|
|
731
|
+
session_id: 'main-wallet-session',
|
|
732
|
+
},
|
|
733
|
+
});
|
|
736
734
|
const promptPassphrase = jest
|
|
737
735
|
.fn()
|
|
738
736
|
.mockResolvedValue({ passphrase: 'hidden-wallet-with-disabled-flag' });
|
|
@@ -746,7 +744,9 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
746
744
|
});
|
|
747
745
|
|
|
748
746
|
expect(promptPassphrase).not.toHaveBeenCalled();
|
|
749
|
-
expect(typedCall).
|
|
747
|
+
expect(typedCall).toHaveBeenCalledWith('ProtocolInfoRequest', 'ProtocolInfo', {
|
|
748
|
+
eventless_wallet_session: true,
|
|
749
|
+
});
|
|
750
750
|
});
|
|
751
751
|
|
|
752
752
|
test('preserves cached settings only while Protocol V2 physical identity stays the same', () => {
|
|
@@ -801,13 +801,8 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
801
801
|
}
|
|
802
802
|
);
|
|
803
803
|
const typedCall = jest.fn().mockImplementation((request: string) => {
|
|
804
|
-
if (request === '
|
|
805
|
-
return Promise.resolve({
|
|
806
|
-
message: {
|
|
807
|
-
btc_test_address: 'state-after-unlock',
|
|
808
|
-
session_id: 'session-after-unlock',
|
|
809
|
-
},
|
|
810
|
-
});
|
|
804
|
+
if (request === 'ProtocolInfoRequest') {
|
|
805
|
+
return Promise.resolve({ message: { version: 2 } });
|
|
811
806
|
}
|
|
812
807
|
if (request === 'DeviceStatusGet') {
|
|
813
808
|
return Promise.resolve({
|
|
@@ -836,7 +831,9 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
836
831
|
|
|
837
832
|
expect(unlockDevice).toHaveBeenCalledTimes(1);
|
|
838
833
|
expect(promptPassphrase).not.toHaveBeenCalled();
|
|
839
|
-
expect(typedCall).
|
|
834
|
+
expect(typedCall).toHaveBeenCalledWith('ProtocolInfoRequest', 'ProtocolInfo', {
|
|
835
|
+
eventless_wallet_session: true,
|
|
836
|
+
});
|
|
840
837
|
});
|
|
841
838
|
|
|
842
839
|
test('onlyMainPin takes precedence over a cached hidden-wallet state', async () => {
|
|
@@ -847,14 +844,28 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
847
844
|
);
|
|
848
845
|
device.passphraseState = 'hidden-state';
|
|
849
846
|
preloadSessionCache('main-wallet-device', 'hidden-state', 'hidden-session');
|
|
850
|
-
const typedCall = jest.fn()
|
|
847
|
+
const typedCall = jest.fn().mockResolvedValue({
|
|
848
|
+
type: 'DeviceSession',
|
|
849
|
+
message: {
|
|
850
|
+
btc_test_address: 'main-wallet-state',
|
|
851
|
+
session_id: 'main-wallet-session',
|
|
852
|
+
},
|
|
853
|
+
});
|
|
851
854
|
(device as any).commands = { typedCall };
|
|
852
855
|
|
|
853
|
-
await
|
|
854
|
-
|
|
856
|
+
await expect(
|
|
857
|
+
getPassphraseState(device, {
|
|
858
|
+
onlyMainPin: true,
|
|
859
|
+
})
|
|
860
|
+
).resolves.toMatchObject({
|
|
861
|
+
passphraseState: undefined,
|
|
862
|
+
newSession: undefined,
|
|
855
863
|
});
|
|
856
|
-
expect(typedCall).
|
|
857
|
-
|
|
864
|
+
expect(typedCall).toHaveBeenCalledWith('ProtocolInfoRequest', 'ProtocolInfo', {
|
|
865
|
+
eventless_wallet_session: true,
|
|
866
|
+
});
|
|
867
|
+
expect(device.passphraseState).toBeUndefined();
|
|
868
|
+
expect(device.getInternalState()).toBeUndefined();
|
|
858
869
|
});
|
|
859
870
|
|
|
860
871
|
test('gets the wallet session selected by the Protocol V2 device', async () => {
|
|
@@ -878,7 +889,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
878
889
|
type: 'DeviceSession',
|
|
879
890
|
message: { session_id: 'hidden-session', btc_test_address: 'hidden-state' },
|
|
880
891
|
});
|
|
881
|
-
const promptPassphrase = jest.fn();
|
|
892
|
+
const promptPassphrase = jest.fn().mockResolvedValue({ passphrase: 'hidden secret' });
|
|
882
893
|
(device as any).commands = { typedCall, promptPassphrase };
|
|
883
894
|
|
|
884
895
|
await expect(getProtocolV2WalletSession(device)).resolves.toMatchObject({
|
|
@@ -886,8 +897,10 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
886
897
|
passphraseState: 'hidden-state',
|
|
887
898
|
});
|
|
888
899
|
|
|
889
|
-
expect(promptPassphrase).
|
|
890
|
-
expect(typedCall).toHaveBeenCalledWith('
|
|
900
|
+
expect(promptPassphrase).toHaveBeenCalled();
|
|
901
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionOpen', 'DeviceSession', {
|
|
902
|
+
select: { host_passphrase: { passphrase: 'hidden secret' } },
|
|
903
|
+
});
|
|
891
904
|
});
|
|
892
905
|
|
|
893
906
|
test('deviceStatusGet returns raw DeviceStatus and updates dynamic features', async () => {
|
|
@@ -991,8 +1004,8 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
991
1004
|
newSession: 'session-b',
|
|
992
1005
|
});
|
|
993
1006
|
|
|
994
|
-
expect(typedCall).toHaveBeenCalledWith('
|
|
995
|
-
session_id: 'session-a',
|
|
1007
|
+
expect(typedCall).toHaveBeenCalledWith('DeviceSessionOpen', 'DeviceSession', {
|
|
1008
|
+
resume: { session_id: 'session-a' },
|
|
996
1009
|
});
|
|
997
1010
|
expect(device.getInternalState()).toBe('session-b');
|
|
998
1011
|
});
|
|
@@ -1010,13 +1023,18 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
1010
1023
|
preloadSessionCache('stable-device-2', 'state-a', 'session-a');
|
|
1011
1024
|
const typedCall = jest.fn().mockResolvedValue({
|
|
1012
1025
|
type: 'DeviceSession',
|
|
1013
|
-
message: {
|
|
1026
|
+
message: {
|
|
1027
|
+
session_id: 'main-session',
|
|
1028
|
+
btc_test_address: 'main-wallet-state',
|
|
1029
|
+
},
|
|
1014
1030
|
});
|
|
1015
1031
|
(device as any).commands = { typedCall };
|
|
1016
1032
|
|
|
1017
1033
|
await getProtocolV2WalletSession(device, { onlyMainPin: true });
|
|
1018
1034
|
|
|
1019
|
-
expect(typedCall).
|
|
1035
|
+
expect(typedCall).toHaveBeenCalledWith('ProtocolInfoRequest', 'ProtocolInfo', {
|
|
1036
|
+
eventless_wallet_session: true,
|
|
1037
|
+
});
|
|
1020
1038
|
expect(device.getInternalState()).toBeUndefined();
|
|
1021
1039
|
});
|
|
1022
1040
|
|
|
@@ -1038,11 +1056,14 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
1038
1056
|
);
|
|
1039
1057
|
device.passphraseState = 'state-a';
|
|
1040
1058
|
preloadSessionCache('stable-device-3', 'state-a', 'session-a');
|
|
1041
|
-
const typedCall = jest
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1059
|
+
const typedCall = jest
|
|
1060
|
+
.fn()
|
|
1061
|
+
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
1062
|
+
.mockRejectedValue(
|
|
1063
|
+
Object.assign(new Error('SE request failed'), {
|
|
1064
|
+
errorCode: HardwareErrorCode.RuntimeError,
|
|
1065
|
+
})
|
|
1066
|
+
);
|
|
1046
1067
|
const promptPassphrase = jest.fn();
|
|
1047
1068
|
(device as any).commands = { typedCall, promptPassphrase };
|
|
1048
1069
|
|
|
@@ -1050,7 +1071,8 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
1050
1071
|
errorCode: HardwareErrorCode.RuntimeError,
|
|
1051
1072
|
});
|
|
1052
1073
|
expect(typedCall.mock.calls).toEqual([
|
|
1053
|
-
['
|
|
1074
|
+
['ProtocolInfoRequest', 'ProtocolInfo', { eventless_wallet_session: true }],
|
|
1075
|
+
['DeviceSessionOpen', 'DeviceSession', { resume: { session_id: 'session-a' } }],
|
|
1054
1076
|
]);
|
|
1055
1077
|
expect(promptPassphrase).not.toHaveBeenCalled();
|
|
1056
1078
|
expect(device.getInternalState()).toBeUndefined();
|
|
@@ -1072,11 +1094,14 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
1072
1094
|
},
|
|
1073
1095
|
}
|
|
1074
1096
|
);
|
|
1075
|
-
const typedCall = jest
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1097
|
+
const typedCall = jest
|
|
1098
|
+
.fn()
|
|
1099
|
+
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
1100
|
+
.mockRejectedValue(
|
|
1101
|
+
Object.assign(new Error('Invalid session'), {
|
|
1102
|
+
errorCode: HardwareErrorCode.WalletSessionInvalid,
|
|
1103
|
+
})
|
|
1104
|
+
);
|
|
1080
1105
|
(device as any).commands = {
|
|
1081
1106
|
typedCall,
|
|
1082
1107
|
promptPassphrase: jest.fn().mockResolvedValue({ passphrase: 'new-secret' }),
|
|
@@ -1085,7 +1110,14 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
1085
1110
|
await expect(getProtocolV2WalletSession(device)).rejects.toMatchObject({
|
|
1086
1111
|
errorCode: HardwareErrorCode.WalletSessionInvalid,
|
|
1087
1112
|
});
|
|
1088
|
-
expect(typedCall.mock.calls).toEqual([
|
|
1113
|
+
expect(typedCall.mock.calls).toEqual([
|
|
1114
|
+
['ProtocolInfoRequest', 'ProtocolInfo', { eventless_wallet_session: true }],
|
|
1115
|
+
[
|
|
1116
|
+
'DeviceSessionOpen',
|
|
1117
|
+
'DeviceSession',
|
|
1118
|
+
{ select: { host_passphrase: { passphrase: 'new-secret' } } },
|
|
1119
|
+
],
|
|
1120
|
+
]);
|
|
1089
1121
|
});
|
|
1090
1122
|
|
|
1091
1123
|
test('rejects a mismatched Pro2 wallet state and clears the selected cache entry', async () => {
|
|
@@ -1123,7 +1155,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
1123
1155
|
expect(device.getInternalState()).toBeUndefined();
|
|
1124
1156
|
});
|
|
1125
1157
|
|
|
1126
|
-
test('unlocks and retries
|
|
1158
|
+
test('unlocks and retries DeviceSessionOpen when wallet selection is locked', async () => {
|
|
1127
1159
|
const device = Device.fromDescriptor({
|
|
1128
1160
|
id: 'cache-device-4',
|
|
1129
1161
|
path: 'cache-path-4',
|
|
@@ -1138,6 +1170,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
1138
1170
|
});
|
|
1139
1171
|
const typedCall = jest
|
|
1140
1172
|
.fn()
|
|
1173
|
+
.mockResolvedValueOnce({ message: { version: 2 } })
|
|
1141
1174
|
.mockRejectedValueOnce(lockedError)
|
|
1142
1175
|
.mockResolvedValueOnce({
|
|
1143
1176
|
message: {
|
|
@@ -1156,7 +1189,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
1156
1189
|
passphraseState: 'state-after-unlock',
|
|
1157
1190
|
});
|
|
1158
1191
|
expect(unlockDevice).toHaveBeenCalledTimes(1);
|
|
1159
|
-
expect(typedCall).toHaveBeenCalledTimes(
|
|
1192
|
+
expect(typedCall).toHaveBeenCalledTimes(3);
|
|
1160
1193
|
});
|
|
1161
1194
|
|
|
1162
1195
|
test('does not request a Pro2 wallet session before features are initialized', async () => {
|
|
@@ -1273,6 +1306,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
1273
1306
|
promptPassphrase: jest.fn().mockResolvedValue({ passphrase: 'state-pro2-secret' }),
|
|
1274
1307
|
},
|
|
1275
1308
|
updateInternalState,
|
|
1309
|
+
getInternalState: () => 'feature-session',
|
|
1276
1310
|
getCurrentDeviceId: () => 'pro-device-id',
|
|
1277
1311
|
getCurrentPassphraseProtection: () => true,
|
|
1278
1312
|
}) as any;
|
|
@@ -1483,7 +1517,9 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
1483
1517
|
expect(device.getInternalState()).toBeUndefined();
|
|
1484
1518
|
device.passphraseState = 'state-auto';
|
|
1485
1519
|
expect(device.getInternalState()).toBe('session-auto');
|
|
1486
|
-
expect(typedCall).toHaveBeenLastCalledWith('
|
|
1520
|
+
expect(typedCall).toHaveBeenLastCalledWith('DeviceSessionOpen', 'DeviceSession', {
|
|
1521
|
+
select: { host_passphrase: { passphrase: 'state-auto-secret' } },
|
|
1522
|
+
});
|
|
1487
1523
|
});
|
|
1488
1524
|
|
|
1489
1525
|
test('does not mark Pro2 passphrase enabled from a main PIN session alone', async () => {
|
|
@@ -1492,6 +1528,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
1492
1528
|
type: 'DeviceSession',
|
|
1493
1529
|
message: {
|
|
1494
1530
|
session_id: 'main-pin-session',
|
|
1531
|
+
btc_test_address: 'main-wallet-state',
|
|
1495
1532
|
},
|
|
1496
1533
|
});
|
|
1497
1534
|
|
|
@@ -1521,7 +1558,9 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
1521
1558
|
expect(device.features?.passphraseProtection).toBe(false);
|
|
1522
1559
|
expect(device.features?.sessionId).toBeNull();
|
|
1523
1560
|
expect(device.getInternalState()).toBeUndefined();
|
|
1524
|
-
expect(typedCall).
|
|
1561
|
+
expect(typedCall).toHaveBeenCalledWith('ProtocolInfoRequest', 'ProtocolInfo', {
|
|
1562
|
+
eventless_wallet_session: true,
|
|
1563
|
+
});
|
|
1525
1564
|
});
|
|
1526
1565
|
|
|
1527
1566
|
test('does not let skipPassphraseCheck hide Pro2 passphrase state mismatch', async () => {
|
|
@@ -1553,12 +1592,20 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
1553
1592
|
);
|
|
1554
1593
|
|
|
1555
1594
|
expect(device.getInternalState()).toBeUndefined();
|
|
1556
|
-
expect(typedCall).toHaveBeenNthCalledWith(
|
|
1595
|
+
expect(typedCall).toHaveBeenNthCalledWith(2, 'DeviceSessionOpen', 'DeviceSession', {
|
|
1596
|
+
select: { host_passphrase: { passphrase: 'expected-secret' } },
|
|
1597
|
+
});
|
|
1557
1598
|
});
|
|
1558
1599
|
|
|
1559
1600
|
test('useEmptyPassphrase ignores a stale hidden-wallet state during Protocol V2 safety check', async () => {
|
|
1560
1601
|
const device = Device.fromDescriptor({ ...descriptor, protocolType: 'V2' } as any);
|
|
1561
|
-
const typedCall = jest.fn()
|
|
1602
|
+
const typedCall = jest.fn().mockResolvedValue({
|
|
1603
|
+
type: 'DeviceSession',
|
|
1604
|
+
message: {
|
|
1605
|
+
session_id: 'main-wallet-session',
|
|
1606
|
+
btc_test_address: 'main-wallet-state',
|
|
1607
|
+
},
|
|
1608
|
+
});
|
|
1562
1609
|
|
|
1563
1610
|
(device as any).features = normalizeProtocolV2Features(
|
|
1564
1611
|
{ ...descriptor, protocolType: 'V2' } as any,
|
|
@@ -1578,7 +1625,10 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
1578
1625
|
await expect(
|
|
1579
1626
|
device.checkPassphraseStateSafety('stale-hidden-state', true, false)
|
|
1580
1627
|
).resolves.toBe(true);
|
|
1581
|
-
expect(typedCall).
|
|
1628
|
+
expect(typedCall).toHaveBeenCalledTimes(1);
|
|
1629
|
+
expect(typedCall).toHaveBeenCalledWith('ProtocolInfoRequest', 'ProtocolInfo', {
|
|
1630
|
+
eventless_wallet_session: true,
|
|
1631
|
+
});
|
|
1582
1632
|
});
|
|
1583
1633
|
|
|
1584
1634
|
test('marks fallback features as unavailable when DeviceInfo is missing', () => {
|
|
@@ -2237,7 +2287,7 @@ describe('Protocol V2 feature adapter', () => {
|
|
|
2237
2287
|
['DeviceSessionAskPin', 'Success', undefined, { timeoutMs: 120_000 }],
|
|
2238
2288
|
]);
|
|
2239
2289
|
expect(typedCall).not.toHaveBeenCalledWith(
|
|
2240
|
-
'
|
|
2290
|
+
'DeviceSessionOpen',
|
|
2241
2291
|
'DeviceSession',
|
|
2242
2292
|
expect.anything()
|
|
2243
2293
|
);
|
|
@@ -2680,6 +2730,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
2680
2730
|
return Promise.resolve({
|
|
2681
2731
|
type: 'DeviceInfo',
|
|
2682
2732
|
message: {
|
|
2733
|
+
hw: { serial_no: 'BLE-PRO2-SERIAL' },
|
|
2683
2734
|
fw: {
|
|
2684
2735
|
bootloader: { version: '0.0.0' },
|
|
2685
2736
|
application: { version: '0.0.0' },
|
|
@@ -2700,6 +2751,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
2700
2751
|
});
|
|
2701
2752
|
const commands = { typedCall };
|
|
2702
2753
|
|
|
2754
|
+
(method as any).protocolV2ExpectedSerialNumber = 'BLE-PRO2-SERIAL';
|
|
2703
2755
|
(method as any).isBleReconnect = jest.fn(() => true);
|
|
2704
2756
|
(method as any).device = stubDevice({
|
|
2705
2757
|
originalDescriptor: { id: 'ble-id', path: 'ble-path', protocolType: 'V2' },
|
|
@@ -2748,7 +2800,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
2748
2800
|
});
|
|
2749
2801
|
});
|
|
2750
2802
|
|
|
2751
|
-
test('
|
|
2803
|
+
test('delegates Protocol V2 mode transition to the phase executor', async () => {
|
|
2752
2804
|
const method = new FirmwareUpdateV4({
|
|
2753
2805
|
id: 1,
|
|
2754
2806
|
payload: {
|
|
@@ -2761,6 +2813,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
2761
2813
|
originalDescriptor: { id: 'ble-id', path: 'ble-path', protocolType: 'V2' },
|
|
2762
2814
|
features: { capabilities: [] },
|
|
2763
2815
|
});
|
|
2816
|
+
(method as any).captureProtocolV2PhysicalIdentity = jest.fn().mockResolvedValue(undefined);
|
|
2764
2817
|
(method as any).prepareBootloaderBinary = jest.fn().mockReturnValue(null);
|
|
2765
2818
|
(method as any).collectExplicitTargetBinaries = jest.fn().mockReturnValue([
|
|
2766
2819
|
{
|
|
@@ -2782,7 +2835,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
2782
2835
|
|
|
2783
2836
|
await method.run();
|
|
2784
2837
|
|
|
2785
|
-
expect((method as any).enterProtocolV2BootloaderMode).
|
|
2838
|
+
expect((method as any).enterProtocolV2BootloaderMode).not.toHaveBeenCalled();
|
|
2786
2839
|
expect((method as any).executeProtocolV2Update).toHaveBeenCalledWith({
|
|
2787
2840
|
fwBinaryMap: [
|
|
2788
2841
|
{
|
|
@@ -2826,6 +2879,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
2826
2879
|
});
|
|
2827
2880
|
(method as any).reconnectProtocolV2Device = reconnectProtocolV2Device;
|
|
2828
2881
|
(method as any).device.getCommands = () => ({ typedCall });
|
|
2882
|
+
(method as any).protocolV2ExpectedSerialNumber = 'PR9999999999';
|
|
2829
2883
|
method.postTipMessage = jest.fn();
|
|
2830
2884
|
|
|
2831
2885
|
await (method as any).enterProtocolV2BootloaderMode();
|
|
@@ -2891,7 +2945,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
2891
2945
|
});
|
|
2892
2946
|
(method as any).reconnectProtocolV2Device = reconnectProtocolV2Device;
|
|
2893
2947
|
(method as any).device.getCommands = () => ({ typedCall });
|
|
2894
|
-
(method as any).
|
|
2948
|
+
(method as any).protocolV2ExpectedSerialNumber = 'PR9999999999';
|
|
2895
2949
|
|
|
2896
2950
|
await (method as any).waitForProtocolV2BootloaderMode(60 * 1000, 0);
|
|
2897
2951
|
|
|
@@ -3010,7 +3064,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3010
3064
|
fw: { application: { version: '1.0.0' } },
|
|
3011
3065
|
},
|
|
3012
3066
|
});
|
|
3013
|
-
(method as any).
|
|
3067
|
+
(method as any).protocolV2ExpectedSerialNumber = 'expected-serial';
|
|
3014
3068
|
(method as any).reconnectProtocolV2Device = reconnectProtocolV2Device;
|
|
3015
3069
|
(method as any).device = stubDevice({
|
|
3016
3070
|
getCommands: () => ({ typedCall }),
|
|
@@ -3036,6 +3090,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3036
3090
|
});
|
|
3037
3091
|
method.postTipMessage = jest.fn();
|
|
3038
3092
|
(method as any).reconnectProtocolV2Device = jest.fn().mockResolvedValue(undefined);
|
|
3093
|
+
(method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(undefined);
|
|
3039
3094
|
(method as any).protocolV2Reboot = jest.fn().mockResolvedValue({
|
|
3040
3095
|
message: 'Device rebooted successfully',
|
|
3041
3096
|
});
|
|
@@ -3099,9 +3154,9 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3099
3154
|
const typedCall = jest
|
|
3100
3155
|
.fn()
|
|
3101
3156
|
.mockRejectedValue(
|
|
3102
|
-
|
|
3103
|
-
"Failed to execute 'open' on 'USBDevice': The device was disconnected",
|
|
3104
|
-
'NotFoundError'
|
|
3157
|
+
Object.assign(
|
|
3158
|
+
new Error("Failed to execute 'open' on 'USBDevice': The device was disconnected"),
|
|
3159
|
+
{ name: 'NotFoundError' }
|
|
3105
3160
|
)
|
|
3106
3161
|
);
|
|
3107
3162
|
|
|
@@ -3172,6 +3227,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3172
3227
|
getCommands: () => ({ typedCall }),
|
|
3173
3228
|
});
|
|
3174
3229
|
(method as any).reconnectProtocolV2Device = reconnectProtocolV2Device;
|
|
3230
|
+
(method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(undefined);
|
|
3175
3231
|
method.postProgressMessage = jest.fn();
|
|
3176
3232
|
|
|
3177
3233
|
await (method as any).waitForProtocolV2FirmwareUpdateComplete([
|
|
@@ -3188,7 +3244,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3188
3244
|
expect(method.postProgressMessage).toHaveBeenCalledWith(100, 'installingFirmware');
|
|
3189
3245
|
});
|
|
3190
3246
|
|
|
3191
|
-
test('
|
|
3247
|
+
test('does not treat a missing firmware status handler as install completion', async () => {
|
|
3192
3248
|
const method = new FirmwareUpdateV4({
|
|
3193
3249
|
id: 1,
|
|
3194
3250
|
payload: {
|
|
@@ -3204,14 +3260,42 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3204
3260
|
getCommands: () => ({ typedCall }),
|
|
3205
3261
|
});
|
|
3206
3262
|
(method as any).reconnectProtocolV2Device = reconnectProtocolV2Device;
|
|
3263
|
+
(method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(undefined);
|
|
3207
3264
|
method.postProgressMessage = jest.fn();
|
|
3208
3265
|
|
|
3209
|
-
await (
|
|
3210
|
-
|
|
3211
|
-
|
|
3266
|
+
await expect(
|
|
3267
|
+
(method as any).waitForProtocolV2FirmwareUpdateComplete([
|
|
3268
|
+
{ target_id: 4, path: 'vol0:/application_p1.bin' },
|
|
3269
|
+
])
|
|
3270
|
+
).rejects.toThrow('Protocol V2 firmware install status is unavailable');
|
|
3212
3271
|
|
|
3213
3272
|
expect(reconnectProtocolV2Device).toHaveBeenCalledTimes(1);
|
|
3214
|
-
expect(typedCall.mock.calls.map(call => call[0])).toEqual([
|
|
3273
|
+
expect(typedCall.mock.calls.map(call => call[0])).toEqual([
|
|
3274
|
+
'DeviceFirmwareUpdateStatusGet',
|
|
3275
|
+
'DeviceInfoGet',
|
|
3276
|
+
]);
|
|
3277
|
+
});
|
|
3278
|
+
|
|
3279
|
+
test('rejects a finished target whose payload version conflicts with the plan', () => {
|
|
3280
|
+
const method = new FirmwareUpdateV4({
|
|
3281
|
+
id: 1,
|
|
3282
|
+
payload: {
|
|
3283
|
+
method: 'firmwareUpdateV4',
|
|
3284
|
+
platform: 'desktop',
|
|
3285
|
+
expectedTargetVersions: {
|
|
3286
|
+
app_v1: '2.0.0',
|
|
3287
|
+
},
|
|
3288
|
+
},
|
|
3289
|
+
});
|
|
3290
|
+
method.init();
|
|
3291
|
+
method.postProgressMessage = jest.fn();
|
|
3292
|
+
|
|
3293
|
+
expect(() =>
|
|
3294
|
+
(method as any).assertProtocolV2TargetStatus(
|
|
3295
|
+
[{ target_id: 4, status: 2, payload_version: 0x010000 }],
|
|
3296
|
+
new Set([4])
|
|
3297
|
+
)
|
|
3298
|
+
).toThrow('expected 131072');
|
|
3215
3299
|
});
|
|
3216
3300
|
|
|
3217
3301
|
test('polls target status after update ACK and finishes when all targets complete', async () => {
|
|
@@ -3236,6 +3320,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3236
3320
|
getCommands: () => ({ typedCall }),
|
|
3237
3321
|
});
|
|
3238
3322
|
(method as any).reconnectProtocolV2Device = reconnectProtocolV2Device;
|
|
3323
|
+
(method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(undefined);
|
|
3239
3324
|
method.postProgressMessage = jest.fn();
|
|
3240
3325
|
|
|
3241
3326
|
await expect(
|
|
@@ -3353,6 +3438,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3353
3438
|
getCommands: () => ({ typedCall }),
|
|
3354
3439
|
});
|
|
3355
3440
|
(method as any).reconnectProtocolV2Device = jest.fn().mockResolvedValue(undefined);
|
|
3441
|
+
(method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(undefined);
|
|
3356
3442
|
(method as any).probeProtocolV2NormalMode = jest.fn().mockResolvedValue(false);
|
|
3357
3443
|
|
|
3358
3444
|
await expect(
|
|
@@ -3388,10 +3474,14 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3388
3474
|
const writtenPaths: string[] = [];
|
|
3389
3475
|
method.postTipMessage = jest.fn();
|
|
3390
3476
|
method.postProgressMessage = jest.fn();
|
|
3391
|
-
(method as any).
|
|
3477
|
+
(method as any).protocolV2SourceUpdateProcess = jest.fn().mockImplementation(params => {
|
|
3392
3478
|
writtenPaths.push(params.filePath);
|
|
3393
|
-
return Number(params.processedSize ?? 0) + Number(params.
|
|
3479
|
+
return Number(params.processedSize ?? 0) + Number(params.source.size);
|
|
3394
3480
|
});
|
|
3481
|
+
(method as any).enterProtocolV2BootloaderMode = jest.fn().mockResolvedValue(undefined);
|
|
3482
|
+
(method as any).exitProtocolV2BootloaderToNormal = jest.fn().mockResolvedValue(undefined);
|
|
3483
|
+
(method as any).waitForProtocolV2FinalFeatures = jest.fn().mockResolvedValue({});
|
|
3484
|
+
(method as any).completeProtocolV2FinalVerification = jest.fn().mockResolvedValue({});
|
|
3395
3485
|
(method as any).verifyProtocolV2StagedFile = jest.fn().mockResolvedValue(undefined);
|
|
3396
3486
|
(method as any).protocolV2StartFirmwareUpdate = jest.fn().mockResolvedValue(undefined);
|
|
3397
3487
|
(method as any).waitForProtocolV2FirmwareUpdateComplete = jest
|
|
@@ -3431,10 +3521,12 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3431
3521
|
'vol0:/coprocessor.bin',
|
|
3432
3522
|
1
|
|
3433
3523
|
);
|
|
3434
|
-
expect((method as any).protocolV2StartFirmwareUpdate).toHaveBeenCalledTimes(
|
|
3435
|
-
expect((method as any).protocolV2StartFirmwareUpdate).
|
|
3524
|
+
expect((method as any).protocolV2StartFirmwareUpdate).toHaveBeenCalledTimes(2);
|
|
3525
|
+
expect((method as any).protocolV2StartFirmwareUpdate).toHaveBeenNthCalledWith(1, {
|
|
3526
|
+
targets: [{ target_id: 3, path: 'vol0:/bootloader.bin' }],
|
|
3527
|
+
});
|
|
3528
|
+
expect((method as any).protocolV2StartFirmwareUpdate).toHaveBeenNthCalledWith(2, {
|
|
3436
3529
|
targets: [
|
|
3437
|
-
{ target_id: 3, path: 'vol0:/bootloader.bin' },
|
|
3438
3530
|
{ target_id: 6, path: 'vol0:/coprocessor.bin' },
|
|
3439
3531
|
{ target_id: 7, path: 'vol0:/se01.bin' },
|
|
3440
3532
|
{ target_id: 4, path: 'vol0:/application_p1.bin' },
|
|
@@ -3444,7 +3536,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3444
3536
|
expect((method as any).waitForProtocolV2FirmwareUpdateComplete).toHaveBeenCalled();
|
|
3445
3537
|
});
|
|
3446
3538
|
|
|
3447
|
-
test('announces
|
|
3539
|
+
test('announces separate resource and component transfer phases', async () => {
|
|
3448
3540
|
const method = new FirmwareUpdateV4({
|
|
3449
3541
|
id: 1,
|
|
3450
3542
|
payload: {
|
|
@@ -3454,11 +3546,14 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3454
3546
|
|
|
3455
3547
|
method.postTipMessage = jest.fn();
|
|
3456
3548
|
method.postProgressMessage = jest.fn();
|
|
3457
|
-
(method as any).
|
|
3549
|
+
(method as any).protocolV2SourceUpdateProcess = jest
|
|
3458
3550
|
.fn()
|
|
3459
3551
|
.mockImplementation(params =>
|
|
3460
|
-
Promise.resolve(Number(params.processedSize ?? 0) + Number(params.
|
|
3552
|
+
Promise.resolve(Number(params.processedSize ?? 0) + Number(params.source.size))
|
|
3461
3553
|
);
|
|
3554
|
+
(method as any).enterProtocolV2BootloaderMode = jest.fn().mockResolvedValue(undefined);
|
|
3555
|
+
(method as any).exitProtocolV2BootloaderToNormal = jest.fn().mockResolvedValue(undefined);
|
|
3556
|
+
(method as any).completeProtocolV2FinalVerification = jest.fn().mockResolvedValue({});
|
|
3462
3557
|
(method as any).verifyProtocolV2StagedFile = jest.fn().mockResolvedValue(undefined);
|
|
3463
3558
|
(method as any).protocolV2StartFirmwareUpdate = jest.fn().mockResolvedValue(undefined);
|
|
3464
3559
|
(method as any).waitForProtocolV2FirmwareUpdateComplete = jest
|
|
@@ -3478,21 +3573,22 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3478
3573
|
{
|
|
3479
3574
|
fileName: 'application_p1.bin',
|
|
3480
3575
|
binary: new Uint8Array([3]).buffer,
|
|
3481
|
-
targetId:
|
|
3576
|
+
targetId: 4,
|
|
3482
3577
|
},
|
|
3483
3578
|
],
|
|
3484
3579
|
});
|
|
3485
3580
|
|
|
3486
|
-
expect(method.postTipMessage).toHaveBeenCalledTimes(
|
|
3581
|
+
expect(method.postTipMessage).toHaveBeenCalledTimes(3);
|
|
3487
3582
|
expect(method.postTipMessage).toHaveBeenNthCalledWith(1, 'StartTransferData');
|
|
3488
|
-
expect(method.postTipMessage).toHaveBeenNthCalledWith(2, '
|
|
3489
|
-
expect(
|
|
3583
|
+
expect(method.postTipMessage).toHaveBeenNthCalledWith(2, 'StartTransferData');
|
|
3584
|
+
expect(method.postTipMessage).toHaveBeenNthCalledWith(3, 'ConfirmOnDevice');
|
|
3585
|
+
expect((method as any).protocolV2SourceUpdateProcess).toHaveBeenNthCalledWith(
|
|
3490
3586
|
1,
|
|
3491
|
-
expect.objectContaining({ processedSize: 0, totalSize:
|
|
3587
|
+
expect.objectContaining({ processedSize: 0, totalSize: 2 })
|
|
3492
3588
|
);
|
|
3493
|
-
expect((method as any).
|
|
3589
|
+
expect((method as any).protocolV2SourceUpdateProcess).toHaveBeenNthCalledWith(
|
|
3494
3590
|
2,
|
|
3495
|
-
expect.objectContaining({ processedSize:
|
|
3591
|
+
expect.objectContaining({ processedSize: 0, totalSize: 1 })
|
|
3496
3592
|
);
|
|
3497
3593
|
});
|
|
3498
3594
|
|
|
@@ -3506,7 +3602,8 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3506
3602
|
|
|
3507
3603
|
method.postTipMessage = jest.fn();
|
|
3508
3604
|
method.postProgressMessage = jest.fn();
|
|
3509
|
-
(method as any).
|
|
3605
|
+
(method as any).protocolV2SourceUpdateProcess = jest.fn().mockResolvedValue(3);
|
|
3606
|
+
(method as any).enterProtocolV2BootloaderMode = jest.fn().mockResolvedValue(undefined);
|
|
3510
3607
|
(method as any).device = stubDevice({
|
|
3511
3608
|
getCommands: () => ({
|
|
3512
3609
|
typedCall: jest.fn().mockResolvedValue({
|
|
@@ -3552,11 +3649,14 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3552
3649
|
|
|
3553
3650
|
method.postTipMessage = jest.fn();
|
|
3554
3651
|
method.postProgressMessage = jest.fn();
|
|
3555
|
-
(method as any).
|
|
3652
|
+
(method as any).protocolV2SourceUpdateProcess = jest
|
|
3556
3653
|
.fn()
|
|
3557
3654
|
.mockImplementation(params =>
|
|
3558
|
-
Promise.resolve(Number(params.processedSize ?? 0) + Number(params.
|
|
3655
|
+
Promise.resolve(Number(params.processedSize ?? 0) + Number(params.source.size))
|
|
3559
3656
|
);
|
|
3657
|
+
(method as any).enterProtocolV2BootloaderMode = jest.fn().mockResolvedValue(undefined);
|
|
3658
|
+
(method as any).exitProtocolV2BootloaderToNormal = jest.fn().mockResolvedValue(undefined);
|
|
3659
|
+
(method as any).completeProtocolV2FinalVerification = jest.fn().mockResolvedValue({});
|
|
3560
3660
|
(method as any).verifyProtocolV2StagedFile = jest.fn().mockResolvedValue(undefined);
|
|
3561
3661
|
(method as any).protocolV2StartFirmwareUpdate = jest.fn().mockResolvedValue(undefined);
|
|
3562
3662
|
(method as any).waitForProtocolV2FirmwareUpdateComplete = jest
|
|
@@ -3736,7 +3836,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3736
3836
|
{
|
|
3737
3837
|
name: 'images',
|
|
3738
3838
|
url: 'https://example.com/images.okpkg',
|
|
3739
|
-
devicePath: '
|
|
3839
|
+
devicePath: 'VOL0:/resource/images/images.okpkg',
|
|
3740
3840
|
version: [2, 0, 0],
|
|
3741
3841
|
payloadHash: 'ab'.repeat(64),
|
|
3742
3842
|
headerHash: 'cd'.repeat(64),
|
|
@@ -3771,6 +3871,58 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3771
3871
|
getFirmwareLatestReleaseSpy.mockRestore();
|
|
3772
3872
|
});
|
|
3773
3873
|
|
|
3874
|
+
test('rejects remote RESC bundle paths before download or bootloader entry', async () => {
|
|
3875
|
+
const method = new FirmwareUpdateV4({
|
|
3876
|
+
id: 1,
|
|
3877
|
+
payload: {
|
|
3878
|
+
method: 'firmwareUpdateV4',
|
|
3879
|
+
platform: 'web',
|
|
3880
|
+
targetsToUpdate: ['resource'],
|
|
3881
|
+
},
|
|
3882
|
+
});
|
|
3883
|
+
method.init();
|
|
3884
|
+
(method as any).captureProtocolV2PhysicalIdentity = jest.fn().mockResolvedValue(undefined);
|
|
3885
|
+
|
|
3886
|
+
const getSysResourceBinarySpy = jest.spyOn(firmwareBinaryApi, 'getSysResourceBinary');
|
|
3887
|
+
const getFirmwareLatestReleaseSpy = jest
|
|
3888
|
+
.spyOn(DataManager, 'getFirmwareLatestRelease')
|
|
3889
|
+
.mockReturnValue({
|
|
3890
|
+
required: false,
|
|
3891
|
+
version: [1, 0, 0],
|
|
3892
|
+
url: '',
|
|
3893
|
+
resourceBundles: [
|
|
3894
|
+
{
|
|
3895
|
+
name: 'images',
|
|
3896
|
+
url: 'https://example.com/images.okpkg',
|
|
3897
|
+
devicePath: 'vol0:/resource/../images.okpkg',
|
|
3898
|
+
},
|
|
3899
|
+
],
|
|
3900
|
+
fingerprint: '',
|
|
3901
|
+
changelog: {
|
|
3902
|
+
'zh-CN': '',
|
|
3903
|
+
'en-US': '',
|
|
3904
|
+
},
|
|
3905
|
+
});
|
|
3906
|
+
|
|
3907
|
+
(method as any).device = stubDevice({
|
|
3908
|
+
originalDescriptor: { protocolType: 'V2' },
|
|
3909
|
+
features: { deviceType: 'pro2', firmwareVersion: '1.0.0', capabilities: [] },
|
|
3910
|
+
});
|
|
3911
|
+
(method as any).prepareRemoteProtocolV2Binaries = jest.fn().mockResolvedValue({
|
|
3912
|
+
bootloaderBinary: null,
|
|
3913
|
+
fwBinaryMap: [],
|
|
3914
|
+
});
|
|
3915
|
+
(method as any).enterProtocolV2BootloaderMode = jest.fn();
|
|
3916
|
+
method.postTipMessage = jest.fn();
|
|
3917
|
+
|
|
3918
|
+
await expect(method.run()).rejects.toThrow('resourceBundles[0].devicePath');
|
|
3919
|
+
expect(getSysResourceBinarySpy).not.toHaveBeenCalled();
|
|
3920
|
+
expect((method as any).enterProtocolV2BootloaderMode).not.toHaveBeenCalled();
|
|
3921
|
+
|
|
3922
|
+
getSysResourceBinarySpy.mockRestore();
|
|
3923
|
+
getFirmwareLatestReleaseSpy.mockRestore();
|
|
3924
|
+
});
|
|
3925
|
+
|
|
3774
3926
|
test('downloads and validates remote RESC bundles before entering bootloader', async () => {
|
|
3775
3927
|
const method = new FirmwareUpdateV4({
|
|
3776
3928
|
id: 1,
|
|
@@ -3781,6 +3933,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3781
3933
|
},
|
|
3782
3934
|
});
|
|
3783
3935
|
method.init();
|
|
3936
|
+
(method as any).captureProtocolV2PhysicalIdentity = jest.fn().mockResolvedValue(undefined);
|
|
3784
3937
|
|
|
3785
3938
|
const order: string[] = [];
|
|
3786
3939
|
const resourceBinary = new Uint8Array([1, 2, 3]).buffer;
|
|
@@ -3800,7 +3953,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3800
3953
|
{
|
|
3801
3954
|
name: 'images',
|
|
3802
3955
|
url: 'https://example.com/images.okpkg',
|
|
3803
|
-
devicePath: '
|
|
3956
|
+
devicePath: ' VOL0:/resource/images/images.okpkg ',
|
|
3804
3957
|
},
|
|
3805
3958
|
],
|
|
3806
3959
|
fingerprint: '',
|
|
@@ -3822,7 +3975,9 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3822
3975
|
order.push('bootloader');
|
|
3823
3976
|
return Promise.resolve(true);
|
|
3824
3977
|
});
|
|
3825
|
-
(method as any
|
|
3978
|
+
const executeProtocolV2UpdateSpy = jest.spyOn(method as any, 'executeProtocolV2Update');
|
|
3979
|
+
(method as any).executeProtocolV2TransferPhase = jest.fn().mockResolvedValue(undefined);
|
|
3980
|
+
(method as any).completeProtocolV2FinalVerification = jest.fn().mockResolvedValue(undefined);
|
|
3826
3981
|
(method as any).exitProtocolV2BootloaderToNormal = jest.fn().mockResolvedValue(undefined);
|
|
3827
3982
|
(method as any).waitForProtocolV2FinalFeatures = jest.fn().mockResolvedValue({
|
|
3828
3983
|
bootloaderVersion: '1.0.0',
|
|
@@ -3834,7 +3989,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3834
3989
|
await method.run();
|
|
3835
3990
|
|
|
3836
3991
|
expect(order).toEqual(['download', 'bootloader']);
|
|
3837
|
-
expect(
|
|
3992
|
+
expect(executeProtocolV2UpdateSpy).toHaveBeenCalledWith({
|
|
3838
3993
|
bootloaderBinary: null,
|
|
3839
3994
|
fwBinaryMap: [],
|
|
3840
3995
|
resourceBundles: [
|
|
@@ -3847,6 +4002,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3847
4002
|
],
|
|
3848
4003
|
});
|
|
3849
4004
|
|
|
4005
|
+
executeProtocolV2UpdateSpy.mockRestore();
|
|
3850
4006
|
getSysResourceBinarySpy.mockRestore();
|
|
3851
4007
|
getFirmwareLatestReleaseSpy.mockRestore();
|
|
3852
4008
|
});
|
|
@@ -3861,6 +4017,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3861
4017
|
},
|
|
3862
4018
|
});
|
|
3863
4019
|
method.init();
|
|
4020
|
+
(method as any).captureProtocolV2PhysicalIdentity = jest.fn().mockResolvedValue(undefined);
|
|
3864
4021
|
|
|
3865
4022
|
const getSysResourceBinarySpy = jest
|
|
3866
4023
|
.spyOn(firmwareBinaryApi, 'getSysResourceBinary')
|
|
@@ -3972,6 +4129,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3972
4129
|
},
|
|
3973
4130
|
});
|
|
3974
4131
|
method.init();
|
|
4132
|
+
(method as any).captureProtocolV2PhysicalIdentity = jest.fn().mockResolvedValue(undefined);
|
|
3975
4133
|
|
|
3976
4134
|
const remoteBinaries = {
|
|
3977
4135
|
bootloaderBinary: new Uint8Array([1]).buffer,
|
|
@@ -4018,6 +4176,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
4018
4176
|
},
|
|
4019
4177
|
});
|
|
4020
4178
|
method.init();
|
|
4179
|
+
(method as any).captureProtocolV2PhysicalIdentity = jest.fn().mockResolvedValue(undefined);
|
|
4021
4180
|
|
|
4022
4181
|
(method as any).device = stubDevice({
|
|
4023
4182
|
originalDescriptor: { protocolType: 'V2' },
|
|
@@ -4053,12 +4212,13 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
4053
4212
|
resourceBundleFiles: [
|
|
4054
4213
|
{
|
|
4055
4214
|
binary: resourceBundle,
|
|
4056
|
-
devicePath: '
|
|
4215
|
+
devicePath: ' VOL0:/resource/images/images.okpkg ',
|
|
4057
4216
|
},
|
|
4058
4217
|
],
|
|
4059
4218
|
},
|
|
4060
4219
|
});
|
|
4061
4220
|
method.init();
|
|
4221
|
+
(method as any).captureProtocolV2PhysicalIdentity = jest.fn().mockResolvedValue(undefined);
|
|
4062
4222
|
|
|
4063
4223
|
(method as any).device = stubDevice({
|
|
4064
4224
|
originalDescriptor: { protocolType: 'V2' },
|
|
@@ -4091,6 +4251,36 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
4091
4251
|
);
|
|
4092
4252
|
});
|
|
4093
4253
|
|
|
4254
|
+
test('rejects manual RESC bundle paths before bootloader entry', async () => {
|
|
4255
|
+
const method = new FirmwareUpdateV4({
|
|
4256
|
+
id: 1,
|
|
4257
|
+
payload: {
|
|
4258
|
+
method: 'firmwareUpdateV4',
|
|
4259
|
+
platform: 'web',
|
|
4260
|
+
resourceBundleFiles: [
|
|
4261
|
+
{
|
|
4262
|
+
binary: new Uint8Array([1, 2, 3]).buffer,
|
|
4263
|
+
devicePath: 'vol2:/resource/images/images.okpkg',
|
|
4264
|
+
},
|
|
4265
|
+
],
|
|
4266
|
+
},
|
|
4267
|
+
});
|
|
4268
|
+
method.init();
|
|
4269
|
+
(method as any).captureProtocolV2PhysicalIdentity = jest.fn().mockResolvedValue(undefined);
|
|
4270
|
+
|
|
4271
|
+
(method as any).device = stubDevice({
|
|
4272
|
+
originalDescriptor: { protocolType: 'V2' },
|
|
4273
|
+
features: { deviceType: 'pro2', firmwareVersion: '0.0.0', capabilities: [] },
|
|
4274
|
+
});
|
|
4275
|
+
(method as any).prepareRemoteProtocolV2Binaries = jest.fn();
|
|
4276
|
+
(method as any).enterProtocolV2BootloaderMode = jest.fn();
|
|
4277
|
+
method.postTipMessage = jest.fn();
|
|
4278
|
+
|
|
4279
|
+
await expect(method.run()).rejects.toThrow('resourceBundleFiles[0].devicePath');
|
|
4280
|
+
expect((method as any).prepareRemoteProtocolV2Binaries).not.toHaveBeenCalled();
|
|
4281
|
+
expect((method as any).enterProtocolV2BootloaderMode).not.toHaveBeenCalled();
|
|
4282
|
+
});
|
|
4283
|
+
|
|
4094
4284
|
test('syncs resource bundles without sending a firmware install request', async () => {
|
|
4095
4285
|
const method = new FirmwareUpdateV4({
|
|
4096
4286
|
id: 1,
|
|
@@ -4101,7 +4291,10 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
4101
4291
|
|
|
4102
4292
|
method.postTipMessage = jest.fn();
|
|
4103
4293
|
method.postProgressMessage = jest.fn();
|
|
4104
|
-
(method as any).
|
|
4294
|
+
(method as any).protocolV2SourceUpdateProcess = jest.fn().mockResolvedValue(3);
|
|
4295
|
+
(method as any).enterProtocolV2BootloaderMode = jest.fn().mockResolvedValue(undefined);
|
|
4296
|
+
(method as any).completeProtocolV2FinalVerification = jest.fn().mockResolvedValue({});
|
|
4297
|
+
(method as any).verifyProtocolV2StagedFile = jest.fn().mockResolvedValue(undefined);
|
|
4105
4298
|
(method as any).protocolV2StartFirmwareUpdate = jest.fn();
|
|
4106
4299
|
(method as any).waitForProtocolV2FirmwareUpdateComplete = jest.fn();
|
|
4107
4300
|
|
|
@@ -4117,7 +4310,7 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
4117
4310
|
fwBinaryMap: [],
|
|
4118
4311
|
});
|
|
4119
4312
|
|
|
4120
|
-
expect((method as any).
|
|
4313
|
+
expect((method as any).protocolV2SourceUpdateProcess).toHaveBeenCalledTimes(1);
|
|
4121
4314
|
expect((method as any).protocolV2StartFirmwareUpdate).not.toHaveBeenCalled();
|
|
4122
4315
|
expect((method as any).waitForProtocolV2FirmwareUpdateComplete).not.toHaveBeenCalled();
|
|
4123
4316
|
});
|
|
@@ -4148,12 +4341,19 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
4148
4341
|
});
|
|
4149
4342
|
method.postProgressMessage = jest.fn();
|
|
4150
4343
|
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
filePath: 'vol1:firmware.bin',
|
|
4154
|
-
processedSize: 0,
|
|
4155
|
-
totalSize: 4097,
|
|
4344
|
+
const source = await openFirmwareByteSource({
|
|
4345
|
+
binary: new Uint8Array(4097).buffer,
|
|
4156
4346
|
});
|
|
4347
|
+
try {
|
|
4348
|
+
await (method as any).protocolV2SourceUpdateProcess({
|
|
4349
|
+
source,
|
|
4350
|
+
filePath: 'vol1:firmware.bin',
|
|
4351
|
+
processedSize: 0,
|
|
4352
|
+
totalSize: 4097,
|
|
4353
|
+
});
|
|
4354
|
+
} finally {
|
|
4355
|
+
await source?.close();
|
|
4356
|
+
}
|
|
4157
4357
|
|
|
4158
4358
|
const writePayloads = typedCall.mock.calls.map(call => call[2]);
|
|
4159
4359
|
expect(writePayloads.map(payload => payload.file.offset)).toEqual([0, 4000]);
|
|
@@ -4204,12 +4404,16 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
4204
4404
|
method.postProgressMessage = jest.fn();
|
|
4205
4405
|
|
|
4206
4406
|
try {
|
|
4207
|
-
|
|
4208
|
-
|
|
4407
|
+
const source = await openFirmwareByteSource({
|
|
4408
|
+
binary: new Uint8Array(8001).buffer,
|
|
4409
|
+
});
|
|
4410
|
+
await (method as any).protocolV2SourceUpdateProcess({
|
|
4411
|
+
source,
|
|
4209
4412
|
filePath: 'vol0:/firmware.bin',
|
|
4210
4413
|
processedSize: 0,
|
|
4211
4414
|
totalSize: 8001,
|
|
4212
4415
|
});
|
|
4416
|
+
await source?.close();
|
|
4213
4417
|
} finally {
|
|
4214
4418
|
setTimeoutSpy.mockRestore();
|
|
4215
4419
|
}
|
|
@@ -4241,16 +4445,21 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
4241
4445
|
});
|
|
4242
4446
|
method.postProgressMessage = jest.fn();
|
|
4243
4447
|
method.postTipMessage = jest.fn();
|
|
4448
|
+
(method as any).recoverProtocolV2FileTransfer = jest.fn().mockResolvedValue(undefined);
|
|
4244
4449
|
|
|
4450
|
+
const source = await openFirmwareByteSource({
|
|
4451
|
+
binary: new Uint8Array(4097).buffer,
|
|
4452
|
+
});
|
|
4245
4453
|
await expect(
|
|
4246
|
-
(method as any).
|
|
4247
|
-
|
|
4454
|
+
(method as any).protocolV2SourceUpdateProcess({
|
|
4455
|
+
source,
|
|
4248
4456
|
filePath: 'vol0:/firmware.bin',
|
|
4249
4457
|
processedSize: 0,
|
|
4250
4458
|
totalSize: 4097,
|
|
4251
4459
|
})
|
|
4252
4460
|
).rejects.toMatchObject({ errorCode: HardwareErrorCode.EmmcFileWriteFirmwareError });
|
|
4253
|
-
|
|
4461
|
+
await source?.close();
|
|
4462
|
+
expect(typedCall).toHaveBeenCalledTimes(6);
|
|
4254
4463
|
});
|
|
4255
4464
|
|
|
4256
4465
|
test('caps native BLE firmware upload chunks below the WebUSB limit', async () => {
|
|
@@ -4283,12 +4492,19 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
4283
4492
|
});
|
|
4284
4493
|
method.postProgressMessage = jest.fn();
|
|
4285
4494
|
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
filePath: 'vol1:ble-firmware.bin',
|
|
4289
|
-
processedSize: 0,
|
|
4290
|
-
totalSize: 1801,
|
|
4495
|
+
const source = await openFirmwareByteSource({
|
|
4496
|
+
binary: new Uint8Array(1801).buffer,
|
|
4291
4497
|
});
|
|
4498
|
+
try {
|
|
4499
|
+
await (method as any).protocolV2SourceUpdateProcess({
|
|
4500
|
+
source,
|
|
4501
|
+
filePath: 'vol1:ble-firmware.bin',
|
|
4502
|
+
processedSize: 0,
|
|
4503
|
+
totalSize: 1801,
|
|
4504
|
+
});
|
|
4505
|
+
} finally {
|
|
4506
|
+
await source?.close();
|
|
4507
|
+
}
|
|
4292
4508
|
|
|
4293
4509
|
const writePayloads = typedCall.mock.calls.map(call => call[2]);
|
|
4294
4510
|
expect(writePayloads.map(payload => payload.file.offset)).toEqual([0, 1800]);
|
|
@@ -4405,9 +4621,9 @@ describe('Protocol V2 firmware update method', () => {
|
|
|
4405
4621
|
const typedCall = jest
|
|
4406
4622
|
.fn()
|
|
4407
4623
|
.mockRejectedValue(
|
|
4408
|
-
|
|
4409
|
-
"Failed to execute 'open' on 'USBDevice': The device was disconnected",
|
|
4410
|
-
'NotFoundError'
|
|
4624
|
+
Object.assign(
|
|
4625
|
+
new Error("Failed to execute 'open' on 'USBDevice': The device was disconnected"),
|
|
4626
|
+
{ name: 'NotFoundError' }
|
|
4411
4627
|
)
|
|
4412
4628
|
);
|
|
4413
4629
|
|
|
@@ -4572,29 +4788,64 @@ describe('Protocol V2 firmware update method', () => {
|
|
|
4572
4788
|
});
|
|
4573
4789
|
|
|
4574
4790
|
describe('Protocol V2 firmware reconnect identity', () => {
|
|
4575
|
-
test('
|
|
4576
|
-
|
|
4791
|
+
test('keeps the host plan identity as the V4 reconnect anchor', () => {
|
|
4792
|
+
const method = new FirmwareUpdateV4({
|
|
4793
|
+
id: 1,
|
|
4794
|
+
payload: {
|
|
4795
|
+
method: 'firmwareUpdateV4',
|
|
4796
|
+
platform: 'native',
|
|
4797
|
+
expectedDeviceId: 'persisted-device-id',
|
|
4798
|
+
},
|
|
4799
|
+
});
|
|
4800
|
+
|
|
4801
|
+
method.init();
|
|
4802
|
+
|
|
4803
|
+
expect((method as any).params.expectedDeviceId).toBe('persisted-device-id');
|
|
4804
|
+
});
|
|
4805
|
+
|
|
4806
|
+
test('requires the same physical serial before firmware transfer resumes', () => {
|
|
4807
|
+
expect(() => assertProtocolV2ReconnectIdentity('expected-serial', 'other-serial')).toThrow(
|
|
4577
4808
|
'identity mismatch'
|
|
4578
4809
|
);
|
|
4579
|
-
expect(() => assertProtocolV2ReconnectIdentity('expected-
|
|
4810
|
+
expect(() => assertProtocolV2ReconnectIdentity('expected-serial', undefined)).toThrow(
|
|
4580
4811
|
'identity unavailable'
|
|
4581
4812
|
);
|
|
4582
4813
|
expect(() =>
|
|
4583
|
-
assertProtocolV2ReconnectIdentity('expected-
|
|
4814
|
+
assertProtocolV2ReconnectIdentity('expected-serial', 'expected-serial')
|
|
4584
4815
|
).not.toThrow();
|
|
4816
|
+
expect(() => assertProtocolV2ReconnectIdentity(undefined, 'actual-serial')).toThrow(
|
|
4817
|
+
'identity unavailable'
|
|
4818
|
+
);
|
|
4585
4819
|
});
|
|
4586
4820
|
|
|
4587
|
-
test('
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4821
|
+
test('captures physical identity from active DeviceInfo instead of wallet deviceId', async () => {
|
|
4822
|
+
const method = new FirmwareUpdateV4({
|
|
4823
|
+
id: 1,
|
|
4824
|
+
payload: {
|
|
4825
|
+
method: 'firmwareUpdateV4',
|
|
4826
|
+
},
|
|
4827
|
+
});
|
|
4828
|
+
const typedCall = jest.fn().mockResolvedValue({
|
|
4829
|
+
type: 'DeviceInfo',
|
|
4830
|
+
message: {
|
|
4831
|
+
protocol_version: 1,
|
|
4832
|
+
hw: { serial_no: 'PRO2-PHYSICAL-1' },
|
|
4833
|
+
},
|
|
4834
|
+
});
|
|
4835
|
+
(method as any).device = stubDevice({
|
|
4836
|
+
features: { deviceId: 'wallet-derived-id' },
|
|
4837
|
+
getCommands: () => ({ typedCall }),
|
|
4838
|
+
});
|
|
4839
|
+
|
|
4840
|
+
await (method as any).captureProtocolV2PhysicalIdentity();
|
|
4841
|
+
|
|
4842
|
+
expect((method as any).protocolV2ExpectedSerialNumber).toBe('PRO2-PHYSICAL-1');
|
|
4843
|
+
expect(typedCall).toHaveBeenCalledWith(
|
|
4844
|
+
'DeviceInfoGet',
|
|
4845
|
+
'DeviceInfo',
|
|
4846
|
+
expect.objectContaining({ targets: expect.objectContaining({ hw: true }) }),
|
|
4847
|
+
{ timeoutMs: 5000 }
|
|
4848
|
+
);
|
|
4598
4849
|
});
|
|
4599
4850
|
});
|
|
4600
4851
|
|
|
@@ -4672,7 +4923,7 @@ describe('Protocol V2 protected method execution', () => {
|
|
|
4672
4923
|
errorCode: HardwareErrorCode.DeviceLocked,
|
|
4673
4924
|
});
|
|
4674
4925
|
|
|
4675
|
-
test('
|
|
4926
|
+
test('does not replay SDK methods unless they are explicitly classified as retry-safe', () => {
|
|
4676
4927
|
class TestBusinessMethod extends BaseMethod {
|
|
4677
4928
|
init() {}
|
|
4678
4929
|
|
|
@@ -4686,7 +4937,7 @@ describe('Protocol V2 protected method execution', () => {
|
|
|
4686
4937
|
payload: { method: 'testBusinessMethod' },
|
|
4687
4938
|
} as any);
|
|
4688
4939
|
|
|
4689
|
-
expect(method.unlockPolicy).toBe('
|
|
4940
|
+
expect(method.unlockPolicy).toBe('none');
|
|
4690
4941
|
});
|
|
4691
4942
|
|
|
4692
4943
|
test.each([
|
|
@@ -4724,7 +4975,6 @@ describe('Protocol V2 protected method execution', () => {
|
|
|
4724
4975
|
test.each([
|
|
4725
4976
|
['deviceInfoGet', DeviceInfoGet],
|
|
4726
4977
|
['deviceStatusGet', DeviceStatusGet],
|
|
4727
|
-
['deviceSettingsGet', DeviceSettingsGet],
|
|
4728
4978
|
])('does not auto-unlock the read-only %s method', (_name, MethodClass) => {
|
|
4729
4979
|
const method = new MethodClass({
|
|
4730
4980
|
id: 1,
|
|
@@ -4782,7 +5032,7 @@ describe('Protocol V2 protected method execution', () => {
|
|
|
4782
5032
|
const calls: string[] = [];
|
|
4783
5033
|
const method = {
|
|
4784
5034
|
name: 'deviceSettingsPageShow',
|
|
4785
|
-
unlockPolicy: '
|
|
5035
|
+
unlockPolicy: 'unlock-before-run',
|
|
4786
5036
|
protocolV2UiInteraction: { reason: 'settings-page' },
|
|
4787
5037
|
run: jest.fn(() => {
|
|
4788
5038
|
calls.push('run');
|
|
@@ -4866,14 +5116,12 @@ describe('Protocol V2 protected method execution', () => {
|
|
|
4866
5116
|
test('keeps auto unlock but suppresses all synthesized UI for eventless methods', async () => {
|
|
4867
5117
|
const method = {
|
|
4868
5118
|
name: 'uploadPortfolio',
|
|
4869
|
-
unlockPolicy: '
|
|
5119
|
+
unlockPolicy: 'unlock-before-run',
|
|
4870
5120
|
protocolV2UiMode: 'none',
|
|
4871
|
-
run: jest
|
|
4872
|
-
.fn()
|
|
4873
|
-
.mockRejectedValueOnce(deviceLockedError())
|
|
4874
|
-
.mockResolvedValueOnce({ message: 'ok' }),
|
|
5121
|
+
run: jest.fn().mockResolvedValue({ message: 'ok' }),
|
|
4875
5122
|
};
|
|
4876
5123
|
const device = {
|
|
5124
|
+
features: { unlocked: false },
|
|
4877
5125
|
isProtocolV2: () => true,
|
|
4878
5126
|
unlockDevice: jest.fn().mockResolvedValue(undefined),
|
|
4879
5127
|
};
|
|
@@ -4892,6 +5140,24 @@ describe('Protocol V2 protected method execution', () => {
|
|
|
4892
5140
|
expect(uiCoordinator.resumeMethodInteraction).not.toHaveBeenCalled();
|
|
4893
5141
|
});
|
|
4894
5142
|
|
|
5143
|
+
test('does not replay a state-changing method after a locked response', async () => {
|
|
5144
|
+
const error = deviceLockedError();
|
|
5145
|
+
const method = {
|
|
5146
|
+
name: 'uploadPortfolio',
|
|
5147
|
+
unlockPolicy: 'unlock-before-run',
|
|
5148
|
+
run: jest.fn().mockRejectedValue(error),
|
|
5149
|
+
};
|
|
5150
|
+
const device = {
|
|
5151
|
+
features: { unlocked: true },
|
|
5152
|
+
isProtocolV2: () => true,
|
|
5153
|
+
unlockDevice: jest.fn(),
|
|
5154
|
+
};
|
|
5155
|
+
|
|
5156
|
+
await expect(runMethodWithUnlockRetry(method as any, device as any)).rejects.toBe(error);
|
|
5157
|
+
expect(method.run).toHaveBeenCalledTimes(1);
|
|
5158
|
+
expect(device.unlockDevice).not.toHaveBeenCalled();
|
|
5159
|
+
});
|
|
5160
|
+
|
|
4895
5161
|
test('does not retry when unlock fails or when the retry is still locked', async () => {
|
|
4896
5162
|
const initialError = deviceLockedError();
|
|
4897
5163
|
const unlockError = new Error('PIN cancelled');
|
|
@@ -4971,7 +5237,7 @@ describe('Protocol V2 current low-level methods', () => {
|
|
|
4971
5237
|
});
|
|
4972
5238
|
|
|
4973
5239
|
await expect(v2Method.run()).resolves.toEqual({ message: 'accepted' });
|
|
4974
|
-
expect(v2Method.unlockPolicy).toBe('
|
|
5240
|
+
expect(v2Method.unlockPolicy).toBe('unlock-before-run');
|
|
4975
5241
|
expect(v2TypedCall).toHaveBeenCalledWith('DeviceSettingsPageShow', 'Success', {
|
|
4976
5242
|
page: DeviceSettingsPage.DeviceReset,
|
|
4977
5243
|
});
|
|
@@ -5014,7 +5280,7 @@ describe('Protocol V2 current low-level methods', () => {
|
|
|
5014
5280
|
});
|
|
5015
5281
|
|
|
5016
5282
|
await expect(v2Method.run()).resolves.toEqual({ message: 'accepted' });
|
|
5017
|
-
expect(v2Method.unlockPolicy).toBe('
|
|
5283
|
+
expect(v2Method.unlockPolicy).toBe('unlock-before-run');
|
|
5018
5284
|
expect(v2TypedCall).toHaveBeenCalledWith('DeviceSettingsPageShow', 'Success', {
|
|
5019
5285
|
page: DeviceSettingsPage.DevicePinChange,
|
|
5020
5286
|
});
|
|
@@ -5098,67 +5364,6 @@ describe('Protocol V2 current low-level methods', () => {
|
|
|
5098
5364
|
expect(typedCall).toHaveBeenLastCalledWith('DeviceFactoryInfoGet', 'DeviceFactoryInfo', {});
|
|
5099
5365
|
});
|
|
5100
5366
|
|
|
5101
|
-
test('gets Protocol V2 device settings', async () => {
|
|
5102
|
-
const typedCall = jest.fn().mockResolvedValue({ message: { brightness: 80 } });
|
|
5103
|
-
const method = new DeviceSettingsGet({
|
|
5104
|
-
id: 1,
|
|
5105
|
-
payload: { method: 'deviceSettingsGet' },
|
|
5106
|
-
});
|
|
5107
|
-
method.init();
|
|
5108
|
-
(method as any).device = stubDevice({ commands: { typedCall } });
|
|
5109
|
-
|
|
5110
|
-
await expect(method.run()).resolves.toEqual({ brightness: 80 });
|
|
5111
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSettingsGet', 'DeviceSettings', {});
|
|
5112
|
-
});
|
|
5113
|
-
|
|
5114
|
-
test('sets Protocol V2 device settings without passphrase fields', async () => {
|
|
5115
|
-
const typedCall = jest.fn().mockResolvedValue({ message: { message: 'ok' } });
|
|
5116
|
-
const method = new DeviceSettingsSet({
|
|
5117
|
-
id: 1,
|
|
5118
|
-
payload: {
|
|
5119
|
-
method: 'deviceSettingsSet',
|
|
5120
|
-
settings: {
|
|
5121
|
-
label: 'My Pro 2',
|
|
5122
|
-
brightness: 80,
|
|
5123
|
-
airgap_mode: true,
|
|
5124
|
-
passphrase_enable: true,
|
|
5125
|
-
},
|
|
5126
|
-
},
|
|
5127
|
-
});
|
|
5128
|
-
method.init();
|
|
5129
|
-
(method as any).device = stubDevice({ commands: { typedCall } });
|
|
5130
|
-
|
|
5131
|
-
await method.run();
|
|
5132
|
-
|
|
5133
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSettingsSet', 'Success', {
|
|
5134
|
-
settings: {
|
|
5135
|
-
label: 'My Pro 2',
|
|
5136
|
-
brightness: 80,
|
|
5137
|
-
},
|
|
5138
|
-
});
|
|
5139
|
-
expect(method.protocolV2UiInteraction).toEqual({
|
|
5140
|
-
request: 'button',
|
|
5141
|
-
source: 'method-lifecycle',
|
|
5142
|
-
reason: 'device-management',
|
|
5143
|
-
completion: 'operation-completed',
|
|
5144
|
-
deviceOnly: true,
|
|
5145
|
-
operation: 'change-label',
|
|
5146
|
-
});
|
|
5147
|
-
});
|
|
5148
|
-
|
|
5149
|
-
test('keeps silent Protocol V2 device settings eventless', () => {
|
|
5150
|
-
const method = new DeviceSettingsSet({
|
|
5151
|
-
id: 1,
|
|
5152
|
-
payload: {
|
|
5153
|
-
method: 'deviceSettingsSet',
|
|
5154
|
-
settings: { brightness: 80 },
|
|
5155
|
-
},
|
|
5156
|
-
});
|
|
5157
|
-
method.init();
|
|
5158
|
-
|
|
5159
|
-
expect(method.protocolV2UiInteraction).toBeUndefined();
|
|
5160
|
-
});
|
|
5161
|
-
|
|
5162
5367
|
test('marks explicit Protocol V2 unlock as an on-device PIN interaction', () => {
|
|
5163
5368
|
const method = new DeviceUnlock({
|
|
5164
5369
|
id: 1,
|
|
@@ -5176,92 +5381,44 @@ describe('Protocol V2 current low-level methods', () => {
|
|
|
5176
5381
|
});
|
|
5177
5382
|
});
|
|
5178
5383
|
|
|
5179
|
-
test('
|
|
5180
|
-
const
|
|
5181
|
-
const getDeviceState = jest.fn().mockResolvedValue({
|
|
5182
|
-
settings: { airgapMode: true },
|
|
5183
|
-
});
|
|
5184
|
-
const method = new DeviceSettingsPageShow({
|
|
5185
|
-
id: 1,
|
|
5186
|
-
payload: {
|
|
5187
|
-
method: 'deviceSettingsPageShow',
|
|
5188
|
-
page: 'DeviceAirgap',
|
|
5189
|
-
fieldName: 'airgap_mode',
|
|
5190
|
-
},
|
|
5191
|
-
});
|
|
5192
|
-
method.init();
|
|
5193
|
-
(method as any).device = stubDevice({ commands: { typedCall }, getDeviceState });
|
|
5194
|
-
|
|
5195
|
-
await method.run();
|
|
5196
|
-
|
|
5197
|
-
expect(typedCall).toHaveBeenCalledWith('DeviceSettingsPageShow', 'Success', {
|
|
5198
|
-
page: 3,
|
|
5199
|
-
field_name: 'airgap_mode',
|
|
5200
|
-
});
|
|
5201
|
-
expect(method.protocolV2UiInteraction).toEqual({
|
|
5202
|
-
request: 'button',
|
|
5203
|
-
source: 'method-lifecycle',
|
|
5204
|
-
reason: 'settings-page',
|
|
5205
|
-
completion: 'operation-completed',
|
|
5206
|
-
deviceOnly: true,
|
|
5207
|
-
page: DeviceSettingsPage.DeviceAirgap,
|
|
5208
|
-
});
|
|
5209
|
-
expect(getDeviceState).toHaveBeenCalledWith({ refreshSections: ['settings'] });
|
|
5210
|
-
});
|
|
5211
|
-
|
|
5212
|
-
test('opens the Protocol V2 passphrase settings page', async () => {
|
|
5213
|
-
const typedCall = jest.fn().mockResolvedValue({ message: { message: 'ok' } });
|
|
5214
|
-
const getDeviceState = jest.fn().mockResolvedValue({
|
|
5215
|
-
status: { passphraseProtection: true },
|
|
5216
|
-
});
|
|
5217
|
-
const method = new DeviceSettingsPageShow({
|
|
5384
|
+
test('preserves the legacy Features response after explicit device unlock', async () => {
|
|
5385
|
+
const method = new DeviceUnlock({
|
|
5218
5386
|
id: 1,
|
|
5219
|
-
payload: {
|
|
5220
|
-
method: 'deviceSettingsPageShow',
|
|
5221
|
-
page: 'DevicePassphrase',
|
|
5222
|
-
},
|
|
5387
|
+
payload: { method: 'deviceUnlock' },
|
|
5223
5388
|
});
|
|
5224
5389
|
method.init();
|
|
5225
|
-
(method as any).device = stubDevice({ commands: { typedCall }, getDeviceState });
|
|
5226
|
-
|
|
5227
|
-
await method.run();
|
|
5228
5390
|
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
const method = new DeviceSettingsGet({
|
|
5238
|
-
id: 1,
|
|
5239
|
-
payload: { method: 'deviceSettingsGet' },
|
|
5240
|
-
});
|
|
5241
|
-
|
|
5242
|
-
method.init();
|
|
5391
|
+
const features = {
|
|
5392
|
+
protocol: 'V2',
|
|
5393
|
+
unlocked: true,
|
|
5394
|
+
sessionId: null,
|
|
5395
|
+
session_id: null,
|
|
5396
|
+
};
|
|
5397
|
+
const unlockDevice = jest.fn().mockResolvedValue(features);
|
|
5398
|
+
(method as any).device = { unlockDevice };
|
|
5243
5399
|
|
|
5244
|
-
expect(method.
|
|
5400
|
+
await expect(method.run()).resolves.toBe(features);
|
|
5401
|
+
expect(unlockDevice).toHaveBeenCalledTimes(1);
|
|
5245
5402
|
});
|
|
5246
5403
|
|
|
5247
5404
|
test.each([
|
|
5248
5405
|
['label', { label: 'My Pro 2' }],
|
|
5249
|
-
['language', { language: 'ja
|
|
5406
|
+
['language', { language: 'ja' }],
|
|
5250
5407
|
['brightness', { brightness: 80 }],
|
|
5251
|
-
['haptic feedback', {
|
|
5408
|
+
['haptic feedback', { hapticFeedback: true }],
|
|
5252
5409
|
[
|
|
5253
5410
|
'combined lock-free settings',
|
|
5254
5411
|
{
|
|
5255
5412
|
label: 'My Pro 2',
|
|
5256
|
-
language: 'ja
|
|
5413
|
+
language: 'ja',
|
|
5257
5414
|
brightness: 80,
|
|
5258
|
-
|
|
5415
|
+
hapticFeedback: true,
|
|
5259
5416
|
},
|
|
5260
5417
|
],
|
|
5261
|
-
])('does not unlock before changing Protocol V2 %s', (_name, settings) => {
|
|
5262
|
-
const method = new
|
|
5418
|
+
])('does not unlock before changing unified Protocol V2 %s', (_name, settings) => {
|
|
5419
|
+
const method = new DeviceSettings({
|
|
5263
5420
|
id: 2,
|
|
5264
|
-
payload: { method: '
|
|
5421
|
+
payload: { method: 'deviceSettings', ...settings },
|
|
5265
5422
|
});
|
|
5266
5423
|
|
|
5267
5424
|
method.init();
|
|
@@ -5270,30 +5427,30 @@ describe('Protocol V2 current low-level methods', () => {
|
|
|
5270
5427
|
});
|
|
5271
5428
|
|
|
5272
5429
|
test.each([
|
|
5273
|
-
['auto lock', {
|
|
5274
|
-
['auto shutdown', {
|
|
5275
|
-
['mixed protected settings', { brightness: 80,
|
|
5276
|
-
['other protected settings', {
|
|
5277
|
-
])('unlocks before changing Protocol V2 %s', (_name, settings) => {
|
|
5278
|
-
const method = new
|
|
5430
|
+
['auto lock', { autoLockDelayMs: 60_000 }],
|
|
5431
|
+
['auto shutdown', { autoShutdownDelayMs: 120_000 }],
|
|
5432
|
+
['mixed protected settings', { brightness: 80, autoLockDelayMs: 60_000 }],
|
|
5433
|
+
['other protected settings', { usbLockEnabled: true }],
|
|
5434
|
+
])('unlocks before changing unified Protocol V2 %s', (_name, settings) => {
|
|
5435
|
+
const method = new DeviceSettings({
|
|
5279
5436
|
id: 2,
|
|
5280
|
-
payload: { method: '
|
|
5437
|
+
payload: { method: 'deviceSettings', ...settings },
|
|
5281
5438
|
});
|
|
5282
5439
|
|
|
5283
5440
|
method.init();
|
|
5284
5441
|
|
|
5285
|
-
expect(method.unlockPolicy).toBe('
|
|
5442
|
+
expect(method.unlockPolicy).toBe('unlock-before-run');
|
|
5286
5443
|
});
|
|
5287
5444
|
|
|
5288
|
-
test('unlocks before opening Protocol V2 settings pages', () => {
|
|
5289
|
-
const method = new
|
|
5445
|
+
test('unlocks before opening Protocol V2 settings pages through the unified method', () => {
|
|
5446
|
+
const method = new DeviceSettings({
|
|
5290
5447
|
id: 3,
|
|
5291
|
-
payload: { method: '
|
|
5448
|
+
payload: { method: 'deviceSettings', usePassphrase: true },
|
|
5292
5449
|
});
|
|
5293
5450
|
|
|
5294
5451
|
method.init();
|
|
5295
5452
|
|
|
5296
|
-
expect(method.unlockPolicy).toBe('
|
|
5453
|
+
expect(method.unlockPolicy).toBe('unlock-before-run');
|
|
5297
5454
|
});
|
|
5298
5455
|
|
|
5299
5456
|
test('keeps firmwareUpdateV4 unlock-before-reboot behavior explicit', () => {
|
|
@@ -5304,7 +5461,7 @@ describe('Protocol V2 current low-level methods', () => {
|
|
|
5304
5461
|
|
|
5305
5462
|
method.init();
|
|
5306
5463
|
|
|
5307
|
-
expect(method.unlockPolicy).toBe('
|
|
5464
|
+
expect(method.unlockPolicy).toBe('unlock-before-run');
|
|
5308
5465
|
});
|
|
5309
5466
|
|
|
5310
5467
|
test('sends FilesystemPermissionFix from filesystemPermissionFix', async () => {
|