@onekeyfe/hd-core 1.0.33 → 1.0.34-alpha.1

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.
Files changed (50) hide show
  1. package/dist/api/GetPassphraseState.d.ts +1 -1
  2. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  3. package/dist/api/allnetwork/AllNetworkGetAddress.d.ts +3 -1
  4. package/dist/api/allnetwork/AllNetworkGetAddress.d.ts.map +1 -1
  5. package/dist/api/device/DeviceUnlock.d.ts +7 -0
  6. package/dist/api/device/DeviceUnlock.d.ts.map +1 -0
  7. package/dist/api/helpers/hexUtils.d.ts +0 -1
  8. package/dist/api/helpers/hexUtils.d.ts.map +1 -1
  9. package/dist/api/index.d.ts +1 -0
  10. package/dist/api/index.d.ts.map +1 -1
  11. package/dist/core/index.d.ts.map +1 -1
  12. package/dist/device/Device.d.ts +9 -3
  13. package/dist/device/Device.d.ts.map +1 -1
  14. package/dist/device/DeviceCommands.d.ts +7 -5
  15. package/dist/device/DeviceCommands.d.ts.map +1 -1
  16. package/dist/events/device.d.ts +3 -0
  17. package/dist/events/device.d.ts.map +1 -1
  18. package/dist/events/ui-request.d.ts +2 -1
  19. package/dist/events/ui-request.d.ts.map +1 -1
  20. package/dist/events/ui-response.d.ts +1 -0
  21. package/dist/events/ui-response.d.ts.map +1 -1
  22. package/dist/index.d.ts +25 -9
  23. package/dist/index.js +207 -69
  24. package/dist/inject.d.ts.map +1 -1
  25. package/dist/types/api/deviceUnlock.d.ts +4 -0
  26. package/dist/types/api/deviceUnlock.d.ts.map +1 -0
  27. package/dist/types/api/index.d.ts +2 -0
  28. package/dist/types/api/index.d.ts.map +1 -1
  29. package/dist/utils/deviceFeaturesUtils.d.ts +16 -2
  30. package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
  31. package/dist/utils/patch.d.ts +1 -1
  32. package/dist/utils/patch.d.ts.map +1 -1
  33. package/package.json +4 -4
  34. package/src/api/GetPassphraseState.ts +19 -3
  35. package/src/api/allnetwork/AllNetworkGetAddress.ts +18 -20
  36. package/src/api/device/DeviceUnlock.ts +26 -0
  37. package/src/api/evm/EVMSignTypedData.ts +2 -2
  38. package/src/api/helpers/hexUtils.ts +0 -29
  39. package/src/api/index.ts +1 -0
  40. package/src/core/index.ts +12 -7
  41. package/src/data/messages/messages.json +57 -2
  42. package/src/device/Device.ts +75 -7
  43. package/src/device/DeviceCommands.ts +15 -4
  44. package/src/events/device.ts +4 -0
  45. package/src/events/ui-request.ts +2 -1
  46. package/src/events/ui-response.ts +1 -0
  47. package/src/inject.ts +2 -0
  48. package/src/types/api/deviceUnlock.ts +4 -0
  49. package/src/types/api/index.ts +2 -0
  50. package/src/utils/deviceFeaturesUtils.ts +71 -7
@@ -3021,7 +3021,8 @@
3021
3021
  "ButtonRequest_Success": 17,
3022
3022
  "ButtonRequest_Warning": 18,
3023
3023
  "ButtonRequest_PassphraseEntry": 19,
3024
- "ButtonRequest_PinEntry": 20
3024
+ "ButtonRequest_PinEntry": 20,
3025
+ "ButtonRequest_AttachPin": 8000
3025
3026
  }
3026
3027
  }
3027
3028
  }
@@ -3071,6 +3072,10 @@
3071
3072
  "options": {
3072
3073
  "deprecated": true
3073
3074
  }
3075
+ },
3076
+ "exists_attach_pin_user": {
3077
+ "type": "bool",
3078
+ "id": 8000
3074
3079
  }
3075
3080
  }
3076
3081
  },
@@ -3090,6 +3095,10 @@
3090
3095
  "on_device": {
3091
3096
  "type": "bool",
3092
3097
  "id": 3
3098
+ },
3099
+ "on_device_attach_pin": {
3100
+ "type": "bool",
3101
+ "id": 8000
3093
3102
  }
3094
3103
  }
3095
3104
  },
@@ -6051,6 +6060,10 @@
6051
6060
  "derive_cardano": {
6052
6061
  "type": "bool",
6053
6062
  "id": 3
6063
+ },
6064
+ "passphrase_state": {
6065
+ "type": "string",
6066
+ "id": 8000
6054
6067
  }
6055
6068
  }
6056
6069
  },
@@ -6429,6 +6442,14 @@
6429
6442
  "onekey_se04_state": {
6430
6443
  "type": "OneKeySEState",
6431
6444
  "id": 624
6445
+ },
6446
+ "attach_to_pin_user": {
6447
+ "type": "bool",
6448
+ "id": 625
6449
+ },
6450
+ "unlocked_attach_pin": {
6451
+ "type": "bool",
6452
+ "id": 626
6432
6453
  }
6433
6454
  },
6434
6455
  "nested": {
@@ -7533,6 +7554,38 @@
7533
7554
  }
7534
7555
  }
7535
7556
  },
7557
+ "GetPassphraseState": {
7558
+ "fields": {
7559
+ "passphrase_state": {
7560
+ "type": "string",
7561
+ "id": 1
7562
+ },
7563
+ "_only_main_pin": {
7564
+ "type": "bool",
7565
+ "id": 2
7566
+ },
7567
+ "allow_create_attach_pin": {
7568
+ "type": "bool",
7569
+ "id": 3
7570
+ }
7571
+ }
7572
+ },
7573
+ "PassphraseState": {
7574
+ "fields": {
7575
+ "passphrase_state": {
7576
+ "type": "string",
7577
+ "id": 1
7578
+ },
7579
+ "session_id": {
7580
+ "type": "bytes",
7581
+ "id": 2
7582
+ },
7583
+ "unlocked_attach_pin": {
7584
+ "type": "bool",
7585
+ "id": 3
7586
+ }
7587
+ }
7588
+ },
7536
7589
  "MoneroTransactionSourceEntry": {
7537
7590
  "fields": {
7538
7591
  "outputs": {
@@ -12144,7 +12197,9 @@
12144
12197
  "MessageType_ListResDir": 10023,
12145
12198
  "MessageType_FileInfoList": 10024,
12146
12199
  "MessageType_OnekeyGetFeatures": 10025,
12147
- "MessageType_OnekeyFeatures": 10026
12200
+ "MessageType_OnekeyFeatures": 10026,
12201
+ "MessageType_GetPassphraseState": 10028,
12202
+ "MessageType_PassphraseState": 10029
12148
12203
  }
12149
12204
  },
12150
12205
  "google": {
@@ -33,7 +33,13 @@ import {
33
33
  type Features,
34
34
  type UnavailableCapabilities,
35
35
  } from '../types';
36
- import { DEVICE, DeviceButtonRequestPayload, DeviceFeaturesPayload, UI_REQUEST } from '../events';
36
+ import {
37
+ DEVICE,
38
+ DeviceButtonRequestPayload,
39
+ DeviceFeaturesPayload,
40
+ PassphraseRequestPayload,
41
+ UI_REQUEST,
42
+ } from '../events';
37
43
  import { PROTO } from '../constants';
38
44
  import { DataManager } from '../data-manager';
39
45
  import TransportManager from '../data-manager/TransportManager';
@@ -61,7 +67,11 @@ export interface DeviceEvents {
61
67
  [DEVICE.PASSPHRASE_ON_DEVICE]: [Device, ((response: any) => void)?];
62
68
  [DEVICE.BUTTON]: [Device, DeviceButtonRequestPayload];
63
69
  [DEVICE.FEATURES]: [Device, DeviceFeaturesPayload];
64
- [DEVICE.PASSPHRASE]: [Device, (response: PassphrasePromptResponse, error?: Error) => void];
70
+ [DEVICE.PASSPHRASE]: [
71
+ Device,
72
+ PassphraseRequestPayload,
73
+ (response: PassphrasePromptResponse, error?: Error) => void
74
+ ];
65
75
  [DEVICE.SELECT_DEVICE_IN_BOOTLOADER_FOR_WEB_DEVICE]: [
66
76
  Device,
67
77
  (err: any, deviceId: string) => void
@@ -323,6 +333,26 @@ export class Device extends EventEmitter {
323
333
  Log.debug('tryFixInternalState session cache: ', deviceSessionCache);
324
334
  }
325
335
 
336
+ // attach to pin to fix internal state
337
+ updateInternalState(state: string, deviceId: string, sessionId: string | null = null) {
338
+ Log.debug(
339
+ 'updateInternalState session param: ',
340
+ `device_id: ${deviceId}`,
341
+ `passphraseState: ${state}`,
342
+ `sessionId: ${sessionId}`
343
+ );
344
+
345
+ if (sessionId) {
346
+ deviceSessionCache[this.generateStateKey(deviceId, state)] = sessionId;
347
+ // delete the old sessionId
348
+ const oldKey = `${deviceId}`;
349
+ if (deviceSessionCache[oldKey]) {
350
+ delete deviceSessionCache[oldKey];
351
+ }
352
+ }
353
+ Log.debug('updateInternalState session cache: ', deviceSessionCache);
354
+ }
355
+
326
356
  private setInternalState(state: string, initSession?: boolean) {
327
357
  Log.debug(
328
358
  'setInternalState session param: ',
@@ -361,7 +391,7 @@ export class Device extends EventEmitter {
361
391
  }
362
392
 
363
393
  async initialize(options?: InitOptions) {
364
- Log.debug('initialize param:', options);
394
+ // Log.debug('initialize param:', options);
365
395
 
366
396
  this.passphraseState = options?.passphraseState;
367
397
 
@@ -378,8 +408,14 @@ export class Device extends EventEmitter {
378
408
  if (options?.deriveCardano) {
379
409
  payload.derive_cardano = true;
380
410
  }
411
+ payload.passphrase_state = options?.passphraseState;
381
412
 
382
- Log.debug('initialize payload:', payload);
413
+ // Log.debug('initialize payload:', payload);
414
+ console.log('=====>>>>>> initialize device begin: ', payload, {
415
+ deviceId: options?.deviceId,
416
+ passphraseState: options?.passphraseState,
417
+ initSession: options?.initSession,
418
+ });
383
419
 
384
420
  try {
385
421
  // @ts-expect-error
@@ -393,6 +429,7 @@ export class Device extends EventEmitter {
393
429
  }),
394
430
  ]);
395
431
 
432
+ console.log('=====>>>>>> initialize device end: ', message);
396
433
  this._updateFeatures(message, options?.initSession);
397
434
  await TransportManager.reconfigure(this.features);
398
435
  } catch (error) {
@@ -693,12 +730,43 @@ export class Device extends EventEmitter {
693
730
  return false;
694
731
  }
695
732
 
696
- async checkPassphraseStateSafety(passphraseState?: string) {
733
+ async lockDevice() {
734
+ const res = await this.commands.typedCall('LockDevice', 'Success', {});
735
+ return res.message;
736
+ }
737
+
738
+ async checkPassphraseStateSafety(passphraseState?: string, useEmptyPassphraseState?: boolean) {
697
739
  if (!this.features) return false;
698
- const newState = await getPassphraseStateWithRefreshDeviceInfo(this);
740
+ const { passphraseState: newPassphraseState, unlockedAttachPin } =
741
+ await getPassphraseStateWithRefreshDeviceInfo(this, {
742
+ expectPassphraseState: passphraseState,
743
+ onlyMainPin: useEmptyPassphraseState,
744
+ });
745
+
746
+ // Main wallet and unlock Attach Pin, throw safe error
747
+ const mainWalletUseAttachPin = unlockedAttachPin && useEmptyPassphraseState;
748
+ const useErrorAttachPin =
749
+ unlockedAttachPin && passphraseState && passphraseState !== newPassphraseState;
750
+
751
+ console.log('=====>>>>>> checkPassphraseStateSafety passphraseState: ', {
752
+ passphraseState,
753
+ newPassphraseState,
754
+ unlockedAttachPin,
755
+ useEmptyPassphraseState,
756
+ });
757
+
758
+ if (mainWalletUseAttachPin || useErrorAttachPin) {
759
+ try {
760
+ await this.lockDevice();
761
+ } catch (error) {
762
+ // ignore error
763
+ }
764
+ this.clearInternalState();
765
+ return Promise.reject(ERRORS.TypedError(HardwareErrorCode.DeviceCheckUnlockTypeError));
766
+ }
699
767
 
700
768
  // When exists passphraseState, check passphraseState
701
- if (passphraseState && passphraseState !== newState) {
769
+ if (passphraseState && passphraseState !== newPassphraseState) {
702
770
  this.clearInternalState();
703
771
  return false;
704
772
  }
@@ -4,12 +4,13 @@ import TransportManager from '../data-manager/TransportManager';
4
4
  import DataManager from '../data-manager/DataManager';
5
5
  import { patchFeatures, getLogger, LoggerNames, getDeviceType } from '../utils';
6
6
  import type { Device } from './Device';
7
- import { DEVICE } from '../events';
7
+ import { DEVICE, type PassphraseRequestPayload } from '../events';
8
8
  import { DeviceModelToTypes } from '../types';
9
9
 
10
10
  export type PassphrasePromptResponse = {
11
11
  passphrase?: string;
12
12
  passphraseOnDevice?: boolean;
13
+ attachPinOnDevice?: boolean;
13
14
  cache?: boolean;
14
15
  };
15
16
 
@@ -438,8 +439,17 @@ export class DeviceCommands {
438
439
  }
439
440
 
440
441
  if (res.type === 'PassphraseRequest') {
441
- return this._promptPassphrase().then(response => {
442
- const { passphrase, passphraseOnDevice } = response;
442
+ const existsAttachPinUser = res.message.exists_attach_pin_user;
443
+ return this._promptPassphrase({
444
+ existsAttachPinUser,
445
+ }).then(response => {
446
+ const { passphrase, passphraseOnDevice, attachPinOnDevice } = response;
447
+
448
+ // Attach PIN on device
449
+ if (attachPinOnDevice && existsAttachPinUser) {
450
+ return this._commonCall('PassphraseAck', { on_device_attach_pin: true });
451
+ }
452
+
443
453
  return !passphraseOnDevice
444
454
  ? this._commonCall('PassphraseAck', { passphrase })
445
455
  : this._commonCall('PassphraseAck', { on_device: true });
@@ -501,7 +511,7 @@ export class DeviceCommands {
501
511
  });
502
512
  }
503
513
 
504
- _promptPassphrase() {
514
+ _promptPassphrase(options: PassphraseRequestPayload) {
505
515
  return new Promise<PassphrasePromptResponse>((resolve, reject) => {
506
516
  const cancelAndReject = (_error?: Error) =>
507
517
  cancelDeviceInPrompt(this.device, false)
@@ -527,6 +537,7 @@ export class DeviceCommands {
527
537
  this.device.emit(
528
538
  DEVICE.PASSPHRASE,
529
539
  this.device,
540
+ options,
530
541
  (response: PassphrasePromptResponse, error?: Error) => {
531
542
  this.device.clearCancelableAction();
532
543
  if (error) {
@@ -44,6 +44,10 @@ export interface DeviceButtonRequestPayload extends Omit<PROTO.ButtonRequest, 'c
44
44
  code?: PROTO.ButtonRequest['code'] | 'ButtonRequest_FirmwareUpdate';
45
45
  }
46
46
 
47
+ export type PassphraseRequestPayload = {
48
+ existsAttachPinUser?: boolean;
49
+ };
50
+
47
51
  export interface DeviceButtonRequest {
48
52
  type: typeof DEVICE.BUTTON;
49
53
  payload: DeviceButtonRequestPayload & { device: Device | null };
@@ -66,7 +66,7 @@ export type UiRequestDeviceAction = {
66
66
  type: typeof UI_REQUEST.REQUEST_PIN;
67
67
  payload: {
68
68
  device: Device;
69
- type?: PROTO.PinMatrixRequestType | 'ButtonRequest_PinEntry';
69
+ type?: PROTO.PinMatrixRequestType | 'ButtonRequest_PinEntry' | 'ButtonRequest_AttachPin';
70
70
  };
71
71
  };
72
72
 
@@ -80,6 +80,7 @@ export interface UiRequestPassphrase {
80
80
  payload: {
81
81
  device: Device;
82
82
  passphraseState?: string;
83
+ existsAttachPinUser?: boolean;
83
84
  };
84
85
  }
85
86
 
@@ -18,6 +18,7 @@ export interface UiResponsePassphrase {
18
18
  payload: {
19
19
  value: string;
20
20
  passphraseOnDevice?: boolean;
21
+ attachPinOnDevice?: boolean;
21
22
  save?: boolean;
22
23
  };
23
24
  }
package/src/inject.ts CHANGED
@@ -138,6 +138,8 @@ export const createCoreApi = (
138
138
  call({ ...params, connectId, method: 'getPassphraseState' }),
139
139
  deviceCancel: (connectId, params) => call({ ...params, connectId, method: 'deviceCancel' }),
140
140
  deviceLock: (connectId, params) => call({ ...params, connectId, method: 'deviceLock' }),
141
+ deviceUnlock: (connectId, params) =>
142
+ call({ ...params, useEmptyPassphrase: true, connectId, method: 'deviceUnlock' }),
141
143
 
142
144
  getNextU2FCounter: (connectId, params) =>
143
145
  call({ ...params, connectId, method: 'getNextU2FCounter' }),
@@ -0,0 +1,4 @@
1
+ import { Features } from '@onekeyfe/hd-transport';
2
+ import type { CommonParams, Response } from '../params';
3
+
4
+ export declare function deviceUnlock(connectId: string, params?: CommonParams): Response<Features>;
@@ -35,6 +35,7 @@ import { deviceSupportFeatures } from './deviceSupportFeatures';
35
35
  import { deviceFullyUploadResource } from './deviceFullyUploadResource';
36
36
  import { deviceUpdateBootloader } from './deviceUpdateBootloader';
37
37
  import { deviceLock } from './deviceLock';
38
+ import { deviceUnlock } from './deviceUnlock';
38
39
  import { deviceCancel } from './deviceCancel';
39
40
 
40
41
  import { getNextU2FCounter } from './getNextU2FCounter';
@@ -214,6 +215,7 @@ export type CoreApi = {
214
215
  deviceFullyUploadResource: typeof deviceFullyUploadResource;
215
216
  deviceUpdateBootloader: typeof deviceUpdateBootloader;
216
217
  deviceLock: typeof deviceLock;
218
+ deviceUnlock: typeof deviceUnlock;
217
219
  deviceCancel: typeof deviceCancel;
218
220
  getNextU2FCounter: typeof getNextU2FCounter;
219
221
  setU2FCounter: typeof setU2FCounter;
@@ -73,11 +73,30 @@ export const supportNewPassphrase = (features?: Features): SupportFeatureType =>
73
73
  return { support: semver.gte(currentVersion, '2.4.0'), require: '2.4.0' };
74
74
  };
75
75
 
76
- export const getPassphraseStateWithRefreshDeviceInfo = async (device: Device) => {
76
+ export const getPassphraseStateWithRefreshDeviceInfo = async (
77
+ device: Device,
78
+ options?: {
79
+ expectPassphraseState?: string;
80
+ onlyMainPin?: boolean;
81
+ }
82
+ ) => {
77
83
  const { features, commands } = device;
78
84
  const locked = features?.unlocked === false;
79
85
 
80
- const passphraseState = await getPassphraseState(features, commands);
86
+ const { passphraseState, newSession, unlockedAttachPin } = await getPassphraseState(
87
+ features,
88
+ commands,
89
+ {
90
+ ...options,
91
+ }
92
+ );
93
+
94
+ // Attach to pin try to fix internal state
95
+ if (newSession && passphraseState && features?.device_id) {
96
+ console.log('=====>>>>>> run updateInternalState newSession:', newSession);
97
+ device.updateInternalState(passphraseState, features.device_id, newSession);
98
+ }
99
+
81
100
  const isModeT =
82
101
  getDeviceType(features) === EDeviceType.Touch || getDeviceType(features) === EDeviceType.Pro;
83
102
 
@@ -93,14 +112,55 @@ export const getPassphraseStateWithRefreshDeviceInfo = async (device: Device) =>
93
112
  await device.getFeatures();
94
113
  }
95
114
 
96
- return passphraseState;
115
+ return { passphraseState, newSession, unlockedAttachPin };
97
116
  };
98
117
 
99
118
  export const getPassphraseState = async (
100
119
  features: Features | undefined,
101
- commands: DeviceCommands
102
- ) => {
103
- if (!features) return false;
120
+ commands: DeviceCommands,
121
+ options?: {
122
+ expectPassphraseState?: string;
123
+ onlyMainPin?: boolean;
124
+ // createAttachPinWallet?: boolean;
125
+ }
126
+ ): Promise<{
127
+ passphraseState: string | undefined;
128
+ newSession: string | undefined;
129
+ unlockedAttachPin: boolean | undefined;
130
+ }> => {
131
+ if (!features)
132
+ return { passphraseState: undefined, newSession: undefined, unlockedAttachPin: undefined };
133
+
134
+ const firmwareVersion = getDeviceFirmwareVersion(features);
135
+ const deviceType = getDeviceType(features);
136
+
137
+ if (deviceType === EDeviceType.Pro && semver.gte(firmwareVersion.join('.'), '4.14.0')) {
138
+ console.log(
139
+ '=====>>>>>> getPassphraseState begin: ',
140
+ options?.onlyMainPin,
141
+ options?.expectPassphraseState
142
+ );
143
+
144
+ const { message, type } = await commands.typedCall('GetPassphraseState', 'PassphraseState', {
145
+ passphrase_state: options?.onlyMainPin ? undefined : options?.expectPassphraseState,
146
+ // allow_create_attach_pin: options?.createAttachPinWallet,
147
+ // _only_main_pin: options?.onlyMainPin,
148
+ });
149
+
150
+ console.log('=====>>>>>> getPassphraseState end: result ', message);
151
+
152
+ // @ts-expect-error
153
+ if (type === 'CallMethodError') {
154
+ throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'Get the passphrase state error');
155
+ }
156
+
157
+ return {
158
+ passphraseState: message.passphrase_state,
159
+ newSession: message.session_id,
160
+ unlockedAttachPin: message.unlocked_attach_pin,
161
+ };
162
+ }
163
+
104
164
  const { message, type } = await commands.typedCall('GetAddress', 'Address', {
105
165
  address_n: [toHardened(44), toHardened(1), toHardened(0), 0, 0],
106
166
  coin_name: 'Testnet',
@@ -113,7 +173,11 @@ export const getPassphraseState = async (
113
173
  throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'Get the passphrase state error');
114
174
  }
115
175
 
116
- return message.address;
176
+ return {
177
+ passphraseState: message.address,
178
+ newSession: undefined,
179
+ unlockedAttachPin: undefined,
180
+ };
117
181
  };
118
182
 
119
183
  export const supportBatchPublicKey = (