@onekeyfe/hd-core 1.2.0-alpha.40 → 1.2.0-alpha.41

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 (195) hide show
  1. package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +0 -78
  2. package/__tests__/DeviceEventRegistration.test.ts +0 -6
  3. package/__tests__/connectSettings.test.ts +47 -5
  4. package/__tests__/firmware-update/check-all-firmware-release.test.ts +175 -0
  5. package/__tests__/firmware-update/firmware-artifact-source.test.ts +119 -0
  6. package/__tests__/firmware-update/firmware-host-binding.test.ts +70 -0
  7. package/__tests__/firmware-update/firmware-preparation-error.test.ts +27 -0
  8. package/__tests__/firmware-update/firmware-update-capabilities.test.ts +13 -0
  9. package/__tests__/firmware-update/firmware-update-plan.test.ts +593 -0
  10. package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +213 -0
  11. package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +59 -31
  12. package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +58 -0
  13. package/__tests__/firmware-update/firmware-upload-source.test.ts +70 -0
  14. package/__tests__/get-device-state.test.ts +12 -132
  15. package/__tests__/homescreen.test.ts +1 -41
  16. package/__tests__/logBlockEvent.test.ts +1 -1
  17. package/__tests__/open-wallet-session.test.ts +18 -259
  18. package/__tests__/protocol-v2-unlock-policy.test.ts +35 -86
  19. package/__tests__/protocol-v2.test.ts +632 -333
  20. package/__tests__/public-pro2-api-boundary.test.ts +0 -1
  21. package/dist/api/BaseMethod.d.ts +1 -3
  22. package/dist/api/BaseMethod.d.ts.map +1 -1
  23. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  24. package/dist/api/FirmwareUpdateV2.d.ts +11 -0
  25. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  26. package/dist/api/FirmwareUpdateV3.d.ts +7 -3
  27. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  28. package/dist/api/FirmwareUpdateV4.d.ts +22 -5
  29. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  30. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  31. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  32. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
  33. package/dist/api/device/DeviceUpdateBootloader.d.ts +5 -1
  34. package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
  35. package/dist/api/firmware/FirmwareArtifactSource.d.ts +25 -0
  36. package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +1 -0
  37. package/dist/api/firmware/FirmwareHostBinding.d.ts +6 -0
  38. package/dist/api/firmware/FirmwareHostBinding.d.ts.map +1 -0
  39. package/dist/api/firmware/FirmwarePreparationError.d.ts +3 -0
  40. package/dist/api/firmware/FirmwarePreparationError.d.ts.map +1 -0
  41. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +8 -0
  42. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  43. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +3 -0
  44. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +1 -0
  45. package/dist/api/firmware/FirmwareUpdatePlan.d.ts +25 -0
  46. package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -0
  47. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +30 -0
  48. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -0
  49. package/dist/api/firmware/getBinary.d.ts +7 -0
  50. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  51. package/dist/api/firmware/progressThrottle.d.ts +3 -0
  52. package/dist/api/firmware/progressThrottle.d.ts.map +1 -0
  53. package/dist/api/firmware/updateBootloader.d.ts +2 -0
  54. package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
  55. package/dist/api/firmware/uploadFirmware.d.ts +9 -1
  56. package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
  57. package/dist/api/helpers/protocolV2FileWrite.d.ts +0 -2
  58. package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
  59. package/dist/api/index.d.ts +0 -1
  60. package/dist/api/index.d.ts.map +1 -1
  61. package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts.map +1 -1
  62. package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
  63. package/dist/core/deviceEventRegistration.d.ts +0 -2
  64. package/dist/core/deviceEventRegistration.d.ts.map +1 -1
  65. package/dist/core/index.d.ts.map +1 -1
  66. package/dist/data-manager/DataManager.d.ts +1 -0
  67. package/dist/data-manager/DataManager.d.ts.map +1 -1
  68. package/dist/data-manager/connectSettings.d.ts.map +1 -1
  69. package/dist/device/Device.d.ts +4 -22
  70. package/dist/device/Device.d.ts.map +1 -1
  71. package/dist/events/device.d.ts +0 -4
  72. package/dist/events/device.d.ts.map +1 -1
  73. package/dist/events/logBlockEvent.d.ts.map +1 -1
  74. package/dist/events/ui-request.d.ts +2 -27
  75. package/dist/events/ui-request.d.ts.map +1 -1
  76. package/dist/index.d.ts +181 -88
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +3162 -1614
  79. package/dist/inject.d.ts.map +1 -1
  80. package/dist/lowLevelInject.d.ts.map +1 -1
  81. package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
  82. package/dist/protocols/protocol-v2/lockedError.d.ts +2 -0
  83. package/dist/protocols/protocol-v2/lockedError.d.ts.map +1 -0
  84. package/dist/protocols/protocol-v2/uiInteraction.d.ts +3 -3
  85. package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -1
  86. package/dist/protocols/protocol-v2/unlockPolicy.d.ts +3 -1
  87. package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -1
  88. package/dist/protocols/protocol-v2/unlockRetry.d.ts +10 -0
  89. package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +1 -0
  90. package/dist/protocols/protocol-v2/walletSession.d.ts +1 -4
  91. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  92. package/dist/topLevelInject.d.ts.map +1 -1
  93. package/dist/types/api/checkAllFirmwareRelease.d.ts +4 -0
  94. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  95. package/dist/types/api/deviceUpdateBootloader.d.ts +6 -0
  96. package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
  97. package/dist/types/api/export.d.ts +4 -1
  98. package/dist/types/api/export.d.ts.map +1 -1
  99. package/dist/types/api/firmwareUpdate.d.ts +69 -0
  100. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  101. package/dist/types/api/firmwareUpdateCapabilities.d.ts +9 -0
  102. package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +1 -0
  103. package/dist/types/api/firmwareUpdatePlan.d.ts +28 -0
  104. package/dist/types/api/firmwareUpdatePlan.d.ts.map +1 -0
  105. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +42 -0
  106. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +1 -0
  107. package/dist/types/api/index.d.ts +10 -3
  108. package/dist/types/api/index.d.ts.map +1 -1
  109. package/dist/types/api/protocolV2.d.ts +0 -3
  110. package/dist/types/api/protocolV2.d.ts.map +1 -1
  111. package/dist/types/settings.d.ts +13 -0
  112. package/dist/types/settings.d.ts.map +1 -1
  113. package/dist/utils/deviceFeaturesUtils.d.ts +0 -2
  114. package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
  115. package/dist/utils/homescreen.d.ts +0 -4
  116. package/dist/utils/homescreen.d.ts.map +1 -1
  117. package/dist/utils/index.d.ts +1 -1
  118. package/dist/utils/index.d.ts.map +1 -1
  119. package/dist/utils/patch.d.ts +1 -1
  120. package/dist/utils/patch.d.ts.map +1 -1
  121. package/dist/utils/pro2Wallpaper.d.ts +0 -10
  122. package/dist/utils/pro2Wallpaper.d.ts.map +1 -1
  123. package/package.json +4 -4
  124. package/src/api/BaseMethod.ts +10 -8
  125. package/src/api/CheckAllFirmwareRelease.ts +51 -6
  126. package/src/api/FirmwareUpdateV2.ts +298 -120
  127. package/src/api/FirmwareUpdateV3.ts +263 -57
  128. package/src/api/FirmwareUpdateV4.ts +748 -281
  129. package/src/api/GetPassphraseState.ts +1 -7
  130. package/src/api/OpenWalletSession.ts +17 -54
  131. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +11 -32
  132. package/src/api/device/DeviceUnlock.ts +1 -1
  133. package/src/api/device/DeviceUpdateBootloader.ts +122 -6
  134. package/src/api/firmware/FirmwareArtifactSource.ts +278 -0
  135. package/src/api/firmware/FirmwareHostBinding.ts +100 -0
  136. package/src/api/firmware/FirmwarePreparationError.ts +12 -0
  137. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +57 -0
  138. package/src/api/firmware/FirmwareUpdateCapabilities.ts +9 -0
  139. package/src/api/firmware/FirmwareUpdatePlan.ts +745 -0
  140. package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +392 -0
  141. package/src/api/firmware/progressThrottle.ts +44 -0
  142. package/src/api/firmware/updateBootloader.ts +19 -4
  143. package/src/api/firmware/uploadFirmware.ts +140 -22
  144. package/src/api/helpers/protocolV2FileWrite.ts +4 -11
  145. package/src/api/index.ts +0 -1
  146. package/src/api/protocol-v2/ProtocolInfoRequest.ts +1 -3
  147. package/src/core/deviceEventRegistration.ts +0 -4
  148. package/src/core/index.ts +75 -118
  149. package/src/data/messages/messages-protocol-v2.json +0 -10
  150. package/src/data-manager/DataManager.ts +33 -33
  151. package/src/data-manager/connectSettings.ts +11 -0
  152. package/src/device/Device.ts +21 -193
  153. package/src/events/device.ts +0 -4
  154. package/src/events/logBlockEvent.ts +0 -1
  155. package/src/events/ui-request.ts +2 -32
  156. package/src/index.ts +5 -0
  157. package/src/inject.ts +22 -3
  158. package/src/lowLevelInject.ts +5 -1
  159. package/src/protocols/protocol-v2/features.ts +2 -9
  160. package/src/protocols/protocol-v2/lockedError.ts +10 -0
  161. package/src/protocols/protocol-v2/uiInteraction.ts +5 -31
  162. package/src/protocols/protocol-v2/unlockPolicy.ts +105 -1
  163. package/src/protocols/protocol-v2/unlockRetry.ts +109 -0
  164. package/src/protocols/protocol-v2/walletSession.ts +18 -93
  165. package/src/topLevelInject.ts +5 -1
  166. package/src/types/api/checkAllFirmwareRelease.ts +4 -0
  167. package/src/types/api/deviceUpdateBootloader.ts +6 -0
  168. package/src/types/api/export.ts +18 -0
  169. package/src/types/api/firmwareUpdate.ts +76 -0
  170. package/src/types/api/firmwareUpdateCapabilities.ts +9 -0
  171. package/src/types/api/firmwareUpdatePlan.ts +38 -0
  172. package/src/types/api/firmwareUpdatePreparedPlan.ts +53 -0
  173. package/src/types/api/index.ts +14 -2
  174. package/src/types/api/protocolV2.ts +0 -13
  175. package/src/types/settings.ts +13 -0
  176. package/src/utils/deviceFeaturesUtils.ts +0 -4
  177. package/src/utils/homescreen.ts +6 -32
  178. package/src/utils/index.ts +1 -6
  179. package/src/utils/pro2Wallpaper.ts +8 -35
  180. package/__tests__/deviceUploadNft.test.ts +0 -187
  181. package/__tests__/pro2Nft.test.ts +0 -108
  182. package/__tests__/protocol-v2-ui-lifecycle.test.ts +0 -56
  183. package/__tests__/uiProgressThrottle.test.ts +0 -74
  184. package/dist/api/protocol-v2/DeviceUploadNft.d.ts +0 -30
  185. package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +0 -1
  186. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +0 -22
  187. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +0 -1
  188. package/dist/utils/pro2Nft.d.ts +0 -29
  189. package/dist/utils/pro2Nft.d.ts.map +0 -1
  190. package/dist/utils/uiProgressThrottle.d.ts +0 -3
  191. package/dist/utils/uiProgressThrottle.d.ts.map +0 -1
  192. package/src/api/protocol-v2/DeviceUploadNft.ts +0 -166
  193. package/src/protocols/protocol-v2/unlockPolicyRunner.ts +0 -117
  194. package/src/utils/pro2Nft.ts +0 -91
  195. package/src/utils/uiProgressThrottle.ts +0 -63
@@ -1,5 +1,4 @@
1
1
  import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
- import { DeviceSessionPinType } from '@onekeyfe/hd-transport';
3
2
 
4
3
  import { UI_REQUEST } from '../constants/ui-request';
5
4
  import { refreshProtocolV2DeviceStatus } from '../protocols/protocol-v2/walletSession';
@@ -25,12 +24,7 @@ export default class GetPassphraseState extends BaseMethod {
25
24
  if (isProtocolV2 && this.payload.useEmptyPassphrase !== true) {
26
25
  const features = await refreshProtocolV2DeviceStatus(this.device);
27
26
  if (features.unlocked === false) {
28
- await this.device.unlockDevice(DeviceSessionPinType.Main, {
29
- source: 'unlock-coordinator',
30
- reason: 'device-locked',
31
- deviceOnly: true,
32
- method: 'getPassphraseState',
33
- });
27
+ await this.device.unlockDevice();
34
28
  }
35
29
  }
36
30
  const { passphraseState } = await getPassphraseStateWithRefreshDeviceInfo(
@@ -1,5 +1,4 @@
1
1
  import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
- import { DeviceSessionPinType } from '@onekeyfe/hd-transport';
3
2
 
4
3
  import { deviceWalletSessionStore } from '../device/DeviceWalletSessionStore';
5
4
  import { getProtocolV2WalletSession } from '../protocols/protocol-v2/walletSession';
@@ -91,40 +90,23 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
91
90
 
92
91
  async run(): Promise<OpenWalletSessionPayload> {
93
92
  const isProtocolV2 = this.device.isProtocolV2();
94
- let state = await this.device.getDeviceState({ refreshSections: ['status'] });
93
+ const state = await this.device.getDeviceState({ refreshSections: ['status'] });
95
94
  let currentDeviceId = state.identity.deviceId;
96
- const hasAuthoritativeProtocolV2WalletStatus = (candidate: typeof state) =>
97
- candidate.status.unlocked === true &&
98
- typeof candidate.status.passphraseProtection === 'boolean' &&
99
- typeof candidate.status.unlockedAttachPin === 'boolean';
100
- const requireAuthoritativeProtocolV2WalletStatus = (candidate: typeof state) => {
101
- if (!hasAuthoritativeProtocolV2WalletStatus(candidate)) {
102
- throw ERRORS.TypedError(HardwareErrorCode.DeviceInitializeFailed);
103
- }
104
- return candidate;
105
- };
106
95
  const requireDeviceId = () => {
107
96
  if (!currentDeviceId) {
108
97
  throw ERRORS.TypedError(HardwareErrorCode.DeviceInitializeFailed);
109
98
  }
110
99
  return currentDeviceId;
111
100
  };
112
- const refreshProtocolV2DeviceState = async () => {
113
- state = await this.device.getDeviceState({ refreshSections: ['status'] });
114
- currentDeviceId = state.identity.deviceId;
115
- return state;
101
+ const refreshProtocolV2DeviceId = async () => {
102
+ const refreshedState = await this.device.getDeviceState({ refreshSections: ['status'] });
103
+ currentDeviceId = refreshedState.identity.deviceId;
104
+ return requireDeviceId();
116
105
  };
117
- const ensureProtocolV2WalletStatus = async () => {
118
- if (isProtocolV2 && !hasAuthoritativeProtocolV2WalletStatus(state)) {
119
- await this.device.unlockDevice(DeviceSessionPinType.Main, {
120
- source: 'unlock-coordinator',
121
- reason: 'device-locked',
122
- deviceOnly: true,
123
- method: 'openWalletSession',
124
- });
125
- requireAuthoritativeProtocolV2WalletStatus(await refreshProtocolV2DeviceState());
106
+ const unlockProtocolV2IfLocked = async () => {
107
+ if (isProtocolV2 && state.status.unlocked === false) {
108
+ await this.device.unlockDevice();
126
109
  }
127
- return state;
128
110
  };
129
111
 
130
112
  const protocol = isProtocolV2 ? 'V2' : 'V1';
@@ -132,25 +114,13 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
132
114
  if (this.params.mode === OpenWalletSessionMode.Standard) {
133
115
  this.device.passphraseState = undefined;
134
116
  const session = isProtocolV2
135
- ? await getProtocolV2WalletSession(this.device, {
136
- onlyMainPin: true,
137
- deriveCardano: this.payload.deriveCardano,
138
- selectMainWalletBeforeRestore:
139
- !hasAuthoritativeProtocolV2WalletStatus(state) ||
140
- state.status.unlockedAttachPin === true,
141
- })
117
+ ? await getProtocolV2WalletSession(this.device, { onlyMainPin: true })
142
118
  : await getPassphraseStateWithRefreshDeviceInfo(this.device, {
143
119
  onlyMainPin: true,
144
120
  initSession: this.payload.initSession,
145
121
  });
146
- const refreshedState = isProtocolV2
147
- ? requireAuthoritativeProtocolV2WalletStatus(await refreshProtocolV2DeviceState())
148
- : state;
149
- const deviceId = requireDeviceId();
150
- if (
151
- session.unlockedAttachPin ||
152
- (isProtocolV2 && refreshedState.status.unlockedAttachPin === true)
153
- ) {
122
+ const deviceId = isProtocolV2 ? await refreshProtocolV2DeviceId() : requireDeviceId();
123
+ if (session.unlockedAttachPin) {
154
124
  try {
155
125
  await this.device.lockDevice();
156
126
  } catch {
@@ -170,8 +140,8 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
170
140
 
171
141
  if (this.params.mode === OpenWalletSessionMode.ResumeHidden) {
172
142
  if (isProtocolV2) {
173
- await ensureProtocolV2WalletStatus();
174
- const refreshedDeviceId = requireDeviceId();
143
+ await unlockProtocolV2IfLocked();
144
+ const refreshedDeviceId = await refreshProtocolV2DeviceId();
175
145
  if (refreshedDeviceId !== this.params.deviceId) {
176
146
  deviceWalletSessionStore.delete(this.params.deviceId, this.params.passphraseState);
177
147
  throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckDeviceIdError);
@@ -196,7 +166,6 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
196
166
  const session = isProtocolV2
197
167
  ? await getProtocolV2WalletSession(this.device, {
198
168
  expectedPassphraseState: this.params.passphraseState,
199
- deriveCardano: this.payload.deriveCardano,
200
169
  })
201
170
  : await getPassphraseStateWithRefreshDeviceInfo(this.device, {
202
171
  expectPassphraseState: this.params.passphraseState,
@@ -216,18 +185,12 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
216
185
  }
217
186
 
218
187
  this.device.passphraseState = undefined;
219
- await ensureProtocolV2WalletStatus();
188
+ await unlockProtocolV2IfLocked();
220
189
  const session = isProtocolV2
221
- ? await getProtocolV2WalletSession(this.device, {
222
- forceWalletSelection: true,
223
- deriveCardano: this.payload.deriveCardano,
224
- })
190
+ ? await getProtocolV2WalletSession(this.device, { forceWalletSelection: true })
225
191
  : await getPassphraseStateWithRefreshDeviceInfo(this.device, { initSession: true });
226
- const refreshedState = isProtocolV2
227
- ? requireAuthoritativeProtocolV2WalletStatus(await refreshProtocolV2DeviceState())
228
- : state;
229
- const deviceId = requireDeviceId();
230
- if (isProtocolV2 && refreshedState.status.passphraseProtection !== true) {
192
+ const deviceId = isProtocolV2 ? await refreshProtocolV2DeviceId() : requireDeviceId();
193
+ if (isProtocolV2 && this.device.getCurrentPassphraseProtection() !== true) {
231
194
  this.device.clearInternalState();
232
195
  throw ERRORS.TypedError(HardwareErrorCode.DeviceNotOpenedPassphrase);
233
196
  }
@@ -14,7 +14,6 @@ import { findMethod } from '../utils';
14
14
  import { DEVICE, IFRAME, createUiMessage } from '../../events';
15
15
  import { UI_REQUEST } from '../../constants/ui-request';
16
16
  import { onDeviceButtonHandler } from '../../core';
17
- import { runMethodWithUnlockPolicy } from '../../protocols/protocol-v2/unlockPolicyRunner';
18
17
  import {
19
18
  completeRequestContext,
20
19
  createRequestContext,
@@ -376,34 +375,16 @@ export default abstract class AllNetworkGetAddressBase extends BaseMethod<
376
375
  this.device.on(DEVICE.PASSPHRASE, onSignalAbort);
377
376
 
378
377
  preCheckDeviceSupport(this.device, method);
379
- const response = await runMethodWithUnlockPolicy<any[]>(method, this.device, {
380
- context: this.protocolV2UnlockContext,
381
- prepare: async () => {
382
- if (this.temporarySafetyCheckPrompted) {
383
- method.temporarySafetyCheckPrompted = true;
384
- } else {
385
- const appliedTemporarySafetyCheck = await method.checkSafetyLevelOnTestNet();
386
- if (appliedTemporarySafetyCheck) {
387
- this.temporarySafetyCheckPrompted = true;
388
- }
389
- }
390
-
391
- // Protocol V2 hands a wallet session to exactly one blockchain request.
392
- // The parent all-network call consumes its first handoff while fetching
393
- // the root fingerprint, so each nested chain method must resume the
394
- // requested hidden wallet before it sends its own device command.
395
- if (this.device.isProtocolV2() && this.payload.passphraseState) {
396
- const passphraseStateSafety = await this.device.checkPassphraseStateSafety(
397
- this.payload.passphraseState,
398
- false,
399
- this.payload.skipPassphraseCheck
400
- );
401
- if (!passphraseStateSafety) {
402
- throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckPassphraseStateError);
403
- }
404
- }
405
- },
406
- });
378
+ if (this.temporarySafetyCheckPrompted) {
379
+ method.temporarySafetyCheckPrompted = true;
380
+ } else {
381
+ const appliedTemporarySafetyCheck = await method.checkSafetyLevelOnTestNet();
382
+ if (appliedTemporarySafetyCheck) {
383
+ this.temporarySafetyCheckPrompted = true;
384
+ }
385
+ }
386
+
387
+ const response = await method.run();
407
388
 
408
389
  if (!Array.isArray(response) || response.length === 0) {
409
390
  throw new Error('No response');
@@ -458,9 +439,7 @@ export default abstract class AllNetworkGetAddressBase extends BaseMethod<
458
439
  show_display: false,
459
440
  });
460
441
 
461
- if (!this.device.isProtocolV2()) {
462
- this.postMessage(createUiMessage(UI_REQUEST.CLOSE_UI_PIN_WINDOW));
463
- }
442
+ this.postMessage(createUiMessage(UI_REQUEST.CLOSE_UI_PIN_WINDOW));
464
443
 
465
444
  if (res.message.root_fingerprint == null) {
466
445
  throw ERRORS.TypedError(HardwareErrorCode.CallMethodInvalidParameter);
@@ -21,6 +21,6 @@ export default class DeviceUnlock extends BaseMethod<LockDevice> {
21
21
  }
22
22
 
23
23
  async run() {
24
- return this.device.unlockDevice(undefined, { emitUiEvent: false });
24
+ return this.device.unlockDevice();
25
25
  }
26
26
  }
@@ -5,15 +5,23 @@ import { UI_REQUEST } from '../../constants/ui-request';
5
5
  import { FirmwareUpdateTipMessage } from '../../events/ui-request';
6
6
  import { FirmwareUpdateBaseMethod } from '../firmware/FirmwareUpdateBaseMethod';
7
7
  import { getSysResourceBinary } from '../firmware/getBinary';
8
- import { updateBootloader } from '../firmware/uploadFirmware';
8
+ import { updateBootloader, updateBootloaderFromSource } from '../firmware/uploadFirmware';
9
9
  import { DeviceModelToTypes } from '../../types';
10
10
  import { DataManager } from '../../data-manager';
11
- import { checkBootloaderLength } from '../firmware/updateBootloader';
11
+ import { checkBootloaderLength, checkBootloaderSourceLength } from '../firmware/updateBootloader';
12
+ import { openFirmwareByteSource } from '../firmware/FirmwareArtifactSource';
13
+ import { resolveFirmwareUpdateHostBinding } from '../firmware/FirmwareHostBinding';
14
+ import {
15
+ assertFirmwareUpdatePreparedPlanBinding,
16
+ assertFirmwareUpdatePreparedPlanDeviceIdentity,
17
+ } from '../firmware/FirmwareUpdatePreparedPlan';
18
+ import { getDeviceUUID } from '../../utils';
12
19
 
13
20
  import type { DeviceUpdateBootloaderParams } from '../../types/api/deviceUpdateBootloader';
14
21
  import type { EFirmwareType } from '@onekeyfe/hd-shared';
15
22
  import type { Device } from '../../device/Device';
16
23
  import type { Features } from '../../types';
24
+ import type { FirmwareByteSource } from '../firmware/FirmwareArtifactSource';
17
25
 
18
26
  export default class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod<any> {
19
27
  init() {
@@ -43,17 +51,68 @@ export default class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod<any
43
51
  return true;
44
52
  }
45
53
 
54
+ async updateBootloaderWithEmmcFileWriteFromSource(_device: Device, source: FirmwareByteSource) {
55
+ const filePath = '0:boot/bootloader.bin';
56
+
57
+ this.postTipMessage(FirmwareUpdateTipMessage.StartTransferData);
58
+ await this.emmcCommonUpdateProcessFromSource({
59
+ source,
60
+ filePath,
61
+ });
62
+ this.postTipMessage(FirmwareUpdateTipMessage.ConfirmOnDevice);
63
+ await this.reboot(RebootType.Normal);
64
+ this.postTipMessage(FirmwareUpdateTipMessage.UpdateBootloaderSuccess);
65
+ return true;
66
+ }
67
+
46
68
  async updateTouchBootloader({
47
69
  device,
48
70
  features,
49
71
  firmwareType,
72
+ binary: preparedBinary,
73
+ source: preparedSource,
50
74
  }: {
51
75
  device: Device;
52
76
  features?: Features;
53
77
  firmwareType: EFirmwareType;
78
+ binary?: ArrayBuffer;
79
+ source?: FirmwareByteSource;
54
80
  }) {
55
- let { binary } = this.payload;
81
+ if (preparedSource) {
82
+ if (!(await checkBootloaderSourceLength(preparedSource))) {
83
+ throw ERRORS.TypedError(HardwareErrorCode.CheckDownloadFileError);
84
+ }
85
+ if (features && device.isBootloader()) {
86
+ this.postTipMessage(FirmwareUpdateTipMessage.UpdateBootloader);
87
+ const result = await this.updateBootloaderWithEmmcFileWriteFromSource(
88
+ device,
89
+ preparedSource
90
+ );
91
+ return result;
92
+ }
93
+ if (features && !device.isBootloader()) {
94
+ await updateBootloaderFromSource(
95
+ this.device.getCommands().typedCall.bind(this.device.getCommands()),
96
+ this.postMessage,
97
+ device,
98
+ preparedSource
99
+ );
100
+ return true;
101
+ }
102
+ }
103
+
104
+ let binary = preparedBinary;
56
105
  if (!binary) {
106
+ if (DataManager.getSettings('firmwareManifestMode') === 'external-only') {
107
+ throw ERRORS.TypedError(
108
+ HardwareErrorCode.RuntimeError,
109
+ 'Bootloader must be prepared by the external firmware host',
110
+ {
111
+ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
112
+ artifactName: 'bootloader',
113
+ }
114
+ );
115
+ }
57
116
  this.postTipMessage(FirmwareUpdateTipMessage.CheckLatestUiResource);
58
117
  const resourceUrl = features
59
118
  ? DataManager.getBootloaderResource(features, firmwareType)
@@ -68,7 +127,7 @@ export default class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod<any
68
127
  }
69
128
  }
70
129
 
71
- if (!checkBootloaderLength(binary)) {
130
+ if (!binary || !checkBootloaderLength(binary)) {
72
131
  throw ERRORS.TypedError(HardwareErrorCode.CheckDownloadFileError);
73
132
  }
74
133
 
@@ -76,7 +135,8 @@ export default class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod<any
76
135
  if (features && device.isBootloader()) {
77
136
  // Use emmcFileWrite + reboot logic for bootloader mode
78
137
  this.postTipMessage(FirmwareUpdateTipMessage.UpdateBootloader);
79
- return this.updateBootloaderWithEmmcFileWrite(device, binary);
138
+ const result = await this.updateBootloaderWithEmmcFileWrite(device, binary);
139
+ return result;
80
140
  }
81
141
 
82
142
  if (features && !device.isBootloader()) {
@@ -96,13 +156,69 @@ export default class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod<any
96
156
  const { features } = device;
97
157
 
98
158
  const payload = this.payload as DeviceUpdateBootloaderParams;
159
+ const hostBinding = payload.artifact
160
+ ? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration)
161
+ : undefined;
162
+ const executionParams = {
163
+ ...payload,
164
+ artifactReader: hostBinding?.artifactReader ?? payload.artifactReader,
165
+ };
166
+ if (payload.artifact) {
167
+ assertFirmwareUpdatePreparedPlanDeviceIdentity({
168
+ preparedPlan: payload.preparedPlan,
169
+ deviceIdentity: getDeviceUUID(features) || undefined,
170
+ });
171
+ assertFirmwareUpdatePreparedPlanBinding({
172
+ preparedPlan: payload.preparedPlan,
173
+ executor: 'v2',
174
+ scopeTargets: ['bootloader'],
175
+ bindings: [
176
+ {
177
+ target: 'bootloader',
178
+ artifact: payload.artifact,
179
+ },
180
+ ],
181
+ });
182
+ const source = await openFirmwareByteSource({
183
+ artifact: payload.artifact,
184
+ reader: executionParams.artifactReader,
185
+ });
186
+ if (!source) {
187
+ throw ERRORS.TypedError(
188
+ HardwareErrorCode.RuntimeError,
189
+ 'Bootloader artifact is not prepared'
190
+ );
191
+ }
192
+ try {
193
+ const deviceType = device.getCurrentDeviceType();
194
+ const deviceFirmwareType = device.getCurrentFirmwareType();
195
+ const firmwareType = payload.firmwareType ?? deviceFirmwareType;
196
+ if (DeviceModelToTypes.model_touch.includes(deviceType)) {
197
+ return await this.updateTouchBootloader({
198
+ device,
199
+ features,
200
+ firmwareType,
201
+ source,
202
+ });
203
+ }
204
+ return true;
205
+ } finally {
206
+ await source.close();
207
+ }
208
+ }
99
209
 
210
+ const { binary } = payload;
100
211
  const deviceType = device.getCurrentDeviceType();
101
212
  const deviceFirmwareType = device.getCurrentFirmwareType();
102
213
  const firmwareType = payload.firmwareType ?? deviceFirmwareType;
103
214
 
104
215
  if (DeviceModelToTypes.model_touch.includes(deviceType)) {
105
- return this.updateTouchBootloader({ device, features, firmwareType });
216
+ return this.updateTouchBootloader({
217
+ device,
218
+ features,
219
+ firmwareType,
220
+ binary,
221
+ });
106
222
  }
107
223
 
108
224
  return Promise.resolve(true);
@@ -0,0 +1,278 @@
1
+ import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
+
3
+ import type {
4
+ FirmwareArtifactReader,
5
+ FirmwareArtifactReference,
6
+ } from '../../types/api/firmwareUpdate';
7
+
8
+ export const MAX_FIRMWARE_ARTIFACT_READ_BYTES = 256 * 1024;
9
+
10
+ export interface FirmwareByteSource {
11
+ readonly size: number;
12
+ readAt(offset: number, length: number): Promise<ArrayBuffer>;
13
+ close(): Promise<void>;
14
+ }
15
+
16
+ const artifactError = (
17
+ code:
18
+ | 'FirmwareArtifactReceiptMismatch'
19
+ | 'FirmwareArtifactReaderInvalid'
20
+ | 'FirmwareArtifactReadOutOfBounds'
21
+ | 'FirmwareArtifactReadTooLarge',
22
+ message: string
23
+ ): never => {
24
+ throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, message, {
25
+ firmwareUpdateCode: code,
26
+ });
27
+ };
28
+
29
+ const assertSafeSize = (value: number, name: string) => {
30
+ if (!Number.isSafeInteger(value) || value <= 0) {
31
+ artifactError('FirmwareArtifactReceiptMismatch', `${name} must be a positive safe integer`);
32
+ }
33
+ };
34
+
35
+ export const assertFirmwareArtifactReference = (
36
+ artifact: FirmwareArtifactReference
37
+ ): FirmwareArtifactReference => {
38
+ if (
39
+ !artifact ||
40
+ typeof artifact.artifactRef !== 'string' ||
41
+ artifact.artifactRef.length === 0 ||
42
+ artifact.artifactRef.length > 160 ||
43
+ artifact.artifactRef.includes('/') ||
44
+ artifact.artifactRef.includes('\\')
45
+ ) {
46
+ artifactError(
47
+ 'FirmwareArtifactReceiptMismatch',
48
+ 'Firmware artifactRef must be an opaque identifier'
49
+ );
50
+ }
51
+ assertSafeSize(artifact.size, 'Firmware artifact size');
52
+ if (typeof artifact.sha256 !== 'string' || !/^[a-f0-9]{64}$/i.test(artifact.sha256)) {
53
+ artifactError(
54
+ 'FirmwareArtifactReceiptMismatch',
55
+ 'Firmware artifact sha256 must be a 32-byte hexadecimal digest'
56
+ );
57
+ }
58
+ return artifact;
59
+ };
60
+
61
+ const assertFirmwareArtifactRead = (size: number, offset: number, length: number) => {
62
+ if (
63
+ !Number.isSafeInteger(offset) ||
64
+ offset < 0 ||
65
+ offset >= size ||
66
+ !Number.isSafeInteger(length) ||
67
+ length <= 0 ||
68
+ offset + length > size
69
+ ) {
70
+ artifactError(
71
+ 'FirmwareArtifactReadOutOfBounds',
72
+ `Firmware artifact read is outside size ${size}: offset=${offset}, length=${length}`
73
+ );
74
+ }
75
+ if (length > MAX_FIRMWARE_ARTIFACT_READ_BYTES) {
76
+ artifactError(
77
+ 'FirmwareArtifactReadTooLarge',
78
+ `Firmware artifact read length ${length} exceeds ${MAX_FIRMWARE_ARTIFACT_READ_BYTES}`
79
+ );
80
+ }
81
+ };
82
+
83
+ const createMemoryFirmwareByteSource = (binary: ArrayBuffer): FirmwareByteSource => {
84
+ let bytes: Uint8Array | null = new Uint8Array(binary);
85
+ const { byteLength: size } = binary;
86
+ assertSafeSize(size, 'Firmware binary size');
87
+ return {
88
+ size,
89
+ readAt: (offset, length) => {
90
+ if (!bytes) {
91
+ return Promise.reject(
92
+ ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'Firmware byte source is closed', {
93
+ firmwareUpdateCode: 'FirmwareArtifactReaderInvalid',
94
+ })
95
+ );
96
+ }
97
+ assertFirmwareArtifactRead(size, offset, length);
98
+ return Promise.resolve(bytes.slice(offset, offset + length).buffer);
99
+ },
100
+ close: () => {
101
+ bytes = null;
102
+ return Promise.resolve();
103
+ },
104
+ };
105
+ };
106
+
107
+ class ReaderFirmwareByteSource implements FirmwareByteSource {
108
+ readonly size: number;
109
+
110
+ private closed = false;
111
+
112
+ private reading = false;
113
+
114
+ private constructor(
115
+ private readonly reader: FirmwareArtifactReader,
116
+ private readonly readerId: string,
117
+ size: number
118
+ ) {
119
+ this.size = size;
120
+ }
121
+
122
+ static async open(
123
+ artifact: FirmwareArtifactReference,
124
+ reader: FirmwareArtifactReader
125
+ ): Promise<ReaderFirmwareByteSource> {
126
+ const opened = await reader.open({ artifactRef: artifact.artifactRef });
127
+ if (
128
+ !opened ||
129
+ typeof opened.readerId !== 'string' ||
130
+ opened.readerId.length === 0 ||
131
+ !Number.isSafeInteger(opened.size) ||
132
+ opened.size !== artifact.size
133
+ ) {
134
+ if (opened?.readerId) {
135
+ await reader.close({ readerId: opened.readerId }).catch(() => undefined);
136
+ }
137
+ return artifactError(
138
+ 'FirmwareArtifactReceiptMismatch',
139
+ `Firmware artifact opened with size ${opened?.size ?? 'unknown'}, expected ${artifact.size}`
140
+ );
141
+ }
142
+ return new ReaderFirmwareByteSource(reader, opened.readerId, opened.size);
143
+ }
144
+
145
+ async readAt(offset: number, length: number): Promise<ArrayBuffer> {
146
+ if (this.closed) {
147
+ return artifactError('FirmwareArtifactReaderInvalid', 'Firmware artifact reader is closed');
148
+ }
149
+ if (this.reading) {
150
+ return artifactError(
151
+ 'FirmwareArtifactReaderInvalid',
152
+ 'Firmware artifact reader only permits one in-flight read'
153
+ );
154
+ }
155
+ assertFirmwareArtifactRead(this.size, offset, length);
156
+ this.reading = true;
157
+ try {
158
+ const result = await this.reader.read({
159
+ readerId: this.readerId,
160
+ offset,
161
+ length,
162
+ });
163
+ const expectedEof = offset + length === this.size;
164
+ if (
165
+ !result ||
166
+ !(result.data instanceof ArrayBuffer) ||
167
+ result.data.byteLength !== length ||
168
+ result.bytesRead !== length ||
169
+ result.eof !== expectedEof
170
+ ) {
171
+ return artifactError(
172
+ 'FirmwareArtifactReaderInvalid',
173
+ 'Firmware artifact reader returned an invalid read result'
174
+ );
175
+ }
176
+ return result.data;
177
+ } finally {
178
+ this.reading = false;
179
+ }
180
+ }
181
+
182
+ async close(): Promise<void> {
183
+ if (this.closed) {
184
+ return;
185
+ }
186
+ this.closed = true;
187
+ await this.reader.close({ readerId: this.readerId });
188
+ }
189
+ }
190
+
191
+ export const openFirmwareByteSource = async ({
192
+ binary,
193
+ artifact,
194
+ reader,
195
+ }: {
196
+ binary?: ArrayBuffer;
197
+ artifact?: FirmwareArtifactReference;
198
+ reader?: FirmwareArtifactReader;
199
+ }): Promise<FirmwareByteSource | null> => {
200
+ if (binary && artifact) {
201
+ return artifactError(
202
+ 'FirmwareArtifactReceiptMismatch',
203
+ 'Firmware input must not contain both binary and artifactRef'
204
+ );
205
+ }
206
+ if (binary) {
207
+ return createMemoryFirmwareByteSource(binary);
208
+ }
209
+ if (!artifact) {
210
+ return null;
211
+ }
212
+ assertFirmwareArtifactReference(artifact);
213
+ if (!reader) {
214
+ return artifactError(
215
+ 'FirmwareArtifactReaderInvalid',
216
+ 'Firmware artifact reader is required for artifactRef input'
217
+ );
218
+ }
219
+ return ReaderFirmwareByteSource.open(artifact, reader);
220
+ };
221
+
222
+ export const readFirmwareByteSourceFully = async (
223
+ source: FirmwareByteSource
224
+ ): Promise<ArrayBuffer> => {
225
+ const output = new Uint8Array(source.size);
226
+ let offset = 0;
227
+ while (offset < source.size) {
228
+ const length = Math.min(MAX_FIRMWARE_ARTIFACT_READ_BYTES, source.size - offset);
229
+ output.set(new Uint8Array(await source.readAt(offset, length)), offset);
230
+ offset += length;
231
+ }
232
+ return output.buffer;
233
+ };
234
+
235
+ export const writeFirmwareByteSource = async ({
236
+ source,
237
+ chunkSize,
238
+ write,
239
+ }: {
240
+ source: FirmwareByteSource;
241
+ chunkSize: number;
242
+ write: (input: {
243
+ data: ArrayBuffer;
244
+ sourceOffset: number;
245
+ length: number;
246
+ first: boolean;
247
+ }) => Promise<number>;
248
+ }) => {
249
+ if (
250
+ !Number.isSafeInteger(chunkSize) ||
251
+ chunkSize <= 0 ||
252
+ chunkSize > MAX_FIRMWARE_ARTIFACT_READ_BYTES
253
+ ) {
254
+ return artifactError(
255
+ 'FirmwareArtifactReadTooLarge',
256
+ `Firmware artifact chunk size must be between 1 and ${MAX_FIRMWARE_ARTIFACT_READ_BYTES}`
257
+ );
258
+ }
259
+ let offset = 0;
260
+ while (offset < source.size) {
261
+ const length = Math.min(chunkSize, source.size - offset);
262
+ const data = await source.readAt(offset, length);
263
+ const processed = await write({
264
+ data,
265
+ sourceOffset: offset,
266
+ length,
267
+ first: offset === 0,
268
+ });
269
+ if (processed !== length) {
270
+ return artifactError(
271
+ 'FirmwareArtifactReaderInvalid',
272
+ `Firmware artifact writer processed ${processed} bytes, expected ${length}`
273
+ );
274
+ }
275
+ offset += length;
276
+ }
277
+ return offset;
278
+ };