@onekeyfe/hd-core 1.2.0-alpha.107 → 1.2.0-alpha.108
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 +140 -26
- package/__tests__/base64Data.test.ts +70 -0
- package/__tests__/device-lifecycle-events.test.ts +113 -2
- package/__tests__/device-pool-state.test.ts +25 -0
- package/__tests__/deviceSettings.test.ts +0 -1
- package/__tests__/deviceUploadNft.test.ts +33 -4
- package/__tests__/firmware-update/firmware-update-v4-install-poll.test.ts +178 -0
- package/__tests__/get-device-state.test.ts +52 -13
- package/__tests__/logBlockEvent.test.ts +13 -1
- package/__tests__/protocol-v2.test.ts +762 -124
- package/__tests__/refresh-device-state.test.ts +3 -1
- package/__tests__/resourceBase64Boundary.test.ts +48 -0
- package/__tests__/ton-sign-message.test.ts +84 -0
- package/dist/api/FirmwareUpdateV4.d.ts +10 -3
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/UploadPortfolio.d.ts +1 -1
- package/dist/api/UploadPortfolio.d.ts.map +1 -1
- package/dist/api/helpers/base64Data.d.ts +16 -0
- package/dist/api/helpers/base64Data.d.ts.map +1 -0
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts +2 -3
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts +2 -3
- package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts.map +1 -1
- package/dist/api/ton/TonSignMessage.d.ts.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/device/Device.d.ts +7 -2
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/device/DevicePool.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/index.d.ts +11 -14
- package/dist/index.js +455 -200
- package/dist/protocols/protocol-v2/features.d.ts +9 -1
- package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/index.d.ts +2 -2
- package/dist/protocols/protocol-v2/index.d.ts.map +1 -1
- package/dist/types/api/protocolV2.d.ts +1 -1
- package/dist/types/api/protocolV2.d.ts.map +1 -1
- package/dist/utils/pro2Nft.d.ts +7 -0
- package/dist/utils/pro2Nft.d.ts.map +1 -1
- package/package.json +6 -4
- package/src/api/FirmwareUpdateV4.ts +326 -174
- package/src/api/UploadPortfolio.ts +9 -2
- package/src/api/helpers/base64Data.ts +85 -0
- package/src/api/protocol-v2/DeviceUploadNft.ts +56 -8
- package/src/api/protocol-v2/DeviceUploadWallpaper.ts +37 -18
- package/src/api/ton/TonSignMessage.ts +5 -3
- package/src/core/index.ts +6 -2
- package/src/device/Device.ts +53 -31
- package/src/device/DeviceCommands.ts +4 -14
- package/src/device/DevicePool.ts +6 -2
- package/src/events/logBlockEvent.ts +14 -1
- package/src/protocols/protocol-v2/features.ts +19 -2
- package/src/protocols/protocol-v2/index.ts +2 -0
- package/src/types/api/protocolV2.ts +1 -1
- package/src/utils/deviceSettings.ts +1 -1
- package/src/utils/pro2Nft.ts +31 -8
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
+
|
|
3
|
+
import FirmwareUpdateV4 from '../../src/api/FirmwareUpdateV4';
|
|
4
|
+
import { DataManager } from '../../src/data-manager';
|
|
5
|
+
|
|
6
|
+
import type { Device } from '../../src/device/Device';
|
|
7
|
+
|
|
8
|
+
jest.mock('../../src/data/config', () => ({
|
|
9
|
+
DEFAULT_DOMAIN: 'https://example.com/',
|
|
10
|
+
getSDKVersion: () => '0.0.0-test',
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
describe('FirmwareUpdateV4 install polling', () => {
|
|
14
|
+
let getSettingsSpy: jest.SpyInstance;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
getSettingsSpy = jest
|
|
18
|
+
.spyOn(DataManager, 'getSettings')
|
|
19
|
+
.mockReturnValue('react-native' as never);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
jest.restoreAllMocks();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('polls status instead of replaying install after React Native BLE releases', async () => {
|
|
27
|
+
const method = new FirmwareUpdateV4({
|
|
28
|
+
id: 1,
|
|
29
|
+
payload: {
|
|
30
|
+
method: 'firmwareUpdateV4',
|
|
31
|
+
connectId: 'pro2-ble',
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
const targets = [{ target_id: 4, path: 'vol0:/application_p1.bin' }];
|
|
35
|
+
const typedCall = jest
|
|
36
|
+
.fn()
|
|
37
|
+
.mockRejectedValueOnce(new Error('React Native BLE transport released'))
|
|
38
|
+
.mockResolvedValueOnce({
|
|
39
|
+
message: {
|
|
40
|
+
records: [
|
|
41
|
+
{
|
|
42
|
+
target_id: 4,
|
|
43
|
+
status: 'FW_MGMT_UPDATER_TASK_STATUS_FINISHED',
|
|
44
|
+
path: 'vol0:/application_p1.bin',
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
method.device = {
|
|
51
|
+
getCommands: () => ({ typedCall }),
|
|
52
|
+
} as unknown as Device;
|
|
53
|
+
method.postTipMessage = jest.fn();
|
|
54
|
+
method.postProgressMessage = jest.fn();
|
|
55
|
+
|
|
56
|
+
const firmwareUpdate = method as unknown as {
|
|
57
|
+
protocolV2StartFirmwareUpdate: (params: { targets: typeof targets }) => Promise<unknown>;
|
|
58
|
+
waitForProtocolV2FirmwareUpdateComplete: (value: typeof targets) => Promise<void>;
|
|
59
|
+
reconnectProtocolV2Device: () => Promise<void>;
|
|
60
|
+
verifyProtocolV2ReconnectIdentity: () => Promise<Record<string, never>>;
|
|
61
|
+
};
|
|
62
|
+
firmwareUpdate.reconnectProtocolV2Device = jest.fn().mockResolvedValue(undefined);
|
|
63
|
+
firmwareUpdate.verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue({});
|
|
64
|
+
|
|
65
|
+
await expect(
|
|
66
|
+
firmwareUpdate.protocolV2StartFirmwareUpdate({ targets })
|
|
67
|
+
).resolves.toBeUndefined();
|
|
68
|
+
await expect(
|
|
69
|
+
firmwareUpdate.waitForProtocolV2FirmwareUpdateComplete(targets)
|
|
70
|
+
).resolves.toBeUndefined();
|
|
71
|
+
|
|
72
|
+
expect(typedCall).toHaveBeenCalledTimes(2);
|
|
73
|
+
expect(typedCall.mock.calls[0]?.[0]).toBe('DeviceFirmwareUpdateRequest');
|
|
74
|
+
expect(typedCall.mock.calls[1]?.[0]).toBe('DeviceFirmwareUpdateStatusGet');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('does not treat an explicit workflow cancellation as an install reboot', async () => {
|
|
78
|
+
const method = new FirmwareUpdateV4({
|
|
79
|
+
id: 1,
|
|
80
|
+
payload: {
|
|
81
|
+
method: 'firmwareUpdateV4',
|
|
82
|
+
connectId: 'pro2-ble',
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
const targets = [{ target_id: 4, path: 'vol0:/application_p1.bin' }];
|
|
86
|
+
const typedCall = jest.fn().mockRejectedValue(new Error('React Native BLE transport released'));
|
|
87
|
+
const abortController = new AbortController();
|
|
88
|
+
abortController.abort();
|
|
89
|
+
|
|
90
|
+
method.abortSignal = abortController.signal;
|
|
91
|
+
method.device = {
|
|
92
|
+
getCommands: () => ({ typedCall }),
|
|
93
|
+
} as unknown as Device;
|
|
94
|
+
|
|
95
|
+
await expect(
|
|
96
|
+
(
|
|
97
|
+
method as unknown as {
|
|
98
|
+
protocolV2StartFirmwareUpdate: (params: { targets: typeof targets }) => Promise<unknown>;
|
|
99
|
+
}
|
|
100
|
+
).protocolV2StartFirmwareUpdate({ targets })
|
|
101
|
+
).rejects.toMatchObject({
|
|
102
|
+
errorCode: HardwareErrorCode.CallQueueActionCancelled,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
expect(typedCall).toHaveBeenCalledTimes(1);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test.each([
|
|
109
|
+
HardwareErrorCode.BleConnectedError,
|
|
110
|
+
HardwareErrorCode.BleCharacteristicNotifyError,
|
|
111
|
+
HardwareErrorCode.BleForceCleanRunPromise,
|
|
112
|
+
HardwareErrorCode.BleDeviceDisconnected,
|
|
113
|
+
])('continues install polling after BLE interruption error %s', async errorCode => {
|
|
114
|
+
const method = new FirmwareUpdateV4({
|
|
115
|
+
id: 1,
|
|
116
|
+
payload: {
|
|
117
|
+
method: 'firmwareUpdateV4',
|
|
118
|
+
connectId: 'pro2-ble',
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
const targets = [{ target_id: 4, path: 'vol0:/application_p1.bin' }];
|
|
122
|
+
const typedCall = jest.fn().mockRejectedValue(ERRORS.TypedError(errorCode));
|
|
123
|
+
|
|
124
|
+
method.device = {
|
|
125
|
+
getCommands: () => ({ typedCall }),
|
|
126
|
+
} as unknown as Device;
|
|
127
|
+
method.postTipMessage = jest.fn();
|
|
128
|
+
method.postProgressMessage = jest.fn();
|
|
129
|
+
|
|
130
|
+
await expect(
|
|
131
|
+
(
|
|
132
|
+
method as unknown as {
|
|
133
|
+
protocolV2StartFirmwareUpdate: (params: { targets: typeof targets }) => Promise<unknown>;
|
|
134
|
+
}
|
|
135
|
+
).protocolV2StartFirmwareUpdate({ targets })
|
|
136
|
+
).resolves.toBeUndefined();
|
|
137
|
+
|
|
138
|
+
expect(typedCall).toHaveBeenCalledTimes(1);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test.each([
|
|
142
|
+
['webusb', 'React Native BLE transport released'],
|
|
143
|
+
['react-native', 'Unrelated transport failure'],
|
|
144
|
+
])(
|
|
145
|
+
'requires both a BLE environment and an explicit transport release signal: %s / %s',
|
|
146
|
+
async (env, message) => {
|
|
147
|
+
getSettingsSpy.mockReturnValue(env);
|
|
148
|
+
const method = new FirmwareUpdateV4({
|
|
149
|
+
id: 1,
|
|
150
|
+
payload: {
|
|
151
|
+
method: 'firmwareUpdateV4',
|
|
152
|
+
connectId: 'pro2-device',
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
const targets = [{ target_id: 4, path: 'vol0:/application_p1.bin' }];
|
|
156
|
+
const typedCall = jest.fn().mockRejectedValue(new Error(message));
|
|
157
|
+
|
|
158
|
+
method.device = {
|
|
159
|
+
getCommands: () => ({ typedCall }),
|
|
160
|
+
} as unknown as Device;
|
|
161
|
+
method.postTipMessage = jest.fn();
|
|
162
|
+
method.postProgressMessage = jest.fn();
|
|
163
|
+
|
|
164
|
+
await expect(
|
|
165
|
+
(
|
|
166
|
+
method as unknown as {
|
|
167
|
+
protocolV2StartFirmwareUpdate: (params: {
|
|
168
|
+
targets: typeof targets;
|
|
169
|
+
}) => Promise<unknown>;
|
|
170
|
+
}
|
|
171
|
+
).protocolV2StartFirmwareUpdate({ targets })
|
|
172
|
+
).rejects.toThrow(message);
|
|
173
|
+
|
|
174
|
+
expect(method.postTipMessage).not.toHaveBeenCalled();
|
|
175
|
+
expect(method.postProgressMessage).not.toHaveBeenCalled();
|
|
176
|
+
}
|
|
177
|
+
);
|
|
178
|
+
});
|
|
@@ -202,25 +202,61 @@ describe('getDeviceState', () => {
|
|
|
202
202
|
expect(state.versions.se01).toBe('1.0.0');
|
|
203
203
|
});
|
|
204
204
|
|
|
205
|
-
test.each([
|
|
206
|
-
'
|
|
207
|
-
|
|
205
|
+
test.each([
|
|
206
|
+
['bootloader', EDeviceType.Pro2, DeviceType.PRO2],
|
|
207
|
+
['romloader', EDeviceType.Pro2, DeviceType.PRO2],
|
|
208
|
+
['bootloader', EDeviceType.Neo, DeviceType.NEO],
|
|
209
|
+
['romloader', EDeviceType.Neo, DeviceType.NEO],
|
|
210
|
+
] as const)(
|
|
211
|
+
'refreshes cached %s state after %s reboots into the application',
|
|
212
|
+
async (mode, deviceType, protocolV2DeviceType) => {
|
|
208
213
|
const typedCall = jest.fn().mockImplementation((requestType: string) => {
|
|
209
|
-
if (requestType === '
|
|
214
|
+
if (requestType === 'ProtocolInfoRequest') {
|
|
215
|
+
return { message: protocolV2ApplicationInfo };
|
|
216
|
+
}
|
|
217
|
+
if (requestType === 'DeviceStatusGet') {
|
|
210
218
|
return {
|
|
211
|
-
message: {
|
|
212
|
-
|
|
219
|
+
message: { init_states: true, unlocked: true, device_id: 'wallet-1' },
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
throw new Error(`Unexpected request: ${requestType}`);
|
|
223
|
+
});
|
|
224
|
+
const device = createV2Device(typedCall);
|
|
225
|
+
device.updateState(
|
|
226
|
+
{
|
|
227
|
+
protocol: 'V2',
|
|
228
|
+
identity: { deviceType },
|
|
229
|
+
status: { mode },
|
|
230
|
+
raw: {
|
|
231
|
+
protocolV2DeviceInfo: {
|
|
232
|
+
hw: { Device_type: protocolV2DeviceType, serial_no: 'SERIAL-1' },
|
|
213
233
|
fw:
|
|
214
234
|
mode === 'romloader'
|
|
215
235
|
? { romloader: { version: '1.0.0' } }
|
|
216
236
|
: { bootloader: { version: '1.0.0' } },
|
|
217
237
|
},
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
238
|
+
protocolV2ProtocolInfo: getProtocolV2LoaderInfo(mode),
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
'initialize'
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
const state = await device.getDeviceState({ refreshSections: ['status'] });
|
|
245
|
+
|
|
246
|
+
expect(state.status.mode).toBe('normal');
|
|
247
|
+
expect(state.identity.deviceId).toBe('wallet-1');
|
|
248
|
+
expect(typedCall.mock.calls.map(call => call[0])).toEqual([
|
|
249
|
+
'ProtocolInfoRequest',
|
|
250
|
+
'DeviceStatusGet',
|
|
251
|
+
]);
|
|
252
|
+
}
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
test.each(['bootloader', 'romloader'] as const)(
|
|
256
|
+
'keeps live %s mode after refreshing cached loader state',
|
|
257
|
+
async mode => {
|
|
258
|
+
const typedCall = jest.fn().mockResolvedValue({
|
|
259
|
+
message: getProtocolV2LoaderInfo(mode),
|
|
224
260
|
});
|
|
225
261
|
const device = createV2Device(typedCall);
|
|
226
262
|
device.updateState(
|
|
@@ -236,7 +272,10 @@ describe('getDeviceState', () => {
|
|
|
236
272
|
const state = await device.getDeviceState({ refreshSections: ['status'] });
|
|
237
273
|
|
|
238
274
|
expect(state.status.mode).toBe(mode);
|
|
239
|
-
expect(typedCall).
|
|
275
|
+
expect(typedCall).toHaveBeenCalledTimes(1);
|
|
276
|
+
expect(typedCall).toHaveBeenCalledWith('ProtocolInfoRequest', 'ProtocolInfo', {
|
|
277
|
+
eventless_wallet_session: true,
|
|
278
|
+
});
|
|
240
279
|
}
|
|
241
280
|
);
|
|
242
281
|
|
|
@@ -104,7 +104,19 @@ describe('getLogBlockLabel', () => {
|
|
|
104
104
|
});
|
|
105
105
|
});
|
|
106
106
|
|
|
107
|
-
it.each(['deviceUploadNft', 'deviceUploadWallpaper', 'uploadPortfolio'
|
|
107
|
+
it.each(['deviceUploadNft', 'deviceUploadWallpaper', 'uploadPortfolio'])(
|
|
108
|
+
'skips large Base64 resource payload logging for %s',
|
|
109
|
+
method => {
|
|
110
|
+
const request = { method, path: 'resource.bin', data: 'A'.repeat(1024 * 1024) };
|
|
111
|
+
expect(getLogBlockLabel(request)).toBe(method);
|
|
112
|
+
expect(getSafeLogPayload(request, method)).toEqual({
|
|
113
|
+
method,
|
|
114
|
+
payload: '[REDACTED]',
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
it.each(['fileWrite', 'fileRead'])(
|
|
108
120
|
'keeps metadata and replaces binary payloads with their size for %s',
|
|
109
121
|
method => {
|
|
110
122
|
const request = { method, path: 'resource.bin', data: new Uint8Array(1024) };
|