@onekeyfe/hd-core 0.1.37 → 0.1.40
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/dist/api/BaseMethod.d.ts +1 -0
- package/dist/api/BaseMethod.d.ts.map +1 -1
- package/dist/api/CheckBLEFirmwareRelease.d.ts.map +1 -1
- package/dist/api/CheckBridgeStatus.d.ts.map +1 -1
- package/dist/api/CheckFirmwareRelease.d.ts.map +1 -1
- package/dist/api/CheckTransportRelease.d.ts.map +1 -1
- package/dist/api/FirmwareUpdate.d.ts.map +1 -1
- package/dist/api/GetFeatures.d.ts.map +1 -1
- package/dist/api/GetLogs.d.ts.map +1 -1
- package/dist/api/GetPassphraseState.d.ts +6 -0
- package/dist/api/GetPassphraseState.d.ts.map +1 -0
- package/dist/api/RequestWebUsbDevice.d.ts.map +1 -1
- package/dist/api/SearchDevices.d.ts.map +1 -1
- package/dist/api/device/DeviceBackup.d.ts.map +1 -1
- package/dist/api/device/DeviceChangePin.d.ts.map +1 -1
- package/dist/api/device/DeviceFlags.d.ts.map +1 -1
- package/dist/api/device/DeviceRebootToBootloader.d.ts.map +1 -1
- package/dist/api/device/DeviceRecovery.d.ts.map +1 -1
- package/dist/api/device/DeviceReset.d.ts.map +1 -1
- package/dist/api/device/DeviceSettings.d.ts +7 -0
- package/dist/api/device/DeviceSettings.d.ts.map +1 -1
- package/dist/api/device/DeviceSupportFeatures.d.ts +1 -1
- package/dist/api/device/DeviceSupportFeatures.d.ts.map +1 -1
- package/dist/api/device/DeviceUpdateReboot.d.ts.map +1 -1
- package/dist/api/device/DeviceVerify.d.ts.map +1 -1
- package/dist/api/device/DeviceWipe.d.ts.map +1 -1
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/device/Device.d.ts +15 -5
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/device/DeviceList.d.ts +2 -2
- package/dist/device/DeviceList.d.ts.map +1 -1
- package/dist/device/DevicePool.d.ts +6 -5
- package/dist/device/DevicePool.d.ts.map +1 -1
- package/dist/events/ui-request.d.ts +9 -1
- package/dist/events/ui-request.d.ts.map +1 -1
- package/dist/index.d.ts +35 -8
- package/dist/index.js +447 -254
- package/dist/inject.d.ts.map +1 -1
- package/dist/types/api/getPassphraseState.d.ts +3 -0
- package/dist/types/api/getPassphraseState.d.ts.map +1 -0
- package/dist/types/api/index.d.ts +2 -0
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/device.d.ts +5 -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/utils/deviceFeaturesUtils.d.ts +5 -2
- package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/package.json +4 -4
- package/src/api/BaseMethod.ts +5 -0
- package/src/api/CheckBLEFirmwareRelease.ts +1 -0
- package/src/api/CheckBridgeStatus.ts +1 -0
- package/src/api/CheckFirmwareRelease.ts +3 -1
- package/src/api/CheckTransportRelease.ts +1 -0
- package/src/api/FirmwareUpdate.ts +1 -0
- package/src/api/GetFeatures.ts +1 -0
- package/src/api/GetLogs.ts +1 -0
- package/src/api/GetPassphraseState.ts +31 -0
- package/src/api/RequestWebUsbDevice.ts +1 -0
- package/src/api/SearchDevices.ts +1 -0
- package/src/api/device/DeviceBackup.ts +3 -1
- package/src/api/device/DeviceChangePin.ts +2 -0
- package/src/api/device/DeviceFlags.ts +2 -0
- package/src/api/device/DeviceRebootToBootloader.ts +3 -1
- package/src/api/device/DeviceRecovery.ts +2 -0
- package/src/api/device/DeviceReset.ts +2 -0
- package/src/api/device/DeviceSettings.ts +13 -2
- package/src/api/device/DeviceSupportFeatures.ts +3 -1
- package/src/api/device/DeviceUpdateReboot.ts +3 -1
- package/src/api/device/DeviceVerify.ts +2 -0
- package/src/api/device/DeviceWipe.ts +3 -1
- package/src/api/index.ts +1 -0
- package/src/core/index.ts +97 -10
- package/src/device/Device.ts +126 -47
- package/src/device/DeviceCommands.ts +13 -9
- package/src/device/DeviceList.ts +7 -3
- package/src/device/DevicePool.ts +24 -12
- package/src/events/ui-request.ts +10 -0
- package/src/inject.ts +2 -0
- package/src/types/api/getPassphraseState.ts +6 -0
- package/src/types/api/index.ts +2 -0
- package/src/types/device.ts +3 -1
- package/src/types/params.ts +8 -0
- package/src/utils/deviceFeaturesUtils.ts +38 -5
package/src/core/index.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import semver from 'semver';
|
|
2
2
|
import EventEmitter from 'events';
|
|
3
|
-
import { OneKeyDeviceInfo } from '@onekeyfe/hd-transport';
|
|
3
|
+
import { Features, OneKeyDeviceInfo } from '@onekeyfe/hd-transport';
|
|
4
4
|
import { createDeferred, Deferred, ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
getDeviceFirmwareVersion,
|
|
7
|
+
getDeviceModel,
|
|
8
|
+
getDeviceType,
|
|
9
|
+
supportNewPassphrase,
|
|
10
|
+
} from '../utils/deviceFeaturesUtils';
|
|
11
|
+
import { Device, DeviceEvents, InitOptions, RunOptions } from '../device/Device';
|
|
6
12
|
import { DeviceList } from '../device/DeviceList';
|
|
7
13
|
import { DevicePool } from '../device/DevicePool';
|
|
8
14
|
import { findMethod } from '../api/utils';
|
|
@@ -26,14 +32,15 @@ import type { BaseMethod } from '../api/BaseMethod';
|
|
|
26
32
|
import type { ConnectSettings, KnownDevice } from '../types';
|
|
27
33
|
import TransportManager from '../data-manager/TransportManager';
|
|
28
34
|
import DeviceConnector from '../device/DeviceConnector';
|
|
29
|
-
import {
|
|
30
|
-
getDeviceFirmwareVersion,
|
|
31
|
-
getDeviceModel,
|
|
32
|
-
getDeviceType,
|
|
33
|
-
} from '../utils/deviceFeaturesUtils';
|
|
34
35
|
|
|
35
36
|
const Log = getLogger(LoggerNames.Core);
|
|
36
37
|
|
|
38
|
+
const parseInitOptions = (method?: BaseMethod): InitOptions => ({
|
|
39
|
+
initSession: method?.payload.initSession,
|
|
40
|
+
passphraseState: method?.payload.passphraseState,
|
|
41
|
+
deviceId: method?.payload.deviceId,
|
|
42
|
+
});
|
|
43
|
+
|
|
37
44
|
let _core: Core;
|
|
38
45
|
let _deviceList: DeviceList | undefined;
|
|
39
46
|
let _connector: DeviceConnector | undefined;
|
|
@@ -45,6 +52,12 @@ const deviceCacheMap = new Map<string, Device>();
|
|
|
45
52
|
let pollingId = 1;
|
|
46
53
|
const pollingState: Record<number, boolean> = {};
|
|
47
54
|
|
|
55
|
+
let preConnectCache: {
|
|
56
|
+
passphraseState: string | undefined;
|
|
57
|
+
} = {
|
|
58
|
+
passphraseState: undefined,
|
|
59
|
+
};
|
|
60
|
+
|
|
48
61
|
export const callAPI = async (message: CoreMessage) => {
|
|
49
62
|
if (!message.id || !message.payload || message.type !== IFRAME.CALL) {
|
|
50
63
|
return Promise.reject(ERRORS.TypedError('on call: message.id or message.payload is missing'));
|
|
@@ -83,6 +96,17 @@ export const callAPI = async (message: CoreMessage) => {
|
|
|
83
96
|
);
|
|
84
97
|
}
|
|
85
98
|
|
|
99
|
+
const connectStateChange = preConnectCache.passphraseState !== method.payload.passphraseState;
|
|
100
|
+
|
|
101
|
+
preConnectCache = {
|
|
102
|
+
passphraseState: method.payload.passphraseState,
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
if (connectStateChange || method.payload.initSession) {
|
|
106
|
+
Log.debug('passphrase state change, clear device cache');
|
|
107
|
+
DevicePool.clearDeviceCache(method.payload.connectId);
|
|
108
|
+
}
|
|
109
|
+
|
|
86
110
|
/**
|
|
87
111
|
* Polling to ensure successful connection
|
|
88
112
|
*/
|
|
@@ -102,6 +126,7 @@ export const callAPI = async (message: CoreMessage) => {
|
|
|
102
126
|
|
|
103
127
|
device.on(DEVICE.PIN, onDevicePinHandler);
|
|
104
128
|
device.on(DEVICE.BUTTON, onDeviceButtonHandler);
|
|
129
|
+
device.on(DEVICE.PASSPHRASE_ON_DEVICE, onDevicePassphraseHandler);
|
|
105
130
|
device.on(DEVICE.FEATURES, onDeviceFeaturesHandler);
|
|
106
131
|
|
|
107
132
|
try {
|
|
@@ -179,6 +204,38 @@ export const callAPI = async (message: CoreMessage) => {
|
|
|
179
204
|
await TransportManager.reconfigure(device.getFirmwareVersion());
|
|
180
205
|
}
|
|
181
206
|
|
|
207
|
+
// Check to see if it is safe to use Passphrase
|
|
208
|
+
checkPassphraseSafety(method, device.features);
|
|
209
|
+
|
|
210
|
+
if (device.hasUsePassphrase() && method.useDevicePassphraseState) {
|
|
211
|
+
// check version
|
|
212
|
+
const support = supportNewPassphrase(device.features);
|
|
213
|
+
if (!support.support) {
|
|
214
|
+
return Promise.reject(
|
|
215
|
+
ERRORS.TypedError(
|
|
216
|
+
HardwareErrorCode.DeviceNotSupportPassphrase,
|
|
217
|
+
`Device not support passphrase, please update to ${support.require}`,
|
|
218
|
+
{
|
|
219
|
+
require: support.require,
|
|
220
|
+
}
|
|
221
|
+
)
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Check Device passphrase State
|
|
226
|
+
const passphraseState = await device.checkPassphraseState();
|
|
227
|
+
|
|
228
|
+
// Double check, handles the special case of Touch/Pro
|
|
229
|
+
checkPassphraseSafety(method, device.features);
|
|
230
|
+
|
|
231
|
+
if (passphraseState) {
|
|
232
|
+
DevicePool.clearDeviceCache(method.payload.connectId);
|
|
233
|
+
return Promise.reject(
|
|
234
|
+
ERRORS.TypedError(HardwareErrorCode.DeviceCheckPassphraseStateError)
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
182
239
|
try {
|
|
183
240
|
const response: object = await method.run();
|
|
184
241
|
Log.debug('Call API - Inner Method Run: ');
|
|
@@ -191,7 +248,12 @@ export const callAPI = async (message: CoreMessage) => {
|
|
|
191
248
|
}
|
|
192
249
|
};
|
|
193
250
|
Log.debug('Call API - Device Run: ', device.mainId);
|
|
194
|
-
|
|
251
|
+
|
|
252
|
+
const runOptions: RunOptions = {
|
|
253
|
+
keepSession: method.payload.keepSession,
|
|
254
|
+
...parseInitOptions(method),
|
|
255
|
+
};
|
|
256
|
+
const deviceRun = () => device.run(inner, runOptions);
|
|
195
257
|
_callPromise = createDeferred(deviceRun);
|
|
196
258
|
|
|
197
259
|
try {
|
|
@@ -247,7 +309,7 @@ async function initDeviceList(method: BaseMethod) {
|
|
|
247
309
|
_deviceList.connector = _connector;
|
|
248
310
|
}
|
|
249
311
|
|
|
250
|
-
await _deviceList.getDeviceLists(method.connectId);
|
|
312
|
+
await _deviceList.getDeviceLists(method.connectId, parseInitOptions(method));
|
|
251
313
|
}
|
|
252
314
|
|
|
253
315
|
function initDevice(method: BaseMethod) {
|
|
@@ -359,12 +421,13 @@ const ensureConnected = async (method: BaseMethod, pollingId: number) => {
|
|
|
359
421
|
if (timer) {
|
|
360
422
|
clearTimeout(timer);
|
|
361
423
|
}
|
|
424
|
+
|
|
362
425
|
/**
|
|
363
426
|
* Bluetooth should call initialize here
|
|
364
427
|
*/
|
|
365
428
|
if (env === 'react-native') {
|
|
366
429
|
await device.acquire();
|
|
367
|
-
await device.initialize();
|
|
430
|
+
await device.initialize(parseInitOptions(method));
|
|
368
431
|
}
|
|
369
432
|
resolve(device);
|
|
370
433
|
return;
|
|
@@ -421,6 +484,20 @@ export const cancel = (connectId?: string) => {
|
|
|
421
484
|
closePopup();
|
|
422
485
|
};
|
|
423
486
|
|
|
487
|
+
const checkPassphraseSafety = (method: BaseMethod, features?: Features) => {
|
|
488
|
+
if (!method.useDevicePassphraseState) return;
|
|
489
|
+
|
|
490
|
+
if (features?.passphrase_protection === true && !method.payload.passphraseState) {
|
|
491
|
+
DevicePool.clearDeviceCache(method.payload.connectId);
|
|
492
|
+
throw ERRORS.TypedError(HardwareErrorCode.DeviceOpenedPassphrase);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
if (features?.passphrase_protection === false && method.payload.passphraseState) {
|
|
496
|
+
DevicePool.clearDeviceCache(method.payload.connectId);
|
|
497
|
+
throw ERRORS.TypedError(HardwareErrorCode.DeviceNotOpenedPassphrase);
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
|
|
424
501
|
const cleanup = () => {
|
|
425
502
|
_uiPromises = [];
|
|
426
503
|
Log.debug('Cleanup...');
|
|
@@ -429,6 +506,7 @@ const cleanup = () => {
|
|
|
429
506
|
const removeDeviceListener = (device: Device) => {
|
|
430
507
|
device.removeListener(DEVICE.PIN, onDevicePinHandler);
|
|
431
508
|
device.removeListener(DEVICE.BUTTON, onDeviceButtonHandler);
|
|
509
|
+
device.removeListener(DEVICE.PASSPHRASE_ON_DEVICE, onDevicePassphraseHandler);
|
|
432
510
|
device.removeListener(DEVICE.FEATURES, onDeviceFeaturesHandler);
|
|
433
511
|
DevicePool.emitter.removeListener(DEVICE.CONNECT, onDeviceConnectHandler);
|
|
434
512
|
// DevicePool.emitter.removeListener(DEVICE.DISCONNECT, onDeviceDisconnectHandler);
|
|
@@ -489,6 +567,15 @@ const onDeviceFeaturesHandler = (...[_, features]: [...DeviceEvents['features']]
|
|
|
489
567
|
postMessage(createDeviceMessage(DEVICE.FEATURES, { ...features }));
|
|
490
568
|
};
|
|
491
569
|
|
|
570
|
+
const onDevicePassphraseHandler = (...[device]: [...DeviceEvents['passphrase_on_device']]) => {
|
|
571
|
+
postMessage(
|
|
572
|
+
createUiMessage(UI_REQUEST.REQUEST_PASSPHRASE_ON_DEVICE, {
|
|
573
|
+
device: device.toMessageObject() as KnownDevice,
|
|
574
|
+
passphraseState: device.passphraseState,
|
|
575
|
+
})
|
|
576
|
+
);
|
|
577
|
+
};
|
|
578
|
+
|
|
492
579
|
/**
|
|
493
580
|
* Emit message to listener (parent).
|
|
494
581
|
* Clear method reference from _callMethods
|
package/src/device/Device.ts
CHANGED
|
@@ -7,11 +7,6 @@ import {
|
|
|
7
7
|
ERRORS,
|
|
8
8
|
HardwareError,
|
|
9
9
|
} from '@onekeyfe/hd-shared';
|
|
10
|
-
|
|
11
|
-
import type DeviceConnector from './DeviceConnector';
|
|
12
|
-
// eslint-disable-next-line import/no-cycle
|
|
13
|
-
import { DeviceCommands } from './DeviceCommands';
|
|
14
|
-
|
|
15
10
|
import {
|
|
16
11
|
getDeviceFirmwareVersion,
|
|
17
12
|
getDeviceLabel,
|
|
@@ -19,7 +14,13 @@ import {
|
|
|
19
14
|
getDeviceUUID,
|
|
20
15
|
getDeviceBLEFirmwareVersion,
|
|
21
16
|
getDeviceTypeOnBootloader,
|
|
17
|
+
getPassphraseState,
|
|
22
18
|
} from '../utils/deviceFeaturesUtils';
|
|
19
|
+
|
|
20
|
+
import type DeviceConnector from './DeviceConnector';
|
|
21
|
+
// eslint-disable-next-line import/no-cycle
|
|
22
|
+
import { DeviceCommands } from './DeviceCommands';
|
|
23
|
+
|
|
23
24
|
import type { Features, Device as DeviceTyped, UnavailableCapabilities } from '../types';
|
|
24
25
|
import { DEVICE, DeviceButtonRequestPayload, DeviceFeaturesPayload } from '../events';
|
|
25
26
|
import { UI_REQUEST } from '../constants/ui-request';
|
|
@@ -27,10 +28,16 @@ import { PROTO } from '../constants';
|
|
|
27
28
|
import { getLogger, LoggerNames } from '../utils';
|
|
28
29
|
import { DataManager } from '../data-manager';
|
|
29
30
|
|
|
30
|
-
type
|
|
31
|
-
|
|
31
|
+
export type InitOptions = {
|
|
32
|
+
initSession?: boolean;
|
|
33
|
+
deviceId?: string;
|
|
34
|
+
passphraseState?: string;
|
|
32
35
|
};
|
|
33
36
|
|
|
37
|
+
export type RunOptions = {
|
|
38
|
+
keepSession?: boolean;
|
|
39
|
+
} & InitOptions;
|
|
40
|
+
|
|
34
41
|
const parseRunOptions = (options?: RunOptions): RunOptions => {
|
|
35
42
|
if (!options) options = {};
|
|
36
43
|
return options;
|
|
@@ -51,6 +58,8 @@ export interface Device {
|
|
|
51
58
|
emit<K extends keyof DeviceEvents>(type: K, ...args: DeviceEvents[K]): boolean;
|
|
52
59
|
}
|
|
53
60
|
|
|
61
|
+
const deviceSessionCache: Record<string, string> = {};
|
|
62
|
+
|
|
54
63
|
export class Device extends EventEmitter {
|
|
55
64
|
/**
|
|
56
65
|
* 设备标识对象
|
|
@@ -102,6 +111,8 @@ export class Device extends EventEmitter {
|
|
|
102
111
|
*/
|
|
103
112
|
keepSession = false;
|
|
104
113
|
|
|
114
|
+
passphraseState: string | undefined = undefined;
|
|
115
|
+
|
|
105
116
|
constructor(descriptor: DeviceDescriptor) {
|
|
106
117
|
super();
|
|
107
118
|
this.originalDescriptor = descriptor;
|
|
@@ -239,46 +250,101 @@ export class Device extends EventEmitter {
|
|
|
239
250
|
return this.commands;
|
|
240
251
|
}
|
|
241
252
|
|
|
242
|
-
getInternalState() {
|
|
243
|
-
|
|
253
|
+
getInternalState(_deviceId?: string) {
|
|
254
|
+
Log.debug(
|
|
255
|
+
'getInternalState session param: ',
|
|
256
|
+
`device_id: ${_deviceId}`,
|
|
257
|
+
`features.device_id: ${this.features?.device_id}`,
|
|
258
|
+
`passphraseState: ${this.passphraseState}`
|
|
259
|
+
);
|
|
260
|
+
Log.debug('getInternalState session cache: ', deviceSessionCache);
|
|
261
|
+
|
|
262
|
+
const deviceId = _deviceId || this.features?.device_id;
|
|
263
|
+
if (!deviceId) return undefined;
|
|
264
|
+
if (!this.passphraseState) return undefined;
|
|
265
|
+
|
|
266
|
+
const usePassKey = `${deviceId}@${this.passphraseState}`;
|
|
267
|
+
|
|
268
|
+
if (!deviceSessionCache[usePassKey]) {
|
|
269
|
+
const key = `${deviceId}`;
|
|
270
|
+
if (deviceSessionCache[key]) {
|
|
271
|
+
deviceSessionCache[usePassKey] = deviceSessionCache[key];
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return deviceSessionCache[usePassKey];
|
|
244
276
|
}
|
|
245
277
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
278
|
+
setInternalState(state: string, initSession?: boolean) {
|
|
279
|
+
Log.debug(
|
|
280
|
+
'setInternalState session param: ',
|
|
281
|
+
`state: ${state}`,
|
|
282
|
+
`initSession: ${initSession}`,
|
|
283
|
+
`device_id: ${this.features?.device_id}`,
|
|
284
|
+
`passphraseState: ${this.passphraseState}`
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
if (!this.features) return;
|
|
288
|
+
if (!this.passphraseState && !initSession) return;
|
|
289
|
+
|
|
290
|
+
let key = `${this.features.device_id}`;
|
|
291
|
+
if (this.passphraseState) {
|
|
292
|
+
key += `@${this.passphraseState}`;
|
|
293
|
+
}
|
|
294
|
+
if (state) {
|
|
295
|
+
deviceSessionCache[key] = state;
|
|
254
296
|
}
|
|
297
|
+
Log.debug('setInternalState done session cache: ', deviceSessionCache);
|
|
298
|
+
}
|
|
255
299
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
}
|
|
268
|
-
}
|
|
300
|
+
clearInternalState(_deviceId?: string) {
|
|
301
|
+
Log.debug('clearInternalState param: ', _deviceId);
|
|
302
|
+
|
|
303
|
+
const deviceId = _deviceId || this.features?.device_id;
|
|
304
|
+
if (!deviceId) return;
|
|
305
|
+
const key = `${deviceId}`;
|
|
306
|
+
delete deviceSessionCache[key];
|
|
307
|
+
|
|
308
|
+
if (this.passphraseState) {
|
|
309
|
+
const usePassKey = `${deviceId}@${this.passphraseState}`;
|
|
310
|
+
delete deviceSessionCache[usePassKey];
|
|
269
311
|
}
|
|
270
312
|
}
|
|
271
313
|
|
|
314
|
+
async initialize(options?: InitOptions) {
|
|
315
|
+
Log.debug('initialize param:', options);
|
|
316
|
+
|
|
317
|
+
this.passphraseState = options?.passphraseState;
|
|
318
|
+
|
|
319
|
+
if (options?.initSession) {
|
|
320
|
+
this.clearInternalState(options?.deviceId);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const internalState = this.getInternalState(options?.deviceId);
|
|
324
|
+
const payload: any = {};
|
|
325
|
+
if (internalState) {
|
|
326
|
+
payload.session_id = internalState;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
Log.debug('initialize payload:', payload);
|
|
330
|
+
|
|
331
|
+
const { message } = await this.commands.typedCall('Initialize', 'Features', payload);
|
|
332
|
+
this._updateFeatures(message, options?.initSession);
|
|
333
|
+
}
|
|
334
|
+
|
|
272
335
|
async getFeatures() {
|
|
273
336
|
const { message } = await this.commands.typedCall('GetFeatures', 'Features', {});
|
|
274
337
|
this._updateFeatures(message);
|
|
275
338
|
}
|
|
276
339
|
|
|
277
|
-
_updateFeatures(feat: Features) {
|
|
340
|
+
_updateFeatures(feat: Features, initSession?: boolean) {
|
|
278
341
|
// GetFeatures doesn't return 'session_id'
|
|
279
342
|
if (this.features && this.features.session_id && !feat.session_id) {
|
|
280
343
|
feat.session_id = this.features.session_id;
|
|
281
344
|
}
|
|
345
|
+
if (this.features && this.features.device_id && feat.session_id) {
|
|
346
|
+
this.setInternalState(feat.session_id, initSession);
|
|
347
|
+
}
|
|
282
348
|
feat.unlocked = feat.unlocked || true;
|
|
283
349
|
|
|
284
350
|
this.features = feat;
|
|
@@ -336,7 +402,7 @@ export class Device extends EventEmitter {
|
|
|
336
402
|
await this.acquire();
|
|
337
403
|
try {
|
|
338
404
|
if (fn) {
|
|
339
|
-
await this.initialize();
|
|
405
|
+
await this.initialize(options);
|
|
340
406
|
}
|
|
341
407
|
} catch (error) {
|
|
342
408
|
this.runPromise = null;
|
|
@@ -350,21 +416,6 @@ export class Device extends EventEmitter {
|
|
|
350
416
|
)
|
|
351
417
|
);
|
|
352
418
|
}
|
|
353
|
-
} else if (env === 'react-native') {
|
|
354
|
-
/**
|
|
355
|
-
* The timing of the mobile initialization is different, so it needs to be closed here
|
|
356
|
-
*/
|
|
357
|
-
if (this.features?.passphrase_protection) {
|
|
358
|
-
if (this.listenerCount(DEVICE.PIN) > 0) {
|
|
359
|
-
Log.debug('try to close passpharse for mobile');
|
|
360
|
-
try {
|
|
361
|
-
await this.commands.typedCall('ApplySettings', 'Success', { use_passphrase: false });
|
|
362
|
-
} catch (e) {
|
|
363
|
-
this.runPromise = null;
|
|
364
|
-
return Promise.reject(e);
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
419
|
}
|
|
369
420
|
}
|
|
370
421
|
|
|
@@ -490,12 +541,40 @@ export class Device extends EventEmitter {
|
|
|
490
541
|
return null;
|
|
491
542
|
}
|
|
492
543
|
|
|
544
|
+
hasUsePassphrase() {
|
|
545
|
+
const isModeT =
|
|
546
|
+
getDeviceType(this.features) === 'touch' || getDeviceType(this.features) === 'pro';
|
|
547
|
+
const preCheckTouch = isModeT && this.features?.unlocked === true;
|
|
548
|
+
|
|
549
|
+
return this.features && (!!this.features.passphrase_protection || preCheckTouch);
|
|
550
|
+
}
|
|
551
|
+
|
|
493
552
|
checkDeviceId(deviceId: string) {
|
|
494
553
|
if (this.features) {
|
|
495
554
|
return this.features.device_id === deviceId;
|
|
496
555
|
}
|
|
497
556
|
return false;
|
|
498
557
|
}
|
|
558
|
+
|
|
559
|
+
async checkPassphraseState() {
|
|
560
|
+
if (!this.features) return false;
|
|
561
|
+
const locked = this.features?.unlocked === true;
|
|
562
|
+
const isModeT =
|
|
563
|
+
getDeviceType(this.features) === 'touch' || getDeviceType(this.features) === 'pro';
|
|
564
|
+
|
|
565
|
+
const newState = await getPassphraseState(this.features, this.commands);
|
|
566
|
+
|
|
567
|
+
// if Touch/Pro was locked before, refresh the passphrase state
|
|
568
|
+
if (isModeT && locked) {
|
|
569
|
+
await this.getFeatures();
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// When exists passphraseState, check passphraseState
|
|
573
|
+
if (this.passphraseState && this.passphraseState !== newState) {
|
|
574
|
+
this.clearInternalState();
|
|
575
|
+
return newState;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
499
578
|
}
|
|
500
579
|
|
|
501
580
|
export default Device;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Transport, Messages } from '@onekeyfe/hd-transport';
|
|
2
2
|
import { ERRORS, HardwareError, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
3
|
-
// eslint-disable-next-line import/no-cycle
|
|
4
3
|
import TransportManager from '../data-manager/TransportManager';
|
|
5
4
|
import DataManager from '../data-manager/DataManager';
|
|
6
5
|
import { patchFeatures, getLogger, LoggerNames } from '../utils';
|
|
@@ -164,6 +163,10 @@ export class DeviceCommands {
|
|
|
164
163
|
error = ERRORS.TypedError(HardwareErrorCode.PinCancelled);
|
|
165
164
|
}
|
|
166
165
|
|
|
166
|
+
if (code === 'Failure_DataError' && message === 'Please confirm the BlindSign enabled') {
|
|
167
|
+
error = ERRORS.TypedError(HardwareErrorCode.BlindSignDisabled);
|
|
168
|
+
}
|
|
169
|
+
|
|
167
170
|
if (error) {
|
|
168
171
|
return Promise.reject(error);
|
|
169
172
|
}
|
|
@@ -214,19 +217,20 @@ export class DeviceCommands {
|
|
|
214
217
|
);
|
|
215
218
|
}
|
|
216
219
|
|
|
217
|
-
/**
|
|
218
|
-
* Temporary, do not support passphrase
|
|
219
|
-
*/
|
|
220
|
-
if (this.device.features?.passphrase_protection) {
|
|
221
|
-
return Promise.reject(ERRORS.TypedError(HardwareErrorCode.DeviceNotSupportPassphrase));
|
|
222
|
-
}
|
|
223
|
-
|
|
224
220
|
if (res.type === 'PassphraseRequest') {
|
|
225
221
|
/**
|
|
226
222
|
* Temporary, do not support passphrase
|
|
227
223
|
*/
|
|
228
224
|
// return this._commonCall('PassphraseAck', { passphrase: '' });
|
|
229
|
-
return Promise.reject(
|
|
225
|
+
return Promise.reject(
|
|
226
|
+
ERRORS.TypedError(
|
|
227
|
+
HardwareErrorCode.DeviceNotSupportPassphrase,
|
|
228
|
+
'Device not support passphrase',
|
|
229
|
+
{
|
|
230
|
+
require: '2.4.0',
|
|
231
|
+
}
|
|
232
|
+
)
|
|
233
|
+
);
|
|
230
234
|
}
|
|
231
235
|
|
|
232
236
|
// TT fw lower than 2.3.0, device send his current state
|
package/src/device/DeviceList.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import EventEmitter from 'events';
|
|
2
2
|
import DeviceConnector from './DeviceConnector';
|
|
3
|
-
import { Device } from './Device';
|
|
3
|
+
import { Device, InitOptions } from './Device';
|
|
4
4
|
import { DevicePool } from './DevicePool';
|
|
5
5
|
|
|
6
6
|
export class DeviceList extends EventEmitter {
|
|
@@ -12,13 +12,17 @@ export class DeviceList extends EventEmitter {
|
|
|
12
12
|
* 获取已连接的设备列表
|
|
13
13
|
* @returns {OneKeyDeviceInfo[]}
|
|
14
14
|
*/
|
|
15
|
-
async getDeviceLists(connectId?: string) {
|
|
15
|
+
async getDeviceLists(connectId?: string, initOptions?: InitOptions) {
|
|
16
16
|
const deviceDiff = await this.connector?.enumerate();
|
|
17
17
|
const descriptorList = deviceDiff?.descriptors ?? [];
|
|
18
18
|
|
|
19
19
|
this.devices = {};
|
|
20
20
|
|
|
21
|
-
const { deviceList, devices } = await DevicePool.getDevices(
|
|
21
|
+
const { deviceList, devices } = await DevicePool.getDevices(
|
|
22
|
+
descriptorList,
|
|
23
|
+
connectId,
|
|
24
|
+
initOptions
|
|
25
|
+
);
|
|
22
26
|
this.devices = devices;
|
|
23
27
|
return deviceList;
|
|
24
28
|
}
|
package/src/device/DevicePool.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import EventEmitter from 'events';
|
|
2
2
|
import { OneKeyDeviceInfo as DeviceDescriptor } from '@onekeyfe/hd-transport';
|
|
3
3
|
// eslint-disable-next-line import/no-cycle
|
|
4
|
-
import { Device } from './Device';
|
|
4
|
+
import { Device, InitOptions } from './Device';
|
|
5
5
|
import { DEVICE } from '../events';
|
|
6
6
|
import type DeviceConnector from './DeviceConnector';
|
|
7
7
|
import { getDeviceUUID, getLogger, LoggerNames } from '../utils';
|
|
@@ -89,8 +89,12 @@ export class DevicePool extends EventEmitter {
|
|
|
89
89
|
this.connector = connector;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
static async getDevices(
|
|
93
|
-
|
|
92
|
+
static async getDevices(
|
|
93
|
+
descriptorList: DeviceDescriptor[],
|
|
94
|
+
connectId?: string,
|
|
95
|
+
initOptions?: InitOptions
|
|
96
|
+
) {
|
|
97
|
+
Log.debug('get device list: connectId: ', connectId);
|
|
94
98
|
|
|
95
99
|
const devices: Record<string, Device> = {};
|
|
96
100
|
const deviceList = [];
|
|
@@ -106,7 +110,7 @@ export class DevicePool extends EventEmitter {
|
|
|
106
110
|
device.updateDescriptor(exist, true);
|
|
107
111
|
devices[connectId] = device;
|
|
108
112
|
deviceList.push(device);
|
|
109
|
-
await this._checkDevicePool();
|
|
113
|
+
await this._checkDevicePool(initOptions);
|
|
110
114
|
return { devices, deviceList };
|
|
111
115
|
}
|
|
112
116
|
Log.debug('found device in cache, but path is different: ', connectId);
|
|
@@ -114,7 +118,7 @@ export class DevicePool extends EventEmitter {
|
|
|
114
118
|
}
|
|
115
119
|
|
|
116
120
|
for await (const descriptor of descriptorList) {
|
|
117
|
-
const device = await this._createDevice(descriptor);
|
|
121
|
+
const device = await this._createDevice(descriptor, initOptions);
|
|
118
122
|
|
|
119
123
|
if (device.features) {
|
|
120
124
|
const uuid = getDeviceUUID(device.features);
|
|
@@ -131,31 +135,39 @@ export class DevicePool extends EventEmitter {
|
|
|
131
135
|
Log.debug('get devices result : ', devices, deviceList);
|
|
132
136
|
console.log('device poll -> connected: ', this.connectedPool);
|
|
133
137
|
console.log('device poll -> disconnected: ', this.disconnectPool);
|
|
134
|
-
await this._checkDevicePool();
|
|
138
|
+
await this._checkDevicePool(initOptions);
|
|
135
139
|
return { devices, deviceList };
|
|
136
140
|
}
|
|
137
141
|
|
|
138
|
-
static
|
|
142
|
+
static clearDeviceCache(connectId?: string) {
|
|
143
|
+
Log.debug('clear device pool cache: connectId', connectId);
|
|
144
|
+
Log.debug('clear device pool cache: ', this.devicesCache);
|
|
145
|
+
if (connectId) {
|
|
146
|
+
delete this.devicesCache[connectId];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
static async _createDevice(descriptor: DeviceDescriptor, initOptions?: InitOptions) {
|
|
139
151
|
let device = this.getDeviceByPath(descriptor.path);
|
|
140
152
|
if (!device) {
|
|
141
153
|
device = Device.fromDescriptor(descriptor);
|
|
142
154
|
device.deviceConnector = this.connector;
|
|
143
155
|
await device.connect();
|
|
144
|
-
await device.initialize();
|
|
156
|
+
await device.initialize(initOptions);
|
|
145
157
|
await device.release();
|
|
146
158
|
}
|
|
147
159
|
return device;
|
|
148
160
|
}
|
|
149
161
|
|
|
150
|
-
static async _checkDevicePool() {
|
|
151
|
-
await this._sendConnectMessage();
|
|
162
|
+
static async _checkDevicePool(initOptions?: InitOptions) {
|
|
163
|
+
await this._sendConnectMessage(initOptions);
|
|
152
164
|
this._sendDisconnectMessage();
|
|
153
165
|
}
|
|
154
166
|
|
|
155
|
-
static async _sendConnectMessage() {
|
|
167
|
+
static async _sendConnectMessage(initOptions?: InitOptions) {
|
|
156
168
|
for (let i = this.connectedPool.length - 1; i >= 0; i--) {
|
|
157
169
|
const descriptor = this.connectedPool[i];
|
|
158
|
-
const device = await this._createDevice(descriptor);
|
|
170
|
+
const device = await this._createDevice(descriptor, initOptions);
|
|
159
171
|
Log.debug('emit DEVICE.CONNECT: ', device);
|
|
160
172
|
this.emitter.emit(DEVICE.CONNECT, device);
|
|
161
173
|
this.connectedPool.splice(i, 1);
|
package/src/events/ui-request.ts
CHANGED
|
@@ -9,6 +9,7 @@ export const UI_REQUEST = {
|
|
|
9
9
|
REQUEST_PIN: 'ui-request_pin',
|
|
10
10
|
INVALID_PIN: 'ui-invalid_pin',
|
|
11
11
|
REQUEST_BUTTON: 'ui-button',
|
|
12
|
+
REQUEST_PASSPHRASE_ON_DEVICE: 'ui-request_passphrase_on_device',
|
|
12
13
|
|
|
13
14
|
CLOSE_UI_WINDOW: 'ui-close_window',
|
|
14
15
|
|
|
@@ -41,6 +42,14 @@ export interface UiRequestButton {
|
|
|
41
42
|
payload: DeviceButtonRequest['payload'];
|
|
42
43
|
}
|
|
43
44
|
|
|
45
|
+
export interface UiRequestPassphrase {
|
|
46
|
+
type: typeof UI_REQUEST.REQUEST_PASSPHRASE_ON_DEVICE;
|
|
47
|
+
payload: {
|
|
48
|
+
device: Device;
|
|
49
|
+
passphraseState?: string;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
44
53
|
export interface FirmwareProgress {
|
|
45
54
|
type: typeof UI_REQUEST.FIRMWARE_PROGRESS;
|
|
46
55
|
payload: {
|
|
@@ -53,6 +62,7 @@ export type UiEvent =
|
|
|
53
62
|
| UiRequestWithoutPayload
|
|
54
63
|
| UiRequestDeviceAction
|
|
55
64
|
| UiRequestButton
|
|
65
|
+
| UiRequestPassphrase
|
|
56
66
|
| FirmwareProgress;
|
|
57
67
|
|
|
58
68
|
export type UiEventMessage = UiEvent & { event: typeof UI_EVENT };
|
package/src/inject.ts
CHANGED
|
@@ -88,6 +88,8 @@ export const inject = ({
|
|
|
88
88
|
deviceSupportFeatures: connectId => call({ connectId, method: 'deviceSupportFeatures' }),
|
|
89
89
|
deviceVerify: (connectId, params) => call({ ...params, connectId, method: 'deviceVerify' }),
|
|
90
90
|
deviceWipe: connectId => call({ connectId, method: 'deviceWipe' }),
|
|
91
|
+
getPassphraseState: (connectId, params) =>
|
|
92
|
+
call({ ...params, connectId, method: 'getPassphraseState' }),
|
|
91
93
|
|
|
92
94
|
evmGetAddress: (connectId, deviceId, params) =>
|
|
93
95
|
call({ ...params, connectId, deviceId, method: 'evmGetAddress' }),
|
package/src/types/api/index.ts
CHANGED
|
@@ -45,6 +45,7 @@ import { firmwareUpdate } from './firmwareUpdate';
|
|
|
45
45
|
import { getLogs } from './getLogs';
|
|
46
46
|
import { deviceSupportFeatures } from './deviceSupportFeatures';
|
|
47
47
|
import { requestWebUsbDevice } from './requestWebUsbDevice';
|
|
48
|
+
import { getPassphraseState } from './getPassphraseState';
|
|
48
49
|
|
|
49
50
|
export * from './export';
|
|
50
51
|
|
|
@@ -92,6 +93,7 @@ export type CoreApi = {
|
|
|
92
93
|
deviceSupportFeatures: typeof deviceSupportFeatures;
|
|
93
94
|
deviceVerify: typeof deviceVerify;
|
|
94
95
|
deviceWipe: typeof deviceWipe;
|
|
96
|
+
getPassphraseState: typeof getPassphraseState;
|
|
95
97
|
|
|
96
98
|
evmGetAddress: typeof evmGetAddress;
|
|
97
99
|
evmGetPublicKey: typeof evmGetPublicKey;
|