@onekeyfe/hd-core 0.1.36 → 0.1.39
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 +442 -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 +98 -10
- package/src/device/Device.ts +120 -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;
|
|
@@ -378,6 +441,7 @@ const ensureConnected = async (method: BaseMethod, pollingId: number) => {
|
|
|
378
441
|
HardwareErrorCode.BleDeviceNotBonded,
|
|
379
442
|
HardwareErrorCode.BleCharacteristicNotifyError,
|
|
380
443
|
HardwareErrorCode.BleWriteCharacteristicError,
|
|
444
|
+
HardwareErrorCode.BleAlreadyConnected,
|
|
381
445
|
].includes(error.errorCode)
|
|
382
446
|
) {
|
|
383
447
|
reject(error);
|
|
@@ -420,6 +484,20 @@ export const cancel = (connectId?: string) => {
|
|
|
420
484
|
closePopup();
|
|
421
485
|
};
|
|
422
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
|
+
|
|
423
501
|
const cleanup = () => {
|
|
424
502
|
_uiPromises = [];
|
|
425
503
|
Log.debug('Cleanup...');
|
|
@@ -428,6 +506,7 @@ const cleanup = () => {
|
|
|
428
506
|
const removeDeviceListener = (device: Device) => {
|
|
429
507
|
device.removeListener(DEVICE.PIN, onDevicePinHandler);
|
|
430
508
|
device.removeListener(DEVICE.BUTTON, onDeviceButtonHandler);
|
|
509
|
+
device.removeListener(DEVICE.PASSPHRASE_ON_DEVICE, onDevicePassphraseHandler);
|
|
431
510
|
device.removeListener(DEVICE.FEATURES, onDeviceFeaturesHandler);
|
|
432
511
|
DevicePool.emitter.removeListener(DEVICE.CONNECT, onDeviceConnectHandler);
|
|
433
512
|
// DevicePool.emitter.removeListener(DEVICE.DISCONNECT, onDeviceDisconnectHandler);
|
|
@@ -488,6 +567,15 @@ const onDeviceFeaturesHandler = (...[_, features]: [...DeviceEvents['features']]
|
|
|
488
567
|
postMessage(createDeviceMessage(DEVICE.FEATURES, { ...features }));
|
|
489
568
|
};
|
|
490
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
|
+
|
|
491
579
|
/**
|
|
492
580
|
* Emit message to listener (parent).
|
|
493
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,95 @@ 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
|
+
|
|
265
|
+
const key = `${deviceId}`;
|
|
266
|
+
const usePassKey = `${deviceId}@${this.passphraseState}`;
|
|
267
|
+
// When creating a wallet, use device_id as the key
|
|
268
|
+
const session = deviceSessionCache[key] ?? deviceSessionCache[usePassKey];
|
|
269
|
+
return this.passphraseState ? session : undefined;
|
|
244
270
|
}
|
|
245
271
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
272
|
+
setInternalState(state: string, initSession?: boolean) {
|
|
273
|
+
Log.debug(
|
|
274
|
+
'setInternalState session param: ',
|
|
275
|
+
`state: ${state}`,
|
|
276
|
+
`initSession: ${initSession}`,
|
|
277
|
+
`device_id: ${this.features?.device_id}`,
|
|
278
|
+
`passphraseState: ${this.passphraseState}`
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
if (!this.features) return;
|
|
282
|
+
if (!this.passphraseState && !initSession) return;
|
|
283
|
+
|
|
284
|
+
let key = `${this.features.device_id}`;
|
|
285
|
+
if (this.passphraseState) {
|
|
286
|
+
key += `@${this.passphraseState}`;
|
|
287
|
+
}
|
|
288
|
+
if (state) {
|
|
289
|
+
deviceSessionCache[key] = state;
|
|
254
290
|
}
|
|
291
|
+
Log.debug('setInternalState done session cache: ', deviceSessionCache);
|
|
292
|
+
}
|
|
255
293
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
}
|
|
268
|
-
}
|
|
294
|
+
clearInternalState(_deviceId?: string) {
|
|
295
|
+
Log.debug('clearInternalState param: ', _deviceId);
|
|
296
|
+
|
|
297
|
+
const deviceId = _deviceId || this.features?.device_id;
|
|
298
|
+
if (!deviceId) return;
|
|
299
|
+
const key = `${deviceId}`;
|
|
300
|
+
delete deviceSessionCache[key];
|
|
301
|
+
|
|
302
|
+
if (this.passphraseState) {
|
|
303
|
+
const usePassKey = `${deviceId}@${this.passphraseState}`;
|
|
304
|
+
delete deviceSessionCache[usePassKey];
|
|
269
305
|
}
|
|
270
306
|
}
|
|
271
307
|
|
|
308
|
+
async initialize(options?: InitOptions) {
|
|
309
|
+
Log.debug('initialize param:', options);
|
|
310
|
+
|
|
311
|
+
this.passphraseState = options?.passphraseState;
|
|
312
|
+
|
|
313
|
+
if (options?.initSession) {
|
|
314
|
+
this.clearInternalState(options?.deviceId);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const internalState = this.getInternalState(options?.deviceId);
|
|
318
|
+
const payload: any = {};
|
|
319
|
+
if (internalState) {
|
|
320
|
+
payload.session_id = internalState;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
Log.debug('initialize payload:', payload);
|
|
324
|
+
|
|
325
|
+
const { message } = await this.commands.typedCall('Initialize', 'Features', payload);
|
|
326
|
+
this._updateFeatures(message, options?.initSession);
|
|
327
|
+
}
|
|
328
|
+
|
|
272
329
|
async getFeatures() {
|
|
273
330
|
const { message } = await this.commands.typedCall('GetFeatures', 'Features', {});
|
|
274
331
|
this._updateFeatures(message);
|
|
275
332
|
}
|
|
276
333
|
|
|
277
|
-
_updateFeatures(feat: Features) {
|
|
334
|
+
_updateFeatures(feat: Features, initSession?: boolean) {
|
|
278
335
|
// GetFeatures doesn't return 'session_id'
|
|
279
336
|
if (this.features && this.features.session_id && !feat.session_id) {
|
|
280
337
|
feat.session_id = this.features.session_id;
|
|
281
338
|
}
|
|
339
|
+
if (this.features && this.features.device_id && feat.session_id) {
|
|
340
|
+
this.setInternalState(feat.session_id, initSession);
|
|
341
|
+
}
|
|
282
342
|
feat.unlocked = feat.unlocked || true;
|
|
283
343
|
|
|
284
344
|
this.features = feat;
|
|
@@ -336,7 +396,7 @@ export class Device extends EventEmitter {
|
|
|
336
396
|
await this.acquire();
|
|
337
397
|
try {
|
|
338
398
|
if (fn) {
|
|
339
|
-
await this.initialize();
|
|
399
|
+
await this.initialize(options);
|
|
340
400
|
}
|
|
341
401
|
} catch (error) {
|
|
342
402
|
this.runPromise = null;
|
|
@@ -350,21 +410,6 @@ export class Device extends EventEmitter {
|
|
|
350
410
|
)
|
|
351
411
|
);
|
|
352
412
|
}
|
|
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
413
|
}
|
|
369
414
|
}
|
|
370
415
|
|
|
@@ -490,12 +535,40 @@ export class Device extends EventEmitter {
|
|
|
490
535
|
return null;
|
|
491
536
|
}
|
|
492
537
|
|
|
538
|
+
hasUsePassphrase() {
|
|
539
|
+
const isModeT =
|
|
540
|
+
getDeviceType(this.features) === 'touch' || getDeviceType(this.features) === 'pro';
|
|
541
|
+
const preCheckTouch = isModeT && this.features?.unlocked === true;
|
|
542
|
+
|
|
543
|
+
return this.features && (!!this.features.passphrase_protection || preCheckTouch);
|
|
544
|
+
}
|
|
545
|
+
|
|
493
546
|
checkDeviceId(deviceId: string) {
|
|
494
547
|
if (this.features) {
|
|
495
548
|
return this.features.device_id === deviceId;
|
|
496
549
|
}
|
|
497
550
|
return false;
|
|
498
551
|
}
|
|
552
|
+
|
|
553
|
+
async checkPassphraseState() {
|
|
554
|
+
if (!this.features) return false;
|
|
555
|
+
const locked = this.features?.unlocked === true;
|
|
556
|
+
const isModeT =
|
|
557
|
+
getDeviceType(this.features) === 'touch' || getDeviceType(this.features) === 'pro';
|
|
558
|
+
|
|
559
|
+
const newState = await getPassphraseState(this.features, this.commands);
|
|
560
|
+
|
|
561
|
+
// if Touch/Pro was locked before, refresh the passphrase state
|
|
562
|
+
if (isModeT && locked) {
|
|
563
|
+
await this.getFeatures();
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// When exists passphraseState, check passphraseState
|
|
567
|
+
if (this.passphraseState && this.passphraseState !== newState) {
|
|
568
|
+
this.clearInternalState();
|
|
569
|
+
return newState;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
499
572
|
}
|
|
500
573
|
|
|
501
574
|
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;
|