@onekeyfe/hd-core 1.2.0-alpha.22 → 1.2.0-alpha.24

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 (151) hide show
  1. package/__tests__/DeviceCommands.test.ts +43 -8
  2. package/__tests__/connectSettings.test.ts +5 -47
  3. package/__tests__/device-lifecycle-events.test.ts +59 -0
  4. package/__tests__/device-settings.test.ts +1 -1
  5. package/__tests__/device-wallet-session-store.test.ts +41 -0
  6. package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +30 -39
  7. package/__tests__/logBlockEvent.test.ts +17 -0
  8. package/__tests__/open-wallet-session.test.ts +233 -111
  9. package/__tests__/protocol-v2-ping.test.ts +28 -0
  10. package/__tests__/protocol-v2.test.ts +513 -313
  11. package/__tests__/public-pro2-api-boundary.test.ts +22 -0
  12. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  13. package/dist/api/FirmwareUpdateV2.d.ts +0 -11
  14. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  15. package/dist/api/FirmwareUpdateV3.d.ts +3 -7
  16. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  17. package/dist/api/FirmwareUpdateV4.d.ts +5 -21
  18. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  19. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  20. package/dist/api/OpenWalletSession.d.ts +1 -8
  21. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  22. package/dist/api/device/DeviceUpdateBootloader.d.ts +1 -5
  23. package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
  24. package/dist/api/device/DeviceWipe.d.ts.map +1 -1
  25. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +0 -7
  26. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  27. package/dist/api/firmware/getBinary.d.ts +0 -7
  28. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  29. package/dist/api/firmware/updateBootloader.d.ts +0 -2
  30. package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
  31. package/dist/api/firmware/uploadFirmware.d.ts +1 -9
  32. package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
  33. package/dist/api/index.d.ts +1 -0
  34. package/dist/api/index.d.ts.map +1 -1
  35. package/dist/api/protocol-v2/Ping.d.ts +2 -0
  36. package/dist/api/protocol-v2/Ping.d.ts.map +1 -1
  37. package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
  38. package/dist/core/index.d.ts.map +1 -1
  39. package/dist/data-manager/DataManager.d.ts +0 -1
  40. package/dist/data-manager/DataManager.d.ts.map +1 -1
  41. package/dist/data-manager/connectSettings.d.ts.map +1 -1
  42. package/dist/device/Device.d.ts +3 -2
  43. package/dist/device/Device.d.ts.map +1 -1
  44. package/dist/device/DeviceCommands.d.ts.map +1 -1
  45. package/dist/events/device.d.ts +1 -0
  46. package/dist/events/device.d.ts.map +1 -1
  47. package/dist/events/logBlockEvent.d.ts.map +1 -1
  48. package/dist/events/ui-request.d.ts +1 -0
  49. package/dist/events/ui-request.d.ts.map +1 -1
  50. package/dist/index.d.ts +98 -278
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +876 -2647
  53. package/dist/inject.d.ts.map +1 -1
  54. package/dist/lowLevelInject.d.ts.map +1 -1
  55. package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts.map +1 -1
  56. package/dist/protocols/protocol-v2/unlockRetry.d.ts +2 -3
  57. package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +1 -1
  58. package/dist/protocols/protocol-v2/walletSession.d.ts +12 -0
  59. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  60. package/dist/topLevelInject.d.ts.map +1 -1
  61. package/dist/types/api/checkAllFirmwareRelease.d.ts +0 -3
  62. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  63. package/dist/types/api/deviceUpdateBootloader.d.ts +0 -6
  64. package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
  65. package/dist/types/api/export.d.ts +1 -4
  66. package/dist/types/api/export.d.ts.map +1 -1
  67. package/dist/types/api/firmwareUpdate.d.ts +0 -69
  68. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  69. package/dist/types/api/getPassphraseState.d.ts.map +1 -1
  70. package/dist/types/api/index.d.ts +4 -10
  71. package/dist/types/api/index.d.ts.map +1 -1
  72. package/dist/types/api/openWalletSession.d.ts +0 -12
  73. package/dist/types/api/openWalletSession.d.ts.map +1 -1
  74. package/dist/types/api/protocolV2.d.ts +4 -0
  75. package/dist/types/api/protocolV2.d.ts.map +1 -1
  76. package/dist/types/settings.d.ts +0 -13
  77. package/dist/types/settings.d.ts.map +1 -1
  78. package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
  79. package/dist/utils/patch.d.ts +1 -1
  80. package/dist/utils/patch.d.ts.map +1 -1
  81. package/package.json +4 -4
  82. package/src/api/CheckAllFirmwareRelease.ts +3 -16
  83. package/src/api/FirmwareUpdateV2.ts +119 -284
  84. package/src/api/FirmwareUpdateV3.ts +55 -248
  85. package/src/api/FirmwareUpdateV4.ts +293 -751
  86. package/src/api/GetPassphraseState.ts +11 -5
  87. package/src/api/OpenWalletSession.ts +23 -86
  88. package/src/api/device/DeviceUpdateBootloader.ts +6 -114
  89. package/src/api/device/DeviceWipe.ts +2 -0
  90. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +0 -50
  91. package/src/api/firmware/updateBootloader.ts +4 -19
  92. package/src/api/firmware/uploadFirmware.ts +22 -140
  93. package/src/api/index.ts +1 -0
  94. package/src/api/protocol-v2/Ping.ts +32 -1
  95. package/src/core/index.ts +40 -7
  96. package/src/data/messages/messages-protocol-v2.json +49 -56
  97. package/src/data-manager/DataManager.ts +33 -33
  98. package/src/data-manager/connectSettings.ts +0 -11
  99. package/src/device/Device.ts +29 -8
  100. package/src/device/DeviceCommands.ts +43 -151
  101. package/src/events/device.ts +1 -0
  102. package/src/events/logBlockEvent.ts +1 -15
  103. package/src/events/ui-request.ts +1 -0
  104. package/src/index.ts +0 -5
  105. package/src/inject.ts +4 -22
  106. package/src/lowLevelInject.ts +1 -5
  107. package/src/protocols/protocol-v2/deviceSession.ts +1 -1
  108. package/src/protocols/protocol-v2/settingsUnlockPolicy.ts +0 -1
  109. package/src/protocols/protocol-v2/unlockRetry.ts +20 -3
  110. package/src/protocols/protocol-v2/walletSession.ts +57 -18
  111. package/src/topLevelInject.ts +1 -5
  112. package/src/types/api/checkAllFirmwareRelease.ts +0 -3
  113. package/src/types/api/deviceUpdateBootloader.ts +0 -6
  114. package/src/types/api/export.ts +0 -18
  115. package/src/types/api/firmwareUpdate.ts +0 -76
  116. package/src/types/api/getPassphraseState.ts +4 -3
  117. package/src/types/api/index.ts +3 -14
  118. package/src/types/api/openWalletSession.ts +0 -19
  119. package/src/types/api/protocolV2.ts +10 -0
  120. package/src/types/settings.ts +0 -13
  121. package/src/utils/deviceInfoUtils.ts +2 -3
  122. package/__tests__/firmware-update/firmware-artifact-source.test.ts +0 -119
  123. package/__tests__/firmware-update/firmware-host-binding.test.ts +0 -70
  124. package/__tests__/firmware-update/firmware-update-capabilities.test.ts +0 -13
  125. package/__tests__/firmware-update/firmware-update-plan.test.ts +0 -326
  126. package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +0 -200
  127. package/__tests__/firmware-update/firmware-upload-source.test.ts +0 -70
  128. package/dist/api/firmware/FirmwareArtifactSource.d.ts +0 -26
  129. package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +0 -1
  130. package/dist/api/firmware/FirmwareHostBinding.d.ts +0 -6
  131. package/dist/api/firmware/FirmwareHostBinding.d.ts.map +0 -1
  132. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +0 -3
  133. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +0 -1
  134. package/dist/api/firmware/FirmwareUpdatePlan.d.ts +0 -24
  135. package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +0 -1
  136. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +0 -25
  137. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +0 -1
  138. package/dist/types/api/firmwareUpdateCapabilities.d.ts +0 -9
  139. package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +0 -1
  140. package/dist/types/api/firmwareUpdatePlan.d.ts +0 -27
  141. package/dist/types/api/firmwareUpdatePlan.d.ts.map +0 -1
  142. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +0 -42
  143. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +0 -1
  144. package/src/api/firmware/FirmwareArtifactSource.ts +0 -278
  145. package/src/api/firmware/FirmwareHostBinding.ts +0 -100
  146. package/src/api/firmware/FirmwareUpdateCapabilities.ts +0 -9
  147. package/src/api/firmware/FirmwareUpdatePlan.ts +0 -621
  148. package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +0 -378
  149. package/src/types/api/firmwareUpdateCapabilities.ts +0 -9
  150. package/src/types/api/firmwareUpdatePlan.ts +0 -36
  151. package/src/types/api/firmwareUpdatePreparedPlan.ts +0 -53
@@ -10,7 +10,6 @@ import { bytesToHex } from '../helpers/hexUtils';
10
10
  import { DataManager } from '../../data-manager';
11
11
  import { DevicePool } from '../../device/DevicePool';
12
12
  import { buildProtocolV1FeaturesPayload } from '../../deviceProfile';
13
- import { openFirmwareByteSource, readFirmwareByteSourceFully } from './FirmwareArtifactSource';
14
13
 
15
14
  import type { KnownDevice } from '../../types';
16
15
  import type { TypedCall, TypedResponseMessage } from '../../device/DeviceCommands';
@@ -18,7 +17,6 @@ import type { PROTO } from '../../constants';
18
17
  import type { CoreMessage, IFirmwareUpdateProgressType } from '../../events';
19
18
  import type { Success } from '@onekeyfe/hd-transport';
20
19
  import type { Device } from '../../device/Device';
21
- import type { FirmwareByteSource } from './FirmwareArtifactSource';
22
20
 
23
21
  const NEW_BOOT_UPRATE_FIRMWARE_VERSION = '2.4.5';
24
22
  const SESSION_ERROR = 'session not found';
@@ -90,20 +88,17 @@ export const waitBleInstall = async (updateType: string) => {
90
88
  }
91
89
  };
92
90
 
93
- const toArrayBuffer = (payload: ArrayBuffer | Buffer): ArrayBuffer => {
94
- if (payload instanceof ArrayBuffer) {
95
- return payload;
96
- }
97
- return new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength).slice().buffer;
98
- };
99
-
100
- export const uploadFirmwareFromSource = async (
91
+ export const uploadFirmware = async (
101
92
  updateType: 'firmware' | 'ble',
102
93
  typedCall: TypedCall,
103
94
  postMessage: (message: CoreMessage) => void,
104
95
  device: Device,
105
- source: FirmwareByteSource,
106
- rebootOnSuccess?: boolean,
96
+ {
97
+ payload,
98
+ rebootOnSuccess,
99
+ }: PROTO.FirmwareUpload & {
100
+ rebootOnSuccess?: boolean;
101
+ },
107
102
  isUpdateBootloader?: boolean
108
103
  ) => {
109
104
  const deviceType = device.getCurrentDeviceType();
@@ -124,20 +119,20 @@ export const uploadFirmwareFromSource = async (
124
119
  if (supportUpgradeFileHeader) {
125
120
  // Extract and validate firmware header (first 1KB)
126
121
  const HEADER_SIZE = 1024;
127
- if (source.size < HEADER_SIZE) {
122
+ if (payload.byteLength < HEADER_SIZE) {
128
123
  throw ERRORS.TypedError(
129
124
  HardwareErrorCode.RuntimeError,
130
- `firmware payload too small: ${source.size} bytes, expected at least ${HEADER_SIZE} bytes`
125
+ `firmware payload too small: ${payload.byteLength} bytes, expected at least ${HEADER_SIZE} bytes`
131
126
  );
132
127
  }
133
128
 
134
129
  Log.debug('Uploading firmware header:', {
135
130
  size: HEADER_SIZE,
136
- totalSize: source.size,
131
+ totalSize: payload.byteLength,
137
132
  });
138
133
  postProgressTip(device, 'UploadingFirmwareHeader', postMessage);
139
134
 
140
- const header = new Uint8Array(await source.readAt(0, HEADER_SIZE));
135
+ const header = new Uint8Array(payload.slice(0, HEADER_SIZE));
141
136
 
142
137
  try {
143
138
  const headerRes = await typedCall('UpgradeFileHeader', 'Success', {
@@ -174,9 +169,6 @@ export const uploadFirmwareFromSource = async (
174
169
  postProgressMessage(device, 0, 'installingFirmware', postMessage);
175
170
  let updateResponse: TypedResponseMessage<'Success'>;
176
171
  try {
177
- // Classic/Mini bootloaders accept one protobuf payload and do not expose
178
- // a request-range protocol. Other device families remain fully streamed.
179
- const payload = await readFirmwareByteSourceFully(source);
180
172
  updateResponse = await typedCall('FirmwareUpload', 'Success', {
181
173
  payload,
182
174
  });
@@ -208,7 +200,9 @@ export const uploadFirmwareFromSource = async (
208
200
  updateType,
209
201
  postMessage,
210
202
  device,
211
- source,
203
+ {
204
+ payload,
205
+ },
212
206
  rebootOnSuccess
213
207
  );
214
208
  return response.message;
@@ -217,7 +211,7 @@ export const uploadFirmwareFromSource = async (
217
211
 
218
212
  postConfirmationMessage(device);
219
213
  postProgressTip(device, 'ConfirmOnDevice', postMessage);
220
- const length = source.size;
214
+ const length = payload.byteLength;
221
215
 
222
216
  let response = await typedCall('FirmwareErase', ['FirmwareRequest', 'Success'], { length });
223
217
  postProgressTip(device, 'FirmwareEraseSuccess', postMessage);
@@ -226,7 +220,7 @@ export const uploadFirmwareFromSource = async (
226
220
  const start = response.message.offset!;
227
221
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
228
222
  const end = response.message.offset! + response.message.length!;
229
- const chunk = await source.readAt(start, end - start);
223
+ const chunk = payload.slice(start, end);
230
224
 
231
225
  if (start > 0) {
232
226
  postProgressMessage(
@@ -255,45 +249,11 @@ export const uploadFirmwareFromSource = async (
255
249
  throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'uploadFirmware: unknown device model');
256
250
  };
257
251
 
258
- export const uploadFirmware = async (
259
- updateType: 'firmware' | 'ble',
260
- typedCall: TypedCall,
261
- postMessage: (message: CoreMessage) => void,
262
- device: Device,
263
- {
264
- payload,
265
- rebootOnSuccess,
266
- }: PROTO.FirmwareUpload & {
267
- rebootOnSuccess?: boolean;
268
- },
269
- isUpdateBootloader?: boolean
270
- ) => {
271
- const source = await openFirmwareByteSource({
272
- binary: toArrayBuffer(payload),
273
- });
274
- if (!source) {
275
- throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'firmware payload is empty');
276
- }
277
- try {
278
- return await uploadFirmwareFromSource(
279
- updateType,
280
- typedCall,
281
- postMessage,
282
- device,
283
- source,
284
- rebootOnSuccess,
285
- isUpdateBootloader
286
- );
287
- } finally {
288
- await source.close();
289
- }
290
- };
291
-
292
252
  const newTouchUpdateProcess = async (
293
253
  updateType: 'firmware' | 'ble',
294
254
  postMessage: (message: CoreMessage) => void,
295
255
  device: Device,
296
- source: FirmwareByteSource,
256
+ { payload }: PROTO.FirmwareUpload,
297
257
  rebootOnSuccess = true
298
258
  ) => {
299
259
  let typedCall = device.getCommands().typedCall.bind(device.getCommands());
@@ -303,13 +263,13 @@ const newTouchUpdateProcess = async (
303
263
  const env = DataManager.getSettings('env');
304
264
  const perPackageSize = DataManager.isBleConnect(env) ? 16 : 128;
305
265
  const chunkSize = 1024 * perPackageSize;
306
- const totalChunks = Math.ceil(source.size / chunkSize);
266
+ const totalChunks = Math.ceil(payload.byteLength / chunkSize);
307
267
  let offset = 0;
308
268
  for (let i = 0; i < totalChunks; i++) {
309
269
  const chunkStart = i * chunkSize;
310
- const chunkEnd = Math.min(chunkStart + chunkSize, source.size);
270
+ const chunkEnd = Math.min(chunkStart + chunkSize, payload.byteLength);
311
271
  const chunkLength = chunkEnd - chunkStart;
312
- const chunk = await source.readAt(chunkStart, chunkLength);
272
+ const chunk = payload.slice(chunkStart, chunkEnd);
313
273
  const overwrite = i === 0;
314
274
  const progress = Math.round(((i + 1) / totalChunks) * 100);
315
275
  const writeRes = await emmcFileWriteWithRetry(
@@ -530,67 +490,6 @@ export const updateResource = async (
530
490
  return processResourceRequest(typedCall, res, data);
531
491
  };
532
492
 
533
- export const updateResourceFromSource = async (
534
- typedCall: TypedCall,
535
- fileName: string,
536
- source: FirmwareByteSource,
537
- onConfirmAfter?: () => void
538
- ) => {
539
- const initialLength = Math.min(INIT_DATA_CHUNK_SIZE, source.size);
540
- const initialChunk = new Uint8Array(await source.readAt(0, initialLength));
541
- let response = await typedCall('ResourceUpdate', ['ResourceRequest', 'Success'], {
542
- file_name: fileName,
543
- data_length: source.size,
544
- initial_data_chunk: bytesToHex(initialChunk),
545
- hash: bytesToHex(blake2s(initialChunk)),
546
- });
547
- onConfirmAfter?.();
548
-
549
- while (response.type !== 'Success') {
550
- const { offset, data_length: dataLength } = response.message;
551
- if (
552
- !Number.isSafeInteger(offset) ||
553
- offset === undefined ||
554
- offset < 0 ||
555
- !Number.isSafeInteger(dataLength) ||
556
- dataLength === undefined ||
557
- dataLength <= 0 ||
558
- offset + dataLength > source.size
559
- ) {
560
- throw ERRORS.TypedError(
561
- HardwareErrorCode.RuntimeError,
562
- 'Device requested an invalid firmware resource range'
563
- );
564
- }
565
- const chunk = new Uint8Array(await source.readAt(offset, dataLength));
566
- response = await typedCall('ResourceAck', ['ResourceRequest', 'Success'], {
567
- data_chunk: bytesToHex(chunk),
568
- hash: bytesToHex(blake2s(chunk)),
569
- });
570
- }
571
- return response.message;
572
- };
573
-
574
- export const updateResourcesFromSources = async (
575
- typedCall: TypedCall,
576
- postMessage: (message: CoreMessage) => void,
577
- device: Device,
578
- entries: ReadonlyArray<{ entryName: string; source: FirmwareByteSource }>
579
- ) => {
580
- postProgressTip(device, 'UpdateSysResource', postMessage);
581
- for (const [index, entry] of entries.entries()) {
582
- await updateResourceFromSource(typedCall, entry.entryName, entry.source);
583
- postProgressMessage(
584
- device,
585
- Math.floor(((index + 1) / entries.length) * 100),
586
- 'installingFirmware',
587
- postMessage
588
- );
589
- }
590
- postProgressTip(device, 'UpdateSysResourceSuccess', postMessage);
591
- return true;
592
- };
593
-
594
493
  export const updateResources = async (
595
494
  typedCall: TypedCall,
596
495
  postMessage: (message: CoreMessage) => void,
@@ -625,28 +524,11 @@ export const updateBootloader = async (
625
524
  typedCall: TypedCall,
626
525
  postMessage: (message: CoreMessage) => void,
627
526
  device: Device,
628
- data: ArrayBuffer
629
- ) => {
630
- const source = await openFirmwareByteSource({ binary: data });
631
- if (!source) {
632
- throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'bootloader payload is empty');
633
- }
634
- try {
635
- return await updateBootloaderFromSource(typedCall, postMessage, device, source);
636
- } finally {
637
- await source.close();
638
- }
639
- };
640
-
641
- export const updateBootloaderFromSource = async (
642
- typedCall: TypedCall,
643
- postMessage: (message: CoreMessage) => void,
644
- device: Device,
645
- source: FirmwareByteSource
527
+ source: ArrayBuffer
646
528
  ) => {
647
529
  postProgressTip(device, 'UpdateBootloader', postMessage);
648
530
  postProgressMessage(device, Math.floor(0), 'installingFirmware', postMessage);
649
- await updateResourceFromSource(typedCall, 'bootloader.bin', source, () => {
531
+ await updateResource(typedCall, 'bootloader.bin', source, () => {
650
532
  postProcessingMessage('resource', postMessage);
651
533
  });
652
534
  postProgressMessage(device, Math.floor(100), 'installingFirmware', postMessage);
package/src/api/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { default as testInitializeDeviceDuration } from './test/TestInitializeDeviceDuration';
2
+ export { default as testProtocolV2Ping } from './protocol-v2/Ping';
2
3
  export { default as preInitialize } from './device/PreInitialize';
3
4
 
4
5
  export { default as searchDevices } from './SearchDevices';
@@ -1,12 +1,43 @@
1
+ import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
+
1
3
  import { BaseMethod } from '../BaseMethod';
2
4
 
5
+ // nanopb max_size:64 includes the terminating NUL for string fields.
6
+ export const PROTOCOL_V2_PING_MAX_MESSAGE_BYTES = 63;
7
+
8
+ const getUtf8ByteLength = (value: string) =>
9
+ Array.from(value).reduce((length, character) => {
10
+ const codePoint = character.codePointAt(0) ?? 0;
11
+ if (codePoint <= 0x7f) return length + 1;
12
+ if (codePoint <= 0x7ff) return length + 2;
13
+ if (codePoint <= 0xffff) return length + 3;
14
+ return length + 4;
15
+ }, 0);
16
+
17
+ export function validateProtocolV2PingMessage(value: unknown): string {
18
+ if (value !== undefined && typeof value !== 'string') {
19
+ throw ERRORS.TypedError(
20
+ HardwareErrorCode.CallMethodInvalidParameter,
21
+ 'Protocol V2 Ping message must be a string.'
22
+ );
23
+ }
24
+ const message = value ?? '';
25
+ if (getUtf8ByteLength(message) > PROTOCOL_V2_PING_MAX_MESSAGE_BYTES) {
26
+ throw ERRORS.TypedError(
27
+ HardwareErrorCode.CallMethodInvalidParameter,
28
+ `Protocol V2 Ping message must not exceed ${PROTOCOL_V2_PING_MAX_MESSAGE_BYTES} UTF-8 bytes.`
29
+ );
30
+ }
31
+ return message;
32
+ }
33
+
3
34
  export default class Ping extends BaseMethod<{ message?: string }> {
4
35
  init() {
5
36
  // Protocol V2 (Pro2) only; Core rejects non-V2 devices.
6
37
  this.requireProtocolV2 = true;
7
38
  this.skipForceUpdateCheck = true;
8
39
  this.useDevicePassphraseState = false;
9
- this.params = { message: this.payload.message };
40
+ this.params = { message: validateProtocolV2PingMessage(this.payload.message) };
10
41
  }
11
42
 
12
43
  async run() {
package/src/core/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import semver from 'semver';
2
2
  import EventEmitter from 'events';
3
+ import { TRANSPORT_EVENT } from '@onekeyfe/hd-transport';
3
4
  import {
4
5
  ERRORS,
5
6
  ERROR_CODES_REQUIRE_RELEASE,
@@ -70,7 +71,11 @@ import type { CoreMessage, IFrameCallMessage, UiPromise, UiPromiseResponse } fro
70
71
  import type { DeviceEvents, InitOptions, RunOptions } from '../device/Device';
71
72
  import type { SdkTracingContext } from '../utils/tracing';
72
73
  import type { Deferred } from '@onekeyfe/hd-shared';
73
- import type { LowlevelTransportSharedPlugin, OneKeyDeviceInfo } from '@onekeyfe/hd-transport';
74
+ import type {
75
+ LowlevelTransportSharedPlugin,
76
+ OneKeyDeviceInfo,
77
+ TransportDeviceDisconnectEvent,
78
+ } from '@onekeyfe/hd-transport';
74
79
  import type { BaseMethod } from '../api/BaseMethod';
75
80
 
76
81
  const Log = getLogger(LoggerNames.Core);
@@ -173,8 +178,6 @@ export const callAPI = async (context: CoreContext, message: CoreMessage) => {
173
178
  return createResponseMessage(method?.responseID ?? message.id, false, { error });
174
179
  }
175
180
 
176
- DevicePool.emitter.on(DEVICE.CONNECT, onDeviceConnectHandler);
177
-
178
181
  if (!method.useDevice) {
179
182
  updateMethodRequestContext(method, { status: 'running' });
180
183
  try {
@@ -236,7 +239,6 @@ const handlePreWarmSignal = async (
236
239
  method: BaseMethod
237
240
  ): Promise<any> => {
238
241
  const createAckResponse = () => {
239
- DevicePool.emitter.removeListener(DEVICE.CONNECT, onDeviceConnectHandler);
240
242
  completeMethodRequestContext(method);
241
243
  method.dispose();
242
244
  return createResponseMessage(method.responseID, true, true);
@@ -874,8 +876,15 @@ function isRetryableBleProtocolV2ProbeError(method: BaseMethod, error: unknown)
874
876
  */
875
877
  async function connectDeviceForBle(method: BaseMethod, device: Device, retryCount = 0) {
876
878
  try {
877
- await device.acquire(method.payload.connectProtocol);
879
+ const shouldAcquire =
880
+ !device.hasDeviceAcquire() || !device.commands || device.commands.disposed;
881
+ if (shouldAcquire) {
882
+ await device.acquire(method.payload.connectProtocol);
883
+ }
878
884
  if (method.payload?.onlyConnectBleDevice) {
885
+ if (shouldAcquire) {
886
+ DevicePool.emitter.emit(DEVICE.CONNECT, device);
887
+ }
879
888
  return;
880
889
  }
881
890
  // Skip initialize if conditions are met
@@ -886,6 +895,9 @@ async function connectDeviceForBle(method: BaseMethod, device: Device, retryCoun
886
895
  passphraseState: initOptions.passphraseState,
887
896
  });
888
897
  }
898
+ if (shouldAcquire) {
899
+ DevicePool.emitter.emit(DEVICE.CONNECT, device);
900
+ }
889
901
  } catch (err) {
890
902
  if (
891
903
  (err.errorCode === HardwareErrorCode.BleTimeoutError ||
@@ -1186,8 +1198,6 @@ const cleanup = () => {
1186
1198
 
1187
1199
  const removeDeviceListener = (device: Device) => {
1188
1200
  device.removeAllListeners();
1189
- DevicePool.emitter.removeAllListeners(DEVICE.CONNECT);
1190
- // DevicePool.emitter.removeListener(DEVICE.DISCONNECT, onDeviceDisconnectHandler);
1191
1201
  };
1192
1202
 
1193
1203
  /**
@@ -1210,6 +1220,20 @@ const onDeviceDisconnectHandler = (device: Device) => {
1210
1220
  postMessage(createDeviceMessage(DEVICE.DISCONNECT, { device: deviceObject }));
1211
1221
  };
1212
1222
 
1223
+ const onTransportDeviceDisconnectHandler = (event: TransportDeviceDisconnectEvent) => {
1224
+ const device =
1225
+ deviceCacheMap.get(event.connectId) ??
1226
+ DevicePool.devicesCache[event.connectId] ??
1227
+ DevicePool.getDeviceByPath(event.connectId);
1228
+ if (!device) {
1229
+ Log.debug('Ignoring transport disconnect for an unknown device:', event.connectId);
1230
+ return;
1231
+ }
1232
+
1233
+ device.markTransportDisconnected();
1234
+ DevicePool.emitter.emit(DEVICE.DISCONNECT, device);
1235
+ };
1236
+
1213
1237
  const onDevicePinHandler = async (...[device, type, callback]: DeviceEvents['pin']) => {
1214
1238
  Log.log('request Input PIN');
1215
1239
  // create ui promise
@@ -1262,6 +1286,7 @@ const onDevicePassphraseHandler = async (
1262
1286
  device: device.toMessageObject() as KnownDevice,
1263
1287
  passphraseState: device.passphraseState,
1264
1288
  existsAttachPinUser: requestPayload.existsAttachPinUser,
1289
+ deviceOnly: requestPayload.deviceOnly,
1265
1290
  source: requestPayload.source,
1266
1291
  reason: requestPayload.reason,
1267
1292
  expectedPassphraseState: requestPayload.expectedPassphraseState,
@@ -1527,7 +1552,15 @@ export const initCore = () => {
1527
1552
 
1528
1553
  export const initConnector = () => {
1529
1554
  _connector = new DeviceConnector();
1555
+ DevicePool.emitter.removeListener(DEVICE.CONNECT, onDeviceConnectHandler);
1556
+ DevicePool.emitter.removeListener(DEVICE.DISCONNECT, onDeviceDisconnectHandler);
1557
+ DevicePool.emitter.removeListener(
1558
+ TRANSPORT_EVENT.DEVICE_DISCONNECT,
1559
+ onTransportDeviceDisconnectHandler
1560
+ );
1561
+ DevicePool.emitter.on(DEVICE.CONNECT, onDeviceConnectHandler);
1530
1562
  DevicePool.emitter.on(DEVICE.DISCONNECT, onDeviceDisconnectHandler);
1563
+ DevicePool.emitter.on(TRANSPORT_EVENT.DEVICE_DISCONNECT, onTransportDeviceDisconnectHandler);
1531
1564
  return _connector;
1532
1565
  };
1533
1566
 
@@ -482,9 +482,10 @@
482
482
  "MessageType_DeviceStatus": 60603,
483
483
  "MessageType_DevGetOnboardingStatus": 60604,
484
484
  "MessageType_DevOnboardingStatus": 60605,
485
+ "MessageType_DeviceSessionGet": 60606,
485
486
  "MessageType_DeviceSession": 60607,
486
487
  "MessageType_DeviceSessionAskPin": 60608,
487
- "MessageType_DeviceSessionOpen": 60609,
488
+ "MessageType_DeviceSessionAskPassphrase": 60609,
488
489
  "MessageType_FilesystemPermissionFix": 60800,
489
490
  "MessageType_FilesystemPathInfo": 60801,
490
491
  "MessageType_FilesystemPathInfoQuery": 60802,
@@ -506,8 +507,7 @@
506
507
  [90, 92],
507
508
  [114, 122],
508
509
  [300, 304],
509
- [309, 312],
510
- [60606, 60606]
510
+ [309, 312]
511
511
  ]
512
512
  },
513
513
  "AlephiumGetAddress": {
@@ -11506,6 +11506,33 @@
11506
11506
  }
11507
11507
  }
11508
11508
  },
11509
+ "UiAnimationType": {
11510
+ "values": {
11511
+ "Unknown": 0,
11512
+ "Signing": 1
11513
+ }
11514
+ },
11515
+ "UiAnimationCommand": {
11516
+ "values": {
11517
+ "CommandUnknown": 0,
11518
+ "Start": 1,
11519
+ "Stop": 2,
11520
+ "Refresh": 3
11521
+ }
11522
+ },
11523
+ "UiAnimationRequest": {
11524
+ "fields": {
11525
+ "command": {
11526
+ "rule": "required",
11527
+ "type": "UiAnimationCommand",
11528
+ "id": 1
11529
+ },
11530
+ "type": {
11531
+ "type": "UiAnimationType",
11532
+ "id": 2
11533
+ }
11534
+ }
11535
+ },
11509
11536
  "ViewAmount": {
11510
11537
  "fields": {
11511
11538
  "is_unlimited": {
@@ -12446,83 +12473,49 @@
12446
12473
  "DeviceSessionError_Busy": 5
12447
12474
  }
12448
12475
  },
12449
- "DeviceSessionResume": {
12476
+ "DeviceSessionGet": {
12450
12477
  "fields": {
12451
12478
  "session_id": {
12452
- "rule": "required",
12453
12479
  "type": "bytes",
12454
12480
  "id": 1
12455
12481
  }
12456
12482
  }
12457
12483
  },
12458
- "DeviceSessionHostPassphrase": {
12459
- "fields": {
12460
- "passphrase": {
12461
- "rule": "required",
12462
- "type": "string",
12463
- "id": 1
12464
- }
12465
- }
12466
- },
12467
- "DeviceSessionPassphraseOnDevice": {
12468
- "fields": {}
12469
- },
12470
- "DeviceSessionAttachPinOnDevice": {
12471
- "fields": {}
12472
- },
12473
- "DeviceSessionSelect": {
12474
- "oneofs": {
12475
- "access": {
12476
- "oneof": ["host_passphrase", "passphrase_on_device", "attach_pin_on_device"]
12477
- }
12478
- },
12484
+ "DeviceSession": {
12479
12485
  "fields": {
12480
- "host_passphrase": {
12481
- "type": "DeviceSessionHostPassphrase",
12486
+ "session_id": {
12487
+ "type": "bytes",
12482
12488
  "id": 1
12483
12489
  },
12484
- "passphrase_on_device": {
12485
- "type": "DeviceSessionPassphraseOnDevice",
12490
+ "btc_test_address": {
12491
+ "type": "string",
12486
12492
  "id": 2
12487
- },
12488
- "attach_pin_on_device": {
12489
- "type": "DeviceSessionAttachPinOnDevice",
12490
- "id": 3
12491
12493
  }
12492
12494
  }
12493
12495
  },
12494
- "DeviceSessionOpen": {
12495
- "oneofs": {
12496
- "mode": {
12497
- "oneof": ["resume", "select"]
12498
- }
12499
- },
12496
+ "DeviceSessionPinType": {
12497
+ "values": {
12498
+ "Any": 1,
12499
+ "Main": 2,
12500
+ "AttachToPin": 3
12501
+ }
12502
+ },
12503
+ "DeviceSessionAskPin": {
12500
12504
  "fields": {
12501
- "resume": {
12502
- "type": "DeviceSessionResume",
12505
+ "type": {
12506
+ "type": "DeviceSessionPinType",
12503
12507
  "id": 1
12504
- },
12505
- "select": {
12506
- "type": "DeviceSessionSelect",
12507
- "id": 2
12508
12508
  }
12509
12509
  }
12510
12510
  },
12511
- "DeviceSession": {
12511
+ "DeviceSessionAskPassphrase": {
12512
12512
  "fields": {
12513
- "session_id": {
12514
- "type": "bytes",
12515
- "id": 1
12516
- },
12517
- "btc_test_address": {
12513
+ "passphrase": {
12518
12514
  "type": "string",
12519
- "id": 2
12515
+ "id": 1
12520
12516
  }
12521
12517
  }
12522
12518
  },
12523
- "DeviceSessionAskPin": {
12524
- "fields": {}
12525
- },
12526
12519
  "DeviceSessionAskPin_FailureSubCodes": {
12527
12520
  "values": {
12528
12521
  "UserCancel": 1