@onekeyfe/hd-core 1.2.0-alpha.99 → 1.2.0

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 (200) hide show
  1. package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +20 -4
  2. package/__tests__/DeviceCommands.test.ts +203 -27
  3. package/__tests__/base64Data.test.ts +69 -0
  4. package/__tests__/check-all-firmware-release-protocol-v2.test.ts +48 -2
  5. package/__tests__/check-firmware-release-protocol-v2.test.ts +82 -13
  6. package/__tests__/device-connector-protocol.test.ts +21 -0
  7. package/__tests__/device-lifecycle-events.test.ts +427 -7
  8. package/__tests__/device-pool-state.test.ts +25 -0
  9. package/__tests__/device-settings.test.ts +237 -9
  10. package/__tests__/device-state-events.test.ts +2 -2
  11. package/__tests__/device-state-mapper.test.ts +61 -5
  12. package/__tests__/device-utils.test.ts +15 -1
  13. package/__tests__/device-wallet-session-store.test.ts +147 -21
  14. package/__tests__/deviceSettings.test.ts +7 -3
  15. package/__tests__/deviceUploadNft.test.ts +36 -4
  16. package/__tests__/firmware-update/device-update-bootloader.test.ts +13 -3
  17. package/__tests__/firmware-update/firmware-artifact-source.test.ts +61 -9
  18. package/__tests__/firmware-update/firmware-prepared-host-digest.test.ts +19 -9
  19. package/__tests__/firmware-update/firmware-prepared-resource-archive.test.ts +21 -0
  20. package/__tests__/firmware-update/firmware-update-bootloader-poll.test.ts +63 -0
  21. package/__tests__/firmware-update/firmware-update-plan.test.ts +59 -55
  22. package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +19 -5
  23. package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +116 -0
  24. package/__tests__/firmware-update/firmware-update-v4-install-poll.test.ts +678 -0
  25. package/__tests__/firmware-update/firmware-update-v4-parameters.test.ts +85 -0
  26. package/__tests__/get-device-state.test.ts +60 -21
  27. package/__tests__/logBlockEvent.test.ts +13 -1
  28. package/__tests__/open-wallet-session.test.ts +127 -1
  29. package/__tests__/protocol-v2-firmware-targets.test.ts +23 -0
  30. package/__tests__/protocol-v2-resources.test.ts +185 -88
  31. package/__tests__/protocol-v2-unlock-policy.test.ts +235 -2
  32. package/__tests__/protocol-v2.test.ts +2198 -486
  33. package/__tests__/refresh-device-state.test.ts +3 -1
  34. package/__tests__/resourceBase64Boundary.test.ts +48 -0
  35. package/__tests__/search-devices.test.ts +79 -32
  36. package/__tests__/ton-sign-message.test.ts +84 -0
  37. package/dist/api/BaseMethod.d.ts +2 -1
  38. package/dist/api/BaseMethod.d.ts.map +1 -1
  39. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  40. package/dist/api/CheckBootloaderRelease.d.ts.map +1 -1
  41. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  42. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  43. package/dist/api/FirmwareUpdateV4.d.ts +19 -6
  44. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  45. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  46. package/dist/api/SearchDevices.d.ts.map +1 -1
  47. package/dist/api/UploadPortfolio.d.ts +1 -1
  48. package/dist/api/UploadPortfolio.d.ts.map +1 -1
  49. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
  50. package/dist/api/device/DeviceChangePin.d.ts.map +1 -1
  51. package/dist/api/device/DeviceRebootToBoardloader.d.ts.map +1 -1
  52. package/dist/api/device/DeviceRebootToBootloader.d.ts.map +1 -1
  53. package/dist/api/device/DeviceSettings.d.ts.map +1 -1
  54. package/dist/api/device/DeviceVerify.d.ts +1 -0
  55. package/dist/api/device/DeviceVerify.d.ts.map +1 -1
  56. package/dist/api/device/DeviceWipe.d.ts.map +1 -1
  57. package/dist/api/firmware/FirmwareArtifactSource.d.ts +5 -1
  58. package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +1 -1
  59. package/dist/api/firmware/FirmwarePreparedResourceArchive.d.ts.map +1 -1
  60. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +2 -2
  61. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  62. package/dist/api/firmware/FirmwareUpdatePlan.d.ts +0 -15
  63. package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -1
  64. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -1
  65. package/dist/api/firmware/getBinary.d.ts +3 -2
  66. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  67. package/dist/api/firmware/protocolV2Release.d.ts.map +1 -1
  68. package/dist/api/helpers/base64Data.d.ts +16 -0
  69. package/dist/api/helpers/base64Data.d.ts.map +1 -0
  70. package/dist/api/protocol-v2/DeviceFirmwareUpdate.d.ts +3 -1
  71. package/dist/api/protocol-v2/DeviceFirmwareUpdate.d.ts.map +1 -1
  72. package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts.map +1 -1
  73. package/dist/api/protocol-v2/DeviceInfoGet.d.ts +1 -1
  74. package/dist/api/protocol-v2/DeviceInfoGet.d.ts.map +1 -1
  75. package/dist/api/protocol-v2/DeviceReboot.d.ts +1 -1
  76. package/dist/api/protocol-v2/DeviceReboot.d.ts.map +1 -1
  77. package/dist/api/protocol-v2/DeviceUploadNft.d.ts +2 -3
  78. package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -1
  79. package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts +2 -3
  80. package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts.map +1 -1
  81. package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
  82. package/dist/api/ton/TonSignMessage.d.ts.map +1 -1
  83. package/dist/core/index.d.ts +6 -1
  84. package/dist/core/index.d.ts.map +1 -1
  85. package/dist/data-manager/DataManager.d.ts +4 -3
  86. package/dist/data-manager/DataManager.d.ts.map +1 -1
  87. package/dist/data-manager/TransportManager.d.ts.map +1 -1
  88. package/dist/device/Device.d.ts +16 -3
  89. package/dist/device/Device.d.ts.map +1 -1
  90. package/dist/device/DeviceCommands.d.ts +4 -4
  91. package/dist/device/DeviceCommands.d.ts.map +1 -1
  92. package/dist/device/DeviceConnector.d.ts +1 -1
  93. package/dist/device/DeviceConnector.d.ts.map +1 -1
  94. package/dist/device/DevicePool.d.ts.map +1 -1
  95. package/dist/device/DeviceStateMapper.d.ts.map +1 -1
  96. package/dist/deviceProfile/buildDeviceFeatures.d.ts.map +1 -1
  97. package/dist/events/logBlockEvent.d.ts.map +1 -1
  98. package/dist/events/ui-request.d.ts +3 -0
  99. package/dist/events/ui-request.d.ts.map +1 -1
  100. package/dist/index.d.ts +54 -84
  101. package/dist/index.d.ts.map +1 -1
  102. package/dist/index.js +2135 -1470
  103. package/dist/protocols/protocol-v2/features.d.ts +13 -5
  104. package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
  105. package/dist/protocols/protocol-v2/index.d.ts +2 -2
  106. package/dist/protocols/protocol-v2/index.d.ts.map +1 -1
  107. package/dist/protocols/protocol-v2/resources.d.ts +12 -7
  108. package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
  109. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +3 -1
  110. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +1 -1
  111. package/dist/protocols/protocol-v2/walletSession.d.ts +3 -0
  112. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  113. package/dist/types/api/firmwareUpdatePlan.d.ts +2 -2
  114. package/dist/types/api/firmwareUpdatePlan.d.ts.map +1 -1
  115. package/dist/types/api/protocolV2.d.ts +1 -1
  116. package/dist/types/api/protocolV2.d.ts.map +1 -1
  117. package/dist/types/device.d.ts.map +1 -1
  118. package/dist/types/settings.d.ts +3 -31
  119. package/dist/types/settings.d.ts.map +1 -1
  120. package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -1
  121. package/dist/utils/deviceFeaturesUtils.d.ts +3 -0
  122. package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
  123. package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
  124. package/dist/utils/deviceSettings.d.ts +1 -0
  125. package/dist/utils/deviceSettings.d.ts.map +1 -1
  126. package/dist/utils/index.d.ts +1 -1
  127. package/dist/utils/index.d.ts.map +1 -1
  128. package/dist/utils/patch.d.ts +1 -1
  129. package/dist/utils/patch.d.ts.map +1 -1
  130. package/dist/utils/pro2Nft.d.ts +7 -0
  131. package/dist/utils/pro2Nft.d.ts.map +1 -1
  132. package/package.json +6 -4
  133. package/src/api/BaseMethod.ts +8 -1
  134. package/src/api/CheckAllFirmwareRelease.ts +2 -4
  135. package/src/api/CheckBLEFirmwareRelease.ts +2 -2
  136. package/src/api/CheckBootloaderRelease.ts +3 -2
  137. package/src/api/CheckFirmwareRelease.ts +2 -2
  138. package/src/api/FirmwareUpdateV2.ts +12 -9
  139. package/src/api/FirmwareUpdateV3.ts +29 -19
  140. package/src/api/FirmwareUpdateV4.ts +918 -741
  141. package/src/api/OpenWalletSession.ts +39 -9
  142. package/src/api/PromptWebDeviceAccess.ts +2 -2
  143. package/src/api/SearchDevices.ts +6 -3
  144. package/src/api/UploadPortfolio.ts +9 -2
  145. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +2 -1
  146. package/src/api/device/DeviceChangePin.ts +4 -1
  147. package/src/api/device/DeviceRebootToBoardloader.ts +3 -1
  148. package/src/api/device/DeviceRebootToBootloader.ts +3 -1
  149. package/src/api/device/DeviceSettings.ts +34 -20
  150. package/src/api/device/DeviceVerify.ts +25 -0
  151. package/src/api/device/DeviceWipe.ts +4 -1
  152. package/src/api/firmware/FirmwareArtifactSource.ts +41 -14
  153. package/src/api/firmware/FirmwarePreparedResourceArchive.ts +16 -27
  154. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +9 -3
  155. package/src/api/firmware/FirmwareUpdatePlan.ts +37 -77
  156. package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +10 -6
  157. package/src/api/firmware/protocolV2Release.ts +7 -2
  158. package/src/api/helpers/base64Data.ts +85 -0
  159. package/src/api/protocol-v2/DeviceFactoryInfoSet.ts +1 -1
  160. package/src/api/protocol-v2/DeviceFirmwareUpdate.ts +6 -28
  161. package/src/api/protocol-v2/DeviceGetFirmwareUpdateStatus.ts +7 -1
  162. package/src/api/protocol-v2/DeviceInfoGet.ts +3 -3
  163. package/src/api/protocol-v2/DeviceReboot.ts +5 -0
  164. package/src/api/protocol-v2/DeviceUploadNft.ts +61 -9
  165. package/src/api/protocol-v2/DeviceUploadWallpaper.ts +53 -19
  166. package/src/api/protocol-v2/helpers.ts +8 -0
  167. package/src/api/ton/TonSignMessage.ts +5 -3
  168. package/src/core/index.ts +264 -55
  169. package/src/data/messages/messages-protocol-v2.json +140 -13
  170. package/src/data-manager/DataManager.ts +46 -39
  171. package/src/data-manager/TransportManager.ts +3 -1
  172. package/src/device/Device.ts +210 -44
  173. package/src/device/DeviceCommands.ts +27 -18
  174. package/src/device/DeviceConnector.ts +17 -3
  175. package/src/device/DevicePool.ts +9 -2
  176. package/src/device/DeviceStateMapper.ts +30 -24
  177. package/src/deviceProfile/buildDeviceFeatures.ts +10 -5
  178. package/src/events/logBlockEvent.ts +14 -1
  179. package/src/events/ui-request.ts +3 -0
  180. package/src/index.ts +0 -10
  181. package/src/protocols/protocol-v2/features.ts +22 -5
  182. package/src/protocols/protocol-v2/index.ts +2 -0
  183. package/src/protocols/protocol-v2/resources.ts +110 -147
  184. package/src/protocols/protocol-v2/unlockPolicyRunner.ts +13 -1
  185. package/src/protocols/protocol-v2/walletSession.ts +65 -22
  186. package/src/types/api/firmwareUpdate.ts +1 -1
  187. package/src/types/api/firmwareUpdatePlan.ts +2 -2
  188. package/src/types/api/protocolV2.ts +1 -1
  189. package/src/types/device.ts +2 -1
  190. package/src/types/settings.ts +6 -34
  191. package/src/utils/deviceFeaturesCompat.ts +9 -4
  192. package/src/utils/deviceFeaturesUtils.ts +4 -0
  193. package/src/utils/deviceInfoUtils.ts +9 -2
  194. package/src/utils/deviceSettings.ts +11 -4
  195. package/src/utils/index.ts +1 -0
  196. package/src/utils/pro2Nft.ts +31 -8
  197. package/__tests__/firmware-memory-host.test.ts +0 -126
  198. package/dist/api/firmware/FirmwareMemoryHost.d.ts +0 -22
  199. package/dist/api/firmware/FirmwareMemoryHost.d.ts.map +0 -1
  200. package/src/api/firmware/FirmwareMemoryHost.ts +0 -143
@@ -1,4 +1,4 @@
1
- import { EFirmwareType } from '@onekeyfe/hd-shared';
1
+ import { EFirmwareType, canonicalizePro2BleAdvertisementName } from '@onekeyfe/hd-shared';
2
2
 
3
3
  import { buildProtocolV1FeaturesPayload } from '../deviceProfile/buildDeviceFeatures';
4
4
  import { resolveProtocolV2DeviceIdentity } from '../deviceProfile/protocolV2DeviceIdentity';
@@ -247,7 +247,9 @@ export const mapProtocolV2DeviceInfoToState = (
247
247
  model: identity.model,
248
248
  vendor: 'onekey.so',
249
249
  serialNo: info.hw?.serial_no,
250
- bleName: info.coprocessor?.bt_adv_name,
250
+ bleName: info.coprocessor?.bt_adv_name
251
+ ? canonicalizePro2BleAdvertisementName(info.coprocessor.bt_adv_name)
252
+ : undefined,
251
253
  deviceId: loader ? null : undefined,
252
254
  }),
253
255
  status: loader
@@ -267,11 +269,11 @@ export const mapProtocolV2DeviceInfoToState = (
267
269
  }
268
270
  : { mode },
269
271
  versions: definedEntries({
270
- firmware: imageVersion(info.fw?.application),
271
- applicationP1: imageVersion(info.fw?.application),
272
- applicationP2: imageVersion(info.fw?.application_data),
273
- bootloader: imageVersion(info.fw?.bootloader),
274
- board: imageVersion(info.fw?.romloader),
272
+ firmware: imageVersion(info.main_mcu?.application),
273
+ applicationP1: imageVersion(info.main_mcu?.application),
274
+ applicationP2: imageVersion(info.main_mcu?.application_data),
275
+ bootloader: imageVersion(info.main_mcu?.bootloader),
276
+ board: imageVersion(info.main_mcu?.romloader),
275
277
  ble: imageVersion(info.coprocessor?.application),
276
278
  se01: imageVersion(info.se1?.application),
277
279
  se02: imageVersion(info.se2?.application),
@@ -283,16 +285,16 @@ export const mapProtocolV2DeviceInfoToState = (
283
285
  se04Boot: imageVersion(info.se4?.bootloader),
284
286
  }),
285
287
  verification: definedEntries({
286
- firmwareBuildId: imageBuildId(info.fw?.application),
287
- firmwareHash: imageHash(info.fw?.application),
288
- applicationP1BuildId: imageBuildId(info.fw?.application),
289
- applicationP1Hash: imageHash(info.fw?.application),
290
- applicationP2BuildId: imageBuildId(info.fw?.application_data),
291
- applicationP2Hash: imageHash(info.fw?.application_data),
292
- bootloaderBuildId: imageBuildId(info.fw?.bootloader),
293
- bootloaderHash: imageHash(info.fw?.bootloader),
294
- boardBuildId: imageBuildId(info.fw?.romloader),
295
- boardHash: imageHash(info.fw?.romloader),
288
+ firmwareBuildId: imageBuildId(info.main_mcu?.application),
289
+ firmwareHash: imageHash(info.main_mcu?.application),
290
+ applicationP1BuildId: imageBuildId(info.main_mcu?.application),
291
+ applicationP1Hash: imageHash(info.main_mcu?.application),
292
+ applicationP2BuildId: imageBuildId(info.main_mcu?.application_data),
293
+ applicationP2Hash: imageHash(info.main_mcu?.application_data),
294
+ bootloaderBuildId: imageBuildId(info.main_mcu?.bootloader),
295
+ bootloaderHash: imageHash(info.main_mcu?.bootloader),
296
+ boardBuildId: imageBuildId(info.main_mcu?.romloader),
297
+ boardHash: imageHash(info.main_mcu?.romloader),
296
298
  bleBuildId: imageBuildId(info.coprocessor?.application),
297
299
  bleHash: imageHash(info.coprocessor?.application),
298
300
  se01BuildId: imageBuildId(info.se1?.application),
@@ -345,8 +347,10 @@ export const mapProtocolV2DeviceStatusToState = (status: DeviceStatus): DeviceSt
345
347
  unlocked: status.unlocked,
346
348
  passphraseProtection: status.unlocked === true ? status.passphrase_enabled ?? null : undefined,
347
349
  backupRequired: status.backup_required,
348
- attachToPinEnabled: status.attach_to_pin_enabled,
349
- unlockedAttachPin: status.unlocked_by_attach_to_pin,
350
+ attachToPinEnabled:
351
+ status.unlocked === true ? status.attach_to_pin_enabled ?? undefined : undefined,
352
+ unlockedAttachPin:
353
+ status.unlocked === true ? status.unlocked_by_attach_to_pin ?? null : undefined,
350
354
  }),
351
355
  raw: { protocolV2DeviceStatus: status },
352
356
  });
@@ -373,21 +377,23 @@ export const mapApplySettingsToState = (settings: ApplySettings): DeviceStatePat
373
377
  };
374
378
 
375
379
  export const mapDeviceSettingsToState = (settings: DeviceSettings): DeviceStatePatch => {
376
- const identity = definedEntries({ label: settings.label });
377
- const status = definedEntries({ passphraseProtection: settings.passphrase_enable });
380
+ const identity = definedEntries({ label: settings.label ?? undefined });
381
+ const status = definedEntries({
382
+ passphraseProtection: settings.passphrase_enable ?? undefined,
383
+ });
378
384
  const stateSettings = definedEntries({
379
385
  bleEnabled: settings.bt_enable,
380
386
  language: mapLanguageFromProtocolV2(settings.language),
381
387
  wallpaperPath: settings.wallpaper_path,
382
388
  brightness: settings.brightness,
383
- autoLockDelayMs: settings.autolock_delay_ms,
384
- autoShutdownDelayMs: settings.autoshutdown_delay_ms,
389
+ autoLockDelayMs: settings.autolock_delay_ms ?? undefined,
390
+ autoShutdownDelayMs: settings.autoshutdown_delay_ms ?? undefined,
385
391
  animationEnabled: settings.animation_enable,
386
392
  tapToWake: settings.tap_to_wake,
387
393
  hapticFeedback: settings.haptic_feedback,
388
394
  deviceNameDisplayEnabled: settings.device_name_display_enabled,
389
395
  airgapMode: settings.airgap_mode,
390
- fidoEnabled: settings.fido_enabled,
396
+ fidoEnabled: settings.fido_enabled ?? undefined,
391
397
  usbLockEnabled: settings.usb_lock_enable,
392
398
  randomKeypad: settings.random_keypad,
393
399
  });
@@ -1,4 +1,8 @@
1
- import { EDeviceType, EFirmwareType } from '@onekeyfe/hd-shared';
1
+ import {
2
+ EDeviceType,
3
+ EFirmwareType,
4
+ canonicalizePro2BleAdvertisementName,
5
+ } from '@onekeyfe/hd-shared';
2
6
 
3
7
  import {
4
8
  resolveDeviceBleFirmwareVersion,
@@ -216,9 +220,9 @@ export const buildProtocolV2FeaturesPayload = ({
216
220
  runtimeMode?: ProtocolV2RuntimeMode;
217
221
  }): Features => {
218
222
  const info = deviceInfo;
219
- const fwApplication = info?.fw?.application;
220
- const fwBootloader = info?.fw?.bootloader;
221
- const fwBoard = info?.fw?.romloader;
223
+ const fwApplication = info?.main_mcu?.application;
224
+ const fwBootloader = info?.main_mcu?.bootloader;
225
+ const fwBoard = info?.main_mcu?.romloader;
222
226
  const bleApplication = info?.coprocessor?.application;
223
227
  const status = deviceStatus;
224
228
  const incomingSerialNo = info?.hw?.serial_no;
@@ -245,7 +249,8 @@ export const buildProtocolV2FeaturesPayload = ({
245
249
  const deviceId = status?.device_id ?? cached?.deviceId ?? null;
246
250
  const serialNo = firstValue(incomingSerialNo, cached?.serialNo) ?? '';
247
251
  const label = cached?.label ?? null;
248
- const bleName = firstValue(info?.coprocessor?.bt_adv_name, cached?.bleName);
252
+ const rawBleName = firstValue(info?.coprocessor?.bt_adv_name, cached?.bleName);
253
+ const bleName = rawBleName ? canonicalizePro2BleAdvertisementName(rawBleName) : rawBleName;
249
254
  const initialized = firstValue(status?.init_states, cached?.initialized) ?? null;
250
255
  // passphrase_enabled from a locked Pro2 is not authoritative. Only DeviceStatus
251
256
  // after PIN unlock can determine the final passphrase setting.
@@ -17,6 +17,14 @@ const LogLabelMethod: Set<string> = new Set([
17
17
  'fileRead',
18
18
  ]);
19
19
 
20
+ // 资源上传参数可能包含很大的 Base64 字符串。这里按方法整段跳过,避免日志层
21
+ // 递归复制和序列化这些数据;资源 API 与传输内容本身保持不变。
22
+ const LogPayloadBlockMethod: Set<string> = new Set([
23
+ 'deviceUploadNft',
24
+ 'deviceUploadWallpaper',
25
+ 'uploadPortfolio',
26
+ ]);
27
+
20
28
  const SensitiveLogKeys: Set<string> = new Set([
21
29
  'devicestate',
22
30
  'entropy',
@@ -86,7 +94,12 @@ export function getLogBlockLabel(message: unknown): string | undefined {
86
94
  }
87
95
 
88
96
  export function getSafeLogPayload(value: unknown, blockLabel?: string): unknown {
89
- if (blockLabel && (LogBlockEvent.has(blockLabel) || isSigningMethod(blockLabel))) {
97
+ if (
98
+ blockLabel &&
99
+ (LogBlockEvent.has(blockLabel) ||
100
+ LogPayloadBlockMethod.has(blockLabel) ||
101
+ isSigningMethod(blockLabel))
102
+ ) {
90
103
  return { method: blockLabel, payload: '[REDACTED]' };
91
104
  }
92
105
 
@@ -189,6 +189,9 @@ export interface FirmwareProgress {
189
189
  totalBytes?: number;
190
190
  rateBytesPerSecond?: number;
191
191
  elapsedMs?: number;
192
+ installTargetId?: number;
193
+ installPhase?: 'prepare' | 'install' | 'verify';
194
+ installPhaseProgress?: number;
192
195
  };
193
196
  }
194
197
 
package/src/index.ts CHANGED
@@ -21,16 +21,6 @@ export { executeCallback, cleanupCallback };
21
21
  export { preloadSessionCache } from './device/Device';
22
22
  export { projectFeatures as projectDeviceStateFeatures } from './device/DeviceStateProjector';
23
23
  export { getMethodSupportedProtocols } from './api/utils';
24
- export {
25
- parseProtocolV2ResourceManifest,
26
- selectProtocolV2ResourceManifestFiles,
27
- } from './protocols/protocol-v2/resources';
28
- export { prepareFirmwareUpdateV4MemoryHost } from './api/firmware/FirmwareMemoryHost';
29
- export type {
30
- FirmwareMemoryArtifact,
31
- FirmwareMemoryArtifactEntry,
32
- FirmwareUpdateV4MemoryHost,
33
- } from './api/firmware/FirmwareMemoryHost';
34
24
  export {
35
25
  getFirmwareUpdateHostBindingGeneration,
36
26
  registerFirmwareUpdateHostBinding,
@@ -56,6 +56,16 @@ export const getProtocolV2SeType = (se?: DeviceSEInfo): string | null =>
56
56
 
57
57
  export type ProtocolV2RuntimeMode = 'normal' | 'bootloader' | 'romloader';
58
58
 
59
+ export type ProtocolV2ProtocolInfo = ProtocolInfo & {
60
+ /** Present only when hd-transport decoded the pre-build-fingerprint wire layout. */
61
+ protobuf_definition?: string | null;
62
+ };
63
+
64
+ export const isLegacyProtocolV2ProtocolInfo = (
65
+ protocolInfo: ProtocolInfo
66
+ ): protocolInfo is ProtocolV2ProtocolInfo & { protobuf_definition: string | null } =>
67
+ Object.prototype.hasOwnProperty.call(protocolInfo, 'protobuf_definition');
68
+
59
69
  /**
60
70
  * Protocol V2 fingerprints use:
61
71
  * <binary>__<version>__<commit>__<PROD|DEV>__<DEBUG|RELEASE>
@@ -87,11 +97,18 @@ export const parseProtocolV2BuildFingerprint = (
87
97
  };
88
98
 
89
99
  export const getProtocolV2RuntimeMode = (
90
- protocolInfo: ProtocolInfo
100
+ protocolInfo: ProtocolInfo,
101
+ deviceInfo?: ProtocolV2DeviceInfo
91
102
  ): ProtocolV2RuntimeMode | undefined => {
92
103
  const binary = parseProtocolV2BuildFingerprint(protocolInfo.build_fingerprint)?.binary;
93
104
  if (binary === 'application') return 'normal';
94
- return binary;
105
+ if (binary) return binary;
106
+
107
+ if (isLegacyProtocolV2ProtocolInfo(protocolInfo) && !deviceInfo?.main_mcu?.application) {
108
+ if (deviceInfo?.main_mcu?.romloader) return 'romloader';
109
+ if (deviceInfo?.main_mcu?.bootloader) return 'bootloader';
110
+ }
111
+ return undefined;
95
112
  };
96
113
 
97
114
  // MessageType_DeviceStatusGet in the Protocol V2 protobuf registry.
@@ -105,7 +122,7 @@ export const supportsProtocolV2Message = (
105
122
  export const PROTOCOL_V2_FEATURES_DEVICE_INFO_REQUEST = {
106
123
  targets: {
107
124
  hw: true,
108
- fw: true,
125
+ main_mcu: true,
109
126
  coprocessor: true,
110
127
  },
111
128
  types: {
@@ -121,7 +138,7 @@ export const PROTOCOL_V2_FEATURES_DEVICE_INFO_REQUEST = {
121
138
  export const PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST = {
122
139
  targets: {
123
140
  hw: true,
124
- fw: true,
141
+ main_mcu: true,
125
142
  coprocessor: true,
126
143
  se1: true,
127
144
  se2: true,
@@ -137,7 +154,7 @@ export const PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST = {
137
154
  export const PROTOCOL_V2_FULL_DEVICE_INFO_REQUEST = {
138
155
  targets: {
139
156
  hw: true,
140
- fw: true,
157
+ main_mcu: true,
141
158
  coprocessor: true,
142
159
  se1: true,
143
160
  se2: true,
@@ -7,6 +7,7 @@ export {
7
7
  getProtocolV2RuntimeMode,
8
8
  getProtocolV2SeState,
9
9
  getProtocolV2SeType,
10
+ isLegacyProtocolV2ProtocolInfo,
10
11
  parseProtocolV2BuildFingerprint,
11
12
  requestProtocolV2ProtocolInfo,
12
13
  supportsProtocolV2Message,
@@ -18,6 +19,7 @@ export type {
18
19
  ProtocolV2SEInfo,
19
20
  ProtocolV2SeStateLabel,
20
21
  ProtocolV2RuntimeMode,
22
+ ProtocolV2ProtocolInfo,
21
23
  } from './features';
22
24
  export * from './firmware';
23
25
  export * from './walletSession';
@@ -1,29 +1,20 @@
1
- import type {
2
- IProtocolV2ResourceManifest,
3
- IProtocolV2ResourceManifestFile,
4
- IProtocolV2Resources,
5
- } from '../../types';
6
- import type { FirmwareUpdateV4Target } from '../../types/api/firmwareUpdate';
1
+ import { bytesToHex } from '@noble/hashes/utils';
2
+
3
+ import type { IProtocolV2Resources, IVersionArray } from '../../types';
7
4
 
8
5
  export const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH =
9
6
  'vol0:/loaders/bootloader/boot_resource.okpkg';
10
7
  export const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_STAGING_PATH = `${PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH}.staging`;
11
8
  export const PROTOCOL_V2_ROM_PARAMS_PACKAGE_PATH = 'vol0:/loaders/rom/params.okpkg';
9
+ export const PROTOCOL_V2_RESOURCE_PACKAGE_HEADER_SIZE = 0x5f90;
12
10
 
13
- const SHA256_HEX_LENGTH = 64;
14
-
15
- function normalizeHex(value: unknown, expectedLength: number, field: string): string {
16
- if (typeof value !== 'string') {
17
- throw new Error(`Invalid Pro2 resource ${field}: expected a hexadecimal string`);
18
- }
19
- const normalized = value.replace(/^0x/i, '').toLowerCase();
20
- if (normalized.length !== expectedLength || !/^[0-9a-f]+$/.test(normalized)) {
21
- throw new Error(
22
- `Invalid Pro2 resource ${field}: expected ${expectedLength} hexadecimal characters`
23
- );
24
- }
25
- return normalized;
26
- }
11
+ const PROTOCOL_V2_RESOURCE_PACKAGE_HEADER_VERSION = 1;
12
+ const PROTOCOL_V2_RESOURCE_PACKAGE_FLEXIBLE_OFFSET = 0x6c;
13
+ const PROTOCOL_V2_RESOURCE_PACKAGE_FLEXIBLE_SIZE = 64;
14
+ const PROTOCOL_V2_RESOURCE_PACKAGE_PAYLOAD_HASH_OFFSET = 0x200;
15
+ const PROTOCOL_V2_RESOURCE_PACKAGE_HEADER_HASH_OFFSET = 0x240;
16
+ const PROTOCOL_V2_RESOURCE_PACKAGE_HASH_SIZE = 64;
17
+ const PROTOCOL_V2_RESOURCE_PACKAGE_TYPE = 'RESC';
27
18
 
28
19
  /** Validate a complete Pro2 stable resource set from remote configuration. */
29
20
  export function parseProtocolV2Resources(value: unknown): IProtocolV2Resources | undefined {
@@ -58,153 +49,125 @@ export function parseProtocolV2Resources(value: unknown): IProtocolV2Resources |
58
49
  };
59
50
  }
60
51
 
61
- const PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS = [
62
- 'vol0:/bundles/',
63
- 'vol0:/loaders/rom/',
64
- ] as const;
52
+ export function isProtocolV2ResourceArchiveEntryName(entryName: string): boolean {
53
+ const normalized = entryName.replace(/\\/g, '/');
54
+ if (!normalized.toLowerCase().endsWith('.okpkg')) {
55
+ return false;
56
+ }
57
+ const parts = normalized.split('/');
58
+ const fileName = parts[parts.length - 1] ?? '';
59
+ return (
60
+ fileName.length > 0 &&
61
+ !fileName.startsWith('.') &&
62
+ !parts.some(
63
+ part =>
64
+ !part ||
65
+ part === '.' ||
66
+ part === '..' ||
67
+ part === '.DS_Store' ||
68
+ part.startsWith('._') ||
69
+ part.toUpperCase() === '__MACOSX'
70
+ )
71
+ );
72
+ }
65
73
 
66
- function isAllowedManifestDevicePath(path: string): boolean {
67
- if (
68
- !path.endsWith('.okpkg') ||
74
+ function isSafeResourceDevicePath(path: string): boolean {
75
+ return !(
69
76
  path.includes('\\') ||
70
77
  path.includes('//') ||
78
+ [...path].some(char => {
79
+ const code = char.charCodeAt(0);
80
+ return code <= 0x1f || code === 0x7f;
81
+ }) ||
71
82
  path.split('/').some(part => part === '.' || part === '..')
72
- ) {
73
- return false;
74
- }
75
- if (path === PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH) {
76
- return true;
77
- }
78
- return PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS.some(root => path.startsWith(root));
83
+ );
79
84
  }
80
85
 
81
- function assertManifestString(value: unknown, field: string): string {
82
- if (typeof value !== 'string' || value.length === 0) {
83
- throw new Error(`Invalid Pro2 resource manifest ${field}`);
84
- }
85
- return value;
86
+ function readAscii(bytes: Uint8Array, offset: number, length: number): string {
87
+ return Array.from(bytes.slice(offset, offset + length))
88
+ .map(byte => String.fromCharCode(byte))
89
+ .join('');
86
90
  }
87
91
 
88
- function assertManifestRelativePath(value: unknown, field: string): string {
89
- const path = assertManifestString(value, field);
92
+ function readResourceDevicePath(bytes: Uint8Array): string {
93
+ const metadata = bytes.slice(
94
+ PROTOCOL_V2_RESOURCE_PACKAGE_FLEXIBLE_OFFSET,
95
+ PROTOCOL_V2_RESOURCE_PACKAGE_FLEXIBLE_OFFSET + PROTOCOL_V2_RESOURCE_PACKAGE_FLEXIBLE_SIZE
96
+ );
97
+ const terminator = metadata.indexOf(0);
98
+ const pathBytes = terminator === -1 ? metadata : metadata.slice(0, terminator);
99
+ const padding = terminator === -1 ? new Uint8Array(0) : metadata.slice(terminator);
90
100
  if (
91
- path.startsWith('/') ||
92
- path.includes('\\') ||
93
- path.includes(':') ||
94
- path.split('/').some(part => !part || part === '.' || part === '..')
101
+ pathBytes.byteLength === 0 ||
102
+ Array.from(pathBytes).some(byte => byte < 0x20 || byte > 0x7e) ||
103
+ Array.from(padding).some(byte => byte !== 0)
95
104
  ) {
96
- throw new Error(`Invalid Pro2 resource manifest ${field}`);
105
+ throw new Error('Invalid Pro2 RESOURCE package device path metadata');
106
+ }
107
+ const path = readAscii(pathBytes, 0, pathBytes.byteLength);
108
+ if (!isSafeResourceDevicePath(path)) {
109
+ throw new Error(`Invalid Pro2 RESOURCE package device path: ${path}`);
97
110
  }
98
111
  return path;
99
112
  }
100
113
 
101
- function parseProtocolV2ResourceManifestFile(
102
- value: unknown,
103
- index: number
104
- ): IProtocolV2ResourceManifestFile {
105
- if (!value || typeof value !== 'object' || Array.isArray(value)) {
106
- throw new Error(`Invalid Pro2 resource manifest files[${index}]`);
107
- }
108
- const file = value as Partial<IProtocolV2ResourceManifestFile>;
109
- const archivePath = assertManifestRelativePath(file.archive_path, `files[${index}].archive_path`);
110
- const originalName = assertManifestRelativePath(
111
- file.original_name,
112
- `files[${index}].original_name`
113
- );
114
- if (originalName.includes('/')) {
115
- throw new Error(`Invalid Pro2 resource manifest files[${index}].original_name`);
116
- }
117
- const devicePath = assertManifestString(file.device_path, `files[${index}].device_path`);
118
- if (!isAllowedManifestDevicePath(devicePath)) {
119
- throw new Error(`Invalid Pro2 resource manifest files[${index}].device_path`);
120
- }
121
- if (!Number.isSafeInteger(file.size) || Number(file.size) <= 0) {
122
- throw new Error(`Invalid Pro2 resource manifest files[${index}].size`);
123
- }
124
- const digest = normalizeHex(file.sha256, SHA256_HEX_LENGTH, `files[${index}].sha256`);
125
- if (file.signed !== true) {
126
- throw new Error(`Invalid Pro2 resource manifest files[${index}].signed`);
127
- }
128
- if (file.sig_algo !== 'ed25519' && file.sig_algo !== 'mldsa65') {
129
- throw new Error(`Invalid Pro2 resource manifest files[${index}].sig_algo`);
130
- }
131
- if (file.payload_version !== null && typeof file.payload_version !== 'string') {
132
- throw new Error(`Invalid Pro2 resource manifest files[${index}].payload_version`);
133
- }
134
- if (!archivePath.endsWith('.okpkg') || !originalName.endsWith('.okpkg')) {
135
- throw new Error(`Invalid Pro2 resource manifest files[${index}] package extension`);
136
- }
137
- return {
138
- archive_path: archivePath,
139
- original_name: originalName,
140
- device_path: devicePath,
141
- size: Number(file.size),
142
- sha256: digest,
143
- signed: true,
144
- sig_algo: file.sig_algo,
145
- payload_version: file.payload_version ?? null,
146
- };
147
- }
114
+ export type ProtocolV2ResourcePackageHeader = {
115
+ version: IVersionArray;
116
+ payloadLength: number;
117
+ devicePath: string;
118
+ payloadHash: string;
119
+ headerHash: string;
120
+ };
148
121
 
149
- export function parseProtocolV2ResourceManifest(value: unknown): IProtocolV2ResourceManifest {
150
- if (!value || typeof value !== 'object' || Array.isArray(value)) {
151
- throw new Error('Invalid Pro2 resource manifest');
152
- }
153
- const manifest = value as Partial<IProtocolV2ResourceManifest>;
122
+ export function parseProtocolV2ResourcePackageHeader(
123
+ bytes: Uint8Array,
124
+ packageSize: number
125
+ ): ProtocolV2ResourcePackageHeader {
126
+ if (bytes.byteLength < PROTOCOL_V2_RESOURCE_PACKAGE_HEADER_SIZE) {
127
+ throw new Error('Pro2 RESOURCE package is shorter than its header');
128
+ }
129
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
130
+ const headerVersion = view.getUint32(0x04, true);
131
+ const headerLength = view.getUint32(0x0c, true);
132
+ const payloadLength = view.getUint32(0x14, true);
154
133
  if (
155
- manifest.schema !== 1 ||
156
- manifest.variant !== 'resource' ||
157
- manifest.device_root !== 'vol0:' ||
158
- manifest.restore_mode !== 'bootloader_update' ||
159
- !Array.isArray(manifest.trees) ||
160
- !Array.isArray(manifest.files)
134
+ readAscii(bytes, 0, 4) !== 'OKPP' ||
135
+ readAscii(bytes, 0x08, 4) !== PROTOCOL_V2_RESOURCE_PACKAGE_TYPE ||
136
+ headerVersion !== PROTOCOL_V2_RESOURCE_PACKAGE_HEADER_VERSION ||
137
+ headerLength !== PROTOCOL_V2_RESOURCE_PACKAGE_HEADER_SIZE ||
138
+ payloadLength <= 0 ||
139
+ headerLength + payloadLength !== packageSize
161
140
  ) {
162
- throw new Error('Invalid Pro2 resource manifest contract');
163
- }
164
- const files = manifest.files.map(parseProtocolV2ResourceManifestFile);
165
- const devicePaths = new Set(files.map(file => file.device_path));
166
- const archivePaths = new Set(files.map(file => file.archive_path));
167
- if (
168
- files.length === 0 ||
169
- devicePaths.size !== files.length ||
170
- archivePaths.size !== files.length ||
171
- !devicePaths.has(PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH) ||
172
- !files.some(file => file.device_path.startsWith('vol0:/bundles/'))
173
- ) {
174
- throw new Error('Invalid Pro2 resource manifest file set');
141
+ throw new Error('Invalid Pro2 RESOURCE package header');
175
142
  }
143
+
144
+ const packedVersion = view.getUint32(0x10, true);
176
145
  return {
177
- schema: 1,
178
- artifact_name: assertManifestString(manifest.artifact_name, 'artifact_name'),
179
- release_name: assertManifestString(manifest.release_name, 'release_name'),
180
- variant: 'resource',
181
- commit: assertManifestString(manifest.commit, 'commit'),
182
- short_sha: assertManifestString(manifest.short_sha, 'short_sha'),
183
- timestamp_utc: assertManifestString(manifest.timestamp_utc, 'timestamp_utc'),
184
- core_version: assertManifestString(manifest.core_version, 'core_version'),
185
- key_set: assertManifestString(manifest.key_set, 'key_set'),
186
- device_root: 'vol0:',
187
- restore_mode: 'bootloader_update',
188
- trees: manifest.trees.map((tree, index) => {
189
- if (!tree || typeof tree !== 'object') {
190
- throw new Error(`Invalid Pro2 resource manifest trees[${index}]`);
191
- }
192
- const item = tree as { path?: unknown; device?: unknown };
193
- return {
194
- path: assertManifestRelativePath(item.path, `trees[${index}].path`),
195
- device: assertManifestString(item.device, `trees[${index}].device`),
196
- };
197
- }),
198
- files,
146
+ version: [
147
+ Math.floor(packedVersion / 0x10000) % 0x100,
148
+ Math.floor(packedVersion / 0x100) % 0x100,
149
+ packedVersion % 0x100,
150
+ ],
151
+ payloadLength,
152
+ devicePath: readResourceDevicePath(bytes),
153
+ payloadHash: bytesToHex(
154
+ bytes.slice(
155
+ PROTOCOL_V2_RESOURCE_PACKAGE_PAYLOAD_HASH_OFFSET,
156
+ PROTOCOL_V2_RESOURCE_PACKAGE_PAYLOAD_HASH_OFFSET + PROTOCOL_V2_RESOURCE_PACKAGE_HASH_SIZE
157
+ )
158
+ ),
159
+ headerHash: bytesToHex(
160
+ bytes.slice(
161
+ PROTOCOL_V2_RESOURCE_PACKAGE_HEADER_HASH_OFFSET,
162
+ PROTOCOL_V2_RESOURCE_PACKAGE_HEADER_HASH_OFFSET + PROTOCOL_V2_RESOURCE_PACKAGE_HASH_SIZE
163
+ )
164
+ ),
199
165
  };
200
166
  }
201
167
 
202
- export function selectProtocolV2ResourceManifestFiles({
203
- manifest,
204
- targetsToUpdate,
205
- }: {
206
- manifest: IProtocolV2ResourceManifest;
207
- targetsToUpdate: readonly FirmwareUpdateV4Target[];
208
- }): IProtocolV2ResourceManifestFile[] {
209
- return targetsToUpdate.includes('resource') ? [...manifest.files] : [];
168
+ export function parseProtocolV2ResourcePackage(
169
+ binary: ArrayBuffer | Uint8Array
170
+ ): ProtocolV2ResourcePackageHeader {
171
+ const bytes = binary instanceof Uint8Array ? binary : new Uint8Array(binary);
172
+ return parseProtocolV2ResourcePackageHeader(bytes, bytes.byteLength);
210
173
  }
@@ -14,10 +14,14 @@ const Log = getLogger(LoggerNames.Core);
14
14
 
15
15
  export type ProtocolV2UnlockContext = {
16
16
  preflightCompleted: boolean;
17
+ preflightStatusRefreshed?: boolean;
18
+ preflightMainPinSelected?: boolean;
17
19
  };
18
20
 
19
21
  export const createProtocolV2UnlockContext = (): ProtocolV2UnlockContext => ({
20
22
  preflightCompleted: false,
23
+ preflightStatusRefreshed: false,
24
+ preflightMainPinSelected: false,
21
25
  });
22
26
 
23
27
  type RunnableMethod = Pick<
@@ -27,6 +31,7 @@ type RunnableMethod = Pick<
27
31
  | 'useDevicePassphraseState'
28
32
  | 'protocolV2UiInteraction'
29
33
  | 'protocolV2UiMode'
34
+ | 'protocolV2PreUnlockPinType'
30
35
  | 'params'
31
36
  | 'payload'
32
37
  > & {
@@ -48,6 +53,9 @@ type RunMethodWithUnlockPolicyOptions<T> = {
48
53
  };
49
54
 
50
55
  const resolvePreUnlockPinType = (method: RunnableMethod) => {
56
+ if (method.protocolV2PreUnlockPinType !== undefined) {
57
+ return method.protocolV2PreUnlockPinType;
58
+ }
51
59
  const targetsKnownHiddenWallet =
52
60
  method.useDevicePassphraseState &&
53
61
  method.payload?.useEmptyPassphrase !== true &&
@@ -80,6 +88,7 @@ export async function runMethodWithUnlockPolicy<T = unknown>(
80
88
  const requiresPreUnlock =
81
89
  device.isProtocolV2() &&
82
90
  (method.useDevicePassphraseState || method.unlockPolicy === 'unlock-before-run') &&
91
+ device.state?.status.initialized !== false &&
83
92
  !device.isBootloader?.() &&
84
93
  !device.isRomloader?.();
85
94
 
@@ -95,11 +104,12 @@ export async function runMethodWithUnlockPolicy<T = unknown>(
95
104
  await afterStatusBeforeUnlock?.();
96
105
 
97
106
  if (!status.unlocked) {
107
+ const preUnlockPinType = resolvePreUnlockPinType(method);
98
108
  const unlockInteraction: HardwareUiInteractionMeta | undefined = shouldCoordinateUi
99
109
  ? uiCoordinator.enterUnlockInteraction(method.name)
100
110
  : undefined;
101
111
  const unlockedStatus = await device.unlockDevice(
102
- resolvePreUnlockPinType(method),
112
+ preUnlockPinType,
103
113
  shouldCoordinateUi
104
114
  ? { emitUiEvent: false, interaction: unlockInteraction }
105
115
  : {
@@ -115,9 +125,11 @@ export async function runMethodWithUnlockPolicy<T = unknown>(
115
125
  'Protocol V2 device remained locked after the unlock flow.'
116
126
  );
117
127
  }
128
+ context.preflightMainPinSelected = preUnlockPinType === DeviceSessionPinType.Main;
118
129
  Log.debug('Protocol V2 pre-unlock completed', { method: method.name });
119
130
  }
120
131
 
132
+ context.preflightStatusRefreshed = true;
121
133
  context.preflightCompleted = true;
122
134
  }
123
135