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

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 (226) hide show
  1. package/__tests__/DeviceCommands.test.ts +87 -2
  2. package/__tests__/connectSettings.test.ts +47 -5
  3. package/__tests__/device-identity.test.ts +24 -2
  4. package/__tests__/device-lifecycle-events.test.ts +1 -1
  5. package/__tests__/device-settings.test.ts +111 -6
  6. package/__tests__/device-state-events.test.ts +3 -3
  7. package/__tests__/device-state-mapper.test.ts +15 -3
  8. package/__tests__/device-state-store.test.ts +1 -1
  9. package/__tests__/device-wallet-session-store.test.ts +111 -7
  10. package/__tests__/deviceSettings.test.ts +55 -15
  11. package/__tests__/evmLedgerLegacySafety.test.ts +6 -5
  12. package/__tests__/firmware-update/firmware-artifact-source.test.ts +119 -0
  13. package/__tests__/firmware-update/firmware-host-binding.test.ts +70 -0
  14. package/__tests__/firmware-update/firmware-update-capabilities.test.ts +13 -0
  15. package/__tests__/firmware-update/firmware-update-plan.test.ts +326 -0
  16. package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +200 -0
  17. package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +39 -30
  18. package/__tests__/firmware-update/firmware-upload-source.test.ts +70 -0
  19. package/__tests__/get-device-state.test.ts +7 -0
  20. package/__tests__/open-wallet-session.test.ts +253 -13
  21. package/__tests__/pro2Wallpaper.test.ts +7 -18
  22. package/__tests__/protocol-v2-unlock-policy.test.ts +45 -0
  23. package/__tests__/protocol-v2.test.ts +439 -282
  24. package/__tests__/public-device-state-api.test.ts +79 -68
  25. package/__tests__/public-pro2-api-boundary.test.ts +22 -29
  26. package/dist/api/BaseMethod.d.ts +2 -4
  27. package/dist/api/BaseMethod.d.ts.map +1 -1
  28. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  29. package/dist/api/ClearSessionCache.d.ts.map +1 -1
  30. package/dist/api/FirmwareUpdate.d.ts.map +1 -1
  31. package/dist/api/FirmwareUpdateV2.d.ts +11 -0
  32. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  33. package/dist/api/FirmwareUpdateV3.d.ts +7 -3
  34. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  35. package/dist/api/FirmwareUpdateV4.d.ts +29 -10
  36. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  37. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  38. package/dist/api/UploadPortfolio.d.ts +0 -1
  39. package/dist/api/UploadPortfolio.d.ts.map +1 -1
  40. package/dist/api/conflux/ConfluxGetAddress.d.ts +1 -0
  41. package/dist/api/conflux/ConfluxGetAddress.d.ts.map +1 -1
  42. package/dist/api/conflux/ConfluxSignMessage.d.ts +1 -0
  43. package/dist/api/conflux/ConfluxSignMessage.d.ts.map +1 -1
  44. package/dist/api/conflux/ConfluxSignMessageCIP23.d.ts +1 -0
  45. package/dist/api/conflux/ConfluxSignMessageCIP23.d.ts.map +1 -1
  46. package/dist/api/conflux/ConfluxSignTransaction.d.ts +1 -0
  47. package/dist/api/conflux/ConfluxSignTransaction.d.ts.map +1 -1
  48. package/dist/api/device/DeviceSettings.d.ts.map +1 -1
  49. package/dist/api/device/DeviceUpdateBootloader.d.ts +5 -1
  50. package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
  51. package/dist/api/firmware/FirmwareArtifactSource.d.ts +26 -0
  52. package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +1 -0
  53. package/dist/api/firmware/FirmwareHostBinding.d.ts +6 -0
  54. package/dist/api/firmware/FirmwareHostBinding.d.ts.map +1 -0
  55. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +7 -0
  56. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  57. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +3 -0
  58. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +1 -0
  59. package/dist/api/firmware/FirmwareUpdatePlan.d.ts +24 -0
  60. package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -0
  61. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +25 -0
  62. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -0
  63. package/dist/api/firmware/getBinary.d.ts +7 -0
  64. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  65. package/dist/api/firmware/updateBootloader.d.ts +2 -0
  66. package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
  67. package/dist/api/firmware/uploadFirmware.d.ts +9 -1
  68. package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
  69. package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
  70. package/dist/api/index.d.ts +0 -20
  71. package/dist/api/index.d.ts.map +1 -1
  72. package/dist/api/nexa/NexaSignTransaction.d.ts +1 -0
  73. package/dist/api/nexa/NexaSignTransaction.d.ts.map +1 -1
  74. package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
  75. package/dist/core/RequestQueue.d.ts +1 -19
  76. package/dist/core/RequestQueue.d.ts.map +1 -1
  77. package/dist/core/index.d.ts +0 -1
  78. package/dist/core/index.d.ts.map +1 -1
  79. package/dist/data-manager/DataManager.d.ts +1 -0
  80. package/dist/data-manager/DataManager.d.ts.map +1 -1
  81. package/dist/data-manager/connectSettings.d.ts.map +1 -1
  82. package/dist/device/Device.d.ts +1 -1
  83. package/dist/device/Device.d.ts.map +1 -1
  84. package/dist/device/DeviceCommands.d.ts.map +1 -1
  85. package/dist/device/DeviceFeaturesState.d.ts +0 -1
  86. package/dist/device/DeviceFeaturesState.d.ts.map +1 -1
  87. package/dist/device/DeviceStateMapper.d.ts.map +1 -1
  88. package/dist/device/DeviceStateProjector.d.ts.map +1 -1
  89. package/dist/deviceProfile/buildDeviceFeatures.d.ts.map +1 -1
  90. package/dist/events/call.d.ts +0 -7
  91. package/dist/events/call.d.ts.map +1 -1
  92. package/dist/events/core.d.ts +2 -2
  93. package/dist/events/core.d.ts.map +1 -1
  94. package/dist/events/iframe.d.ts +0 -1
  95. package/dist/events/iframe.d.ts.map +1 -1
  96. package/dist/events/logBlockEvent.d.ts.map +1 -1
  97. package/dist/index.d.ts +320 -277
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/index.js +3210 -1856
  100. package/dist/inject.d.ts +2 -3
  101. package/dist/inject.d.ts.map +1 -1
  102. package/dist/lowLevelInject.d.ts +1 -2
  103. package/dist/lowLevelInject.d.ts.map +1 -1
  104. package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts.map +1 -1
  105. package/dist/protocols/protocol-v2/unlockPolicy.d.ts +4 -0
  106. package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -0
  107. package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +1 -1
  108. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  109. package/dist/topLevelInject.d.ts.map +1 -1
  110. package/dist/types/api/checkAllFirmwareRelease.d.ts +3 -0
  111. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  112. package/dist/types/api/deviceSettings.d.ts +2 -2
  113. package/dist/types/api/deviceSettings.d.ts.map +1 -1
  114. package/dist/types/api/deviceUpdateBootloader.d.ts +6 -0
  115. package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
  116. package/dist/types/api/export.d.ts +4 -1
  117. package/dist/types/api/export.d.ts.map +1 -1
  118. package/dist/types/api/firmwareUpdate.d.ts +69 -0
  119. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  120. package/dist/types/api/firmwareUpdateCapabilities.d.ts +9 -0
  121. package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +1 -0
  122. package/dist/types/api/firmwareUpdatePlan.d.ts +27 -0
  123. package/dist/types/api/firmwareUpdatePlan.d.ts.map +1 -0
  124. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +42 -0
  125. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +1 -0
  126. package/dist/types/api/index.d.ts +10 -23
  127. package/dist/types/api/index.d.ts.map +1 -1
  128. package/dist/types/api/openWalletSession.d.ts +1 -0
  129. package/dist/types/api/openWalletSession.d.ts.map +1 -1
  130. package/dist/types/api/protocolV2.d.ts +3 -84
  131. package/dist/types/api/protocolV2.d.ts.map +1 -1
  132. package/dist/types/api/sessionCache.d.ts +4 -1
  133. package/dist/types/api/sessionCache.d.ts.map +1 -1
  134. package/dist/types/device.d.ts +4 -4
  135. package/dist/types/device.d.ts.map +1 -1
  136. package/dist/types/settings.d.ts +13 -0
  137. package/dist/types/settings.d.ts.map +1 -1
  138. package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
  139. package/dist/utils/deviceSettings.d.ts +36 -7
  140. package/dist/utils/deviceSettings.d.ts.map +1 -1
  141. package/dist/utils/index.d.ts +2 -1
  142. package/dist/utils/index.d.ts.map +1 -1
  143. package/dist/utils/patch.d.ts +1 -1
  144. package/dist/utils/patch.d.ts.map +1 -1
  145. package/package.json +4 -4
  146. package/src/api/BaseMethod.ts +11 -12
  147. package/src/api/CheckAllFirmwareRelease.ts +16 -3
  148. package/src/api/ClearSessionCache.ts +4 -0
  149. package/src/api/FirmwareUpdate.ts +8 -1
  150. package/src/api/FirmwareUpdateV2.ts +284 -119
  151. package/src/api/FirmwareUpdateV3.ts +248 -55
  152. package/src/api/FirmwareUpdateV4.ts +816 -328
  153. package/src/api/OpenWalletSession.ts +74 -25
  154. package/src/api/UploadPortfolio.ts +3 -13
  155. package/src/api/conflux/ConfluxGetAddress.ts +2 -0
  156. package/src/api/conflux/ConfluxSignMessage.ts +2 -0
  157. package/src/api/conflux/ConfluxSignMessageCIP23.ts +2 -0
  158. package/src/api/conflux/ConfluxSignTransaction.ts +2 -0
  159. package/src/api/device/DeviceChangePin.ts +1 -1
  160. package/src/api/device/DeviceSettings.ts +66 -5
  161. package/src/api/device/DeviceUpdateBootloader.ts +114 -6
  162. package/src/api/device/DeviceWipe.ts +1 -1
  163. package/src/api/firmware/FirmwareArtifactSource.ts +278 -0
  164. package/src/api/firmware/FirmwareHostBinding.ts +100 -0
  165. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +50 -0
  166. package/src/api/firmware/FirmwareUpdateCapabilities.ts +9 -0
  167. package/src/api/firmware/FirmwareUpdatePlan.ts +621 -0
  168. package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +378 -0
  169. package/src/api/firmware/updateBootloader.ts +19 -4
  170. package/src/api/firmware/uploadFirmware.ts +140 -22
  171. package/src/api/helpers/protocolV2FileWrite.ts +6 -0
  172. package/src/api/index.ts +0 -21
  173. package/src/api/nexa/NexaSignTransaction.ts +2 -0
  174. package/src/api/protocol-v2/DeviceUploadWallpaper.ts +1 -1
  175. package/src/core/RequestQueue.ts +4 -123
  176. package/src/core/index.ts +25 -31
  177. package/src/data/messages/messages-protocol-v2.json +77 -4
  178. package/src/data-manager/DataManager.ts +33 -33
  179. package/src/data-manager/connectSettings.ts +11 -0
  180. package/src/device/Device.ts +51 -61
  181. package/src/device/DeviceCommands.ts +58 -14
  182. package/src/device/DeviceFeaturesState.ts +0 -9
  183. package/src/device/DeviceStateMapper.ts +26 -8
  184. package/src/device/DeviceStateProjector.ts +7 -1
  185. package/src/deviceProfile/buildDeviceFeatures.ts +2 -1
  186. package/src/events/call.ts +0 -6
  187. package/src/events/core.ts +0 -2
  188. package/src/events/iframe.ts +0 -1
  189. package/src/events/logBlockEvent.ts +1 -0
  190. package/src/index.ts +5 -4
  191. package/src/inject.ts +22 -35
  192. package/src/lowLevelInject.ts +5 -4
  193. package/src/protocols/protocol-v2/deviceSession.ts +1 -1
  194. package/src/protocols/protocol-v2/settingsUnlockPolicy.ts +2 -2
  195. package/src/protocols/protocol-v2/unlockPolicy.ts +105 -0
  196. package/src/protocols/protocol-v2/unlockRetry.ts +1 -3
  197. package/src/protocols/protocol-v2/walletSession.ts +68 -12
  198. package/src/topLevelInject.ts +5 -3
  199. package/src/types/api/checkAllFirmwareRelease.ts +3 -0
  200. package/src/types/api/deviceSettings.ts +17 -2
  201. package/src/types/api/deviceUpdateBootloader.ts +6 -0
  202. package/src/types/api/export.ts +18 -0
  203. package/src/types/api/firmwareUpdate.ts +76 -0
  204. package/src/types/api/firmwareUpdateCapabilities.ts +9 -0
  205. package/src/types/api/firmwareUpdatePlan.ts +36 -0
  206. package/src/types/api/firmwareUpdatePreparedPlan.ts +53 -0
  207. package/src/types/api/index.ts +14 -41
  208. package/src/types/api/openWalletSession.ts +2 -0
  209. package/src/types/api/protocolV2.ts +3 -187
  210. package/src/types/api/sessionCache.ts +9 -4
  211. package/src/types/device.ts +5 -3
  212. package/src/types/settings.ts +13 -0
  213. package/src/utils/deviceFeaturesUtils.ts +5 -1
  214. package/src/utils/deviceSettings.ts +130 -56
  215. package/src/utils/index.ts +18 -1
  216. package/__tests__/RequestQueue.test.ts +0 -140
  217. package/__tests__/UploadPortfolio.test.ts +0 -46
  218. package/dist/api/protocol-v2/DeviceSettingsGet.d.ts +0 -6
  219. package/dist/api/protocol-v2/DeviceSettingsGet.d.ts.map +0 -1
  220. package/dist/api/protocol-v2/DeviceSettingsPageShow.d.ts +0 -16
  221. package/dist/api/protocol-v2/DeviceSettingsPageShow.d.ts.map +0 -1
  222. package/dist/api/protocol-v2/DeviceSettingsSet.d.ts +0 -12
  223. package/dist/api/protocol-v2/DeviceSettingsSet.d.ts.map +0 -1
  224. package/src/api/protocol-v2/DeviceSettingsGet.ts +0 -18
  225. package/src/api/protocol-v2/DeviceSettingsPageShow.ts +0 -70
  226. package/src/api/protocol-v2/DeviceSettingsSet.ts +0 -44
@@ -153,7 +153,8 @@ export interface Device {
153
153
  * This allows short-lived processes (e.g. CLI) to restore a previously
154
154
  * obtained session, avoiding the need to re-enter passphrase on every
155
155
  * invocation. The session must have been obtained from a prior
156
- * getPassphraseState() call on the same device.
156
+ * wallet-session call on the same device. This compatibility hook is intended
157
+ * for a trusted CLI process restoring its own OS-keychain entry.
157
158
  *
158
159
  * @param deviceId - The device's device_id (from features)
159
160
  * @param passphraseState - The passphrase state token
@@ -222,24 +223,7 @@ export class Device extends EventEmitter {
222
223
 
223
224
  get features(): Features | undefined {
224
225
  if (!this.state) return undefined;
225
- const features = projectFeatures(this.state);
226
- const sessionCacheDeviceKey =
227
- this.state.identity.deviceId ||
228
- (this.isProtocolV2()
229
- ? this.originalDescriptor.path || this.originalDescriptor.id
230
- : undefined);
231
- const sessionId =
232
- sessionCacheDeviceKey && this.passphraseState
233
- ? deviceWalletSessionStore.get(sessionCacheDeviceKey, this.passphraseState)
234
- : undefined;
235
- return sessionId
236
- ? {
237
- ...features,
238
- sessionId,
239
- session_id: sessionId,
240
- passphraseState: this.passphraseState,
241
- }
242
- : features;
226
+ return projectFeatures(this.state);
243
227
  }
244
228
 
245
229
  set features(features: Features | undefined) {
@@ -334,7 +318,7 @@ export class Device extends EventEmitter {
334
318
  instanceId: this.instanceId,
335
319
  createdAt: this.createdAt,
336
320
  deviceType,
337
- /** ID for current seeds, will clear after replace a new seed at device */
321
+ /** Wallet-lifecycle ID; changes after the device is wiped or reinitialized. */
338
322
  deviceId,
339
323
  path: this.originalDescriptor?.path,
340
324
  bleName,
@@ -691,16 +675,14 @@ export class Device extends EventEmitter {
691
675
  const deviceId = _deviceId || this.getCurrentDeviceId();
692
676
  if (deviceId) return deviceId;
693
677
  if (this.isProtocolV2()) {
694
- return this.originalDescriptor.path || this.originalDescriptor.id;
678
+ return this.originalDescriptor.path;
695
679
  }
696
680
  return undefined;
697
681
  }
698
682
 
699
683
  private reconcileSessionCacheDeviceIdentity(previousDeviceId?: string) {
700
684
  deviceWalletSessionStore.reconcileDeviceIdentity({
701
- temporaryKey: this.isProtocolV2()
702
- ? this.originalDescriptor.path || this.originalDescriptor.id
703
- : undefined,
685
+ temporaryKey: this.isProtocolV2() ? this.originalDescriptor.path : undefined,
704
686
  previousDeviceId,
705
687
  nextDeviceId: this.getCurrentDeviceId(),
706
688
  });
@@ -806,43 +788,55 @@ export class Device extends EventEmitter {
806
788
  return;
807
789
  }
808
790
 
809
- // Log.debug('initialize param:', options);
791
+ try {
792
+ const callInitialize = async (payload: Record<string, unknown>, initSession?: boolean) => {
793
+ const initStartAt = Date.now();
794
+ const { message } = await this.commands.typedCall('Initialize', 'Features', payload, {
795
+ // iOS BLE bound devices can need close to 20 seconds.
796
+ timeoutMs: 25 * 1000,
797
+ });
798
+ this.setLastInitializeDuration(Date.now() - initStartAt);
799
+ this._updateFeatures(message, initSession);
800
+ await TransportManager.reconfigure(this.features);
801
+ };
810
802
 
811
- this.passphraseState = options?.passphraseState;
803
+ const expectedDeviceId = options?.deviceId;
804
+ if (expectedDeviceId) {
805
+ // Establish the live physical identity before sending wallet-bound state.
806
+ this.passphraseState = undefined;
807
+ await callInitialize({ is_contains_attach: true });
808
+ if (!this.checkDeviceId(expectedDeviceId)) {
809
+ throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckDeviceIdError);
810
+ }
811
+ }
812
812
 
813
- if (options?.initSession) {
814
- this.clearInternalState(options?.deviceId);
815
- }
813
+ this.passphraseState = options?.passphraseState;
816
814
 
817
- const internalState = this.getInternalState(options?.deviceId);
818
- const payload: any = {};
819
- if (internalState) {
820
- payload.session_id = internalState;
821
- }
815
+ if (options?.initSession) {
816
+ this.clearInternalState(options?.deviceId);
817
+ }
822
818
 
823
- if (options?.deriveCardano) {
824
- payload.derive_cardano = true;
825
- }
826
- payload.passphrase_state = options?.passphraseState;
827
- payload.is_contains_attach = true;
819
+ const internalState = this.getInternalState(options?.deviceId);
820
+ const payload: Record<string, unknown> = {
821
+ passphrase_state: options?.passphraseState,
822
+ is_contains_attach: true,
823
+ };
824
+ if (internalState) {
825
+ payload.session_id = internalState;
826
+ }
827
+ if (options?.deriveCardano) {
828
+ payload.derive_cardano = true;
829
+ }
828
830
 
829
- const initStartAt = Date.now();
830
- try {
831
- // @ts-expect-error
832
- const { message } = await Promise.race([
833
- this.commands.typedCall('Initialize', 'Features', payload),
834
- new Promise((_, reject) => {
835
- setTimeout(() => {
836
- reject(ERRORS.TypedError(HardwareErrorCode.DeviceInitializeFailed));
837
- // iOS ble bound device timeout 20s
838
- }, 25 * 1000);
839
- }),
840
- ]);
841
-
842
- const initCostMs = Date.now() - initStartAt;
843
- this.setLastInitializeDuration(initCostMs);
844
- this._updateFeatures(message, options?.initSession);
845
- await TransportManager.reconfigure(this.features);
831
+ const requiresWalletInitialize =
832
+ !expectedDeviceId ||
833
+ Boolean(internalState) ||
834
+ Boolean(options?.passphraseState) ||
835
+ options?.deriveCardano === true ||
836
+ options?.initSession === true;
837
+ if (requiresWalletInitialize) {
838
+ await callInitialize(payload, options?.initSession);
839
+ }
846
840
  } catch (error) {
847
841
  Log.error('Initialization failed:', error);
848
842
  throw error;
@@ -955,7 +949,7 @@ export class Device extends EventEmitter {
955
949
  'DeviceSettings',
956
950
  {}
957
951
  );
958
- this.updateState(mapDeviceSettingsToState(message), 'apply-settings');
952
+ this.updateState(mapDeviceSettingsToState(message), 'settings-read');
959
953
  }
960
954
  }
961
955
 
@@ -972,10 +966,6 @@ export class Device extends EventEmitter {
972
966
  ? protoFeatures
973
967
  : buildProtocolV1FeaturesPayload(protoFeatures, this.features);
974
968
 
975
- // GetFeatures doesn't return 'session_id'
976
- if (this.features?.sessionId && !feat.sessionId) {
977
- feat.sessionId = this.features.sessionId;
978
- }
979
969
  feat.unlocked = feat.unlocked ?? true;
980
970
 
981
971
  feat = fixFeaturesFirmwareVersion(feat);
@@ -1,6 +1,7 @@
1
1
  import { ERRORS, HardwareError, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
2
  import {
3
3
  DeviceErrorCode,
4
+ DeviceSessionErrorCode,
4
5
  type FailureType,
5
6
  type Messages,
6
7
  type Transport,
@@ -52,7 +53,7 @@ const HIGH_VOLUME_DEBUG_CALLS = new Set([
52
53
  'FirmwareUpload',
53
54
  'ResourceAck',
54
55
  ]);
55
- const SENSITIVE_DEBUG_CALLS = new Set(['DeviceSessionGet']);
56
+ const SENSITIVE_DEBUG_CALLS = new Set(['DeviceSessionOpen']);
56
57
 
57
58
  function shouldReduceDebugForCall(type: string) {
58
59
  return HIGH_VOLUME_DEBUG_CALLS.has(type);
@@ -337,20 +338,27 @@ export class DeviceCommands {
337
338
  if (this.disposed) {
338
339
  return;
339
340
  }
340
- this.dispose(true);
341
- if (this.callPromise) {
342
- try {
343
- await Promise.all([
344
- new Promise((_resolve, reject) =>
345
- // eslint-disable-next-line no-promise-executor-return
346
- setTimeout(() => reject(new Error('cancel timeout')), 10 * 1000)
347
- ),
348
- await this.callPromise,
349
- ]);
350
- } catch {
351
- // device error
341
+ const activeCall = this.callPromise;
342
+ let timer: ReturnType<typeof setTimeout> | undefined;
343
+ const cancellation = (async () => {
344
+ await this.dispose(true);
345
+ await activeCall?.catch(() => undefined);
346
+ })();
347
+
348
+ try {
349
+ await Promise.race([
350
+ cancellation,
351
+ new Promise<void>(resolve => {
352
+ timer = setTimeout(resolve, 10 * 1000);
353
+ }),
354
+ ]);
355
+ } finally {
356
+ if (timer) clearTimeout(timer);
357
+ if (this.callPromise === activeCall) {
352
358
  this.callPromise = undefined;
353
359
  }
360
+ // The cancellation work may finish after the bounded wait.
361
+ cancellation.catch(() => undefined);
354
362
  }
355
363
  }
356
364
 
@@ -451,7 +459,7 @@ export class DeviceCommands {
451
459
  'PinMatrixAck',
452
460
  'PassphraseAck',
453
461
  'Cancel',
454
- 'DeviceSessionGet',
462
+ 'DeviceSessionOpen',
455
463
  'BixinPinInputOnDevice',
456
464
  'FilesystemFileRead',
457
465
  'FilesystemFileWrite',
@@ -599,6 +607,42 @@ export class DeviceCommands {
599
607
  const isLegacyProtocolV2LockedFailure =
600
608
  this.device.isProtocolV2() && /^device (?:is )?locked$/i.test(normalizedMessage);
601
609
  if (
610
+ callType === 'DeviceSessionOpen' &&
611
+ subcode === DeviceSessionErrorCode.DeviceSessionError_InvalidSession
612
+ ) {
613
+ error = ERRORS.TypedError(HardwareErrorCode.WalletSessionInvalid, message, {
614
+ failureCode: code,
615
+ subcode,
616
+ firmwareMessage: message,
617
+ });
618
+ } else if (
619
+ callType === 'DeviceSessionOpen' &&
620
+ subcode === DeviceSessionErrorCode.DeviceSessionError_UserCancelled
621
+ ) {
622
+ error = ERRORS.TypedError(HardwareErrorCode.ActionCancelled, message, {
623
+ failureCode: code,
624
+ subcode,
625
+ firmwareMessage: message,
626
+ });
627
+ } else if (
628
+ callType === 'DeviceSessionOpen' &&
629
+ subcode === DeviceSessionErrorCode.DeviceSessionError_AttachPinUnavailable
630
+ ) {
631
+ error = ERRORS.TypedError(HardwareErrorCode.DeviceCheckUnlockTypeError, message, {
632
+ failureCode: code,
633
+ subcode,
634
+ firmwareMessage: message,
635
+ });
636
+ } else if (
637
+ callType === 'DeviceSessionOpen' &&
638
+ subcode === DeviceSessionErrorCode.DeviceSessionError_PassphraseDisabled
639
+ ) {
640
+ error = ERRORS.TypedError(HardwareErrorCode.DeviceNotOpenedPassphrase, message, {
641
+ failureCode: code,
642
+ subcode,
643
+ firmwareMessage: message,
644
+ });
645
+ } else if (
602
646
  subcode === DeviceErrorCode.DeviceError_ActionCancelled ||
603
647
  isLegacyProtocolV2ActionCancelledFailure
604
648
  ) {
@@ -1,14 +1,5 @@
1
1
  import type { Features } from '../types';
2
2
 
3
- export type DeviceFeaturesUpdateSource =
4
- | 'device-info'
5
- | 'device-status'
6
- | 'device-settings-get'
7
- | 'device-settings-set'
8
- | 'apply-settings'
9
- | 'unlock'
10
- | 'cache';
11
-
12
3
  /**
13
4
  * Merge a field-level device-state patch.
14
5
  *
@@ -1,7 +1,11 @@
1
1
  import { EDeviceType, EFirmwareType } from '@onekeyfe/hd-shared';
2
2
 
3
3
  import { buildProtocolV1FeaturesPayload } from '../deviceProfile/buildDeviceFeatures';
4
- import { mapLanguageToProtocolV2 } from '../utils/deviceSettings';
4
+ import {
5
+ mapLanguageFromProtocolV2,
6
+ mapLanguageToProtocolV2,
7
+ normalizeSafetyCheckLevel,
8
+ } from '../utils/deviceSettings';
5
9
 
6
10
  import type {
7
11
  ApplySettings,
@@ -25,6 +29,23 @@ const definedEntries = <T extends Record<string, unknown>>(value: T): T =>
25
29
  Object.entries(value).filter(([, fieldValue]) => fieldValue !== undefined)
26
30
  ) as T;
27
31
 
32
+ const sanitizeRawFeatures = (features: Features): Features['raw'] => {
33
+ if (!features.raw) return undefined;
34
+
35
+ const raw = { ...features.raw };
36
+ if (raw.protocolV1Features) {
37
+ const { session_id: _sessionId, ...protocolV1Features } = raw.protocolV1Features;
38
+ const compatibilityFields = protocolV1Features as typeof protocolV1Features & {
39
+ sessionId?: string;
40
+ passphraseState?: string;
41
+ };
42
+ delete compatibilityFields.sessionId;
43
+ delete compatibilityFields.passphraseState;
44
+ raw.protocolV1Features = compatibilityFields as PROTO.Features;
45
+ }
46
+ return raw;
47
+ };
48
+
28
49
  const imageVersion = (image?: DeviceFirmwareImageInfo | null) => image?.version ?? undefined;
29
50
 
30
51
  const bytesToHex = (value: unknown): string | undefined => {
@@ -123,7 +144,7 @@ export const mapFeaturesToState = (features: Features): DeviceStatePatch => ({
123
144
  },
124
145
  capabilities: features.capabilities,
125
146
  verification: definedEntries(features.verify ?? {}),
126
- raw: features.raw,
147
+ raw: sanitizeRawFeatures(features),
127
148
  });
128
149
 
129
150
  export const mapProtocolV1FeaturesToState = (
@@ -289,9 +310,10 @@ export const mapApplySettingsToState = (settings: ApplySettings): DeviceStatePat
289
310
  autoShutdownDelayMs: settings.auto_shutdown_delay_ms,
290
311
  displayRotation: settings.display_rotation,
291
312
  passphraseAlwaysOnDevice: settings.passphrase_always_on_device,
292
- safetyChecks: settings.safety_checks,
313
+ safetyChecks: normalizeSafetyCheckLevel(settings.safety_checks),
293
314
  experimentalFeatures: settings.experimental_features,
294
315
  hapticFeedback: settings.haptic_feedback,
316
+ bleEnabled: settings.use_ble,
295
317
  });
296
318
  return {
297
319
  ...(Object.keys(identity).length ? { identity } : {}),
@@ -301,14 +323,11 @@ export const mapApplySettingsToState = (settings: ApplySettings): DeviceStatePat
301
323
  };
302
324
 
303
325
  export const mapDeviceSettingsToState = (settings: DeviceSettings): DeviceStatePatch => {
304
- const settingsWithExperimental = settings as DeviceSettings & {
305
- experimental_features?: boolean;
306
- };
307
326
  const identity = definedEntries({ label: settings.label });
308
327
  const status = definedEntries({ passphraseProtection: settings.passphrase_enable });
309
328
  const stateSettings = definedEntries({
310
329
  bleEnabled: settings.bt_enable,
311
- language: settings.language,
330
+ language: mapLanguageFromProtocolV2(settings.language),
312
331
  wallpaperPath: settings.wallpaper_path,
313
332
  brightness: settings.brightness,
314
333
  autoLockDelayMs: settings.autolock_delay_ms,
@@ -319,7 +338,6 @@ export const mapDeviceSettingsToState = (settings: DeviceSettings): DeviceStateP
319
338
  deviceNameDisplayEnabled: settings.device_name_display_enabled,
320
339
  airgapMode: settings.airgap_mode,
321
340
  fidoEnabled: settings.fido_enabled,
322
- experimentalFeatures: settingsWithExperimental.experimental_features,
323
341
  usbLockEnabled: settings.usb_lock_enable,
324
342
  randomKeypad: settings.random_keypad,
325
343
  });
@@ -16,6 +16,12 @@ export const projectFeatures = (state: StoredDeviceState): Features => {
16
16
  delete publicRawFeatures.session_id;
17
17
  delete publicRawFeatures.sessionId;
18
18
  delete publicRawFeatures.passphraseState;
19
+ const publicRaw = snapshot.raw
20
+ ? {
21
+ ...snapshot.raw,
22
+ protocolV1Features: publicRawFeatures,
23
+ }
24
+ : undefined;
19
25
  const rawOneKeyFeatures = snapshot.raw?.protocolV1OneKeyFeatures ?? {};
20
26
  const bootloaderMode =
21
27
  snapshot.protocol === 'V1'
@@ -84,7 +90,7 @@ export const projectFeatures = (state: StoredDeviceState): Features => {
84
90
  se04BootVersion: snapshot.versions.se04Boot,
85
91
  seVersion: snapshot.versions.se ?? null,
86
92
  verify: snapshot.verification,
87
- raw: snapshot.raw,
93
+ raw: publicRaw,
88
94
  device_id: snapshot.identity.deviceId ?? undefined,
89
95
  ble_name: snapshot.identity.bleName ?? undefined,
90
96
  passphrase_protection: snapshot.status.passphraseProtection ?? undefined,
@@ -10,6 +10,7 @@ import {
10
10
  resolveDeviceSerialNo,
11
11
  resolveDeviceType,
12
12
  } from '../utils/deviceFeaturesCompat';
13
+ import { normalizeSafetyCheckLevel } from '../utils/deviceSettings';
13
14
 
14
15
  import type {
15
16
  DeviceFirmwareImageInfo,
@@ -121,7 +122,7 @@ export const buildProtocolV1FeaturesPayload = (
121
122
  passphraseAlwaysOnDevice: features.passphrase_always_on_device ?? null,
122
123
  attachToPinEnabled: features.attach_to_pin_user ?? previous?.attachToPinEnabled ?? null,
123
124
  unlockedAttachPin: features.unlocked_attach_pin ?? previous?.unlockedAttachPin ?? undefined,
124
- safetyChecks: features.safety_checks ?? null,
125
+ safetyChecks: normalizeSafetyCheckLevel(features.safety_checks) ?? null,
125
126
  autoLockDelayMs: features.auto_lock_delay_ms ?? null,
126
127
  autoShutdownDelayMs: features.auto_shutdown_delay_ms ?? null,
127
128
  displayRotation: features.display_rotation ?? null,
@@ -53,12 +53,6 @@ export interface IFrameCancelMessage {
53
53
  payload: { connectId?: string };
54
54
  }
55
55
 
56
- export interface IFrameCancelOperationMessage {
57
- event: typeof IFRAME.CANCEL_OPERATION;
58
- type: typeof IFRAME.CANCEL_OPERATION;
59
- payload: { operationId: string };
60
- }
61
-
62
56
  export interface IFrameSwitchTransportMessage {
63
57
  event: typeof IFRAME.SWITCH_TRANSPORT;
64
58
  type: typeof IFRAME.SWITCH_TRANSPORT;
@@ -5,7 +5,6 @@ import type {
5
5
  IFrameCallMessage,
6
6
  IFrameCallbackMessage,
7
7
  IFrameCancelMessage,
8
- IFrameCancelOperationMessage,
9
8
  IFrameSwitchTransportMessage,
10
9
  } from './call';
11
10
  import type { DeviceEventMessage } from './device';
@@ -24,7 +23,6 @@ export type CoreMessage = {
24
23
  | IFrameEventMessage
25
24
  | IFrameCallMessage
26
25
  | IFrameCancelMessage
27
- | IFrameCancelOperationMessage
28
26
  | IFrameSwitchTransportMessage
29
27
  | IFrameCallbackMessage
30
28
  | UiResponseMessage
@@ -8,7 +8,6 @@ export const IFRAME = {
8
8
  INIT_BRIDGE: 'iframe-init-bridge',
9
9
  CALL: 'iframe-call',
10
10
  CANCEL: 'iframe-cancel',
11
- CANCEL_OPERATION: 'iframe-cancel-operation',
12
11
  SWITCH_TRANSPORT: 'iframe-switch-transport',
13
12
  CALLBACK: 'iframe-callback',
14
13
  } as const;
@@ -8,6 +8,7 @@ export const LogBlockEvent: Set<string> = new Set([
8
8
  const LogBlockMethod: Set<string> = new Set([
9
9
  'evmSignTypedData',
10
10
  'openWalletSession',
11
+ 'DeviceSessionOpen',
11
12
  'deviceUploadWallpaper',
12
13
  'uploadPortfolio',
13
14
  'fileWrite',
package/src/index.ts CHANGED
@@ -19,6 +19,11 @@ export * from './types';
19
19
  export { whitelist, whitelistExtension } from './data/config';
20
20
  export { executeCallback, cleanupCallback };
21
21
  export { preloadSessionCache } from './device/Device';
22
+ export {
23
+ getFirmwareUpdateHostBindingGeneration,
24
+ registerFirmwareUpdateHostBinding,
25
+ unregisterFirmwareUpdateHostBinding,
26
+ } from './api/firmware/FirmwareHostBinding';
22
27
 
23
28
  const HardwareSdk = ({
24
29
  init,
@@ -27,7 +32,6 @@ const HardwareSdk = ({
27
32
  eventEmitter,
28
33
  uiResponse,
29
34
  cancel,
30
- cancelOperation,
31
35
  updateSettings,
32
36
  switchTransport,
33
37
  }: InjectApi): CoreApi =>
@@ -38,7 +42,6 @@ const HardwareSdk = ({
38
42
  eventEmitter,
39
43
  uiResponse,
40
44
  cancel,
41
- cancelOperation,
42
45
  updateSettings,
43
46
  switchTransport,
44
47
  });
@@ -51,7 +54,6 @@ const HardwareSDKLowLevel = ({
51
54
  addHardwareGlobalEventListener,
52
55
  uiResponse,
53
56
  cancel,
54
- cancelOperation,
55
57
  updateSettings,
56
58
  switchTransport,
57
59
  }: LowLevelInjectApi): LowLevelCoreApi =>
@@ -63,7 +65,6 @@ const HardwareSDKLowLevel = ({
63
65
  addHardwareGlobalEventListener,
64
66
  uiResponse,
65
67
  cancel,
66
- cancelOperation,
67
68
  updateSettings,
68
69
  switchTransport,
69
70
  });
package/src/inject.ts CHANGED
@@ -1,6 +1,17 @@
1
- import type { Unsuccessful } from './types';
1
+ import { getFirmwareUpdateCapabilities } from './api/firmware/FirmwareUpdateCapabilities';
2
+ import {
3
+ prepareFirmwareUpdatePlan,
4
+ validateFirmwareUpdatePreparedPlan,
5
+ } from './api/firmware/FirmwareUpdatePreparedPlan';
6
+ import {
7
+ getFirmwareUpdateHostBindingGeneration,
8
+ registerFirmwareUpdateHostBinding,
9
+ unregisterFirmwareUpdateHostBinding,
10
+ } from './api/firmware/FirmwareHostBinding';
11
+
2
12
  import type { EventEmitter } from 'events';
3
13
  import type { CallMethod } from './events';
14
+ import type { Unsuccessful } from './types';
4
15
  import type { CoreApi } from './types/api';
5
16
  import type { AllNetworkAddress } from './types/api/allNetworkGetAddress';
6
17
 
@@ -36,14 +47,12 @@ export interface InjectApi {
36
47
  dispose: CoreApi['dispose'];
37
48
  uiResponse: CoreApi['uiResponse'];
38
49
  cancel: CoreApi['cancel'];
39
- cancelOperation: CoreApi['cancelOperation'];
40
50
  switchTransport: CoreApi['switchTransport'];
41
51
  }
42
52
 
43
53
  export const inject = ({
44
54
  call,
45
55
  cancel,
46
- cancelOperation,
47
56
  dispose,
48
57
  eventEmitter,
49
58
  init,
@@ -70,12 +79,14 @@ export const inject = ({
70
79
 
71
80
  call,
72
81
 
73
- dispose,
82
+ dispose: async () => {
83
+ unregisterFirmwareUpdateHostBinding();
84
+ await dispose();
85
+ },
74
86
 
75
87
  uiResponse,
76
88
 
77
89
  cancel,
78
- cancelOperation,
79
90
 
80
91
  updateSettings,
81
92
 
@@ -99,10 +110,15 @@ export const createCoreApi = (
99
110
  | 'dispose'
100
111
  | 'uiResponse'
101
112
  | 'cancel'
102
- | 'cancelOperation'
103
113
  | 'updateSettings'
104
114
  | 'switchTransport'
105
115
  > => ({
116
+ getFirmwareUpdateCapabilities,
117
+ registerFirmwareUpdateHostBinding,
118
+ unregisterFirmwareUpdateHostBinding,
119
+ getFirmwareUpdateHostBindingGeneration,
120
+ prepareFirmwareUpdatePlan,
121
+ validateFirmwareUpdatePreparedPlan,
106
122
  getLogs: () => call({ method: 'getLogs' }),
107
123
  clearSessionCache: params => call({ ...params, method: 'clearSessionCache' }),
108
124
  /**
@@ -164,36 +180,7 @@ export const createCoreApi = (
164
180
  call({ ...params, connectId, method: 'deviceGetOnboardingStatus' }),
165
181
  deviceUploadWallpaper: (connectId, params) =>
166
182
  call({ ...params, connectId, method: 'deviceUploadWallpaper' }),
167
- deviceInfoGet: (connectId, params) => call({ ...params, connectId, method: 'deviceInfoGet' }),
168
- deviceStatusGet: (connectId, params) => call({ ...params, connectId, method: 'deviceStatusGet' }),
169
- deviceSettingsGet: (connectId, params) =>
170
- call({ ...params, connectId, method: 'deviceSettingsGet' }),
171
- protocolInfoRequest: (connectId, params) =>
172
- call({ ...params, connectId, method: 'protocolInfoRequest' }),
173
- ping: (connectId, params) => call({ ...params, connectId, method: 'ping' }),
174
- deviceFirmwareUpdate: (connectId, params) =>
175
- call({ ...params, connectId, method: 'deviceFirmwareUpdate' }),
176
- deviceGetFirmwareUpdateStatus: (connectId, params) =>
177
- call({ ...params, connectId, method: 'deviceGetFirmwareUpdateStatus' }),
178
- deviceFactoryInfoSet: (connectId, params) =>
179
- call({ ...params, connectId, method: 'deviceFactoryInfoSet' }),
180
- deviceFactoryInfoGet: (connectId, params) =>
181
- call({ ...params, connectId, method: 'deviceFactoryInfoGet' }),
182
- deviceSettingsSet: (connectId, params) =>
183
- call({ ...params, connectId, method: 'deviceSettingsSet' }),
184
- deviceSettingsPageShow: (connectId, params) =>
185
- call({ ...params, connectId, method: 'deviceSettingsPageShow' }),
186
- filesystemPermissionFix: (connectId, params) =>
187
- call({ ...params, connectId, method: 'filesystemPermissionFix' }),
188
- filesystemFormat: connectId => call({ connectId, method: 'filesystemFormat' }),
189
183
  uploadPortfolio: (connectId, params) => call({ ...params, connectId, method: 'uploadPortfolio' }),
190
- fileRead: (connectId, params) => call({ ...params, connectId, method: 'fileRead' }),
191
- fileWrite: (connectId, params) => call({ ...params, connectId, method: 'fileWrite' }),
192
- fileDelete: (connectId, params) => call({ ...params, connectId, method: 'fileDelete' }),
193
- dirList: (connectId, params) => call({ ...params, connectId, method: 'dirList' }),
194
- dirMake: (connectId, params) => call({ ...params, connectId, method: 'dirMake' }),
195
- dirRemove: (connectId, params) => call({ ...params, connectId, method: 'dirRemove' }),
196
- pathInfo: (connectId, params) => call({ ...params, connectId, method: 'pathInfo' }),
197
184
  deviceRecovery: (connectId, params) => call({ ...params, connectId, method: 'deviceRecovery' }),
198
185
  deviceReset: (connectId, params) => call({ ...params, connectId, method: 'deviceReset' }),
199
186
  deviceSettings: (connectId, params) => call({ ...params, connectId, method: 'deviceSettings' }),
@@ -1,4 +1,5 @@
1
1
  import { createCoreApi } from './inject';
2
+ import { unregisterFirmwareUpdateHostBinding } from './api/firmware/FirmwareHostBinding';
2
3
 
3
4
  import type { EventEmitter } from 'events';
4
5
  import type { CallMethod, CoreMessage } from './events';
@@ -13,7 +14,6 @@ export interface LowLevelInjectApi {
13
14
  dispose: CoreApi['dispose'];
14
15
  uiResponse: CoreApi['uiResponse'];
15
16
  cancel: CoreApi['cancel'];
16
- cancelOperation: CoreApi['cancelOperation'];
17
17
  updateSettings: CoreApi['updateSettings'];
18
18
  switchTransport: CoreApi['switchTransport'];
19
19
  addHardwareGlobalEventListener: (listener: IAddHardwareGlobalEventListener) => void;
@@ -26,7 +26,6 @@ export type LowLevelCoreApi = Omit<CoreApi, 'on' | 'off'> & {
26
26
  export const lowLevelInject = ({
27
27
  call,
28
28
  cancel,
29
- cancelOperation,
30
29
  dispose,
31
30
  eventEmitter,
32
31
  init,
@@ -45,12 +44,14 @@ export const lowLevelInject = ({
45
44
 
46
45
  call,
47
46
 
48
- dispose,
47
+ dispose: async () => {
48
+ unregisterFirmwareUpdateHostBinding();
49
+ await dispose();
50
+ },
49
51
 
50
52
  uiResponse,
51
53
 
52
54
  cancel,
53
- cancelOperation,
54
55
 
55
56
  updateSettings,
56
57
 
@@ -18,7 +18,7 @@ export function assertCompleteDeviceSession(
18
18
  ) {
19
19
  throw ERRORS.TypedError(
20
20
  HardwareErrorCode.RuntimeError,
21
- 'DeviceSessionGet returned an incomplete DeviceSession response.'
21
+ 'DeviceSessionOpen returned an incomplete DeviceSession response.'
22
22
  );
23
23
  }
24
24
  }
@@ -12,7 +12,7 @@ const LOCK_FREE_DEVICE_SETTINGS = new Set<keyof DeviceSettings>([
12
12
  export const getProtocolV2SettingsUnlockPolicy = (settings: DeviceSettings): UnlockPolicy =>
13
13
  Object.keys(settings).every(key => LOCK_FREE_DEVICE_SETTINGS.has(key as keyof DeviceSettings))
14
14
  ? 'none'
15
- : 'retry-on-locked';
15
+ : 'unlock-before-run';
16
16
 
17
17
  export type ProtocolV2SettingsOperation =
18
18
  | {
@@ -32,7 +32,7 @@ export const getProtocolV2SettingsBehavior = (
32
32
  } => {
33
33
  if (operation.kind === 'page') {
34
34
  return {
35
- unlockPolicy: 'retry-on-locked',
35
+ unlockPolicy: 'unlock-before-run',
36
36
  uiInteraction: {
37
37
  request: 'button',
38
38
  source: 'method-lifecycle',