@onekeyfe/hd-core 1.2.0-alpha.22 → 1.2.0-alpha.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__tests__/DeviceCommands.test.ts +43 -8
- package/__tests__/connectSettings.test.ts +5 -47
- package/__tests__/device-lifecycle-events.test.ts +59 -0
- package/__tests__/device-settings.test.ts +1 -1
- package/__tests__/device-wallet-session-store.test.ts +41 -0
- package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +30 -39
- package/__tests__/logBlockEvent.test.ts +17 -0
- package/__tests__/open-wallet-session.test.ts +233 -111
- package/__tests__/protocol-v2-ping.test.ts +28 -0
- package/__tests__/protocol-v2.test.ts +513 -313
- package/__tests__/public-pro2-api-boundary.test.ts +22 -0
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV2.d.ts +0 -11
- package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts +3 -7
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +5 -21
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/GetPassphraseState.d.ts.map +1 -1
- package/dist/api/OpenWalletSession.d.ts +1 -8
- package/dist/api/OpenWalletSession.d.ts.map +1 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts +1 -5
- package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
- package/dist/api/device/DeviceWipe.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +0 -7
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
- package/dist/api/firmware/getBinary.d.ts +0 -7
- package/dist/api/firmware/getBinary.d.ts.map +1 -1
- package/dist/api/firmware/updateBootloader.d.ts +0 -2
- package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/uploadFirmware.d.ts +1 -9
- package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/protocol-v2/Ping.d.ts +2 -0
- package/dist/api/protocol-v2/Ping.d.ts.map +1 -1
- package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/data-manager/DataManager.d.ts +0 -1
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/data-manager/connectSettings.d.ts.map +1 -1
- package/dist/device/Device.d.ts +3 -2
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/events/device.d.ts +1 -0
- package/dist/events/device.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/events/ui-request.d.ts +1 -0
- package/dist/events/ui-request.d.ts.map +1 -1
- package/dist/index.d.ts +98 -278
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +876 -2647
- package/dist/inject.d.ts.map +1 -1
- package/dist/lowLevelInject.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockRetry.d.ts +2 -3
- package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/walletSession.d.ts +12 -0
- package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
- package/dist/topLevelInject.d.ts.map +1 -1
- package/dist/types/api/checkAllFirmwareRelease.d.ts +0 -3
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/deviceUpdateBootloader.d.ts +0 -6
- package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
- package/dist/types/api/export.d.ts +1 -4
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdate.d.ts +0 -69
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/dist/types/api/getPassphraseState.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +4 -10
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/openWalletSession.d.ts +0 -12
- package/dist/types/api/openWalletSession.d.ts.map +1 -1
- package/dist/types/api/protocolV2.d.ts +4 -0
- package/dist/types/api/protocolV2.d.ts.map +1 -1
- package/dist/types/settings.d.ts +0 -13
- package/dist/types/settings.d.ts.map +1 -1
- package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/CheckAllFirmwareRelease.ts +3 -16
- package/src/api/FirmwareUpdateV2.ts +119 -284
- package/src/api/FirmwareUpdateV3.ts +55 -248
- package/src/api/FirmwareUpdateV4.ts +293 -751
- package/src/api/GetPassphraseState.ts +11 -5
- package/src/api/OpenWalletSession.ts +23 -86
- package/src/api/device/DeviceUpdateBootloader.ts +6 -114
- package/src/api/device/DeviceWipe.ts +2 -0
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +0 -50
- package/src/api/firmware/updateBootloader.ts +4 -19
- package/src/api/firmware/uploadFirmware.ts +22 -140
- package/src/api/index.ts +1 -0
- package/src/api/protocol-v2/Ping.ts +32 -1
- package/src/core/index.ts +40 -7
- package/src/data/messages/messages-protocol-v2.json +49 -56
- package/src/data-manager/DataManager.ts +33 -33
- package/src/data-manager/connectSettings.ts +0 -11
- package/src/device/Device.ts +29 -8
- package/src/device/DeviceCommands.ts +43 -151
- package/src/events/device.ts +1 -0
- package/src/events/logBlockEvent.ts +1 -15
- package/src/events/ui-request.ts +1 -0
- package/src/index.ts +0 -5
- package/src/inject.ts +4 -22
- package/src/lowLevelInject.ts +1 -5
- package/src/protocols/protocol-v2/deviceSession.ts +1 -1
- package/src/protocols/protocol-v2/settingsUnlockPolicy.ts +0 -1
- package/src/protocols/protocol-v2/unlockRetry.ts +20 -3
- package/src/protocols/protocol-v2/walletSession.ts +57 -18
- package/src/topLevelInject.ts +1 -5
- package/src/types/api/checkAllFirmwareRelease.ts +0 -3
- package/src/types/api/deviceUpdateBootloader.ts +0 -6
- package/src/types/api/export.ts +0 -18
- package/src/types/api/firmwareUpdate.ts +0 -76
- package/src/types/api/getPassphraseState.ts +4 -3
- package/src/types/api/index.ts +3 -14
- package/src/types/api/openWalletSession.ts +0 -19
- package/src/types/api/protocolV2.ts +10 -0
- package/src/types/settings.ts +0 -13
- package/src/utils/deviceInfoUtils.ts +2 -3
- package/__tests__/firmware-update/firmware-artifact-source.test.ts +0 -119
- package/__tests__/firmware-update/firmware-host-binding.test.ts +0 -70
- package/__tests__/firmware-update/firmware-update-capabilities.test.ts +0 -13
- package/__tests__/firmware-update/firmware-update-plan.test.ts +0 -326
- package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +0 -200
- package/__tests__/firmware-update/firmware-upload-source.test.ts +0 -70
- package/dist/api/firmware/FirmwareArtifactSource.d.ts +0 -26
- package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareHostBinding.d.ts +0 -6
- package/dist/api/firmware/FirmwareHostBinding.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +0 -3
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +0 -24
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +0 -25
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdateCapabilities.d.ts +0 -9
- package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdatePlan.d.ts +0 -27
- package/dist/types/api/firmwareUpdatePlan.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +0 -42
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +0 -1
- package/src/api/firmware/FirmwareArtifactSource.ts +0 -278
- package/src/api/firmware/FirmwareHostBinding.ts +0 -100
- package/src/api/firmware/FirmwareUpdateCapabilities.ts +0 -9
- package/src/api/firmware/FirmwareUpdatePlan.ts +0 -621
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +0 -378
- package/src/types/api/firmwareUpdateCapabilities.ts +0 -9
- package/src/types/api/firmwareUpdatePlan.ts +0 -36
- package/src/types/api/firmwareUpdatePreparedPlan.ts +0 -53
|
@@ -19,7 +19,7 @@ const createCommands = () => {
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
describe('DeviceCommands failure mapping', () => {
|
|
22
|
-
it('does not log
|
|
22
|
+
it('does not log DeviceSessionGet response secrets', async () => {
|
|
23
23
|
const commands = createCommands();
|
|
24
24
|
const log = getLogger(LoggerNames.DeviceCommands);
|
|
25
25
|
log.messages.length = 0;
|
|
@@ -33,7 +33,7 @@ describe('DeviceCommands failure mapping', () => {
|
|
|
33
33
|
btc_test_address: 'secret-wallet-address',
|
|
34
34
|
},
|
|
35
35
|
} as any,
|
|
36
|
-
'
|
|
36
|
+
'DeviceSessionGet'
|
|
37
37
|
)
|
|
38
38
|
).resolves.toMatchObject({ type: 'DeviceSession' });
|
|
39
39
|
|
|
@@ -41,7 +41,7 @@ describe('DeviceCommands failure mapping', () => {
|
|
|
41
41
|
expect(JSON.stringify(log.messages)).not.toContain('secret-wallet-address');
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
it('maps an invalid
|
|
44
|
+
it('maps an invalid DeviceSessionGet resume to WalletSessionInvalid', async () => {
|
|
45
45
|
const commands = createCommands();
|
|
46
46
|
|
|
47
47
|
await expect(
|
|
@@ -54,7 +54,7 @@ describe('DeviceCommands failure mapping', () => {
|
|
|
54
54
|
message: 'Invalid session',
|
|
55
55
|
},
|
|
56
56
|
} as any,
|
|
57
|
-
'
|
|
57
|
+
'DeviceSessionGet'
|
|
58
58
|
)
|
|
59
59
|
).rejects.toMatchObject({
|
|
60
60
|
errorCode: HardwareErrorCode.WalletSessionInvalid,
|
|
@@ -66,7 +66,7 @@ describe('DeviceCommands failure mapping', () => {
|
|
|
66
66
|
});
|
|
67
67
|
});
|
|
68
68
|
|
|
69
|
-
it('maps
|
|
69
|
+
it('maps wallet-session user cancellation to ActionCancelled', async () => {
|
|
70
70
|
const commands = createCommands();
|
|
71
71
|
|
|
72
72
|
await expect(
|
|
@@ -79,7 +79,7 @@ describe('DeviceCommands failure mapping', () => {
|
|
|
79
79
|
message: 'Cancelled on device',
|
|
80
80
|
},
|
|
81
81
|
} as any,
|
|
82
|
-
'
|
|
82
|
+
'DeviceSessionAskPassphrase'
|
|
83
83
|
)
|
|
84
84
|
).rejects.toMatchObject({
|
|
85
85
|
errorCode: HardwareErrorCode.ActionCancelled,
|
|
@@ -89,7 +89,7 @@ describe('DeviceCommands failure mapping', () => {
|
|
|
89
89
|
it.each([
|
|
90
90
|
[3, HardwareErrorCode.DeviceCheckUnlockTypeError],
|
|
91
91
|
[4, HardwareErrorCode.DeviceNotOpenedPassphrase],
|
|
92
|
-
])('maps
|
|
92
|
+
])('maps wallet-session subcode %s to its canonical wallet error', async (subcode, code) => {
|
|
93
93
|
const commands = createCommands();
|
|
94
94
|
|
|
95
95
|
await expect(
|
|
@@ -98,11 +98,46 @@ describe('DeviceCommands failure mapping', () => {
|
|
|
98
98
|
type: 'Failure',
|
|
99
99
|
message: { code: 'Failure_ProcessError', subcode, message: 'Session selection failed' },
|
|
100
100
|
} as any,
|
|
101
|
-
'
|
|
101
|
+
'DeviceSessionAskPin'
|
|
102
102
|
)
|
|
103
103
|
).rejects.toMatchObject({ errorCode: code });
|
|
104
104
|
});
|
|
105
105
|
|
|
106
|
+
it.each([
|
|
107
|
+
['DeviceSessionGet', 5, 'Another flow in progress'],
|
|
108
|
+
['DeviceSessionAskPin', 0, 'Busy'],
|
|
109
|
+
])('maps %s firmware busy failures to DeviceBusy', async (callType, subcode, message) => {
|
|
110
|
+
const commands = createCommands();
|
|
111
|
+
|
|
112
|
+
await expect(
|
|
113
|
+
commands._filterCommonTypes(
|
|
114
|
+
{
|
|
115
|
+
type: 'Failure',
|
|
116
|
+
message: { code: 'Failure_ProcessError', subcode, message },
|
|
117
|
+
} as any,
|
|
118
|
+
callType
|
|
119
|
+
)
|
|
120
|
+
).rejects.toMatchObject({ errorCode: HardwareErrorCode.DeviceBusy });
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('maps the current AskPin passphrase-disabled response without relying on a subcode', async () => {
|
|
124
|
+
const commands = createCommands();
|
|
125
|
+
|
|
126
|
+
await expect(
|
|
127
|
+
commands._filterCommonTypes(
|
|
128
|
+
{
|
|
129
|
+
type: 'Failure',
|
|
130
|
+
message: {
|
|
131
|
+
code: 'Failure_ProcessError',
|
|
132
|
+
subcode: 0,
|
|
133
|
+
message: 'Passphrase disabled',
|
|
134
|
+
},
|
|
135
|
+
} as any,
|
|
136
|
+
'DeviceSessionAskPin'
|
|
137
|
+
)
|
|
138
|
+
).rejects.toMatchObject({ errorCode: HardwareErrorCode.DeviceNotOpenedPassphrase });
|
|
139
|
+
});
|
|
140
|
+
|
|
106
141
|
it('rejects the Pro2 bootloader DeviceStatusGet unsupported response', async () => {
|
|
107
142
|
const commands = createCommands();
|
|
108
143
|
|
|
@@ -1,61 +1,19 @@
|
|
|
1
|
-
import DataManager from '../src/data-manager/DataManager';
|
|
2
1
|
import { parseConnectSettings } from '../src/data-manager/connectSettings';
|
|
3
2
|
|
|
4
|
-
import type { RemoteConfigResponse } from '../src/types';
|
|
5
|
-
|
|
6
|
-
jest.mock('axios', () => ({
|
|
7
|
-
get: jest.fn(),
|
|
8
|
-
}));
|
|
9
|
-
|
|
10
3
|
jest.mock('../src/data/config', () => ({
|
|
11
4
|
getSDKVersion: jest.fn(() => '1.0.0'),
|
|
12
5
|
DEFAULT_DOMAIN: 'https://jssdk.onekey.so/1.0.0/',
|
|
13
6
|
}));
|
|
14
7
|
|
|
15
|
-
const mockAxiosGet: jest.Mock = jest.requireMock('axios').get;
|
|
16
|
-
|
|
17
8
|
describe('parseConnectSettings', () => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
classic: { firmware: [], ble: [] },
|
|
21
|
-
classic1s: { firmware: [], ble: [] },
|
|
22
|
-
classicpure: { firmware: [], ble: [] },
|
|
23
|
-
mini: { firmware: [], ble: [] },
|
|
24
|
-
touch: { firmware: [], ble: [] },
|
|
25
|
-
pro: { firmware: [], ble: [] },
|
|
26
|
-
pro2: { firmware: [], ble: [] },
|
|
27
|
-
} as unknown as RemoteConfigResponse;
|
|
28
|
-
|
|
29
|
-
it('keeps a serializable preloaded config in parsed settings', () => {
|
|
30
|
-
const settings = parseConnectSettings({
|
|
31
|
-
firmwareManifestMode: 'sdk-managed',
|
|
32
|
-
preloadedConfig,
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
expect(settings.firmwareManifestMode).toBe('sdk-managed');
|
|
36
|
-
expect(settings.preloadedConfig).toBe(preloadedConfig);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('uses the preloaded config before the SDK network client', async () => {
|
|
40
|
-
const settings = parseConnectSettings({
|
|
41
|
-
firmwareManifestMode: 'sdk-managed',
|
|
42
|
-
preloadedConfig,
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
await DataManager.load(settings);
|
|
46
|
-
|
|
47
|
-
expect(mockAxiosGet).not.toHaveBeenCalled();
|
|
48
|
-
expect(DataManager.deviceMap.classic).toEqual({ firmware: [], ble: [] });
|
|
49
|
-
});
|
|
9
|
+
it('keeps custom configFetcher in parsed settings', () => {
|
|
10
|
+
const configFetcher = jest.fn();
|
|
50
11
|
|
|
51
|
-
it('fails closed without a preloaded config in external-only mode', async () => {
|
|
52
12
|
const settings = parseConnectSettings({
|
|
53
|
-
|
|
13
|
+
fetchConfig: true,
|
|
14
|
+
configFetcher,
|
|
54
15
|
});
|
|
55
16
|
|
|
56
|
-
|
|
57
|
-
'External firmware config snapshot is required'
|
|
58
|
-
);
|
|
59
|
-
expect(mockAxiosGet).not.toHaveBeenCalled();
|
|
17
|
+
expect(settings.configFetcher).toBe(configFetcher);
|
|
60
18
|
});
|
|
61
19
|
});
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { TRANSPORT_EVENT } from '@onekeyfe/hd-transport';
|
|
2
|
+
|
|
1
3
|
import { initConnector, initCore } from '../src/core';
|
|
2
4
|
import { DataManager } from '../src/data-manager';
|
|
3
5
|
import TransportManager from '../src/data-manager/TransportManager';
|
|
@@ -59,6 +61,63 @@ describe('public device lifecycle events', () => {
|
|
|
59
61
|
jest.restoreAllMocks();
|
|
60
62
|
});
|
|
61
63
|
|
|
64
|
+
test('registers the shared device lifecycle listeners exactly once', async () => {
|
|
65
|
+
jest.spyOn(DataManager, 'getSettings').mockReturnValue('react-native' as never);
|
|
66
|
+
core = initCore();
|
|
67
|
+
initConnector();
|
|
68
|
+
|
|
69
|
+
for (const id of ['first-call', 'second-call']) {
|
|
70
|
+
await core.handleMessage({
|
|
71
|
+
id,
|
|
72
|
+
event: IFRAME.CALL,
|
|
73
|
+
type: IFRAME.CALL,
|
|
74
|
+
payload: { method: 'clearSessionCache' },
|
|
75
|
+
} as CoreMessage);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
expect(DevicePool.emitter.listenerCount(DEVICE.CONNECT)).toBe(1);
|
|
79
|
+
expect(DevicePool.emitter.listenerCount(DEVICE.DISCONNECT)).toBe(1);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('converts an internal transport disconnect into a public KnownDevice snapshot', () => {
|
|
83
|
+
jest.spyOn(DataManager, 'getSettings').mockReturnValue('react-native' as never);
|
|
84
|
+
core = initCore();
|
|
85
|
+
initConnector();
|
|
86
|
+
const messages: CoreMessage[] = [];
|
|
87
|
+
core.on(CORE_EVENT, message => messages.push(message));
|
|
88
|
+
const device = createInitializedDevice('V2');
|
|
89
|
+
DevicePool.devicesCache['ble-connect-id'] = device;
|
|
90
|
+
|
|
91
|
+
DevicePool.emitter.emit(TRANSPORT_EVENT.DEVICE_DISCONNECT, {
|
|
92
|
+
id: 'ble-connect-id',
|
|
93
|
+
connectId: 'ble-connect-id',
|
|
94
|
+
name: 'OneKey Test BLE',
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const disconnectMessage = messages.find(message => message.type === DEVICE.DISCONNECT);
|
|
98
|
+
expect(disconnectMessage?.payload.device).toMatchObject({
|
|
99
|
+
connectId: 'ble-connect-id',
|
|
100
|
+
serialNo: 'SERIAL-001',
|
|
101
|
+
state: { protocol: 'V2' },
|
|
102
|
+
});
|
|
103
|
+
expect(() => JSON.stringify(disconnectMessage?.payload.device)).not.toThrow();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test('treats an acquired BLE device as reusable until the transport disconnects', async () => {
|
|
107
|
+
jest.spyOn(DataManager, 'getSettings').mockReturnValue('desktop-web-ble' as never);
|
|
108
|
+
const device = createInitializedDevice('V2');
|
|
109
|
+
const acquire = jest.spyOn(device, 'acquire').mockResolvedValue(undefined);
|
|
110
|
+
(device as unknown as { deviceAcquired: boolean }).deviceAcquired = true;
|
|
111
|
+
(device as any).commands = { disposed: false };
|
|
112
|
+
|
|
113
|
+
expect(device.isUsedHere()).toBe(true);
|
|
114
|
+
await expect(device.connect('V2')).resolves.toBe(true);
|
|
115
|
+
expect(acquire).not.toHaveBeenCalled();
|
|
116
|
+
|
|
117
|
+
device.markTransportDisconnected();
|
|
118
|
+
expect(device.isUsedHere()).toBe(false);
|
|
119
|
+
});
|
|
120
|
+
|
|
62
121
|
test.each([
|
|
63
122
|
['react-native', 'V1'],
|
|
64
123
|
['react-native', 'V2'],
|
|
@@ -37,7 +37,6 @@ function createDevice({ protocol }: { protocol: 'V1' | 'V2' }) {
|
|
|
37
37
|
|
|
38
38
|
describe('DeviceSettings protocol routing', () => {
|
|
39
39
|
it.each([
|
|
40
|
-
['label', { label: 'Shared Label' }],
|
|
41
40
|
['language', { language: 'ja-JP' }],
|
|
42
41
|
['brightness', { brightness: 80 }],
|
|
43
42
|
['haptic feedback', { hapticFeedback: true }],
|
|
@@ -56,6 +55,7 @@ describe('DeviceSettings protocol routing', () => {
|
|
|
56
55
|
});
|
|
57
56
|
|
|
58
57
|
it.each([
|
|
58
|
+
['label', { label: 'Shared Label' }],
|
|
59
59
|
['auto lock', { autoLockDelayMs: 60_000 }],
|
|
60
60
|
['auto shutdown', { autoShutdownDelayMs: 120_000 }],
|
|
61
61
|
['mixed settings', { brightness: 80, autoLockDelayMs: 60_000 }],
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
2
|
|
|
3
3
|
import ClearSessionCache from '../src/api/ClearSessionCache';
|
|
4
|
+
import DeviceWipe from '../src/api/device/DeviceWipe';
|
|
4
5
|
import {
|
|
5
6
|
DeviceWalletSessionStore,
|
|
6
7
|
deviceWalletSessionStore,
|
|
@@ -96,6 +97,46 @@ describe('DeviceWalletSessionStore', () => {
|
|
|
96
97
|
});
|
|
97
98
|
});
|
|
98
99
|
|
|
100
|
+
describe('Device wipe lifecycle invalidation', () => {
|
|
101
|
+
beforeEach(() => {
|
|
102
|
+
deviceWalletSessionStore.clear();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('clears the old Protocol V2 identity and wallet sessions after wipe succeeds', async () => {
|
|
106
|
+
const device = Device.fromDescriptor({
|
|
107
|
+
id: 'pro2-descriptor',
|
|
108
|
+
path: 'pro2-path',
|
|
109
|
+
protocolType: 'V2',
|
|
110
|
+
} as never);
|
|
111
|
+
device.features = {
|
|
112
|
+
protocol: 'V2',
|
|
113
|
+
deviceId: 'old-device-id',
|
|
114
|
+
unlocked: true,
|
|
115
|
+
passphraseProtection: true,
|
|
116
|
+
} as never;
|
|
117
|
+
device.passphraseState = 'hidden-a';
|
|
118
|
+
deviceWalletSessionStore.set('old-device-id', 'hidden-a', 'old-session');
|
|
119
|
+
deviceWalletSessionStore.set('pro2-path', 'hidden-a', 'temporary-session');
|
|
120
|
+
device.markPreInitialized({ passphraseState: 'hidden-a' });
|
|
121
|
+
device.commands = {
|
|
122
|
+
typedCall: jest.fn().mockResolvedValue({ message: { message: 'accepted' } }),
|
|
123
|
+
} as never;
|
|
124
|
+
|
|
125
|
+
const method = new DeviceWipe({ id: 1, payload: { method: 'deviceWipe' } });
|
|
126
|
+
method.init();
|
|
127
|
+
(method as any).device = device;
|
|
128
|
+
|
|
129
|
+
await expect(method.run()).resolves.toEqual({ message: 'accepted' });
|
|
130
|
+
|
|
131
|
+
expect(device.features).toBeUndefined();
|
|
132
|
+
expect(device.passphraseState).toBeUndefined();
|
|
133
|
+
expect(device.needReloadDevice).toBe(true);
|
|
134
|
+
expect(device.isPreInitializedValid(60_000)).toBe(false);
|
|
135
|
+
expect(deviceWalletSessionStore.get('old-device-id', 'hidden-a')).toBeUndefined();
|
|
136
|
+
expect(deviceWalletSessionStore.get('pro2-path', 'hidden-a')).toBeUndefined();
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
99
140
|
describe('ClearSessionCache', () => {
|
|
100
141
|
beforeEach(() => {
|
|
101
142
|
deviceWalletSessionStore.clear();
|
|
@@ -2,7 +2,7 @@ import { EDeviceType, EFirmwareType, HardwareErrorCode } from '@onekeyfe/hd-shar
|
|
|
2
2
|
|
|
3
3
|
import FirmwareUpdateV2 from '../../src/api/FirmwareUpdateV2';
|
|
4
4
|
import { getBinary } from '../../src/api/firmware/getBinary';
|
|
5
|
-
import {
|
|
5
|
+
import { uploadFirmware } from '../../src/api/firmware/uploadFirmware';
|
|
6
6
|
import * as utils from '../../src/utils';
|
|
7
7
|
|
|
8
8
|
jest.mock('../../src/data/config', () => ({
|
|
@@ -18,8 +18,7 @@ jest.mock('../../src/api/firmware/getBinary', () => ({
|
|
|
18
18
|
|
|
19
19
|
jest.mock('../../src/api/firmware/uploadFirmware', () => ({
|
|
20
20
|
updateResources: jest.fn(),
|
|
21
|
-
|
|
22
|
-
uploadFirmwareFromSource: jest.fn(),
|
|
21
|
+
uploadFirmware: jest.fn(),
|
|
23
22
|
}));
|
|
24
23
|
|
|
25
24
|
jest.mock('../../src/device/DevicePool', () => ({
|
|
@@ -30,9 +29,7 @@ jest.mock('../../src/device/DevicePool', () => ({
|
|
|
30
29
|
}));
|
|
31
30
|
|
|
32
31
|
const mockGetBinary = getBinary as jest.MockedFunction<typeof getBinary>;
|
|
33
|
-
const
|
|
34
|
-
typeof uploadFirmwareFromSource
|
|
35
|
-
>;
|
|
32
|
+
const mockUploadFirmware = uploadFirmware as jest.MockedFunction<typeof uploadFirmware>;
|
|
36
33
|
|
|
37
34
|
type DeviceType = 'CLASSIC1S' | 'PURE';
|
|
38
35
|
|
|
@@ -178,7 +175,7 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
|
|
|
178
175
|
expect(mockGetBinary).toHaveBeenCalledTimes(1);
|
|
179
176
|
expectNoFirmwareMutationCalls(typedCall);
|
|
180
177
|
expect(acquire).not.toHaveBeenCalled();
|
|
181
|
-
expect(
|
|
178
|
+
expect(mockUploadFirmware).not.toHaveBeenCalled();
|
|
182
179
|
});
|
|
183
180
|
|
|
184
181
|
it.each([
|
|
@@ -219,11 +216,9 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
|
|
|
219
216
|
binary: firmwareBinary,
|
|
220
217
|
} as Awaited<ReturnType<typeof getBinary>>);
|
|
221
218
|
});
|
|
222
|
-
|
|
219
|
+
mockUploadFirmware.mockImplementation(() => {
|
|
223
220
|
callOrder.push('upload');
|
|
224
|
-
return Promise.resolve(
|
|
225
|
-
expectedResponse as Awaited<ReturnType<typeof uploadFirmwareFromSource>>
|
|
226
|
-
);
|
|
221
|
+
return Promise.resolve(expectedResponse as Awaited<ReturnType<typeof uploadFirmware>>);
|
|
227
222
|
});
|
|
228
223
|
const { method, typedCall } = createMethod({
|
|
229
224
|
updateType,
|
|
@@ -253,15 +248,15 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
|
|
|
253
248
|
},
|
|
254
249
|
})
|
|
255
250
|
);
|
|
256
|
-
expect(
|
|
251
|
+
expect(mockUploadFirmware).toHaveBeenCalledWith(
|
|
257
252
|
updateType,
|
|
258
253
|
expect.any(Function),
|
|
259
254
|
expect.any(Function),
|
|
260
255
|
method.device,
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
256
|
+
{
|
|
257
|
+
payload: firmwareBinary,
|
|
258
|
+
rebootOnSuccess: true,
|
|
259
|
+
},
|
|
265
260
|
isUpdateBootloader
|
|
266
261
|
);
|
|
267
262
|
}
|
|
@@ -276,11 +271,11 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
|
|
|
276
271
|
binary: firmwareBinary,
|
|
277
272
|
} as Awaited<ReturnType<typeof getBinary>>);
|
|
278
273
|
});
|
|
279
|
-
|
|
274
|
+
mockUploadFirmware.mockImplementation(() => {
|
|
280
275
|
callOrder.push('upload');
|
|
281
276
|
return Promise.resolve({
|
|
282
277
|
success: true,
|
|
283
|
-
} as Awaited<ReturnType<typeof
|
|
278
|
+
} as Awaited<ReturnType<typeof uploadFirmware>>);
|
|
284
279
|
});
|
|
285
280
|
const { method, typedCall, acquire } = createMethod({
|
|
286
281
|
bootloaderMode: true,
|
|
@@ -305,9 +300,9 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
|
|
|
305
300
|
resolveDownload = resolve;
|
|
306
301
|
})
|
|
307
302
|
);
|
|
308
|
-
|
|
303
|
+
mockUploadFirmware.mockResolvedValue({
|
|
309
304
|
success: true,
|
|
310
|
-
} as Awaited<ReturnType<typeof
|
|
305
|
+
} as Awaited<ReturnType<typeof uploadFirmware>>);
|
|
311
306
|
const { method, typedCall } = createMethod();
|
|
312
307
|
|
|
313
308
|
const runPromise = method.run();
|
|
@@ -338,7 +333,7 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
|
|
|
338
333
|
|
|
339
334
|
expectNoFirmwareMutationCalls(typedCall);
|
|
340
335
|
expect(acquire).not.toHaveBeenCalled();
|
|
341
|
-
expect(
|
|
336
|
+
expect(mockUploadFirmware).not.toHaveBeenCalled();
|
|
342
337
|
});
|
|
343
338
|
|
|
344
339
|
it.each([
|
|
@@ -347,23 +342,23 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
|
|
|
347
342
|
])(
|
|
348
343
|
'keeps the non-empty %s binary overload and never downloads it again',
|
|
349
344
|
async (_kind, binary) => {
|
|
350
|
-
|
|
345
|
+
mockUploadFirmware.mockResolvedValue({
|
|
351
346
|
success: true,
|
|
352
|
-
} as Awaited<ReturnType<typeof
|
|
347
|
+
} as Awaited<ReturnType<typeof uploadFirmware>>);
|
|
353
348
|
const { method } = createMethod({ binary });
|
|
354
349
|
|
|
355
350
|
await method.run();
|
|
356
351
|
|
|
357
352
|
expect(mockGetBinary).not.toHaveBeenCalled();
|
|
358
|
-
expect(
|
|
353
|
+
expect(mockUploadFirmware).toHaveBeenCalledWith(
|
|
359
354
|
'firmware',
|
|
360
355
|
expect.any(Function),
|
|
361
356
|
expect.any(Function),
|
|
362
357
|
method.device,
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
358
|
+
{
|
|
359
|
+
payload: binary,
|
|
360
|
+
rebootOnSuccess: true,
|
|
361
|
+
},
|
|
367
362
|
undefined
|
|
368
363
|
);
|
|
369
364
|
}
|
|
@@ -374,21 +369,17 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
|
|
|
374
369
|
['DataView', new DataView(new Uint8Array([9, 3, 4, 9]).buffer, 1, 2), [3, 4]],
|
|
375
370
|
['custom Buffer', createCustomBuffer(4), [1, 2, 3, 4]],
|
|
376
371
|
])('normalizes a non-empty %s before rebooting', async (_kind, binary, expectedBytes) => {
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
uploadedBytes = Array.from(new Uint8Array(await source.readAt(0, source.size)));
|
|
381
|
-
return {
|
|
382
|
-
success: true,
|
|
383
|
-
} as Awaited<ReturnType<typeof uploadFirmwareFromSource>>;
|
|
384
|
-
}
|
|
385
|
-
);
|
|
372
|
+
mockUploadFirmware.mockResolvedValue({
|
|
373
|
+
success: true,
|
|
374
|
+
} as Awaited<ReturnType<typeof uploadFirmware>>);
|
|
386
375
|
const { method } = createMethod({ binary });
|
|
387
376
|
|
|
388
377
|
await method.run();
|
|
389
378
|
|
|
390
379
|
expect(mockGetBinary).not.toHaveBeenCalled();
|
|
391
|
-
|
|
380
|
+
const normalizedBinary = mockUploadFirmware.mock.calls[0][4].payload;
|
|
381
|
+
expect(normalizedBinary).toBeInstanceOf(ArrayBuffer);
|
|
382
|
+
expect(Array.from(new Uint8Array(normalizedBinary))).toEqual(expectedBytes);
|
|
392
383
|
});
|
|
393
384
|
|
|
394
385
|
it.each([
|
|
@@ -406,6 +397,6 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
|
|
|
406
397
|
expect(mockGetBinary).not.toHaveBeenCalled();
|
|
407
398
|
expectNoFirmwareMutationCalls(typedCall);
|
|
408
399
|
expect(acquire).not.toHaveBeenCalled();
|
|
409
|
-
expect(
|
|
400
|
+
expect(mockUploadFirmware).not.toHaveBeenCalled();
|
|
410
401
|
});
|
|
411
402
|
});
|
|
@@ -60,4 +60,21 @@ describe('getLogBlockLabel', () => {
|
|
|
60
60
|
expect(getLogBlockLabel({ payload: { method, data: new Uint8Array(1024) } })).toBe(method);
|
|
61
61
|
}
|
|
62
62
|
);
|
|
63
|
+
|
|
64
|
+
it.each(['evmSignMessage', 'btcSignMessage', 'evmSignTransaction'])(
|
|
65
|
+
'blocks request and response payload logging for every API method including %s',
|
|
66
|
+
method => {
|
|
67
|
+
expect(getLogBlockLabel({ method, message: 'sensitive signing payload' })).toBe(method);
|
|
68
|
+
expect(
|
|
69
|
+
getLogBlockLabel({
|
|
70
|
+
event: 'iframe-call',
|
|
71
|
+
payload: { method, message: 'sensitive signing payload' },
|
|
72
|
+
})
|
|
73
|
+
).toBe(method);
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
it('does not classify events without an API method as method calls', () => {
|
|
78
|
+
expect(getLogBlockLabel({ event: 'DEVICE_EVENT', type: 'device-connect' })).toBeUndefined();
|
|
79
|
+
});
|
|
63
80
|
});
|