@onekeyfe/hd-core 1.2.0-alpha.135 → 1.2.0-alpha.136

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.
package/dist/index.js CHANGED
@@ -43538,7 +43538,7 @@ const DEVICE_CONTROL_CALLS = new Set([
43538
43538
  'DeviceCertificateSign',
43539
43539
  'DeviceMiscUsbMscControl',
43540
43540
  ]);
43541
- const isProtocolV2ActionCancelledMessage = (message) => /^(?:cancel(?:led|ed)(?: on device)?|confirm dismissed|update cancel(?:led|ed)|user cancel(?:led|ed)(?:\s+.*)?)$/i.test(message);
43541
+ const isProtocolV2ActionCancelledMessage = (message) => /^(?:cancel(?:led|ed)(?: on device)?|confirm dismissed|user cancel(?:led|ed)(?:\s+.*)?)$/i.test(message);
43542
43542
  function shouldReduceDebugForCall(type) {
43543
43543
  return HIGH_VOLUME_DEBUG_CALLS.has(type);
43544
43544
  }
@@ -45617,15 +45617,6 @@ class Device extends events.exports {
45617
45617
  yield TransportManager.reconfigure(this.features);
45618
45618
  });
45619
45619
  const expectedDeviceId = options === null || options === void 0 ? void 0 : options.deviceId;
45620
- if (expectedDeviceId) {
45621
- this.passphraseState = undefined;
45622
- const { message } = yield this.commands.typedCall('GetFeatures', 'Features', {});
45623
- this._updateFeatures(message);
45624
- yield TransportManager.reconfigure(this.features);
45625
- if (!this.checkDeviceId(expectedDeviceId)) {
45626
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckDeviceIdError);
45627
- }
45628
- }
45629
45620
  this.passphraseState = options === null || options === void 0 ? void 0 : options.passphraseState;
45630
45621
  if (options === null || options === void 0 ? void 0 : options.initSession) {
45631
45622
  this.clearInternalState(options === null || options === void 0 ? void 0 : options.deviceId);
@@ -45641,7 +45632,23 @@ class Device extends events.exports {
45641
45632
  if (options === null || options === void 0 ? void 0 : options.deriveCardano) {
45642
45633
  payload.derive_cardano = true;
45643
45634
  }
45644
- yield callInitialize(payload, options === null || options === void 0 ? void 0 : options.initSession);
45635
+ if (this.features) {
45636
+ yield TransportManager.reconfigure(this.features);
45637
+ }
45638
+ const assertExpectedDeviceIdentity = () => {
45639
+ if (expectedDeviceId && !this.checkDeviceId(expectedDeviceId)) {
45640
+ this.clearInternalState();
45641
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckDeviceIdError);
45642
+ }
45643
+ };
45644
+ try {
45645
+ yield callInitialize(payload, options === null || options === void 0 ? void 0 : options.initSession);
45646
+ }
45647
+ catch (error) {
45648
+ assertExpectedDeviceIdentity();
45649
+ throw error;
45650
+ }
45651
+ assertExpectedDeviceIdentity();
45645
45652
  }
45646
45653
  catch (error) {
45647
45654
  Log$h.error('Initialization failed:', error);
@@ -46115,17 +46122,14 @@ class Device extends events.exports {
46115
46122
  const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInterruptedFromUser);
46116
46123
  const cleanupPromise = this.runCleanupPromise;
46117
46124
  const { cancelableAction } = this;
46118
- const env = DataManager.getSettings('env');
46119
46125
  if (cancelableAction) {
46120
46126
  yield cancelableAction(error);
46121
46127
  }
46122
46128
  else if (this.isProtocolV2() &&
46123
- (DataManager.isBleConnect(env) ||
46124
- DataManager.isBrowserWebUsb(env) ||
46125
- DataManager.isDesktopWebUsb(env)) &&
46129
+ DataManager.isBleConnect(DataManager.getSettings('env')) &&
46126
46130
  this.hasDeviceAcquire()) {
46127
46131
  yield ((_b = (_a = this.commands) === null || _a === void 0 ? void 0 : _a.cancelDevice) === null || _b === void 0 ? void 0 : _b.call(_a).catch(cancelError => {
46128
- Log$h.debug('Protocol V2 fallback cancel error', cancelError);
46132
+ Log$h.debug('Protocol V2 BLE fallback cancel error', cancelError);
46129
46133
  }));
46130
46134
  }
46131
46135
  yield ((_c = this.commands) === null || _c === void 0 ? void 0 : _c.cancel());
@@ -48180,7 +48184,6 @@ class DeviceChangePin extends BaseMethod {
48180
48184
  }
48181
48185
  init() {
48182
48186
  this.unlockPolicy = 'unlock-before-run';
48183
- this.protocolV2PreUnlockPinType = hdTransport.DeviceSessionPinType.Any;
48184
48187
  this.useDevicePassphraseState = false;
48185
48188
  validateParams(this.payload, [{ name: 'remove', type: 'boolean' }]);
48186
48189
  this.params = {
@@ -48790,12 +48793,7 @@ class DeviceSupportFeatures extends BaseMethod {
48790
48793
  }
48791
48794
 
48792
48795
  class DeviceVerify extends BaseMethod {
48793
- getSupportedProtocols() {
48794
- return ['V1', 'V2'];
48795
- }
48796
48796
  init() {
48797
- this.unlockPolicy = 'unlock-before-run';
48798
- this.protocolV2PreUnlockPinType = hdTransport.DeviceSessionPinType.Any;
48799
48797
  this.useDevicePassphraseState = false;
48800
48798
  validateParams(this.payload, [{ name: 'dataHex', type: 'hexString' }]);
48801
48799
  this.params = {
@@ -48834,7 +48832,6 @@ class DeviceWipe extends BaseMethod {
48834
48832
  }
48835
48833
  init() {
48836
48834
  this.unlockPolicy = 'unlock-before-run';
48837
- this.protocolV2PreUnlockPinType = hdTransport.DeviceSessionPinType.Any;
48838
48835
  this.useDevicePassphraseState = false;
48839
48836
  this.protocolV2UiInteraction = {
48840
48837
  request: 'button',
@@ -51722,8 +51719,9 @@ const PROTOCOL_V2_BOOTLOADER_RECONNECT_TIMEOUT = 90 * 1000;
51722
51719
  const PROTOCOL_V2_FINAL_RECONNECT_TIMEOUT = 3 * 60 * 1000;
51723
51720
  const PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT = 5 * 1000;
51724
51721
  const PROTOCOL_V2_FIRMWARE_STATUS_RESPONSE_TIMEOUT = 15 * 1000;
51725
- const PROTOCOL_V2_INSTALL_TIMEOUT = 5 * 60 * 1000;
51722
+ const PROTOCOL_V2_INSTALL_TIMEOUT = 8 * 60 * 1000;
51726
51723
  const PROTOCOL_V2_INSTALL_STATUS_INITIAL_DELAY = 1000;
51724
+ const PROTOCOL_V2_MISSING_TARGET_STATUS_GRACE_TIMEOUT = 30 * 1000;
51727
51725
  const PROTOCOL_V2_TARGET_STATUS_PENDING = 0;
51728
51726
  const PROTOCOL_V2_TARGET_STATUS_IN_PROGRESS = 1;
51729
51727
  const PROTOCOL_V2_TARGET_STATUS_FINISHED = 2;
@@ -51737,8 +51735,6 @@ const PROTOCOL_V2_CONNECT_SINGLE_TIMEOUT = 75 * 1000;
51737
51735
  const PROTOCOL_V2_DEVICE_INFO_READY_TIMEOUT = 30 * 1000;
51738
51736
  const PROTOCOL_V2_FILE_TRANSFER_RETRY_COUNT = 3;
51739
51737
  const PROTOCOL_V2_INSTALL_STATUS_CONFLICT_CODE = 'FirmwareInstallStatusConflict';
51740
- const PROTOCOL_V2_INSTALL_FAILED_CODE = 'FirmwareInstallFailed';
51741
- const PROTOCOL_V2_INSTALL_TIMEOUT_CODE = 'FirmwareInstallTimeout';
51742
51738
  const PROTOCOL_V2_OKPP_HEADER_SIZE = 0x52a0;
51743
51739
  const PROTOCOL_V2_OKPP_PAYLOAD_HASH_OFFSET = 0x200;
51744
51740
  const PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET = 0x240;
@@ -51894,8 +51890,7 @@ const isProtocolV2FirmwareStatusEndpointUnavailable = (error) => {
51894
51890
  const isProtocolV2TerminalInstallStatusError = (error) => {
51895
51891
  var _a;
51896
51892
  return error instanceof hdShared.HardwareError &&
51897
- (error.errorCode === hdShared.HardwareErrorCode.ActionCancelled ||
51898
- error.errorCode === hdShared.HardwareErrorCode.FirmwareError ||
51893
+ (error.errorCode === hdShared.HardwareErrorCode.FirmwareError ||
51899
51894
  error.errorCode === hdShared.HardwareErrorCode.FirmwareVerificationFailed ||
51900
51895
  ((_a = error.params) === null || _a === void 0 ? void 0 : _a.firmwareUpdateCode) === PROTOCOL_V2_INSTALL_STATUS_CONFLICT_CODE);
51901
51896
  };
@@ -52037,7 +52032,6 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52037
52032
  this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
52038
52033
  this.requireDeviceMode = [];
52039
52034
  this.unlockPolicy = 'unlock-before-run';
52040
- this.protocolV2PreUnlockPinType = hdTransport.DeviceSessionPinType.Any;
52041
52035
  this.useDevicePassphraseState = false;
52042
52036
  this.skipForceUpdateCheck = true;
52043
52037
  const { payload } = this;
@@ -52771,9 +52765,8 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52771
52765
  ? visibleVersions[target]
52772
52766
  : `${Math.floor(statusVersion / 0x10000) % 0x100}.${Math.floor(statusVersion / 0x100) % 0x100}.${statusVersion % 0x100}`;
52773
52767
  if (!observedVersion) {
52774
- const isUnobservableApplicationSlot = applicationTargets.length > 1 && (target === 'app_v1' || target === 'app_v2');
52775
- if (this.protocolV2FinalStatusVerified || isUnobservableApplicationSlot) {
52776
- Log$7.warn(`Protocol V2 target ${target} has no observable final version; install completion is authoritative`);
52768
+ if (this.protocolV2FinalStatusVerified) {
52769
+ Log$7.warn(`Protocol V2 target ${target} has no observable final version; completed target status is authoritative`);
52777
52770
  }
52778
52771
  else {
52779
52772
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareVerificationFailed, `Protocol V2 target ${target} has no observable final version after status fallback`);
@@ -53443,6 +53436,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53443
53436
  });
53444
53437
  }
53445
53438
  assertProtocolV2TargetStatus(statusTargets, expectedTargetIds, expectedPaths = new Map()) {
53439
+ var _a, _b, _c;
53446
53440
  Log$7.log(`[FirmwareUpdateV4] DeviceFirmwareUpdateStatus records=${JSON.stringify(statusTargets)}`);
53447
53441
  const failedTarget = statusTargets.find(target => {
53448
53442
  var _a;
@@ -53457,9 +53451,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53457
53451
  path: failedTarget.path,
53458
53452
  });
53459
53453
  Log$7.error(`[FirmwareUpdateV4] firmware install failed target=${failedTargetDetails}`);
53460
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareError, undefined, {
53461
- firmwareUpdateCode: PROTOCOL_V2_INSTALL_FAILED_CODE,
53462
- });
53454
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareError, `Protocol V2 firmware target failed: target=${failedTarget.target_id} status=${(_a = failedTarget.status) !== null && _a !== void 0 ? _a : 'unknown'} payloadVersion=${(_b = failedTarget.payload_version) !== null && _b !== void 0 ? _b : 'unknown'} path=${(_c = failedTarget.path) !== null && _c !== void 0 ? _c : 'unknown'}`);
53463
53455
  }
53464
53456
  const matchingTargets = statusTargets.filter(target => { var _a; return expectedTargetIds.has((_a = normalizeProtocolV2TargetId(target.target_id)) !== null && _a !== void 0 ? _a : -1); });
53465
53457
  const seenTargetIds = new Set();
@@ -53468,8 +53460,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53468
53460
  if (targetId === undefined ||
53469
53461
  seenTargetIds.has(targetId) ||
53470
53462
  (target.path && expectedPaths.get(targetId) && target.path !== expectedPaths.get(targetId))) {
53471
- Log$7.error(`[FirmwareUpdateV4] install status conflicts with target=${target.target_id}`);
53472
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareError, undefined, {
53463
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 install status conflicts with target ${target.target_id}`, {
53473
53464
  firmwareUpdateCode: PROTOCOL_V2_INSTALL_STATUS_CONFLICT_CODE,
53474
53465
  });
53475
53466
  }
@@ -53562,8 +53553,15 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53562
53553
  let lastError;
53563
53554
  let shouldReconnect = false;
53564
53555
  let deviceInfo;
53556
+ let missingTargetStatusSince;
53557
+ let missingTargetStatusKey;
53558
+ let normalModeWithoutInstallEvidenceSince;
53565
53559
  let installEvidenceObserved = false;
53566
53560
  let currentInstallStatusObserved = false;
53561
+ const resetMissingTargetStatusGrace = () => {
53562
+ missingTargetStatusSince = undefined;
53563
+ missingTargetStatusKey = undefined;
53564
+ };
53567
53565
  while (Date.now() - startTime < PROTOCOL_V2_INSTALL_TIMEOUT) {
53568
53566
  this.throwIfAborted();
53569
53567
  try {
@@ -53583,6 +53581,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53583
53581
  }, { timeoutMs: PROTOCOL_V2_FIRMWARE_STATUS_RESPONSE_TIMEOUT });
53584
53582
  if (statusResponse.type === 'Success') {
53585
53583
  installEvidenceObserved = true;
53584
+ resetMissingTargetStatusGrace();
53586
53585
  lastError = new Error('Protocol V2 firmware install acknowledged; waiting for target status');
53587
53586
  }
53588
53587
  const statusTargets = statusResponse.type === 'DeviceFirmwareUpdateStatus'
@@ -53604,6 +53603,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53604
53603
  if (hasMatchingTargetStatus &&
53605
53604
  (!requireCurrentInstallStatus || currentInstallStatusObserved)) {
53606
53605
  installEvidenceObserved = true;
53606
+ normalModeWithoutInstallEvidenceSince = undefined;
53607
53607
  }
53608
53608
  const matchingStatusTargets = statusTargets.filter(target => {
53609
53609
  const targetId = normalizeProtocolV2TargetId(target.target_id);
@@ -53631,6 +53631,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53631
53631
  }
53632
53632
  }
53633
53633
  if (statusTargets.length === 0) {
53634
+ resetMissingTargetStatusGrace();
53634
53635
  if (statusResponse.type !== 'Success') {
53635
53636
  lastError = new Error('Protocol V2 firmware update is waiting for user confirmation or target status');
53636
53637
  }
@@ -53638,10 +53639,23 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53638
53639
  else {
53639
53640
  const missingTargetIds = this.getProtocolV2MissingTargetIds(statusTargets, expectedTargetIds);
53640
53641
  if (missingTargetIds.length > 0) {
53642
+ const now = Date.now();
53641
53643
  const missingKey = missingTargetIds.join(',');
53644
+ if (missingTargetStatusSince === undefined || missingTargetStatusKey !== missingKey) {
53645
+ missingTargetStatusSince = now;
53646
+ missingTargetStatusKey = missingKey;
53647
+ }
53648
+ else if (now - missingTargetStatusSince >=
53649
+ PROTOCOL_V2_MISSING_TARGET_STATUS_GRACE_TIMEOUT) {
53650
+ const reportedTargetIds = statusTargets
53651
+ .map(target => normalizeProtocolV2TargetId(target.target_id))
53652
+ .filter((targetId) => targetId !== undefined);
53653
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareError, `Protocol V2 firmware status is missing requested records: targetIds=${missingKey} reportedTargetIds=${reportedTargetIds.join(',')}`);
53654
+ }
53642
53655
  lastError = new Error(`Protocol V2 firmware status is temporarily missing targetIds=${missingKey}`);
53643
53656
  }
53644
53657
  else {
53658
+ resetMissingTargetStatusGrace();
53645
53659
  lastError = new Error('Protocol V2 firmware targets are still installing');
53646
53660
  }
53647
53661
  }
@@ -53650,6 +53664,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53650
53664
  if (isProtocolV2TerminalInstallStatusError(error)) {
53651
53665
  throw error;
53652
53666
  }
53667
+ resetMissingTargetStatusGrace();
53653
53668
  if (isProtocolV2FirmwareStatusEndpointUnavailable(error)) {
53654
53669
  if (!currentDeviceInfo) {
53655
53670
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 device identity is unavailable during install polling');
@@ -53663,9 +53678,16 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53663
53678
  return;
53664
53679
  }
53665
53680
  if (isNormalMode) {
53681
+ const now = Date.now();
53682
+ normalModeWithoutInstallEvidenceSince !== null && normalModeWithoutInstallEvidenceSince !== void 0 ? normalModeWithoutInstallEvidenceSince : (normalModeWithoutInstallEvidenceSince = now);
53683
+ if (now - normalModeWithoutInstallEvidenceSince >=
53684
+ PROTOCOL_V2_MISSING_TARGET_STATUS_GRACE_TIMEOUT) {
53685
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareError, 'Protocol V2 device returned to normal mode without install ACK, target status, or version change');
53686
+ }
53666
53687
  lastError = new Error('Protocol V2 device is in normal mode but installation is not yet confirmed');
53667
53688
  }
53668
53689
  else {
53690
+ normalModeWithoutInstallEvidenceSince = undefined;
53669
53691
  lastError = new Error('Protocol V2 firmware status endpoint is unavailable while the device remains in loader mode');
53670
53692
  }
53671
53693
  }
@@ -53691,14 +53713,12 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53691
53713
  }
53692
53714
  shouldReconnect = true;
53693
53715
  deviceInfo = undefined;
53716
+ resetMissingTargetStatusGrace();
53694
53717
  Log$7.log('Protocol V2 firmware install device readiness probe failed: ', error);
53695
53718
  }
53696
53719
  yield hdShared.wait(1000);
53697
53720
  }
53698
- Log$7.error(`[FirmwareUpdateV4] install timed out after ${PROTOCOL_V2_INSTALL_TIMEOUT / 1000}s: ${this.normalizeErrorMessage(lastError)}`);
53699
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareError, undefined, {
53700
- firmwareUpdateCode: PROTOCOL_V2_INSTALL_TIMEOUT_CODE,
53701
- });
53721
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 firmware update status not complete within ${PROTOCOL_V2_INSTALL_TIMEOUT / 1000}s: ${this.normalizeErrorMessage(lastError)}`);
53702
53722
  });
53703
53723
  }
53704
53724
  exitProtocolV2BootloaderToNormal() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-core",
3
- "version": "1.2.0-alpha.135",
3
+ "version": "1.2.0-alpha.136",
4
4
  "description": "Core processes and APIs for communicating with OneKey hardware devices.",
5
5
  "author": "OneKey",
6
6
  "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
@@ -25,8 +25,8 @@
25
25
  "url": "https://github.com/OneKeyHQ/hardware-js-sdk/issues"
26
26
  },
27
27
  "dependencies": {
28
- "@onekeyfe/hd-shared": "1.2.0-alpha.135",
29
- "@onekeyfe/hd-transport": "1.2.0-alpha.135",
28
+ "@onekeyfe/hd-shared": "1.2.0-alpha.136",
29
+ "@onekeyfe/hd-transport": "1.2.0-alpha.136",
30
30
  "axios": "1.15.2",
31
31
  "bignumber.js": "^9.0.2",
32
32
  "buffer": "^6.0.3",
@@ -46,5 +46,5 @@
46
46
  "@types/w3c-web-usb": "^1.0.10",
47
47
  "@types/web-bluetooth": "^0.0.21"
48
48
  },
49
- "gitHead": "321e900381de2c1a9c583e90e8abfc2f8dab8266"
49
+ "gitHead": "92945bc4aae3d6602dd44c2e028e902e6bce7b55"
50
50
  }
@@ -2,7 +2,6 @@ import { EDeviceType, ERRORS, HardwareError, HardwareErrorCode, wait } from '@on
2
2
  import JSZip from 'jszip';
3
3
  import {
4
4
  DeviceRebootType,
5
- DeviceSessionPinType,
6
5
  PROTOCOL_V2_BLE_FILE_CHUNK_SIZE,
7
6
  PROTOCOL_V2_BLE_FILE_READ_CHUNK_SIZE,
8
7
  PROTOCOL_V2_BLE_FIRMWARE_FILE_CHUNK_SIZE,
@@ -91,8 +90,9 @@ const PROTOCOL_V2_BOOTLOADER_RECONNECT_TIMEOUT = 90 * 1000;
91
90
  const PROTOCOL_V2_FINAL_RECONNECT_TIMEOUT = 3 * 60 * 1000;
92
91
  const PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT = 5 * 1000;
93
92
  const PROTOCOL_V2_FIRMWARE_STATUS_RESPONSE_TIMEOUT = 15 * 1000;
94
- const PROTOCOL_V2_INSTALL_TIMEOUT = 5 * 60 * 1000;
93
+ const PROTOCOL_V2_INSTALL_TIMEOUT = 8 * 60 * 1000;
95
94
  const PROTOCOL_V2_INSTALL_STATUS_INITIAL_DELAY = 1000;
95
+ const PROTOCOL_V2_MISSING_TARGET_STATUS_GRACE_TIMEOUT = 30 * 1000;
96
96
  const PROTOCOL_V2_TARGET_STATUS_PENDING = 0;
97
97
  const PROTOCOL_V2_TARGET_STATUS_IN_PROGRESS = 1;
98
98
  const PROTOCOL_V2_TARGET_STATUS_FINISHED = 2;
@@ -106,8 +106,6 @@ const PROTOCOL_V2_CONNECT_SINGLE_TIMEOUT = 75 * 1000;
106
106
  const PROTOCOL_V2_DEVICE_INFO_READY_TIMEOUT = 30 * 1000;
107
107
  const PROTOCOL_V2_FILE_TRANSFER_RETRY_COUNT = 3;
108
108
  const PROTOCOL_V2_INSTALL_STATUS_CONFLICT_CODE = 'FirmwareInstallStatusConflict';
109
- const PROTOCOL_V2_INSTALL_FAILED_CODE = 'FirmwareInstallFailed';
110
- const PROTOCOL_V2_INSTALL_TIMEOUT_CODE = 'FirmwareInstallTimeout';
111
109
  const PROTOCOL_V2_OKPP_HEADER_SIZE = 0x52a0;
112
110
  const PROTOCOL_V2_OKPP_PAYLOAD_HASH_OFFSET = 0x200;
113
111
  const PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET = 0x240;
@@ -393,8 +391,7 @@ const isProtocolV2FirmwareStatusEndpointUnavailable = (error: unknown) => {
393
391
 
394
392
  const isProtocolV2TerminalInstallStatusError = (error: unknown) =>
395
393
  error instanceof HardwareError &&
396
- (error.errorCode === HardwareErrorCode.ActionCancelled ||
397
- error.errorCode === HardwareErrorCode.FirmwareError ||
394
+ (error.errorCode === HardwareErrorCode.FirmwareError ||
398
395
  error.errorCode === HardwareErrorCode.FirmwareVerificationFailed ||
399
396
  error.params?.firmwareUpdateCode === PROTOCOL_V2_INSTALL_STATUS_CONFLICT_CODE);
400
397
 
@@ -602,9 +599,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
602
599
  this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
603
600
  this.requireDeviceMode = [];
604
601
  this.unlockPolicy = 'unlock-before-run';
605
- // Protocol V2 device-management actions are not wallet-scoped, so either
606
- // the main PIN or an Attach PIN may authorize them.
607
- this.protocolV2PreUnlockPinType = DeviceSessionPinType.Any;
608
602
  this.useDevicePassphraseState = false;
609
603
  this.skipForceUpdateCheck = true;
610
604
 
@@ -1629,11 +1623,9 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1629
1623
  Math.floor(statusVersion / 0x100) % 0x100
1630
1624
  }.${statusVersion % 0x100}`;
1631
1625
  if (!observedVersion) {
1632
- const isUnobservableApplicationSlot =
1633
- applicationTargets.length > 1 && (target === 'app_v1' || target === 'app_v2');
1634
- if (this.protocolV2FinalStatusVerified || isUnobservableApplicationSlot) {
1626
+ if (this.protocolV2FinalStatusVerified) {
1635
1627
  Log.warn(
1636
- `Protocol V2 target ${target} has no observable final version; install completion is authoritative`
1628
+ `Protocol V2 target ${target} has no observable final version; completed target status is authoritative`
1637
1629
  );
1638
1630
  } else {
1639
1631
  throw ERRORS.TypedError(
@@ -2507,9 +2499,14 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2507
2499
  path: failedTarget.path,
2508
2500
  });
2509
2501
  Log.error(`[FirmwareUpdateV4] firmware install failed target=${failedTargetDetails}`);
2510
- throw ERRORS.TypedError(HardwareErrorCode.FirmwareError, undefined, {
2511
- firmwareUpdateCode: PROTOCOL_V2_INSTALL_FAILED_CODE,
2512
- });
2502
+ throw ERRORS.TypedError(
2503
+ HardwareErrorCode.FirmwareError,
2504
+ `Protocol V2 firmware target failed: target=${failedTarget.target_id} status=${
2505
+ failedTarget.status ?? 'unknown'
2506
+ } payloadVersion=${failedTarget.payload_version ?? 'unknown'} path=${
2507
+ failedTarget.path ?? 'unknown'
2508
+ }`
2509
+ );
2513
2510
  }
2514
2511
 
2515
2512
  const matchingTargets = statusTargets.filter(target =>
@@ -2523,10 +2520,13 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2523
2520
  seenTargetIds.has(targetId) ||
2524
2521
  (target.path && expectedPaths.get(targetId) && target.path !== expectedPaths.get(targetId))
2525
2522
  ) {
2526
- Log.error(`[FirmwareUpdateV4] install status conflicts with target=${target.target_id}`);
2527
- throw ERRORS.TypedError(HardwareErrorCode.FirmwareError, undefined, {
2528
- firmwareUpdateCode: PROTOCOL_V2_INSTALL_STATUS_CONFLICT_CODE,
2529
- });
2523
+ throw ERRORS.TypedError(
2524
+ HardwareErrorCode.RuntimeError,
2525
+ `Protocol V2 install status conflicts with target ${target.target_id}`,
2526
+ {
2527
+ firmwareUpdateCode: PROTOCOL_V2_INSTALL_STATUS_CONFLICT_CODE,
2528
+ }
2529
+ );
2530
2530
  }
2531
2531
  seenTargetIds.add(targetId);
2532
2532
  }
@@ -2651,8 +2651,15 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2651
2651
  // Reconnecting here probes DeviceInfo, which loaders reject while installation is active.
2652
2652
  let shouldReconnect = false;
2653
2653
  let deviceInfo: ProtocolV2DeviceInfo | undefined;
2654
+ let missingTargetStatusSince: number | undefined;
2655
+ let missingTargetStatusKey: string | undefined;
2656
+ let normalModeWithoutInstallEvidenceSince: number | undefined;
2654
2657
  let installEvidenceObserved = false;
2655
2658
  let currentInstallStatusObserved = false;
2659
+ const resetMissingTargetStatusGrace = () => {
2660
+ missingTargetStatusSince = undefined;
2661
+ missingTargetStatusKey = undefined;
2662
+ };
2656
2663
 
2657
2664
  while (Date.now() - startTime < PROTOCOL_V2_INSTALL_TIMEOUT) {
2658
2665
  // A transport release caused by an explicit workflow cancellation must not
@@ -2680,6 +2687,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2680
2687
  );
2681
2688
  if (statusResponse.type === 'Success') {
2682
2689
  installEvidenceObserved = true;
2690
+ resetMissingTargetStatusGrace();
2683
2691
  lastError = new Error(
2684
2692
  'Protocol V2 firmware install acknowledged; waiting for target status'
2685
2693
  );
@@ -2708,6 +2716,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2708
2716
  (!requireCurrentInstallStatus || currentInstallStatusObserved)
2709
2717
  ) {
2710
2718
  installEvidenceObserved = true;
2719
+ normalModeWithoutInstallEvidenceSince = undefined;
2711
2720
  }
2712
2721
  const matchingStatusTargets = statusTargets.filter(target => {
2713
2722
  const targetId = normalizeProtocolV2TargetId(target.target_id);
@@ -2749,6 +2758,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2749
2758
  }
2750
2759
 
2751
2760
  if (statusTargets.length === 0) {
2761
+ resetMissingTargetStatusGrace();
2752
2762
  if (statusResponse.type !== 'Success') {
2753
2763
  lastError = new Error(
2754
2764
  'Protocol V2 firmware update is waiting for user confirmation or target status'
@@ -2760,11 +2770,30 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2760
2770
  expectedTargetIds
2761
2771
  );
2762
2772
  if (missingTargetIds.length > 0) {
2773
+ const now = Date.now();
2763
2774
  const missingKey = missingTargetIds.join(',');
2775
+ if (missingTargetStatusSince === undefined || missingTargetStatusKey !== missingKey) {
2776
+ missingTargetStatusSince = now;
2777
+ missingTargetStatusKey = missingKey;
2778
+ } else if (
2779
+ now - missingTargetStatusSince >=
2780
+ PROTOCOL_V2_MISSING_TARGET_STATUS_GRACE_TIMEOUT
2781
+ ) {
2782
+ const reportedTargetIds = statusTargets
2783
+ .map(target => normalizeProtocolV2TargetId(target.target_id))
2784
+ .filter((targetId): targetId is number => targetId !== undefined);
2785
+ throw ERRORS.TypedError(
2786
+ HardwareErrorCode.FirmwareError,
2787
+ `Protocol V2 firmware status is missing requested records: targetIds=${missingKey} reportedTargetIds=${reportedTargetIds.join(
2788
+ ','
2789
+ )}`
2790
+ );
2791
+ }
2764
2792
  lastError = new Error(
2765
2793
  `Protocol V2 firmware status is temporarily missing targetIds=${missingKey}`
2766
2794
  );
2767
2795
  } else {
2796
+ resetMissingTargetStatusGrace();
2768
2797
  lastError = new Error('Protocol V2 firmware targets are still installing');
2769
2798
  }
2770
2799
  }
@@ -2772,6 +2801,9 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2772
2801
  if (isProtocolV2TerminalInstallStatusError(error)) {
2773
2802
  throw error;
2774
2803
  }
2804
+ // Only consecutive full status dumps can prove that a record is absent.
2805
+ // A reboot or transport interruption starts a fresh grace window.
2806
+ resetMissingTargetStatusGrace();
2775
2807
  // App firmware does not register DeviceFirmwareUpdateStatusGet. Treat the
2776
2808
  // missing endpoint as completion only after the runtime probe confirms App mode.
2777
2809
  if (isProtocolV2FirmwareStatusEndpointUnavailable(error)) {
@@ -2794,10 +2826,22 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2794
2826
  return;
2795
2827
  }
2796
2828
  if (isNormalMode) {
2829
+ const now = Date.now();
2830
+ normalModeWithoutInstallEvidenceSince ??= now;
2831
+ if (
2832
+ now - normalModeWithoutInstallEvidenceSince >=
2833
+ PROTOCOL_V2_MISSING_TARGET_STATUS_GRACE_TIMEOUT
2834
+ ) {
2835
+ throw ERRORS.TypedError(
2836
+ HardwareErrorCode.FirmwareError,
2837
+ 'Protocol V2 device returned to normal mode without install ACK, target status, or version change'
2838
+ );
2839
+ }
2797
2840
  lastError = new Error(
2798
2841
  'Protocol V2 device is in normal mode but installation is not yet confirmed'
2799
2842
  );
2800
2843
  } else {
2844
+ normalModeWithoutInstallEvidenceSince = undefined;
2801
2845
  lastError = new Error(
2802
2846
  'Protocol V2 firmware status endpoint is unavailable while the device remains in loader mode'
2803
2847
  );
@@ -2828,19 +2872,18 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2828
2872
  }
2829
2873
  shouldReconnect = true;
2830
2874
  deviceInfo = undefined;
2875
+ resetMissingTargetStatusGrace();
2831
2876
  Log.log('Protocol V2 firmware install device readiness probe failed: ', error);
2832
2877
  }
2833
2878
  await wait(1000);
2834
2879
  }
2835
2880
 
2836
- Log.error(
2837
- `[FirmwareUpdateV4] install timed out after ${
2881
+ throw ERRORS.TypedError(
2882
+ HardwareErrorCode.RuntimeError,
2883
+ `Protocol V2 firmware update status not complete within ${
2838
2884
  PROTOCOL_V2_INSTALL_TIMEOUT / 1000
2839
2885
  }s: ${this.normalizeErrorMessage(lastError)}`
2840
2886
  );
2841
- throw ERRORS.TypedError(HardwareErrorCode.FirmwareError, undefined, {
2842
- firmwareUpdateCode: PROTOCOL_V2_INSTALL_TIMEOUT_CODE,
2843
- });
2844
2887
  }
2845
2888
 
2846
2889
  private async exitProtocolV2BootloaderToNormal() {
@@ -1,4 +1,4 @@
1
- import { DeviceSessionPinType, DeviceSettingsPage } from '@onekeyfe/hd-transport';
1
+ import { DeviceSettingsPage } from '@onekeyfe/hd-transport';
2
2
 
3
3
  import { BaseMethod } from '../BaseMethod';
4
4
  import { validateParams } from '../helpers/paramsValidator';
@@ -13,9 +13,6 @@ export default class DeviceChangePin extends BaseMethod<ChangePin> {
13
13
 
14
14
  init() {
15
15
  this.unlockPolicy = 'unlock-before-run';
16
- // Protocol V2 device-management actions are not wallet-scoped, so either
17
- // the main PIN or an Attach PIN may authorize them.
18
- this.protocolV2PreUnlockPinType = DeviceSessionPinType.Any;
19
16
  this.useDevicePassphraseState = false;
20
17
 
21
18
  // check payload
@@ -1,6 +1,5 @@
1
1
  import { sha256 } from '@noble/hashes/sha256';
2
2
  import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
3
- import { DeviceSessionPinType } from '@onekeyfe/hd-transport';
4
3
  import { bytesToHex } from '@noble/hashes/utils';
5
4
 
6
5
  import { formatAnyHex } from '../helpers/hexUtils';
@@ -12,15 +11,7 @@ import type { BixinVerifyDeviceRequest } from '@onekeyfe/hd-transport';
12
11
  import type { DeviceVerifySignature } from '../../types';
13
12
 
14
13
  export default class DeviceVerify extends BaseMethod<BixinVerifyDeviceRequest> {
15
- getSupportedProtocols() {
16
- return ['V1', 'V2'] as const;
17
- }
18
-
19
14
  init() {
20
- this.unlockPolicy = 'unlock-before-run';
21
- // Protocol V2 device-management actions are not wallet-scoped, so either
22
- // the main PIN or an Attach PIN may authorize them.
23
- this.protocolV2PreUnlockPinType = DeviceSessionPinType.Any;
24
15
  this.useDevicePassphraseState = false;
25
16
 
26
17
  // check payload
@@ -1,4 +1,4 @@
1
- import { DeviceSessionPinType, DeviceSettingsPage } from '@onekeyfe/hd-transport';
1
+ import { DeviceSettingsPage } from '@onekeyfe/hd-transport';
2
2
 
3
3
  import { BaseMethod } from '../BaseMethod';
4
4
 
@@ -11,9 +11,6 @@ export default class DeviceWipe extends BaseMethod<WipeDevice> {
11
11
 
12
12
  init() {
13
13
  this.unlockPolicy = 'unlock-before-run';
14
- // Protocol V2 device-management actions are not wallet-scoped, so either
15
- // the main PIN or an Attach PIN may authorize them.
16
- this.protocolV2PreUnlockPinType = DeviceSessionPinType.Any;
17
14
  this.useDevicePassphraseState = false;
18
15
  this.protocolV2UiInteraction = {
19
16
  request: 'button',