@onekeyfe/hd-core 1.1.26-alpha.12 → 1.1.26-alpha.30
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__/protocol-v2.test.ts +912 -0
- package/dist/api/DirList.d.ts +10 -0
- package/dist/api/DirList.d.ts.map +1 -0
- package/dist/api/DirMake.d.ts +9 -0
- package/dist/api/DirMake.d.ts.map +1 -0
- package/dist/api/DirRemove.d.ts +9 -0
- package/dist/api/DirRemove.d.ts.map +1 -0
- package/dist/api/FileDelete.d.ts +9 -0
- package/dist/api/FileDelete.d.ts.map +1 -0
- package/dist/api/FileRead.d.ts +19 -0
- package/dist/api/FileRead.d.ts.map +1 -0
- package/dist/api/FileWrite.d.ts +23 -0
- package/dist/api/FileWrite.d.ts.map +1 -0
- package/dist/api/FirmwareUpdateV3.d.ts +1 -0
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +32 -0
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -0
- package/dist/api/GetOnekeyFeatures.d.ts.map +1 -1
- package/dist/api/PathInfo.d.ts +9 -0
- package/dist/api/PathInfo.d.ts.map +1 -0
- package/dist/api/SearchDevices.d.ts +2 -1
- package/dist/api/SearchDevices.d.ts.map +1 -1
- package/dist/api/device/DeviceRebootToBoardloader.d.ts +1 -1
- package/dist/api/device/DeviceRebootToBoardloader.d.ts.map +1 -1
- package/dist/api/device/DeviceRebootToBootloader.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +10 -2
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
- package/dist/api/index.d.ts +26 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/protocol-v2/DevFirmwareUpdate.d.ts +7 -0
- package/dist/api/protocol-v2/DevFirmwareUpdate.d.ts.map +1 -0
- package/dist/api/protocol-v2/DevGetDeviceInfo.d.ts +7 -0
- package/dist/api/protocol-v2/DevGetDeviceInfo.d.ts.map +1 -0
- package/dist/api/protocol-v2/DevGetFirmwareUpdateStatus.d.ts +6 -0
- package/dist/api/protocol-v2/DevGetFirmwareUpdateStatus.d.ts.map +1 -0
- package/dist/api/protocol-v2/DevGetOnboardingStatus.d.ts +6 -0
- package/dist/api/protocol-v2/DevGetOnboardingStatus.d.ts.map +1 -0
- package/dist/api/protocol-v2/DevReboot.d.ts +7 -0
- package/dist/api/protocol-v2/DevReboot.d.ts.map +1 -0
- package/dist/api/protocol-v2/FactoryDeviceInfoSettings.d.ts +7 -0
- package/dist/api/protocol-v2/FactoryDeviceInfoSettings.d.ts.map +1 -0
- package/dist/api/protocol-v2/FactoryGetDeviceInfo.d.ts +6 -0
- package/dist/api/protocol-v2/FactoryGetDeviceInfo.d.ts.map +1 -0
- package/dist/api/protocol-v2/FilesystemFixPermission.d.ts +6 -0
- package/dist/api/protocol-v2/FilesystemFixPermission.d.ts.map +1 -0
- package/dist/api/protocol-v2/FilesystemFormat.d.ts +6 -0
- package/dist/api/protocol-v2/FilesystemFormat.d.ts.map +1 -0
- package/dist/api/protocol-v2/GetProtoVersion.d.ts +6 -0
- package/dist/api/protocol-v2/GetProtoVersion.d.ts.map +1 -0
- package/dist/api/protocol-v2/Ping.d.ts +8 -0
- package/dist/api/protocol-v2/Ping.d.ts.map +1 -0
- package/dist/api/protocol-v2/helpers.d.ts +49 -0
- package/dist/api/protocol-v2/helpers.d.ts.map +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/data-manager/DataManager.d.ts +4 -2
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/data-manager/TransportManager.d.ts +2 -1
- package/dist/data-manager/TransportManager.d.ts.map +1 -1
- package/dist/device/Device.d.ts +5 -3
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts +8 -8
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/device/DeviceConnector.d.ts +2 -1
- package/dist/device/DeviceConnector.d.ts.map +1 -1
- package/dist/events/ui-request.d.ts +8 -0
- package/dist/events/ui-request.d.ts.map +1 -1
- package/dist/index.d.ts +187 -20
- package/dist/index.js +2664 -182
- package/dist/inject.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/features.d.ts +56 -0
- package/dist/protocols/protocol-v2/features.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/firmware.d.ts +12 -0
- package/dist/protocols/protocol-v2/firmware.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/index.d.ts +3 -0
- package/dist/protocols/protocol-v2/index.d.ts.map +1 -0
- package/dist/types/api/export.d.ts +1 -1
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdate.d.ts +7 -0
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +28 -1
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/protocolV2.d.ts +123 -0
- package/dist/types/api/protocolV2.d.ts.map +1 -0
- package/dist/types/api/searchDevices.d.ts +2 -2
- package/dist/types/api/searchDevices.d.ts.map +1 -1
- package/dist/types/device.d.ts +1 -1
- package/dist/types/device.d.ts.map +1 -1
- package/dist/types/params.d.ts +2 -0
- package/dist/types/params.d.ts.map +1 -1
- package/dist/types/settings.d.ts +1 -1
- 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/dist/utils/versionUtils.d.ts +1 -1
- package/package.json +4 -4
- package/src/api/DirList.ts +25 -0
- package/src/api/DirMake.ts +20 -0
- package/src/api/DirRemove.ts +20 -0
- package/src/api/FileDelete.ts +20 -0
- package/src/api/FileRead.ts +161 -0
- package/src/api/FileWrite.ts +191 -0
- package/src/api/FirmwareUpdateV3.ts +21 -4
- package/src/api/FirmwareUpdateV4.ts +810 -0
- package/src/api/GetOnekeyFeatures.ts +75 -3
- package/src/api/PathInfo.ts +24 -0
- package/src/api/SearchDevices.ts +7 -2
- package/src/api/device/DeviceRebootToBoardloader.ts +10 -1
- package/src/api/device/DeviceRebootToBootloader.ts +10 -1
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +27 -4
- package/src/api/index.ts +28 -0
- package/src/api/protocol-v2/DevFirmwareUpdate.ts +33 -0
- package/src/api/protocol-v2/DevGetDeviceInfo.ts +35 -0
- package/src/api/protocol-v2/DevGetFirmwareUpdateStatus.ts +18 -0
- package/src/api/protocol-v2/DevGetOnboardingStatus.ts +18 -0
- package/src/api/protocol-v2/DevReboot.ts +22 -0
- package/src/api/protocol-v2/FactoryDeviceInfoSettings.ts +27 -0
- package/src/api/protocol-v2/FactoryGetDeviceInfo.ts +18 -0
- package/src/api/protocol-v2/FilesystemFixPermission.ts +14 -0
- package/src/api/protocol-v2/FilesystemFormat.ts +14 -0
- package/src/api/protocol-v2/GetProtoVersion.ts +14 -0
- package/src/api/protocol-v2/Ping.ts +16 -0
- package/src/api/protocol-v2/helpers.ts +140 -0
- package/src/core/index.ts +19 -2
- package/src/data/messages/messages-pro2.json +733 -0
- package/src/data-manager/DataManager.ts +6 -2
- package/src/data-manager/TransportManager.ts +29 -3
- package/src/device/Device.ts +66 -8
- package/src/device/DeviceCommands.ts +156 -26
- package/src/device/DeviceConnector.ts +29 -4
- package/src/device/DevicePool.ts +1 -1
- package/src/events/ui-request.ts +8 -0
- package/src/inject.ts +43 -1
- package/src/protocols/protocol-v2/features.ts +259 -0
- package/src/protocols/protocol-v2/firmware.ts +26 -0
- package/src/protocols/protocol-v2/index.ts +2 -0
- package/src/types/api/export.ts +1 -0
- package/src/types/api/firmwareUpdate.ts +12 -0
- package/src/types/api/index.ts +63 -1
- package/src/types/api/protocolV2.ts +221 -0
- package/src/types/api/searchDevices.ts +2 -2
- package/src/types/device.ts +3 -1
- package/src/types/params.ts +7 -0
- package/src/types/settings.ts +1 -1
- package/src/utils/deviceInfoUtils.ts +9 -5
|
@@ -4,6 +4,7 @@ import { EDeviceType, EFirmwareType } from '@onekeyfe/hd-shared';
|
|
|
4
4
|
|
|
5
5
|
import MessagesJSON from '../data/messages/messages.json';
|
|
6
6
|
import MessagesLegacyV1JSON from '../data/messages/messages_legacy_v1.json';
|
|
7
|
+
import MessagesPro2JSON from '../data/messages/messages-pro2.json';
|
|
7
8
|
import {
|
|
8
9
|
LoggerNames,
|
|
9
10
|
getDeviceBLEFirmwareVersion,
|
|
@@ -40,7 +41,7 @@ export const FIRMWARE_FIELDS = [
|
|
|
40
41
|
|
|
41
42
|
export type IFirmwareField = (typeof FIRMWARE_FIELDS)[number];
|
|
42
43
|
|
|
43
|
-
export type MessageVersion = 'latest' | 'v1';
|
|
44
|
+
export type MessageVersion = 'latest' | 'v1' | 'protocolV2';
|
|
44
45
|
|
|
45
46
|
const FIRMWARE_FIELD_TYPE_MAP: Readonly<Record<IFirmwareField, EFirmwareType>> = {
|
|
46
47
|
firmware: EFirmwareType.Universal,
|
|
@@ -62,7 +63,9 @@ function getFirmwareTypeFromField(firmwareField: IFirmwareField): EFirmwareType
|
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
export default class DataManager {
|
|
65
|
-
static deviceMap: DeviceTypeMap
|
|
66
|
+
static deviceMap: DeviceTypeMap & {
|
|
67
|
+
[k: string]: DeviceTypeMap[keyof DeviceTypeMap] | undefined;
|
|
68
|
+
} = {
|
|
66
69
|
[EDeviceType.Classic]: {
|
|
67
70
|
firmware: [],
|
|
68
71
|
ble: [],
|
|
@@ -96,6 +99,7 @@ export default class DataManager {
|
|
|
96
99
|
static messages: { [version in MessageVersion]: JSON } = {
|
|
97
100
|
latest: MessagesJSON as unknown as JSON,
|
|
98
101
|
v1: MessagesLegacyV1JSON as unknown as JSON,
|
|
102
|
+
protocolV2: MessagesPro2JSON as unknown as JSON,
|
|
99
103
|
};
|
|
100
104
|
|
|
101
105
|
static lastCheckTimestamp = 0;
|
|
@@ -17,6 +17,7 @@ const LowLevelLogger = getLogger(LoggerNames.HdTransportLowLevel);
|
|
|
17
17
|
const NodeUsbLogger = getLogger(LoggerNames.HdTransportNodeUsb);
|
|
18
18
|
const WebBleLogger = getLogger(LoggerNames.HdWebBleTransport);
|
|
19
19
|
const WebUsbLogger = getLogger(LoggerNames.HdTransportWebUsb);
|
|
20
|
+
const REACT_NATIVE_BLE_SCAN_TIMEOUT_MS = 8000;
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* transport 在同一个环境中只会存在一个
|
|
@@ -74,6 +75,9 @@ export default class TransportManager {
|
|
|
74
75
|
}
|
|
75
76
|
Log.debug('Configuring transports');
|
|
76
77
|
await this.transport.configure(JSON.stringify(this.defaultMessages));
|
|
78
|
+
this.currentMessages = this.defaultMessages;
|
|
79
|
+
this.messageVersion = 'latest';
|
|
80
|
+
await this.configureProtocolV2Messages();
|
|
77
81
|
Log.debug('Configuring transports done');
|
|
78
82
|
} catch (error) {
|
|
79
83
|
Log.debug('Initializing transports error: ', error);
|
|
@@ -83,8 +87,19 @@ export default class TransportManager {
|
|
|
83
87
|
}
|
|
84
88
|
}
|
|
85
89
|
|
|
86
|
-
|
|
87
|
-
|
|
90
|
+
/**
|
|
91
|
+
* Re-load the transport's main protobuf schema based on a device's reported features.
|
|
92
|
+
*
|
|
93
|
+
* This handles message-version compatibility within Protocol V1 (e.g. Touch's classic
|
|
94
|
+
* vs latest schema). It is NOT used to switch between Protocol V1 and Protocol V2 —
|
|
95
|
+
* the transport already holds both schemas after initial configure(), and routes per
|
|
96
|
+
* device by `getProtocolType()`.
|
|
97
|
+
*/
|
|
98
|
+
static async reconfigure(features?: Features) {
|
|
99
|
+
if (!features) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
88
103
|
const { messageVersion, messages } = getSupportMessageVersion(features);
|
|
89
104
|
|
|
90
105
|
if (this.currentMessages === messages || !messages) {
|
|
@@ -109,7 +124,9 @@ export default class TransportManager {
|
|
|
109
124
|
const env = DataManager.getSettings('env');
|
|
110
125
|
if (env === 'react-native') {
|
|
111
126
|
/** Actually initializes the ReactNativeTransport */
|
|
112
|
-
this.transport = new TransportConstructor({
|
|
127
|
+
this.transport = new TransportConstructor({
|
|
128
|
+
scanTimeout: REACT_NATIVE_BLE_SCAN_TIMEOUT_MS,
|
|
129
|
+
}) as unknown as Transport;
|
|
113
130
|
} else {
|
|
114
131
|
/** Actually initializes the HttpTransport */
|
|
115
132
|
this.transport = new TransportConstructor() as unknown as Transport;
|
|
@@ -130,6 +147,15 @@ export default class TransportManager {
|
|
|
130
147
|
return this.transport;
|
|
131
148
|
}
|
|
132
149
|
|
|
150
|
+
private static async configureProtocolV2Messages() {
|
|
151
|
+
const protocolV2Messages = DataManager.getProtobufMessages('protocolV2');
|
|
152
|
+
const { configureProtocolV2 } = this.transport;
|
|
153
|
+
if (protocolV2Messages && typeof configureProtocolV2 === 'function') {
|
|
154
|
+
await configureProtocolV2.call(this.transport, JSON.stringify(protocolV2Messages));
|
|
155
|
+
Log.debug('Protocol V2 messages configured');
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
133
159
|
static getDefaultMessages() {
|
|
134
160
|
return this.defaultMessages;
|
|
135
161
|
}
|
package/src/device/Device.ts
CHANGED
|
@@ -41,6 +41,7 @@ import { DataManager } from '../data-manager';
|
|
|
41
41
|
import TransportManager from '../data-manager/TransportManager';
|
|
42
42
|
import { toHardened } from '../api/helpers/pathUtils';
|
|
43
43
|
import { existCapability } from '../utils/capabilitieUtils';
|
|
44
|
+
import { getProtocolV2Features } from '../protocols/protocol-v2';
|
|
44
45
|
|
|
45
46
|
import type { PROTO } from '../constants';
|
|
46
47
|
import type {
|
|
@@ -49,7 +50,7 @@ import type {
|
|
|
49
50
|
PassphraseRequestPayload,
|
|
50
51
|
} from '../events';
|
|
51
52
|
import type { PassphrasePromptResponse } from './DeviceCommands';
|
|
52
|
-
import type { Deferred } from '@onekeyfe/hd-shared';
|
|
53
|
+
import type { Deferred, HardwareConnectProtocol } from '@onekeyfe/hd-shared';
|
|
53
54
|
import type { OneKeyDeviceInfo as DeviceDescriptor } from '@onekeyfe/hd-transport';
|
|
54
55
|
import type DeviceConnector from './DeviceConnector';
|
|
55
56
|
|
|
@@ -58,6 +59,7 @@ export type InitOptions = {
|
|
|
58
59
|
deviceId?: string;
|
|
59
60
|
passphraseState?: string;
|
|
60
61
|
deriveCardano?: boolean;
|
|
62
|
+
connectProtocol?: HardwareConnectProtocol;
|
|
61
63
|
};
|
|
62
64
|
|
|
63
65
|
export type RunOptions = {
|
|
@@ -252,13 +254,13 @@ export class Device extends EventEmitter {
|
|
|
252
254
|
* Device connect
|
|
253
255
|
* @returns {Promise<boolean>}
|
|
254
256
|
*/
|
|
255
|
-
connect() {
|
|
257
|
+
connect(connectProtocol?: HardwareConnectProtocol) {
|
|
256
258
|
const env = DataManager.getSettings('env');
|
|
257
259
|
// eslint-disable-next-line no-async-promise-executor
|
|
258
260
|
return new Promise<boolean>(async (resolve, reject) => {
|
|
259
261
|
if (DataManager.isBleConnect(env)) {
|
|
260
262
|
try {
|
|
261
|
-
await this.acquire();
|
|
263
|
+
await this.acquire(connectProtocol);
|
|
262
264
|
resolve(true);
|
|
263
265
|
} catch (error) {
|
|
264
266
|
reject(error);
|
|
@@ -268,7 +270,7 @@ export class Device extends EventEmitter {
|
|
|
268
270
|
// 不存在 Session ID 或存在 Session ID 但设备在别处使用,都需要 acquire 获取最新 sessionID
|
|
269
271
|
if (!this.mainId || (!this.isUsedHere() && this.originalDescriptor)) {
|
|
270
272
|
try {
|
|
271
|
-
await this.acquire();
|
|
273
|
+
await this.acquire(connectProtocol);
|
|
272
274
|
resolve(true);
|
|
273
275
|
} catch (error) {
|
|
274
276
|
reject(error);
|
|
@@ -283,23 +285,40 @@ export class Device extends EventEmitter {
|
|
|
283
285
|
});
|
|
284
286
|
}
|
|
285
287
|
|
|
286
|
-
async acquire() {
|
|
288
|
+
async acquire(connectProtocol?: HardwareConnectProtocol) {
|
|
287
289
|
const env = DataManager.getSettings('env');
|
|
288
290
|
const mainIdKey = DataManager.isBleConnect(env) ? 'id' : 'session';
|
|
291
|
+
const expectedProtocol = connectProtocol ?? this.originalDescriptor.protocolType;
|
|
289
292
|
try {
|
|
290
293
|
if (DataManager.isBleConnect(env)) {
|
|
291
|
-
const res = await this.deviceConnector?.acquire(
|
|
294
|
+
const res = await this.deviceConnector?.acquire(
|
|
295
|
+
this.originalDescriptor.id,
|
|
296
|
+
undefined,
|
|
297
|
+
true,
|
|
298
|
+
expectedProtocol
|
|
299
|
+
);
|
|
292
300
|
this.mainId = (res as unknown as any).uuid ?? '';
|
|
293
301
|
Log.debug('Expected uuid:', this.mainId);
|
|
294
302
|
} else {
|
|
295
303
|
this.mainId = await this.deviceConnector?.acquire(
|
|
296
304
|
this.originalDescriptor.path,
|
|
297
|
-
this.originalDescriptor.session
|
|
305
|
+
this.originalDescriptor.session,
|
|
306
|
+
undefined,
|
|
307
|
+
expectedProtocol
|
|
298
308
|
);
|
|
299
309
|
Log.debug('Expected session id:', this.mainId);
|
|
300
310
|
}
|
|
301
311
|
this.deviceAcquired = true;
|
|
302
312
|
this.updateDescriptor({ [mainIdKey]: this.mainId } as unknown as DeviceDescriptor);
|
|
313
|
+
|
|
314
|
+
// Propagate protocol version detected during acquire.
|
|
315
|
+
const detectedProtocol = TransportManager.transport?.getProtocolType?.(
|
|
316
|
+
DataManager.isBleConnect(env) ? this.originalDescriptor.id : this.originalDescriptor.path
|
|
317
|
+
);
|
|
318
|
+
if (detectedProtocol) {
|
|
319
|
+
this.originalDescriptor.protocolType = detectedProtocol;
|
|
320
|
+
}
|
|
321
|
+
|
|
303
322
|
if (this.commands) {
|
|
304
323
|
await this.commands.dispose(false);
|
|
305
324
|
}
|
|
@@ -462,6 +481,12 @@ export class Device extends EventEmitter {
|
|
|
462
481
|
}
|
|
463
482
|
|
|
464
483
|
async initialize(options?: InitOptions) {
|
|
484
|
+
// Protocol V2 不支持传统 Initialize,直接使用协议专用初始化流程。
|
|
485
|
+
if (this.originalDescriptor.protocolType === 'V2') {
|
|
486
|
+
await this._initializeProtocolV2();
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
|
|
465
490
|
// Log.debug('initialize param:', options);
|
|
466
491
|
|
|
467
492
|
this.passphraseState = options?.passphraseState;
|
|
@@ -510,6 +535,39 @@ export class Device extends EventEmitter {
|
|
|
510
535
|
}
|
|
511
536
|
}
|
|
512
537
|
|
|
538
|
+
/**
|
|
539
|
+
* Device initialization over Protocol V2.
|
|
540
|
+
*
|
|
541
|
+
* Protocol V2 不走传统 Initialize/GetFeatures。这里通过
|
|
542
|
+
* Ping + DevGetDeviceInfo 建立统一的 Features 视图。
|
|
543
|
+
*/
|
|
544
|
+
private async _initializeProtocolV2() {
|
|
545
|
+
Log.debug('Initialize device via Protocol V2 feature adapter');
|
|
546
|
+
|
|
547
|
+
try {
|
|
548
|
+
const features = await Promise.race([
|
|
549
|
+
getProtocolV2Features({
|
|
550
|
+
commands: this.commands,
|
|
551
|
+
descriptor: this.originalDescriptor,
|
|
552
|
+
onDeviceInfoError: error => {
|
|
553
|
+
Log.debug('Protocol V2 DevGetDeviceInfo failed:', error);
|
|
554
|
+
},
|
|
555
|
+
timeoutMs: 10 * 1000,
|
|
556
|
+
}),
|
|
557
|
+
new Promise<never>((_, reject) => {
|
|
558
|
+
setTimeout(() => {
|
|
559
|
+
reject(ERRORS.TypedError(HardwareErrorCode.DeviceInitializeFailed));
|
|
560
|
+
}, 10 * 1000);
|
|
561
|
+
}),
|
|
562
|
+
]);
|
|
563
|
+
Log.debug('Protocol V2 normalized features:', features);
|
|
564
|
+
this._updateFeatures(features);
|
|
565
|
+
} catch (error) {
|
|
566
|
+
Log.error('Protocol V2 initialization failed:', error);
|
|
567
|
+
throw error;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
513
571
|
async getFeatures() {
|
|
514
572
|
const { message } = await this.commands.typedCall('GetFeatures', 'Features', {});
|
|
515
573
|
this._updateFeatures(message);
|
|
@@ -580,7 +638,7 @@ export class Device extends EventEmitter {
|
|
|
580
638
|
const env = DataManager.getSettings('env');
|
|
581
639
|
if (env !== 'react-native') {
|
|
582
640
|
try {
|
|
583
|
-
await this.acquire();
|
|
641
|
+
await this.acquire(options.connectProtocol);
|
|
584
642
|
} catch (error) {
|
|
585
643
|
this.runPromise = null;
|
|
586
644
|
return Promise.reject(error);
|
|
@@ -12,7 +12,12 @@ import {
|
|
|
12
12
|
} from '../utils/tracing';
|
|
13
13
|
|
|
14
14
|
import type { Device } from './Device';
|
|
15
|
-
import type {
|
|
15
|
+
import type {
|
|
16
|
+
FailureType,
|
|
17
|
+
Messages,
|
|
18
|
+
Transport,
|
|
19
|
+
TransportCallOptions,
|
|
20
|
+
} from '@onekeyfe/hd-transport';
|
|
16
21
|
|
|
17
22
|
export type PassphrasePromptResponse = {
|
|
18
23
|
passphrase?: string;
|
|
@@ -22,16 +27,116 @@ export type PassphrasePromptResponse = {
|
|
|
22
27
|
};
|
|
23
28
|
|
|
24
29
|
type MessageType = Messages.MessageType;
|
|
25
|
-
type MessageKey = keyof MessageType
|
|
30
|
+
type MessageKey = Extract<keyof MessageType, string>;
|
|
26
31
|
export type TypedResponseMessage<T extends MessageKey> = {
|
|
27
32
|
type: T;
|
|
28
33
|
message: MessageType[T];
|
|
29
34
|
};
|
|
30
35
|
type TypedCallResponseMap = {
|
|
31
|
-
[K in
|
|
36
|
+
[K in MessageKey]: TypedResponseMessage<K>;
|
|
32
37
|
};
|
|
33
38
|
export type DefaultMessageResponse = TypedCallResponseMap[keyof MessageType];
|
|
34
39
|
|
|
40
|
+
const MAX_DEBUG_ARRAY_ITEMS = 20;
|
|
41
|
+
const MAX_DEBUG_OBJECT_KEYS = 40;
|
|
42
|
+
const MAX_DEBUG_STRING_LENGTH = 512;
|
|
43
|
+
const MAX_DEBUG_DEPTH = 4;
|
|
44
|
+
const HIGH_VOLUME_DEBUG_CALLS = new Set([
|
|
45
|
+
'FilesystemFileWrite',
|
|
46
|
+
'FileWrite',
|
|
47
|
+
'EmmcFileWrite',
|
|
48
|
+
'FirmwareUpload',
|
|
49
|
+
'ResourceAck',
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
function shouldReduceDebugForCall(type: string) {
|
|
53
|
+
return HIGH_VOLUME_DEBUG_CALLS.has(type);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getBinaryByteLength(value: unknown): number | undefined {
|
|
57
|
+
if (value instanceof ArrayBuffer) {
|
|
58
|
+
return value.byteLength;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (ArrayBuffer.isView(value)) {
|
|
62
|
+
return value.byteLength;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (typeof Blob !== 'undefined' && value instanceof Blob) {
|
|
66
|
+
return value.size;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function summarizeRedactedData(value: unknown): string {
|
|
73
|
+
const byteLength = getBinaryByteLength(value);
|
|
74
|
+
if (byteLength !== undefined) {
|
|
75
|
+
return `[redacted data: ${byteLength} bytes]`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (typeof value === 'string') {
|
|
79
|
+
return `[redacted data: string length=${value.length}]`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (Array.isArray(value)) {
|
|
83
|
+
return `[redacted data: array length=${value.length}]`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (value && typeof value === 'object') {
|
|
87
|
+
return `[redacted data: object keys=${Object.keys(value).length}]`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return `[redacted data: ${typeof value}]`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function sanitizeDebugPayload(value: unknown, key = '', depth = 0): unknown {
|
|
94
|
+
if (key === 'data' && value !== null && value !== undefined) {
|
|
95
|
+
return summarizeRedactedData(value);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const byteLength = getBinaryByteLength(value);
|
|
99
|
+
if (byteLength !== undefined) {
|
|
100
|
+
return `[binary: ${byteLength} bytes]`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (typeof value === 'string') {
|
|
104
|
+
return value.length > MAX_DEBUG_STRING_LENGTH
|
|
105
|
+
? `${value.slice(0, MAX_DEBUG_STRING_LENGTH)}... (len=${value.length})`
|
|
106
|
+
: value;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (!value || typeof value !== 'object') {
|
|
110
|
+
return value;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (depth >= MAX_DEBUG_DEPTH) {
|
|
114
|
+
return Array.isArray(value)
|
|
115
|
+
? `[array length=${value.length}]`
|
|
116
|
+
: `[object keys=${Object.keys(value).length}]`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (Array.isArray(value)) {
|
|
120
|
+
const items = value
|
|
121
|
+
.slice(0, MAX_DEBUG_ARRAY_ITEMS)
|
|
122
|
+
.map(item => sanitizeDebugPayload(item, key, depth + 1));
|
|
123
|
+
if (value.length > MAX_DEBUG_ARRAY_ITEMS) {
|
|
124
|
+
items.push(`... (${value.length - MAX_DEBUG_ARRAY_ITEMS} more)`);
|
|
125
|
+
}
|
|
126
|
+
return items;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const entries = Object.entries(value).slice(0, MAX_DEBUG_OBJECT_KEYS);
|
|
130
|
+
const sanitized: Record<string, unknown> = {};
|
|
131
|
+
entries.forEach(([entryKey, entryValue]) => {
|
|
132
|
+
sanitized[entryKey] = sanitizeDebugPayload(entryValue, entryKey, depth + 1);
|
|
133
|
+
});
|
|
134
|
+
if (Object.keys(value).length > MAX_DEBUG_OBJECT_KEYS) {
|
|
135
|
+
sanitized.__truncated__ = `${Object.keys(value).length - MAX_DEBUG_OBJECT_KEYS} more keys`;
|
|
136
|
+
}
|
|
137
|
+
return sanitized;
|
|
138
|
+
}
|
|
139
|
+
|
|
35
140
|
const assertType = (res: DefaultMessageResponse, resType: string | string[]) => {
|
|
36
141
|
const splitResTypes = Array.isArray(resType) ? resType : resType.split('|');
|
|
37
142
|
if (!splitResTypes.includes(res.type)) {
|
|
@@ -224,17 +329,21 @@ export class DeviceCommands {
|
|
|
224
329
|
// Sends an async message to the opened device.
|
|
225
330
|
async call(
|
|
226
331
|
type: MessageKey,
|
|
227
|
-
msg
|
|
332
|
+
msg?: DefaultMessageResponse['message'],
|
|
333
|
+
options?: TransportCallOptions
|
|
228
334
|
): Promise<DefaultMessageResponse> {
|
|
229
|
-
|
|
335
|
+
const shouldReduceDebug = shouldReduceDebugForCall(type);
|
|
336
|
+
if (!shouldReduceDebug) {
|
|
337
|
+
Log.debug('[DeviceCommands] [call] Sending', type);
|
|
338
|
+
}
|
|
230
339
|
|
|
231
340
|
try {
|
|
232
|
-
const promise = this.transport.call(this.mainId, type, msg) as any;
|
|
341
|
+
const promise = this.transport.call(this.mainId, type, msg ?? {}, options) as any;
|
|
233
342
|
this.callPromise = promise;
|
|
234
343
|
const res = await promise;
|
|
235
344
|
if (res.type === 'Failure') {
|
|
236
345
|
LogCore.debug('[DeviceCommands] [call] Received', res.type, res.message);
|
|
237
|
-
} else {
|
|
346
|
+
} else if (!shouldReduceDebug) {
|
|
238
347
|
LogCore.debug('[DeviceCommands] [call] Received', res.type);
|
|
239
348
|
}
|
|
240
349
|
return res;
|
|
@@ -283,19 +392,22 @@ export class DeviceCommands {
|
|
|
283
392
|
typedCall<T extends MessageKey, R extends MessageKey[]>(
|
|
284
393
|
type: T,
|
|
285
394
|
resType: R,
|
|
286
|
-
msg?: MessageType[T]
|
|
395
|
+
msg?: MessageType[T],
|
|
396
|
+
options?: TransportCallOptions
|
|
287
397
|
): Promise<TypedCallResponseMap[R[number]]>;
|
|
288
398
|
|
|
289
399
|
typedCall<T extends MessageKey, R extends MessageKey>(
|
|
290
400
|
type: T,
|
|
291
401
|
resType: R,
|
|
292
|
-
msg?: MessageType[T]
|
|
402
|
+
msg?: MessageType[T],
|
|
403
|
+
options?: TransportCallOptions
|
|
293
404
|
): Promise<TypedResponseMessage<R>>;
|
|
294
405
|
|
|
295
406
|
async typedCall(
|
|
296
407
|
type: MessageKey,
|
|
297
408
|
resType: MessageKey | MessageKey[],
|
|
298
|
-
msg?: DefaultMessageResponse['message']
|
|
409
|
+
msg?: DefaultMessageResponse['message'],
|
|
410
|
+
options?: TransportCallOptions
|
|
299
411
|
) {
|
|
300
412
|
if (this.disposed) {
|
|
301
413
|
throw ERRORS.TypedError(
|
|
@@ -312,16 +424,21 @@ export class DeviceCommands {
|
|
|
312
424
|
'PassphraseAck',
|
|
313
425
|
'Cancel',
|
|
314
426
|
'BixinPinInputOnDevice',
|
|
427
|
+
'FilesystemFileWrite',
|
|
428
|
+
'FileWrite',
|
|
429
|
+
'EmmcFileWrite',
|
|
430
|
+
'FirmwareUpload',
|
|
431
|
+
'ResourceAck',
|
|
315
432
|
] as any;
|
|
316
433
|
if (!skipTypes.includes(type) && msg) {
|
|
317
434
|
// Use debug channel to avoid noise escalation
|
|
318
|
-
Log.debug('[DeviceCommands] [typedCall] Sending payload', type, msg);
|
|
435
|
+
Log.debug('[DeviceCommands] [typedCall] Sending payload', type, sanitizeDebugPayload(msg));
|
|
319
436
|
}
|
|
320
437
|
} catch (e) {
|
|
321
438
|
// ignore logging errors
|
|
322
439
|
}
|
|
323
440
|
|
|
324
|
-
const response = await this._commonCall(type, msg);
|
|
441
|
+
const response = await this._commonCall(type, msg, options);
|
|
325
442
|
try {
|
|
326
443
|
assertType(response, resType);
|
|
327
444
|
} catch (error) {
|
|
@@ -334,6 +451,12 @@ export class DeviceCommands {
|
|
|
334
451
|
// throw bridge network error
|
|
335
452
|
if (error instanceof HardwareError) {
|
|
336
453
|
if (error.errorCode === HardwareErrorCode.ResponseUnexpectTypeError) {
|
|
454
|
+
Log.debug('[DeviceCommands] [typedCall] Unexpected response type', {
|
|
455
|
+
request: type,
|
|
456
|
+
expected: resType,
|
|
457
|
+
received: response.type,
|
|
458
|
+
response: sanitizeDebugPayload(response.message),
|
|
459
|
+
});
|
|
337
460
|
// Do not intercept CallMethodError
|
|
338
461
|
// Do not intercept “assertType: Response of unexpected type” error
|
|
339
462
|
// Blocking the above two messages will not know what the specific error message is, and the specific error should be handled by the subsequent business logic.
|
|
@@ -347,7 +470,7 @@ export class DeviceCommands {
|
|
|
347
470
|
if (error.message.indexOf('BridgeDeviceDisconnected') > -1) {
|
|
348
471
|
throw ERRORS.TypedError(HardwareErrorCode.BridgeDeviceDisconnected);
|
|
349
472
|
}
|
|
350
|
-
throw
|
|
473
|
+
throw error;
|
|
351
474
|
}
|
|
352
475
|
} else {
|
|
353
476
|
// throw error anyway, next call should be resolved properly// throw error anyway, next call should be resolved properly
|
|
@@ -357,20 +480,27 @@ export class DeviceCommands {
|
|
|
357
480
|
return response;
|
|
358
481
|
}
|
|
359
482
|
|
|
360
|
-
async _commonCall(
|
|
361
|
-
|
|
362
|
-
|
|
483
|
+
async _commonCall(
|
|
484
|
+
type: MessageKey,
|
|
485
|
+
msg?: DefaultMessageResponse['message'],
|
|
486
|
+
options?: TransportCallOptions
|
|
487
|
+
) {
|
|
488
|
+
const resp = await this.call(type, msg, options);
|
|
489
|
+
return this._filterCommonTypes(resp, type, options);
|
|
363
490
|
}
|
|
364
491
|
|
|
365
492
|
_filterCommonTypes(
|
|
366
493
|
res: DefaultMessageResponse,
|
|
367
|
-
callType: MessageKey
|
|
494
|
+
callType: MessageKey,
|
|
495
|
+
options?: TransportCallOptions
|
|
368
496
|
): Promise<DefaultMessageResponse> {
|
|
369
497
|
try {
|
|
370
|
-
if (
|
|
371
|
-
|
|
498
|
+
if (shouldReduceDebugForCall(callType)) {
|
|
499
|
+
// 高频文件写入每个 chunk 都会经过这里,避免 debug log 反向拖慢传输。
|
|
500
|
+
} else if (DataManager.getSettings('env') === 'react-native') {
|
|
501
|
+
Log.debug('_filterCommonTypes: ', JSON.stringify(sanitizeDebugPayload(res)));
|
|
372
502
|
} else {
|
|
373
|
-
Log.debug('_filterCommonTypes: ', res);
|
|
503
|
+
Log.debug('_filterCommonTypes: ', sanitizeDebugPayload(res));
|
|
374
504
|
}
|
|
375
505
|
} catch (error) {
|
|
376
506
|
// ignore
|
|
@@ -472,7 +602,7 @@ export class DeviceCommands {
|
|
|
472
602
|
} else {
|
|
473
603
|
this.device.emit(DEVICE.BUTTON, this.device, res.message);
|
|
474
604
|
}
|
|
475
|
-
return this._commonCall('ButtonAck', {});
|
|
605
|
+
return this._commonCall('ButtonAck', {}, options);
|
|
476
606
|
}
|
|
477
607
|
|
|
478
608
|
if (res.type === 'EntropyRequest') {
|
|
@@ -485,11 +615,11 @@ export class DeviceCommands {
|
|
|
485
615
|
if (pin === '@@ONEKEY_INPUT_PIN_IN_DEVICE') {
|
|
486
616
|
// only classic\1s\mini\pure
|
|
487
617
|
this.device.setCancelableAction(() => this.cancelDeviceOnOneKeyDevice());
|
|
488
|
-
return this._commonCall('BixinPinInputOnDevice').finally(() => {
|
|
618
|
+
return this._commonCall('BixinPinInputOnDevice', {}, options).finally(() => {
|
|
489
619
|
this.device.clearCancelableAction();
|
|
490
620
|
});
|
|
491
621
|
}
|
|
492
|
-
return this._commonCall('PinMatrixAck', { pin });
|
|
622
|
+
return this._commonCall('PinMatrixAck', { pin }, options);
|
|
493
623
|
},
|
|
494
624
|
error => Promise.reject(error)
|
|
495
625
|
);
|
|
@@ -504,12 +634,12 @@ export class DeviceCommands {
|
|
|
504
634
|
|
|
505
635
|
// Attach PIN on device
|
|
506
636
|
if (attachPinOnDevice && existsAttachPinUser) {
|
|
507
|
-
return this._commonCall('PassphraseAck', { on_device_attach_pin: true });
|
|
637
|
+
return this._commonCall('PassphraseAck', { on_device_attach_pin: true }, options);
|
|
508
638
|
}
|
|
509
639
|
|
|
510
640
|
return !passphraseOnDevice
|
|
511
|
-
? this._commonCall('PassphraseAck', { passphrase })
|
|
512
|
-
: this._commonCall('PassphraseAck', { on_device: true });
|
|
641
|
+
? this._commonCall('PassphraseAck', { passphrase }, options)
|
|
642
|
+
: this._commonCall('PassphraseAck', { on_device: true }, options);
|
|
513
643
|
});
|
|
514
644
|
}
|
|
515
645
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
+
|
|
1
3
|
import { safeThrowError } from '../constants';
|
|
2
4
|
import { DataManager } from '../data-manager';
|
|
3
5
|
import TransportManager from '../data-manager/TransportManager';
|
|
@@ -6,6 +8,7 @@ import { resolveAfter } from '../utils/promiseUtils';
|
|
|
6
8
|
import { LoggerNames, getLogger } from '../utils';
|
|
7
9
|
|
|
8
10
|
import type { DeviceDescriptorDiff } from './DevicePool';
|
|
11
|
+
import type { HardwareConnectProtocol } from '@onekeyfe/hd-shared';
|
|
9
12
|
import type { OneKeyDeviceInfo as DeviceDescriptor, Transport } from '@onekeyfe/hd-transport';
|
|
10
13
|
|
|
11
14
|
const Log = getLogger(LoggerNames.DeviceConnector);
|
|
@@ -75,15 +78,37 @@ export default class DeviceConnector {
|
|
|
75
78
|
this.listening = false;
|
|
76
79
|
}
|
|
77
80
|
|
|
78
|
-
async acquire(
|
|
79
|
-
|
|
81
|
+
async acquire(
|
|
82
|
+
path: string,
|
|
83
|
+
session?: string | null,
|
|
84
|
+
forceCleanRunPromise?: boolean,
|
|
85
|
+
connectProtocol?: HardwareConnectProtocol
|
|
86
|
+
) {
|
|
87
|
+
Log.debug('acquire', path, session, connectProtocol);
|
|
80
88
|
const env = DataManager.getSettings('env');
|
|
81
89
|
try {
|
|
82
90
|
let res;
|
|
83
91
|
if (DataManager.isBleConnect(env)) {
|
|
84
|
-
res = await this.transport.acquire({
|
|
92
|
+
res = await this.transport.acquire({
|
|
93
|
+
uuid: path,
|
|
94
|
+
forceCleanRunPromise,
|
|
95
|
+
expectedProtocol: connectProtocol,
|
|
96
|
+
});
|
|
85
97
|
} else {
|
|
86
|
-
res = await this.transport.acquire({
|
|
98
|
+
res = await this.transport.acquire({
|
|
99
|
+
path,
|
|
100
|
+
previous: session ?? null,
|
|
101
|
+
expectedProtocol: connectProtocol,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
if (connectProtocol) {
|
|
105
|
+
const detectedProtocol = this.transport.getProtocolType(path);
|
|
106
|
+
if (detectedProtocol !== connectProtocol) {
|
|
107
|
+
throw ERRORS.TypedError(
|
|
108
|
+
HardwareErrorCode.RuntimeError,
|
|
109
|
+
`Device protocol mismatch: expected ${connectProtocol}, detected ${detectedProtocol}`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
87
112
|
}
|
|
88
113
|
return res;
|
|
89
114
|
} catch (error) {
|
package/src/device/DevicePool.ts
CHANGED
|
@@ -150,7 +150,7 @@ export class DevicePool extends EventEmitter {
|
|
|
150
150
|
if (!device) {
|
|
151
151
|
device = Device.fromDescriptor(descriptor);
|
|
152
152
|
device.deviceConnector = this.connector;
|
|
153
|
-
await device.connect();
|
|
153
|
+
await device.connect(initOptions?.connectProtocol);
|
|
154
154
|
await device.initialize(initOptions);
|
|
155
155
|
await device.release();
|
|
156
156
|
}
|
package/src/events/ui-request.ts
CHANGED
|
@@ -129,6 +129,10 @@ export interface FirmwareProgress {
|
|
|
129
129
|
device: Device;
|
|
130
130
|
progress: number;
|
|
131
131
|
progressType: IFirmwareUpdateProgressType;
|
|
132
|
+
transferredBytes?: number;
|
|
133
|
+
totalBytes?: number;
|
|
134
|
+
rateBytesPerSecond?: number;
|
|
135
|
+
elapsedMs?: number;
|
|
132
136
|
};
|
|
133
137
|
}
|
|
134
138
|
|
|
@@ -144,6 +148,10 @@ export interface DeviceProgress {
|
|
|
144
148
|
type: typeof UI_REQUEST.DEVICE_PROGRESS;
|
|
145
149
|
payload: {
|
|
146
150
|
progress?: number;
|
|
151
|
+
transferredBytes?: number;
|
|
152
|
+
totalBytes?: number;
|
|
153
|
+
rateBytesPerSecond?: number;
|
|
154
|
+
elapsedMs?: number;
|
|
147
155
|
};
|
|
148
156
|
}
|
|
149
157
|
|