@onekeyfe/hd-core 1.2.0-alpha.98 → 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.
- package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +20 -4
- package/__tests__/DeviceCommands.test.ts +203 -27
- package/__tests__/base64Data.test.ts +69 -0
- package/__tests__/check-all-firmware-release-protocol-v2.test.ts +89 -38
- package/__tests__/check-firmware-release-protocol-v2.test.ts +83 -14
- package/__tests__/device-connector-protocol.test.ts +21 -0
- package/__tests__/device-lifecycle-events.test.ts +427 -7
- package/__tests__/device-pool-state.test.ts +25 -0
- package/__tests__/device-settings.test.ts +237 -9
- package/__tests__/device-state-events.test.ts +2 -2
- package/__tests__/device-state-mapper.test.ts +61 -5
- package/__tests__/device-utils.test.ts +15 -1
- package/__tests__/device-wallet-session-store.test.ts +147 -21
- package/__tests__/deviceSettings.test.ts +7 -3
- package/__tests__/deviceUploadNft.test.ts +36 -4
- package/__tests__/firmware-update/device-update-bootloader.test.ts +14 -3
- package/__tests__/firmware-update/firmware-artifact-source.test.ts +61 -9
- package/__tests__/firmware-update/firmware-prepared-host-digest.test.ts +19 -9
- package/__tests__/firmware-update/firmware-prepared-resource-archive.test.ts +21 -0
- package/__tests__/firmware-update/firmware-update-bootloader-poll.test.ts +128 -2
- package/__tests__/firmware-update/firmware-update-plan-bootloader-identity.test.ts +80 -0
- package/__tests__/firmware-update/firmware-update-plan.test.ts +114 -50
- package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +19 -5
- package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +116 -0
- package/__tests__/firmware-update/firmware-update-v4-install-poll.test.ts +678 -0
- package/__tests__/firmware-update/firmware-update-v4-parameters.test.ts +85 -0
- package/__tests__/get-device-state.test.ts +60 -21
- package/__tests__/logBlockEvent.test.ts +13 -1
- package/__tests__/open-wallet-session.test.ts +127 -1
- package/__tests__/protocol-v2-firmware-targets.test.ts +39 -0
- package/__tests__/protocol-v2-resources.test.ts +185 -88
- package/__tests__/protocol-v2-unlock-policy.test.ts +235 -2
- package/__tests__/protocol-v2.test.ts +2274 -466
- package/__tests__/refresh-device-state.test.ts +3 -1
- package/__tests__/resourceBase64Boundary.test.ts +48 -0
- package/__tests__/search-devices.test.ts +79 -32
- package/__tests__/ton-sign-message.test.ts +84 -0
- package/dist/api/BaseMethod.d.ts +2 -1
- package/dist/api/BaseMethod.d.ts.map +1 -1
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/CheckBootloaderRelease.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +22 -7
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/OpenWalletSession.d.ts.map +1 -1
- package/dist/api/SearchDevices.d.ts.map +1 -1
- package/dist/api/UploadPortfolio.d.ts +1 -1
- package/dist/api/UploadPortfolio.d.ts.map +1 -1
- package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
- package/dist/api/device/DeviceChangePin.d.ts.map +1 -1
- package/dist/api/device/DeviceRebootToBoardloader.d.ts.map +1 -1
- package/dist/api/device/DeviceRebootToBootloader.d.ts.map +1 -1
- package/dist/api/device/DeviceSettings.d.ts.map +1 -1
- package/dist/api/device/DeviceVerify.d.ts +1 -0
- package/dist/api/device/DeviceVerify.d.ts.map +1 -1
- package/dist/api/device/DeviceWipe.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareArtifactSource.d.ts +5 -1
- package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareHostBinding.d.ts.map +1 -1
- package/dist/api/firmware/FirmwarePreparedResourceArchive.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +2 -2
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +0 -15
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +1 -0
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -1
- package/dist/api/firmware/getBinary.d.ts +3 -2
- package/dist/api/firmware/getBinary.d.ts.map +1 -1
- package/dist/api/firmware/protocolV2Release.d.ts.map +1 -1
- package/dist/api/helpers/base64Data.d.ts +16 -0
- package/dist/api/helpers/base64Data.d.ts.map +1 -0
- package/dist/api/protocol-v2/DeviceFirmwareUpdate.d.ts +3 -1
- package/dist/api/protocol-v2/DeviceFirmwareUpdate.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceInfoGet.d.ts +1 -1
- package/dist/api/protocol-v2/DeviceInfoGet.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceReboot.d.ts +1 -1
- package/dist/api/protocol-v2/DeviceReboot.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts +2 -3
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts +2 -3
- package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts.map +1 -1
- package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
- package/dist/api/ton/TonSignMessage.d.ts.map +1 -1
- package/dist/core/index.d.ts +6 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/data-manager/DataManager.d.ts +4 -3
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/data-manager/TransportManager.d.ts.map +1 -1
- package/dist/device/Device.d.ts +16 -3
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts +4 -4
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/device/DeviceConnector.d.ts +1 -1
- package/dist/device/DeviceConnector.d.ts.map +1 -1
- package/dist/device/DevicePool.d.ts.map +1 -1
- package/dist/device/DeviceStateMapper.d.ts.map +1 -1
- package/dist/deviceProfile/buildDeviceFeatures.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/events/ui-request.d.ts +3 -0
- package/dist/events/ui-request.d.ts.map +1 -1
- package/dist/index.d.ts +54 -84
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2333 -1515
- package/dist/protocols/protocol-v2/features.d.ts +13 -5
- package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/index.d.ts +2 -2
- package/dist/protocols/protocol-v2/index.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/resources.d.ts +12 -7
- package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +3 -1
- package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/walletSession.d.ts +3 -0
- package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdatePlan.d.ts +2 -2
- package/dist/types/api/firmwareUpdatePlan.d.ts.map +1 -1
- package/dist/types/api/protocolV2.d.ts +1 -1
- package/dist/types/api/protocolV2.d.ts.map +1 -1
- package/dist/types/device.d.ts.map +1 -1
- package/dist/types/settings.d.ts +3 -31
- package/dist/types/settings.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesUtils.d.ts +3 -0
- package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
- package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
- package/dist/utils/deviceSettings.d.ts +1 -0
- package/dist/utils/deviceSettings.d.ts.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/dist/utils/pro2Nft.d.ts +7 -0
- package/dist/utils/pro2Nft.d.ts.map +1 -1
- package/package.json +6 -4
- package/src/api/BaseMethod.ts +8 -1
- package/src/api/CheckAllFirmwareRelease.ts +8 -5
- package/src/api/CheckBLEFirmwareRelease.ts +2 -2
- package/src/api/CheckBootloaderRelease.ts +3 -2
- package/src/api/CheckFirmwareRelease.ts +2 -2
- package/src/api/FirmwareUpdateV2.ts +130 -69
- package/src/api/FirmwareUpdateV3.ts +29 -19
- package/src/api/FirmwareUpdateV4.ts +966 -743
- package/src/api/OpenWalletSession.ts +39 -9
- package/src/api/PromptWebDeviceAccess.ts +2 -2
- package/src/api/SearchDevices.ts +6 -3
- package/src/api/UploadPortfolio.ts +9 -2
- package/src/api/allnetwork/AllNetworkGetAddressBase.ts +2 -1
- package/src/api/device/DeviceChangePin.ts +4 -1
- package/src/api/device/DeviceRebootToBoardloader.ts +3 -1
- package/src/api/device/DeviceRebootToBootloader.ts +3 -1
- package/src/api/device/DeviceSettings.ts +34 -20
- package/src/api/device/DeviceVerify.ts +25 -0
- package/src/api/device/DeviceWipe.ts +4 -1
- package/src/api/firmware/FirmwareArtifactSource.ts +41 -14
- package/src/api/firmware/FirmwareHostBinding.ts +10 -0
- package/src/api/firmware/FirmwarePreparedResourceArchive.ts +16 -27
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +131 -76
- package/src/api/firmware/FirmwareUpdatePlan.ts +55 -82
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +32 -15
- package/src/api/firmware/protocolV2Release.ts +7 -2
- package/src/api/helpers/base64Data.ts +85 -0
- package/src/api/protocol-v2/DeviceFactoryInfoSet.ts +1 -1
- package/src/api/protocol-v2/DeviceFirmwareUpdate.ts +6 -28
- package/src/api/protocol-v2/DeviceGetFirmwareUpdateStatus.ts +7 -1
- package/src/api/protocol-v2/DeviceInfoGet.ts +3 -3
- package/src/api/protocol-v2/DeviceReboot.ts +5 -0
- package/src/api/protocol-v2/DeviceUploadNft.ts +61 -9
- package/src/api/protocol-v2/DeviceUploadWallpaper.ts +53 -19
- package/src/api/protocol-v2/helpers.ts +8 -0
- package/src/api/ton/TonSignMessage.ts +5 -3
- package/src/core/index.ts +264 -55
- package/src/data/messages/messages-protocol-v2.json +140 -13
- package/src/data-manager/DataManager.ts +46 -39
- package/src/data-manager/TransportManager.ts +3 -1
- package/src/device/Device.ts +210 -44
- package/src/device/DeviceCommands.ts +27 -18
- package/src/device/DeviceConnector.ts +17 -3
- package/src/device/DevicePool.ts +9 -2
- package/src/device/DeviceStateMapper.ts +30 -24
- package/src/deviceProfile/buildDeviceFeatures.ts +10 -5
- package/src/events/logBlockEvent.ts +14 -1
- package/src/events/ui-request.ts +3 -0
- package/src/index.ts +0 -10
- package/src/protocols/protocol-v2/features.ts +22 -5
- package/src/protocols/protocol-v2/index.ts +2 -0
- package/src/protocols/protocol-v2/resources.ts +110 -147
- package/src/protocols/protocol-v2/unlockPolicyRunner.ts +13 -1
- package/src/protocols/protocol-v2/walletSession.ts +65 -22
- package/src/types/api/firmwareUpdate.ts +1 -1
- package/src/types/api/firmwareUpdatePlan.ts +2 -2
- package/src/types/api/protocolV2.ts +1 -1
- package/src/types/device.ts +2 -1
- package/src/types/settings.ts +6 -34
- package/src/utils/deviceFeaturesCompat.ts +9 -4
- package/src/utils/deviceFeaturesUtils.ts +4 -0
- package/src/utils/deviceInfoUtils.ts +9 -2
- package/src/utils/deviceSettings.ts +11 -4
- package/src/utils/index.ts +1 -0
- package/src/utils/pro2Nft.ts +31 -8
- package/__tests__/firmware-memory-host.test.ts +0 -112
- package/dist/api/firmware/FirmwareMemoryHost.d.ts +0 -22
- package/dist/api/firmware/FirmwareMemoryHost.d.ts.map +0 -1
- package/src/api/firmware/FirmwareMemoryHost.ts +0 -142
package/src/device/Device.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
ERROR_CODES_REQUIRE_RELEASE,
|
|
10
10
|
HardwareError,
|
|
11
11
|
HardwareErrorCode,
|
|
12
|
+
canonicalizePro2BleAdvertisementName,
|
|
12
13
|
createDeferred,
|
|
13
14
|
createDeviceNotSupportMethodError,
|
|
14
15
|
} from '@onekeyfe/hd-shared';
|
|
@@ -61,6 +62,7 @@ import {
|
|
|
61
62
|
PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST,
|
|
62
63
|
type ProtocolV2RuntimeMode,
|
|
63
64
|
getProtocolV2RuntimeMode,
|
|
65
|
+
isLegacyProtocolV2ProtocolInfo,
|
|
64
66
|
requestProtocolV2DeviceInfo,
|
|
65
67
|
requestProtocolV2DeviceStatus,
|
|
66
68
|
requestProtocolV2ProtocolInfo,
|
|
@@ -234,6 +236,15 @@ export class Device extends EventEmitter {
|
|
|
234
236
|
*/
|
|
235
237
|
private deviceAcquired = false;
|
|
236
238
|
|
|
239
|
+
/**
|
|
240
|
+
* Connection-attempt generation. interruptionFromUser() pins the current
|
|
241
|
+
* attempt so a late acquire cannot finish, while the next public connect
|
|
242
|
+
* increments this and is allowed to proceed.
|
|
243
|
+
*/
|
|
244
|
+
private connectionAttempt = 0;
|
|
245
|
+
|
|
246
|
+
private interruptedAttempt: number | null = null;
|
|
247
|
+
|
|
237
248
|
/** Canonical device-state cache; legacy Features is a compatibility projection. */
|
|
238
249
|
private stateStore = new DeviceStateStore();
|
|
239
250
|
|
|
@@ -283,6 +294,9 @@ export class Device extends EventEmitter {
|
|
|
283
294
|
|
|
284
295
|
runPromise?: Deferred<void> | null;
|
|
285
296
|
|
|
297
|
+
/** Resolves only after the active run has completed its release path. */
|
|
298
|
+
private runCleanupPromise?: Promise<void>;
|
|
299
|
+
|
|
286
300
|
externalState: string[] = [];
|
|
287
301
|
|
|
288
302
|
unavailableCapabilities: UnavailableCapabilities = {};
|
|
@@ -425,6 +439,8 @@ export class Device extends EventEmitter {
|
|
|
425
439
|
expectedProtocol?: HardwareConnectProtocol,
|
|
426
440
|
options?: { throwOnRunPromiseError?: boolean; forceProtocolDetection?: boolean }
|
|
427
441
|
) {
|
|
442
|
+
const attempt = this.connectionAttempt;
|
|
443
|
+
this.throwIfInterruptedByUser();
|
|
428
444
|
const env = DataManager.getSettings('env');
|
|
429
445
|
const mainIdKey = DataManager.isBleConnect(env) ? 'id' : 'session';
|
|
430
446
|
const previousProtocol = this.originalDescriptor.protocolType;
|
|
@@ -445,7 +461,8 @@ export class Device extends EventEmitter {
|
|
|
445
461
|
undefined,
|
|
446
462
|
true,
|
|
447
463
|
strictProtocol,
|
|
448
|
-
undefined
|
|
464
|
+
undefined,
|
|
465
|
+
options?.forceProtocolDetection
|
|
449
466
|
);
|
|
450
467
|
this.mainId = (acquireResult as any)?.uuid ?? '';
|
|
451
468
|
Log.debug('Expected uuid:', this.mainId);
|
|
@@ -455,7 +472,8 @@ export class Device extends EventEmitter {
|
|
|
455
472
|
this.originalDescriptor.session,
|
|
456
473
|
undefined,
|
|
457
474
|
strictProtocol,
|
|
458
|
-
undefined
|
|
475
|
+
undefined,
|
|
476
|
+
options?.forceProtocolDetection
|
|
459
477
|
);
|
|
460
478
|
this.mainId = acquireResult as string | undefined;
|
|
461
479
|
Log.debug('Expected session id:', this.mainId);
|
|
@@ -477,6 +495,15 @@ export class Device extends EventEmitter {
|
|
|
477
495
|
if (detectedProtocol) {
|
|
478
496
|
this.originalDescriptor.protocolType = detectedProtocol;
|
|
479
497
|
}
|
|
498
|
+
if (this.interruptedAttempt === attempt || this.connectionAttempt !== attempt) {
|
|
499
|
+
const session = this.mainId;
|
|
500
|
+
if (session && this.deviceConnector?.disconnect) {
|
|
501
|
+
await this.deviceConnector.disconnect(session).catch(disconnectError => {
|
|
502
|
+
Log.debug('Ignored disconnect after user cancel during acquire', disconnectError);
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
throw ERRORS.TypedError(HardwareErrorCode.DeviceInterruptedFromUser);
|
|
506
|
+
}
|
|
480
507
|
this.deviceAcquired = true;
|
|
481
508
|
this.updateDescriptor({ [mainIdKey]: this.mainId } as unknown as DeviceDescriptor);
|
|
482
509
|
|
|
@@ -485,6 +512,10 @@ export class Device extends EventEmitter {
|
|
|
485
512
|
}
|
|
486
513
|
|
|
487
514
|
this.commands = new DeviceCommands(this, this.mainId ?? '');
|
|
515
|
+
// Protocol V2 runtime metadata belongs to one active transport link. A
|
|
516
|
+
// successful acquire creates a fresh link/session, so never carry cached
|
|
517
|
+
// ProtocolInfo or pre-initialize state across that boundary.
|
|
518
|
+
this.invalidateProtocolV2RuntimeState();
|
|
488
519
|
} catch (error) {
|
|
489
520
|
if (options?.forceProtocolDetection) {
|
|
490
521
|
this.originalDescriptor.protocolType = previousProtocol;
|
|
@@ -642,7 +673,8 @@ export class Device extends EventEmitter {
|
|
|
642
673
|
}
|
|
643
674
|
|
|
644
675
|
getCurrentBleName() {
|
|
645
|
-
|
|
676
|
+
const bleName = this.state?.identity.bleName ?? null;
|
|
677
|
+
return bleName ? canonicalizePro2BleAdvertisementName(bleName) : null;
|
|
646
678
|
}
|
|
647
679
|
|
|
648
680
|
getCurrentLabel() {
|
|
@@ -893,6 +925,7 @@ export class Device extends EventEmitter {
|
|
|
893
925
|
}
|
|
894
926
|
|
|
895
927
|
async initialize(options?: InitOptions) {
|
|
928
|
+
this.throwIfInterruptedByUser();
|
|
896
929
|
// Protocol V2 does not support legacy Initialize; use its dedicated flow.
|
|
897
930
|
if (this.isProtocolV2()) {
|
|
898
931
|
this.passphraseState = options?.passphraseState;
|
|
@@ -922,13 +955,18 @@ export class Device extends EventEmitter {
|
|
|
922
955
|
};
|
|
923
956
|
|
|
924
957
|
const expectedDeviceId = options?.deviceId;
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
//
|
|
958
|
+
|
|
959
|
+
if (expectedDeviceId && !(this.features && this.checkDeviceId(expectedDeviceId))) {
|
|
960
|
+
// No locally-cached evidence that the device at this path is the
|
|
961
|
+
// expected one (first contact, or the cached features already disagree
|
|
962
|
+
// with the caller). Establish identity with a context-free Initialize
|
|
963
|
+
// BEFORE any wallet context (session_id / passphrase_state) goes on
|
|
964
|
+
// the wire. In normal flows features are always fresh — enumerate /
|
|
965
|
+
// getFeatures run first and every call response refreshes them — so
|
|
966
|
+
// this extra round trip is confined to the ambiguous cases where the
|
|
967
|
+
// disclosure risk actually lives.
|
|
928
968
|
this.passphraseState = undefined;
|
|
929
|
-
|
|
930
|
-
this._updateFeatures(message);
|
|
931
|
-
await TransportManager.reconfigure(this.features);
|
|
969
|
+
await callInitialize({ is_contains_attach: true });
|
|
932
970
|
if (!this.checkDeviceId(expectedDeviceId)) {
|
|
933
971
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckDeviceIdError);
|
|
934
972
|
}
|
|
@@ -952,7 +990,46 @@ export class Device extends EventEmitter {
|
|
|
952
990
|
payload.derive_cardano = true;
|
|
953
991
|
}
|
|
954
992
|
|
|
955
|
-
|
|
993
|
+
if (this.features) {
|
|
994
|
+
// Re-sync the V1 message schema for THIS device before encoding
|
|
995
|
+
// Initialize: the process-global schema may still reflect another
|
|
996
|
+
// device (e.g. legacy-firmware Touch/Mini) on multi-device setups, and
|
|
997
|
+
// a stale legacy schema would silently strip passphrase_state /
|
|
998
|
+
// is_contains_attach from the wire message. Local operation, no wire
|
|
999
|
+
// I/O; a no-op when the schema is unchanged.
|
|
1000
|
+
await TransportManager.reconfigure(this.features);
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
// Initialize's own Features response carries device_id, so the physical
|
|
1004
|
+
// device identity is validated on the same round trip instead of via a
|
|
1005
|
+
// separate read-only GetFeatures preflight (which doubled the wire cost
|
|
1006
|
+
// of every deviceId-carrying call). The method fn has not run yet, so a
|
|
1007
|
+
// mismatch still fails before any wallet data can be derived, with the
|
|
1008
|
+
// same DeviceCheckDeviceIdError. Wallet-context selection is unchanged:
|
|
1009
|
+
// it is decided by the Initialize payload above either way.
|
|
1010
|
+
const assertExpectedDeviceIdentity = () => {
|
|
1011
|
+
if (expectedDeviceId && !this.checkDeviceId(expectedDeviceId)) {
|
|
1012
|
+
// The mismatched Initialize may have cached a session under the wrong
|
|
1013
|
+
// device's identity; drop it so no wallet context survives from it.
|
|
1014
|
+
// (This also evicts any session the wrong device legitimately cached
|
|
1015
|
+
// under the same passphraseState — a deliberate conservative purge
|
|
1016
|
+
// after a physical-swap event, consistent with
|
|
1017
|
+
// reconcileDeviceIdentity purging the previous device's sessions.)
|
|
1018
|
+
this.clearInternalState();
|
|
1019
|
+
throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckDeviceIdError);
|
|
1020
|
+
}
|
|
1021
|
+
};
|
|
1022
|
+
|
|
1023
|
+
try {
|
|
1024
|
+
await callInitialize(payload, options?.initSession);
|
|
1025
|
+
} catch (error) {
|
|
1026
|
+
// callInitialize can fail AFTER the wire call cached the session (e.g.
|
|
1027
|
+
// TransportManager.reconfigure rejecting); the identity check must
|
|
1028
|
+
// still run so a wrong-device session never survives the error path.
|
|
1029
|
+
assertExpectedDeviceIdentity();
|
|
1030
|
+
throw error;
|
|
1031
|
+
}
|
|
1032
|
+
assertExpectedDeviceIdentity();
|
|
956
1033
|
} catch (error) {
|
|
957
1034
|
Log.error('Initialization failed:', error);
|
|
958
1035
|
throw error;
|
|
@@ -977,11 +1054,7 @@ export class Device extends EventEmitter {
|
|
|
977
1054
|
});
|
|
978
1055
|
// The default request excludes SE/hash data and therefore uses basic scope.
|
|
979
1056
|
// Full version and verification data require getDeviceState({ scope: 'firmware' }).
|
|
980
|
-
|
|
981
|
-
deviceInfo,
|
|
982
|
-
options?.protocolV2DeviceInfoTimeoutMs
|
|
983
|
-
);
|
|
984
|
-
Log.debug('Protocol V2 features:', features);
|
|
1057
|
+
await this.probeProtocolV2RuntimeState(deviceInfo, options?.protocolV2DeviceInfoTimeoutMs);
|
|
985
1058
|
} catch (error) {
|
|
986
1059
|
Log.error('Protocol V2 initialization failed:', error);
|
|
987
1060
|
throw error;
|
|
@@ -1053,7 +1126,13 @@ export class Device extends EventEmitter {
|
|
|
1053
1126
|
}
|
|
1054
1127
|
|
|
1055
1128
|
if (refresh.has('status') && !initializedWithDeviceInfo) {
|
|
1056
|
-
|
|
1129
|
+
const cachedMode = this.state?.status.mode;
|
|
1130
|
+
await this.probeProtocolV2RuntimeState(refreshedDeviceInfo, undefined, {
|
|
1131
|
+
// Loader firmware does not support DeviceStatusGet. Renegotiate ProtocolInfo
|
|
1132
|
+
// during an explicit refresh so a device rebooted into application firmware
|
|
1133
|
+
// can leave the cached loader state.
|
|
1134
|
+
forceRuntimeContextRefresh: cachedMode === 'bootloader' || cachedMode === 'romloader',
|
|
1135
|
+
});
|
|
1057
1136
|
}
|
|
1058
1137
|
|
|
1059
1138
|
if (refresh.has('settings') && this.state?.status.mode === 'normal') {
|
|
@@ -1072,6 +1151,10 @@ export class Device extends EventEmitter {
|
|
|
1072
1151
|
return params.includeRaw ? cloneDeviceState(this.state) : createPublicDeviceState(this.state);
|
|
1073
1152
|
}
|
|
1074
1153
|
|
|
1154
|
+
async refreshProtocolV2SettingsAfterMutation() {
|
|
1155
|
+
return this.getDeviceState({ refreshSections: ['status', 'settings'] });
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1075
1158
|
_updateFeatures(protoFeatures: PROTO.Features | Features, initSession?: boolean) {
|
|
1076
1159
|
const previousDeviceId = this.getCurrentDeviceId();
|
|
1077
1160
|
let feat =
|
|
@@ -1101,9 +1184,10 @@ export class Device extends EventEmitter {
|
|
|
1101
1184
|
source,
|
|
1102
1185
|
changedKeys: result.changedKeys,
|
|
1103
1186
|
};
|
|
1104
|
-
Log.debug('Device state
|
|
1187
|
+
Log.debug('Device state updated', {
|
|
1105
1188
|
source,
|
|
1106
|
-
|
|
1189
|
+
revision: result.revision,
|
|
1190
|
+
changedKeyCount: result.changedKeys.length,
|
|
1107
1191
|
});
|
|
1108
1192
|
this.emit(DEVICE.STATE, this, event);
|
|
1109
1193
|
if (result.state.protocol === 'V1') {
|
|
@@ -1124,12 +1208,17 @@ export class Device extends EventEmitter {
|
|
|
1124
1208
|
return this.features;
|
|
1125
1209
|
}
|
|
1126
1210
|
|
|
1127
|
-
async ensureProtocolV2RuntimeContext(
|
|
1211
|
+
async ensureProtocolV2RuntimeContext(
|
|
1212
|
+
timeoutMs?: number,
|
|
1213
|
+
options?: { forceRefresh?: boolean }
|
|
1214
|
+
): Promise<ProtocolInfo> {
|
|
1128
1215
|
const cachedProtocolInfo =
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1216
|
+
options?.forceRefresh === true
|
|
1217
|
+
? undefined
|
|
1218
|
+
: this.protocolV2RuntimeContext ??
|
|
1219
|
+
(!this.protocolV2StateNeedsReload
|
|
1220
|
+
? this.state?.raw?.protocolV2ProtocolInfo ?? undefined
|
|
1221
|
+
: undefined);
|
|
1133
1222
|
if (cachedProtocolInfo) {
|
|
1134
1223
|
this.protocolV2RuntimeContext = cachedProtocolInfo;
|
|
1135
1224
|
return cachedProtocolInfo;
|
|
@@ -1169,10 +1258,19 @@ export class Device extends EventEmitter {
|
|
|
1169
1258
|
}
|
|
1170
1259
|
}
|
|
1171
1260
|
|
|
1172
|
-
async probeProtocolV2RuntimeState(
|
|
1173
|
-
|
|
1174
|
-
|
|
1261
|
+
async probeProtocolV2RuntimeState(
|
|
1262
|
+
deviceInfo?: ProtocolV2DeviceInfo,
|
|
1263
|
+
timeoutMs?: number,
|
|
1264
|
+
options?: {
|
|
1265
|
+
forceRuntimeContextRefresh?: boolean;
|
|
1266
|
+
}
|
|
1267
|
+
) {
|
|
1268
|
+
const protocolInfo = await this.ensureProtocolV2RuntimeContext(timeoutMs, {
|
|
1269
|
+
forceRefresh: options?.forceRuntimeContextRefresh,
|
|
1270
|
+
});
|
|
1175
1271
|
const runtimeDeviceInfo = deviceInfo ?? this.state?.raw?.protocolV2DeviceInfo;
|
|
1272
|
+
const runtimeMode = getProtocolV2RuntimeMode(protocolInfo, runtimeDeviceInfo);
|
|
1273
|
+
const legacyProtocolInfo = isLegacyProtocolV2ProtocolInfo(protocolInfo);
|
|
1176
1274
|
const protocolV2DeviceType = runtimeDeviceInfo
|
|
1177
1275
|
? resolveProtocolV2DeviceIdentity(runtimeDeviceInfo.hw?.Device_type).deviceType
|
|
1178
1276
|
: this.getCurrentDeviceType();
|
|
@@ -1186,10 +1284,9 @@ export class Device extends EventEmitter {
|
|
|
1186
1284
|
'Protocol V2 romloader mode is only supported for Pro2 and Neo.'
|
|
1187
1285
|
);
|
|
1188
1286
|
}
|
|
1189
|
-
const deviceStatusSupported =
|
|
1190
|
-
|
|
1191
|
-
PROTOCOL_V2_DEVICE_STATUS_GET_MESSAGE_TYPE
|
|
1192
|
-
);
|
|
1287
|
+
const deviceStatusSupported =
|
|
1288
|
+
legacyProtocolInfo ||
|
|
1289
|
+
supportsProtocolV2Message(protocolInfo, PROTOCOL_V2_DEVICE_STATUS_GET_MESSAGE_TYPE);
|
|
1193
1290
|
|
|
1194
1291
|
if (runtimeMode === 'bootloader' || runtimeMode === 'romloader') {
|
|
1195
1292
|
return this.updateProtocolV2Features(deviceInfo, null, runtimeMode, protocolInfo);
|
|
@@ -1250,8 +1347,7 @@ export class Device extends EventEmitter {
|
|
|
1250
1347
|
});
|
|
1251
1348
|
}
|
|
1252
1349
|
|
|
1253
|
-
|
|
1254
|
-
this.deviceAcquired = false;
|
|
1350
|
+
private invalidateProtocolV2RuntimeState() {
|
|
1255
1351
|
if (!this.isProtocolV2()) return;
|
|
1256
1352
|
this.protocolV2StateNeedsReload = true;
|
|
1257
1353
|
this.protocolV2RuntimeContext = undefined;
|
|
@@ -1260,6 +1356,11 @@ export class Device extends EventEmitter {
|
|
|
1260
1356
|
this.clearPreInitialized();
|
|
1261
1357
|
}
|
|
1262
1358
|
|
|
1359
|
+
markTransportDisconnected() {
|
|
1360
|
+
this.deviceAcquired = false;
|
|
1361
|
+
this.invalidateProtocolV2RuntimeState();
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1263
1364
|
invalidateAfterWipe() {
|
|
1264
1365
|
const deviceId = this.getCurrentDeviceId();
|
|
1265
1366
|
if (deviceId) {
|
|
@@ -1269,10 +1370,7 @@ export class Device extends EventEmitter {
|
|
|
1269
1370
|
if (this.originalDescriptor.path !== deviceId) {
|
|
1270
1371
|
deviceWalletSessionStore.deleteDevice(this.originalDescriptor.path);
|
|
1271
1372
|
}
|
|
1272
|
-
this.
|
|
1273
|
-
this.protocolV2RuntimeContext = undefined;
|
|
1274
|
-
this.protocolV2RuntimeContextPromise = undefined;
|
|
1275
|
-
this.protocolV2RuntimeContextRequestToken = undefined;
|
|
1373
|
+
this.invalidateProtocolV2RuntimeState();
|
|
1276
1374
|
}
|
|
1277
1375
|
|
|
1278
1376
|
this.passphraseState = undefined;
|
|
@@ -1284,11 +1382,7 @@ export class Device extends EventEmitter {
|
|
|
1284
1382
|
markProtocolV2Reboot(rebootType: DeviceRebootType) {
|
|
1285
1383
|
if (!this.isProtocolV2()) return;
|
|
1286
1384
|
|
|
1287
|
-
this.
|
|
1288
|
-
this.protocolV2RuntimeContext = undefined;
|
|
1289
|
-
this.protocolV2RuntimeContextPromise = undefined;
|
|
1290
|
-
this.protocolV2RuntimeContextRequestToken = undefined;
|
|
1291
|
-
this.clearPreInitialized();
|
|
1385
|
+
this.invalidateProtocolV2RuntimeState();
|
|
1292
1386
|
let loaderMode: 'bootloader' | 'romloader' | undefined;
|
|
1293
1387
|
if (rebootType === DeviceRebootType.Bootloader) {
|
|
1294
1388
|
loaderMode = 'bootloader';
|
|
@@ -1362,6 +1456,10 @@ export class Device extends EventEmitter {
|
|
|
1362
1456
|
if (device.features) {
|
|
1363
1457
|
this._updateFeatures(device.features);
|
|
1364
1458
|
}
|
|
1459
|
+
// Adopting another Device instance's command channel also crosses an active
|
|
1460
|
+
// link boundary. Renegotiate runtime metadata on that channel instead of
|
|
1461
|
+
// retaining ProtocolInfo from the previous instance/session.
|
|
1462
|
+
this.invalidateProtocolV2RuntimeState();
|
|
1365
1463
|
}
|
|
1366
1464
|
|
|
1367
1465
|
async run(fn?: () => Promise<void>, options?: RunOptions) {
|
|
@@ -1370,16 +1468,25 @@ export class Device extends EventEmitter {
|
|
|
1370
1468
|
Log.debug('[Device] run error:', 'Device is running, but will cancel previous operate');
|
|
1371
1469
|
}
|
|
1372
1470
|
|
|
1471
|
+
this.beginConnectionAttempt();
|
|
1373
1472
|
options = parseRunOptions(options);
|
|
1374
1473
|
|
|
1375
1474
|
const runPromise = createDeferred<void>();
|
|
1376
1475
|
this.runPromise = runPromise;
|
|
1377
|
-
this._runInner(fn, options, runPromise).catch(error => {
|
|
1476
|
+
const cleanupPromise = this._runInner(fn, options, runPromise).catch(error => {
|
|
1378
1477
|
if (this.runPromise === runPromise) {
|
|
1379
1478
|
this.runPromise = null;
|
|
1380
1479
|
}
|
|
1381
1480
|
runPromise.reject(error);
|
|
1382
1481
|
});
|
|
1482
|
+
this.runCleanupPromise = cleanupPromise;
|
|
1483
|
+
cleanupPromise
|
|
1484
|
+
.finally(() => {
|
|
1485
|
+
if (this.runCleanupPromise === cleanupPromise) {
|
|
1486
|
+
this.runCleanupPromise = undefined;
|
|
1487
|
+
}
|
|
1488
|
+
})
|
|
1489
|
+
.catch(() => undefined);
|
|
1383
1490
|
return runPromise.promise;
|
|
1384
1491
|
}
|
|
1385
1492
|
|
|
@@ -1491,13 +1598,32 @@ export class Device extends EventEmitter {
|
|
|
1491
1598
|
|
|
1492
1599
|
async interruptionFromUser() {
|
|
1493
1600
|
const error = ERRORS.TypedError(HardwareErrorCode.DeviceInterruptedFromUser);
|
|
1494
|
-
|
|
1601
|
+
this.interruptedAttempt = this.connectionAttempt;
|
|
1602
|
+
const cleanupPromise = this.runCleanupPromise;
|
|
1603
|
+
const { cancelableAction } = this;
|
|
1604
|
+
if (cancelableAction) {
|
|
1605
|
+
await cancelableAction(error);
|
|
1606
|
+
} else if (this.shouldSendFallbackProtocolCancel()) {
|
|
1607
|
+
await this.commands?.cancelDevice?.().catch(cancelError => {
|
|
1608
|
+
Log.debug('Protocol V2 fallback cancel error', cancelError);
|
|
1609
|
+
});
|
|
1610
|
+
} else if (!this.hasDeviceAcquire()) {
|
|
1611
|
+
// Pairing / connect-native / probe: drop the physical link only.
|
|
1612
|
+
// Never acquire or send protocol Cancel just to abort setup.
|
|
1613
|
+
if (this.mainId && this.deviceConnector?.disconnect) {
|
|
1614
|
+
await this.deviceConnector.disconnect(this.mainId).catch(disconnectError => {
|
|
1615
|
+
Log.debug('Ignored disconnect during user cancel without acquire', disconnectError);
|
|
1616
|
+
});
|
|
1617
|
+
}
|
|
1618
|
+
this.markTransportDisconnected();
|
|
1619
|
+
}
|
|
1495
1620
|
await this.commands?.cancel();
|
|
1496
1621
|
|
|
1497
1622
|
if (this.runPromise) {
|
|
1498
1623
|
this.runPromise.reject(error);
|
|
1499
1624
|
this.runPromise = null;
|
|
1500
1625
|
}
|
|
1626
|
+
await cleanupPromise?.catch(() => undefined);
|
|
1501
1627
|
}
|
|
1502
1628
|
|
|
1503
1629
|
setCancelableAction(callback: (err?: Error) => Promise<unknown>) {
|
|
@@ -1553,6 +1679,44 @@ export class Device extends EventEmitter {
|
|
|
1553
1679
|
return typeof this.originalDescriptor.session === 'string';
|
|
1554
1680
|
}
|
|
1555
1681
|
|
|
1682
|
+
beginConnectionAttempt() {
|
|
1683
|
+
this.connectionAttempt += 1;
|
|
1684
|
+
return this.connectionAttempt;
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
wasInterruptedByUser() {
|
|
1688
|
+
return (
|
|
1689
|
+
typeof this.interruptedAttempt === 'number' &&
|
|
1690
|
+
this.interruptedAttempt === this.connectionAttempt
|
|
1691
|
+
);
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
private throwIfInterruptedByUser() {
|
|
1695
|
+
if (this.wasInterruptedByUser()) {
|
|
1696
|
+
throw ERRORS.TypedError(HardwareErrorCode.DeviceInterruptedFromUser);
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
/**
|
|
1701
|
+
* Protocol Cancel is only for an acquired session that is already in a
|
|
1702
|
+
* user-facing prompt. Connect, probe and initialize must not send Cancel
|
|
1703
|
+
* and must not re-acquire just to deliver one.
|
|
1704
|
+
*/
|
|
1705
|
+
private shouldSendFallbackProtocolCancel() {
|
|
1706
|
+
if (!this.hasDeviceAcquire() || !this.isProtocolV2()) {
|
|
1707
|
+
return false;
|
|
1708
|
+
}
|
|
1709
|
+
if (!this.hasOpenProtocolV2UiInteraction()) {
|
|
1710
|
+
return false;
|
|
1711
|
+
}
|
|
1712
|
+
const env = DataManager.getSettings('env');
|
|
1713
|
+
return (
|
|
1714
|
+
DataManager.isBleConnect(env) ||
|
|
1715
|
+
DataManager.isBrowserWebUsb(env) ||
|
|
1716
|
+
DataManager.isDesktopWebUsb(env)
|
|
1717
|
+
);
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1556
1720
|
hasDeviceAcquire() {
|
|
1557
1721
|
const env = DataManager.getSettings('env');
|
|
1558
1722
|
if (DataManager.isBleConnect(env)) {
|
|
@@ -1841,7 +2005,8 @@ export class Device extends EventEmitter {
|
|
|
1841
2005
|
passphraseState?: string,
|
|
1842
2006
|
useEmptyPassphrase?: boolean,
|
|
1843
2007
|
skipPassphraseCheck?: boolean,
|
|
1844
|
-
deriveCardano?: boolean
|
|
2008
|
+
deriveCardano?: boolean,
|
|
2009
|
+
mainPinSelected?: boolean
|
|
1845
2010
|
) {
|
|
1846
2011
|
if (this.isUnacquired()) return false;
|
|
1847
2012
|
|
|
@@ -1852,6 +2017,7 @@ export class Device extends EventEmitter {
|
|
|
1852
2017
|
onlyMainPin: useEmptyPassphrase,
|
|
1853
2018
|
deriveCardano,
|
|
1854
2019
|
rejectAttachPinForMainWallet: useEmptyPassphrase === true,
|
|
2020
|
+
mainPinSelected,
|
|
1855
2021
|
});
|
|
1856
2022
|
|
|
1857
2023
|
// Main wallet and unlock Attach Pin, throw safe error
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
type Transport,
|
|
8
8
|
type TransportCallOptions,
|
|
9
9
|
getSafeTransportLogPayload,
|
|
10
|
+
isProtocolV2LinkDisabledFailure,
|
|
10
11
|
} from '@onekeyfe/hd-transport';
|
|
11
12
|
|
|
12
13
|
import TransportManager from '../data-manager/TransportManager';
|
|
@@ -68,7 +69,7 @@ const DEVICE_CONTROL_CALLS = new Set([
|
|
|
68
69
|
// Older Protocol V2 firmware may omit the cancellation subcode, so retain a
|
|
69
70
|
// narrow message fallback for compatibility.
|
|
70
71
|
const isProtocolV2ActionCancelledMessage = (message: string) =>
|
|
71
|
-
/^(?:cancel(?:led|ed)(?: on device)?|confirm dismissed|user cancel(?:led|ed)(?:\s+.*)?)$/i.test(
|
|
72
|
+
/^(?:cancel(?:led|ed)(?: on device)?|confirm dismissed|update cancel(?:led|ed)|user cancel(?:led|ed)(?:\s+.*)?)$/i.test(
|
|
72
73
|
message
|
|
73
74
|
);
|
|
74
75
|
|
|
@@ -263,6 +264,7 @@ export class DeviceCommands {
|
|
|
263
264
|
}
|
|
264
265
|
const activeCall = this.callPromise;
|
|
265
266
|
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
267
|
+
let timedOut = false;
|
|
266
268
|
const cancellation = (async () => {
|
|
267
269
|
await this.dispose(true);
|
|
268
270
|
await activeCall?.catch(() => undefined);
|
|
@@ -272,11 +274,23 @@ export class DeviceCommands {
|
|
|
272
274
|
await Promise.race([
|
|
273
275
|
cancellation,
|
|
274
276
|
new Promise<void>(resolve => {
|
|
275
|
-
timer = setTimeout(
|
|
277
|
+
timer = setTimeout(() => {
|
|
278
|
+
timedOut = true;
|
|
279
|
+
resolve();
|
|
280
|
+
}, 10 * 1000);
|
|
276
281
|
}),
|
|
277
282
|
]);
|
|
278
283
|
} finally {
|
|
279
284
|
if (timer) clearTimeout(timer);
|
|
285
|
+
if (
|
|
286
|
+
timedOut &&
|
|
287
|
+
this.transport.name === 'ReactNativeBleTransport' &&
|
|
288
|
+
this.transport.disconnect
|
|
289
|
+
) {
|
|
290
|
+
await this.transport.disconnect(this.mainId).catch(error => {
|
|
291
|
+
Log.debug('BLE cancellation timeout disconnect error (ignored)', error);
|
|
292
|
+
});
|
|
293
|
+
}
|
|
280
294
|
if (this.callPromise === activeCall) {
|
|
281
295
|
this.callPromise = undefined;
|
|
282
296
|
}
|
|
@@ -304,13 +318,6 @@ export class DeviceCommands {
|
|
|
304
318
|
const promise = this.transport.call(this.mainId, type, msg ?? {}, options) as any;
|
|
305
319
|
this.callPromise = promise;
|
|
306
320
|
const res = await promise;
|
|
307
|
-
if (!shouldReduceDebug) {
|
|
308
|
-
LogCore.debug(
|
|
309
|
-
'[DeviceCommands] [call] Received',
|
|
310
|
-
res.type,
|
|
311
|
-
getSafeTransportLogPayload(res.message, res.type)
|
|
312
|
-
);
|
|
313
|
-
}
|
|
314
321
|
return res;
|
|
315
322
|
} catch (error) {
|
|
316
323
|
LogCore.debug('[DeviceCommands] [call] Received error', {
|
|
@@ -445,13 +452,10 @@ export class DeviceCommands {
|
|
|
445
452
|
if (!shouldReduceDebugForCall(callType)) {
|
|
446
453
|
Log.debug('_filterCommonTypes: ', {
|
|
447
454
|
request: callType,
|
|
448
|
-
response:
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
message: getSafeTransportLogPayload(res.message, res.type),
|
|
453
|
-
}
|
|
454
|
-
: res.type,
|
|
455
|
+
response: {
|
|
456
|
+
type: res.type,
|
|
457
|
+
message: getSafeTransportLogPayload(res.message, res.type),
|
|
458
|
+
},
|
|
455
459
|
});
|
|
456
460
|
}
|
|
457
461
|
} catch (error) {
|
|
@@ -491,7 +495,7 @@ export class DeviceCommands {
|
|
|
491
495
|
if (message === 'Please confirm the BlindSign enabled') {
|
|
492
496
|
error = ERRORS.TypedError(HardwareErrorCode.BlindSignDisabled);
|
|
493
497
|
}
|
|
494
|
-
if (message === 'File already exists') {
|
|
498
|
+
if (message === 'File already exists' || message === 'NFT already exists') {
|
|
495
499
|
error = ERRORS.TypedError(HardwareErrorCode.FileAlreadyExists);
|
|
496
500
|
}
|
|
497
501
|
if (message?.includes('bytes overflow')) {
|
|
@@ -505,7 +509,12 @@ export class DeviceCommands {
|
|
|
505
509
|
}
|
|
506
510
|
}
|
|
507
511
|
|
|
508
|
-
if (code
|
|
512
|
+
if (isProtocolV2LinkDisabledFailure(code, message)) {
|
|
513
|
+
error = ERRORS.TypedError(HardwareErrorCode.BleUnavailableWhileUsbConnected, undefined, {
|
|
514
|
+
failureCode: code,
|
|
515
|
+
firmwareMessage: message,
|
|
516
|
+
});
|
|
517
|
+
} else if (code === 'Failure_ProcessError') {
|
|
509
518
|
const normalizedMessage = message?.trim() ?? '';
|
|
510
519
|
const isProtocolV2ActionCancelledFailure =
|
|
511
520
|
this.device.isProtocolV2() && isProtocolV2ActionCancelledMessage(normalizedMessage);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isProtocolV2LinkDisabledError } from '@onekeyfe/hd-transport';
|
|
1
2
|
import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
3
|
|
|
3
4
|
import { safeThrowError } from '../constants';
|
|
@@ -94,7 +95,9 @@ export default class DeviceConnector {
|
|
|
94
95
|
session?: string | null,
|
|
95
96
|
forceCleanRunPromise?: boolean,
|
|
96
97
|
expectedProtocol?: HardwareConnectProtocol,
|
|
97
|
-
protocolHint?: HardwareConnectProtocol
|
|
98
|
+
protocolHint?: HardwareConnectProtocol,
|
|
99
|
+
forceProtocolDetection?: boolean,
|
|
100
|
+
skipProtocolProbe?: boolean
|
|
98
101
|
) {
|
|
99
102
|
Log.debug('acquire', path, session, expectedProtocol, protocolHint);
|
|
100
103
|
const env = DataManager.getSettings('env');
|
|
@@ -102,18 +105,23 @@ export default class DeviceConnector {
|
|
|
102
105
|
const transport = this.getActiveTransport();
|
|
103
106
|
let res;
|
|
104
107
|
if (DataManager.isBleConnect(env)) {
|
|
105
|
-
|
|
108
|
+
const acquireInput: Parameters<Transport['acquire']>[0] = {
|
|
106
109
|
uuid: path,
|
|
107
110
|
forceCleanRunPromise,
|
|
108
111
|
expectedProtocol,
|
|
109
112
|
protocolHint,
|
|
110
|
-
|
|
113
|
+
forceProtocolDetection,
|
|
114
|
+
skipProtocolProbe,
|
|
115
|
+
};
|
|
116
|
+
res = await transport.acquire(acquireInput);
|
|
111
117
|
} else {
|
|
112
118
|
res = await transport.acquire({
|
|
113
119
|
path,
|
|
114
120
|
previous: session ?? null,
|
|
115
121
|
expectedProtocol,
|
|
116
122
|
protocolHint,
|
|
123
|
+
forceProtocolDetection,
|
|
124
|
+
skipProtocolProbe,
|
|
117
125
|
});
|
|
118
126
|
}
|
|
119
127
|
if (expectedProtocol) {
|
|
@@ -134,6 +142,12 @@ export default class DeviceConnector {
|
|
|
134
142
|
return res;
|
|
135
143
|
} catch (error) {
|
|
136
144
|
Log.error('acquire error: ', error.message);
|
|
145
|
+
if (isProtocolV2LinkDisabledError(error)) {
|
|
146
|
+
throw ERRORS.TypedError(HardwareErrorCode.BleUnavailableWhileUsbConnected, undefined, {
|
|
147
|
+
failureCode: error.failureCode,
|
|
148
|
+
firmwareMessage: error.firmwareMessage,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
137
151
|
safeThrowError(error);
|
|
138
152
|
}
|
|
139
153
|
}
|
package/src/device/DevicePool.ts
CHANGED
|
@@ -172,6 +172,9 @@ export class DevicePool extends EventEmitter {
|
|
|
172
172
|
const device = cachedDevice ?? Device.fromDescriptor(descriptor);
|
|
173
173
|
if (isNewDevice || forceProtocolDetection) {
|
|
174
174
|
device.deviceConnector = this.connector;
|
|
175
|
+
// Search/discovery acquires outside Device.run(). Start a new attempt so
|
|
176
|
+
// a previous user cancel does not hide this device from later searches.
|
|
177
|
+
device.beginConnectionAttempt?.();
|
|
175
178
|
if (forceProtocolDetection && !isNewDevice) {
|
|
176
179
|
await device.acquire(initOptions?.connectProtocol, { forceProtocolDetection: true });
|
|
177
180
|
} else {
|
|
@@ -218,9 +221,13 @@ export class DevicePool extends EventEmitter {
|
|
|
218
221
|
* Device.getDeviceState skips unsupported status/settings calls in loader mode.
|
|
219
222
|
*/
|
|
220
223
|
static async _refreshProtocolV2DiscoveryState(device: Device) {
|
|
221
|
-
await device.getDeviceState({
|
|
224
|
+
await device.getDeviceState({
|
|
225
|
+
refreshSections: ['status'],
|
|
226
|
+
});
|
|
222
227
|
try {
|
|
223
|
-
await device.getDeviceState({
|
|
228
|
+
await device.getDeviceState({
|
|
229
|
+
refreshSections: ['settings'],
|
|
230
|
+
});
|
|
224
231
|
} catch (error) {
|
|
225
232
|
Log.debug('Unable to refresh Protocol V2 device label during discovery', error);
|
|
226
233
|
}
|