@onekeyfe/hd-core 1.2.0-alpha.33 → 1.2.0-alpha.35
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__/DeviceCommands.test.ts +84 -0
- package/__tests__/check-all-firmware-release-protocol-v2.test.ts +31 -0
- package/__tests__/core-dispose.test.ts +3 -3
- package/__tests__/device-lifecycle-events.test.ts +52 -0
- package/__tests__/device-pool-state.test.ts +14 -2
- package/__tests__/device-settings.test.ts +25 -0
- package/__tests__/device-state-mapper.test.ts +13 -2
- package/__tests__/device-state-projector.test.ts +2 -2
- package/__tests__/device-utils.test.ts +1 -0
- package/__tests__/device-wallet-session-store.test.ts +137 -17
- package/__tests__/evmSignTransaction.test.ts +69 -0
- package/__tests__/get-device-state.test.ts +78 -30
- package/__tests__/kaspaSignTransaction.test.ts +9 -0
- package/__tests__/known-device-public-types.type-test.ts +3 -0
- package/__tests__/logBlockEvent.test.ts +89 -5
- package/__tests__/open-wallet-session.test.ts +499 -60
- package/__tests__/pro2Wallpaper.test.ts +1 -1
- package/__tests__/protocol-v2.test.ts +1180 -169
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +2 -0
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/GetPassphraseState.d.ts.map +1 -1
- package/dist/api/OpenWalletSession.d.ts.map +1 -1
- package/dist/api/device/DeviceSettings.d.ts.map +1 -1
- package/dist/api/evm/EVMSignTypedData.d.ts.map +1 -1
- package/dist/api/evm/protocol.d.ts +3 -0
- package/dist/api/evm/protocol.d.ts.map +1 -0
- package/dist/api/kaspa/KaspaSignTransaction.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceGetOnboardingStatus.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/device/Device.d.ts +10 -4
- package/dist/device/Device.d.ts.map +1 -1
- 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 +1 -0
- package/dist/device/DevicePool.d.ts.map +1 -1
- package/dist/device/DeviceStateMapper.d.ts.map +1 -1
- package/dist/device/DeviceStateProjector.d.ts.map +1 -1
- package/dist/device/DeviceWalletSessionStore.d.ts +7 -0
- package/dist/device/DeviceWalletSessionStore.d.ts.map +1 -1
- package/dist/deviceProfile/buildDeviceFeatures.d.ts.map +1 -1
- package/dist/deviceProfile/protocolV2DeviceIdentity.d.ts +7 -0
- package/dist/deviceProfile/protocolV2DeviceIdentity.d.ts.map +1 -0
- package/dist/events/logBlockEvent.d.ts +2 -0
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/index.d.ts +25 -11
- package/dist/index.js +1037 -838
- package/dist/protocols/protocol-v2/features.d.ts +17 -6
- 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/settingsUnlockPolicy.d.ts +1 -0
- package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/walletSession.d.ts +1 -10
- package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
- package/dist/types/api/protocolV2.d.ts +2 -2
- package/dist/types/api/protocolV2.d.ts.map +1 -1
- package/dist/types/device.d.ts +6 -3
- package/dist/types/device.d.ts.map +1 -1
- package/dist/types/params.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesUtils.d.ts +0 -5
- package/dist/utils/deviceFeaturesUtils.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/pro2Wallpaper.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/CheckAllFirmwareRelease.ts +11 -81
- package/src/api/FirmwareUpdateV4.ts +59 -25
- package/src/api/GetPassphraseState.ts +11 -2
- package/src/api/OpenWalletSession.ts +16 -8
- package/src/api/device/DeviceSettings.ts +8 -1
- package/src/api/evm/EVMGetAddress.ts +2 -2
- package/src/api/evm/EVMGetPublicKey.ts +2 -2
- package/src/api/evm/EVMSignMessage.ts +2 -2
- package/src/api/evm/EVMSignTransaction.ts +2 -2
- package/src/api/evm/EVMSignTypedData.ts +35 -45
- package/src/api/evm/EVMVerifyMessage.ts +2 -2
- package/src/api/evm/protocol.ts +6 -0
- package/src/api/kaspa/KaspaSignTransaction.ts +7 -0
- package/src/api/protocol-v2/DeviceGetOnboardingStatus.ts +2 -2
- package/src/api/protocol-v2/DeviceUploadWallpaper.ts +1 -1
- package/src/core/index.ts +7 -5
- package/src/data/messages/messages-protocol-v2.json +393 -485
- package/src/device/Device.ts +98 -44
- package/src/device/DeviceCommands.ts +12 -2
- package/src/device/DeviceConnector.ts +10 -7
- package/src/device/DevicePool.ts +5 -3
- package/src/device/DeviceStateMapper.ts +5 -3
- package/src/device/DeviceStateProjector.ts +0 -7
- package/src/device/DeviceWalletSessionStore.ts +43 -4
- package/src/deviceProfile/buildDeviceFeatures.ts +11 -4
- package/src/deviceProfile/protocolV2DeviceIdentity.ts +32 -0
- package/src/events/logBlockEvent.ts +84 -1
- package/src/protocols/protocol-v2/deviceSession.ts +1 -1
- package/src/protocols/protocol-v2/features.ts +58 -16
- package/src/protocols/protocol-v2/index.ts +5 -0
- package/src/protocols/protocol-v2/settingsUnlockPolicy.ts +8 -3
- package/src/protocols/protocol-v2/unlockRetry.ts +18 -7
- package/src/protocols/protocol-v2/walletSession.ts +144 -62
- package/src/types/api/protocolV2.ts +2 -2
- package/src/types/device.ts +8 -2
- package/src/types/params.ts +2 -1
- package/src/utils/deviceFeaturesCompat.ts +8 -1
- package/src/utils/pro2Wallpaper.ts +3 -9
- package/tsconfig.type-tests.json +5 -1
package/src/device/Device.ts
CHANGED
|
@@ -55,6 +55,7 @@ import { DataManager } from '../data-manager';
|
|
|
55
55
|
import TransportManager from '../data-manager/TransportManager';
|
|
56
56
|
import { toHardened } from '../api/helpers/pathUtils';
|
|
57
57
|
import {
|
|
58
|
+
PROTOCOL_V2_DEVICE_STATUS_GET_MESSAGE_TYPE,
|
|
58
59
|
PROTOCOL_V2_FEATURES_DEVICE_INFO_REQUEST,
|
|
59
60
|
PROTOCOL_V2_FULL_DEVICE_INFO_REQUEST,
|
|
60
61
|
PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST,
|
|
@@ -62,8 +63,11 @@ import {
|
|
|
62
63
|
getProtocolV2RuntimeMode,
|
|
63
64
|
requestProtocolV2DeviceInfo,
|
|
64
65
|
requestProtocolV2DeviceStatus,
|
|
66
|
+
requestProtocolV2ProtocolInfo,
|
|
67
|
+
supportsProtocolV2Message,
|
|
65
68
|
} from '../protocols/protocol-v2/features';
|
|
66
69
|
import { buildProtocolV1FeaturesPayload } from '../deviceProfile';
|
|
70
|
+
import { resolveProtocolV2DeviceIdentity } from '../deviceProfile/protocolV2DeviceIdentity';
|
|
67
71
|
|
|
68
72
|
import type { PROTO } from '../constants';
|
|
69
73
|
import type { DeviceStateReadOptions } from '../types/api/getDeviceState';
|
|
@@ -77,6 +81,7 @@ import type { Deferred, HardwareConnectProtocol } from '@onekeyfe/hd-shared';
|
|
|
77
81
|
import type {
|
|
78
82
|
OneKeyDeviceInfo as DeviceDescriptor,
|
|
79
83
|
DeviceStatus,
|
|
84
|
+
ProtocolInfo,
|
|
80
85
|
ProtocolV2DeviceInfo,
|
|
81
86
|
Success,
|
|
82
87
|
} from '@onekeyfe/hd-transport';
|
|
@@ -280,7 +285,7 @@ export class Device extends EventEmitter {
|
|
|
280
285
|
|
|
281
286
|
// simplified object to pass via postMessage
|
|
282
287
|
toMessageObject(): DeviceTyped | null {
|
|
283
|
-
if (this.isUnacquired()) return null;
|
|
288
|
+
if (this.isUnacquired() || !this.features) return null;
|
|
284
289
|
|
|
285
290
|
const env = DataManager.getSettings('env');
|
|
286
291
|
const deviceType = this.getCurrentDeviceType();
|
|
@@ -297,6 +302,8 @@ export class Device extends EventEmitter {
|
|
|
297
302
|
return {
|
|
298
303
|
/** Android uses a MAC address, while iOS and USB use transport-specific identifiers. */
|
|
299
304
|
connectId: DataManager.isBleConnect(env) ? this.mainId || null : connectId,
|
|
305
|
+
/** Persist this after the first active probe so later calls do not need to guess. */
|
|
306
|
+
connectProtocol: this.originalDescriptor.protocolType,
|
|
300
307
|
/** Stable physical-device identity. */
|
|
301
308
|
serialNo,
|
|
302
309
|
/** @deprecated Use serialNo instead. */
|
|
@@ -364,12 +371,12 @@ export class Device extends EventEmitter {
|
|
|
364
371
|
}
|
|
365
372
|
|
|
366
373
|
async acquire(
|
|
367
|
-
|
|
374
|
+
expectedProtocol?: HardwareConnectProtocol,
|
|
368
375
|
options?: { throwOnRunPromiseError?: boolean }
|
|
369
376
|
) {
|
|
370
377
|
const env = DataManager.getSettings('env');
|
|
371
378
|
const mainIdKey = DataManager.isBleConnect(env) ? 'id' : 'session';
|
|
372
|
-
const
|
|
379
|
+
const protocolHint = expectedProtocol ? undefined : this.originalDescriptor.protocolType;
|
|
373
380
|
try {
|
|
374
381
|
let acquireResult: unknown;
|
|
375
382
|
if (DataManager.isBleConnect(env)) {
|
|
@@ -381,7 +388,8 @@ export class Device extends EventEmitter {
|
|
|
381
388
|
this.originalDescriptor.id,
|
|
382
389
|
undefined,
|
|
383
390
|
true,
|
|
384
|
-
expectedProtocol
|
|
391
|
+
expectedProtocol,
|
|
392
|
+
protocolHint
|
|
385
393
|
);
|
|
386
394
|
this.mainId = (acquireResult as any)?.uuid ?? '';
|
|
387
395
|
Log.debug('Expected uuid:', this.mainId);
|
|
@@ -390,7 +398,8 @@ export class Device extends EventEmitter {
|
|
|
390
398
|
this.originalDescriptor.path,
|
|
391
399
|
this.originalDescriptor.session,
|
|
392
400
|
undefined,
|
|
393
|
-
expectedProtocol
|
|
401
|
+
expectedProtocol,
|
|
402
|
+
protocolHint
|
|
394
403
|
);
|
|
395
404
|
this.mainId = acquireResult as string | undefined;
|
|
396
405
|
Log.debug('Expected session id:', this.mainId);
|
|
@@ -717,13 +726,20 @@ export class Device extends EventEmitter {
|
|
|
717
726
|
return deviceWalletSessionStore.get(deviceId, this.passphraseState);
|
|
718
727
|
}
|
|
719
728
|
|
|
729
|
+
getStandardInternalState(_deviceId?: string) {
|
|
730
|
+
const deviceId = this.getSessionCacheDeviceKey(_deviceId);
|
|
731
|
+
if (!deviceId) return undefined;
|
|
732
|
+
return deviceWalletSessionStore.getStandard(deviceId);
|
|
733
|
+
}
|
|
734
|
+
|
|
720
735
|
// attach to pin to fix internal state
|
|
721
736
|
updateInternalState(
|
|
722
737
|
enablePassphrase: boolean,
|
|
723
738
|
passphraseState: string | undefined,
|
|
724
739
|
deviceId: string | undefined,
|
|
725
740
|
sessionId: string | null = null,
|
|
726
|
-
featuresSessionId: string | null = null
|
|
741
|
+
featuresSessionId: string | null = null,
|
|
742
|
+
walletType: 'standard' | 'hidden' = 'hidden'
|
|
727
743
|
) {
|
|
728
744
|
Log.debug(
|
|
729
745
|
'updateInternalState session param: ',
|
|
@@ -740,7 +756,15 @@ export class Device extends EventEmitter {
|
|
|
740
756
|
if (enablePassphrase) {
|
|
741
757
|
const walletSessionId =
|
|
742
758
|
sessionId || featuresSessionId || deviceWalletSessionStore.getPending(cacheDeviceKey);
|
|
743
|
-
|
|
759
|
+
if (walletType === 'standard') {
|
|
760
|
+
deviceWalletSessionStore.setStandard(
|
|
761
|
+
cacheDeviceKey,
|
|
762
|
+
passphraseState,
|
|
763
|
+
walletSessionId ?? undefined
|
|
764
|
+
);
|
|
765
|
+
} else {
|
|
766
|
+
deviceWalletSessionStore.set(cacheDeviceKey, passphraseState, walletSessionId ?? undefined);
|
|
767
|
+
}
|
|
744
768
|
}
|
|
745
769
|
|
|
746
770
|
deviceWalletSessionStore.deletePending(cacheDeviceKey);
|
|
@@ -779,6 +803,12 @@ export class Device extends EventEmitter {
|
|
|
779
803
|
}
|
|
780
804
|
}
|
|
781
805
|
|
|
806
|
+
clearStandardInternalState(_deviceId?: string) {
|
|
807
|
+
const deviceId = this.getSessionCacheDeviceKey(_deviceId);
|
|
808
|
+
if (!deviceId) return;
|
|
809
|
+
deviceWalletSessionStore.deleteStandard(deviceId);
|
|
810
|
+
}
|
|
811
|
+
|
|
782
812
|
async initialize(options?: InitOptions) {
|
|
783
813
|
// Protocol V2 does not support legacy Initialize; use its dedicated flow.
|
|
784
814
|
if (this.isProtocolV2()) {
|
|
@@ -810,9 +840,12 @@ export class Device extends EventEmitter {
|
|
|
810
840
|
|
|
811
841
|
const expectedDeviceId = options?.deviceId;
|
|
812
842
|
if (expectedDeviceId) {
|
|
813
|
-
//
|
|
843
|
+
// 先只读校验物理设备身份;钱包上下文仍由下方携带完整参数的
|
|
844
|
+
// Initialize 选择,避免标准钱包请求复用此前的隐藏钱包上下文。
|
|
814
845
|
this.passphraseState = undefined;
|
|
815
|
-
await
|
|
846
|
+
const { message } = await this.commands.typedCall('GetFeatures', 'Features', {});
|
|
847
|
+
this._updateFeatures(message);
|
|
848
|
+
await TransportManager.reconfigure(this.features);
|
|
816
849
|
if (!this.checkDeviceId(expectedDeviceId)) {
|
|
817
850
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckDeviceIdError);
|
|
818
851
|
}
|
|
@@ -836,15 +869,7 @@ export class Device extends EventEmitter {
|
|
|
836
869
|
payload.derive_cardano = true;
|
|
837
870
|
}
|
|
838
871
|
|
|
839
|
-
|
|
840
|
-
!expectedDeviceId ||
|
|
841
|
-
Boolean(internalState) ||
|
|
842
|
-
Boolean(options?.passphraseState) ||
|
|
843
|
-
options?.deriveCardano === true ||
|
|
844
|
-
options?.initSession === true;
|
|
845
|
-
if (requiresWalletInitialize) {
|
|
846
|
-
await callInitialize(payload, options?.initSession);
|
|
847
|
-
}
|
|
872
|
+
await callInitialize(payload, options?.initSession);
|
|
848
873
|
} catch (error) {
|
|
849
874
|
Log.error('Initialization failed:', error);
|
|
850
875
|
throw error;
|
|
@@ -1020,40 +1045,60 @@ export class Device extends EventEmitter {
|
|
|
1020
1045
|
}
|
|
1021
1046
|
|
|
1022
1047
|
async probeProtocolV2RuntimeState(deviceInfo: ProtocolV2DeviceInfo, timeoutMs?: number) {
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1048
|
+
const protocolInfo = await requestProtocolV2ProtocolInfo({
|
|
1049
|
+
commands: this.commands,
|
|
1050
|
+
timeoutMs,
|
|
1051
|
+
});
|
|
1052
|
+
const runtimeMode = getProtocolV2RuntimeMode(protocolInfo);
|
|
1053
|
+
const protocolV2DeviceType = resolveProtocolV2DeviceIdentity(
|
|
1054
|
+
deviceInfo.hw?.Device_type
|
|
1055
|
+
).deviceType;
|
|
1056
|
+
if (runtimeMode === 'romloader' && protocolV2DeviceType !== EDeviceType.Pro2) {
|
|
1057
|
+
throw ERRORS.TypedError(
|
|
1058
|
+
HardwareErrorCode.DeviceInitializeFailed,
|
|
1059
|
+
'Protocol V2 romloader mode is only supported for Pro2.'
|
|
1060
|
+
);
|
|
1061
|
+
}
|
|
1062
|
+
const deviceStatusSupported = supportsProtocolV2Message(
|
|
1063
|
+
protocolInfo,
|
|
1064
|
+
PROTOCOL_V2_DEVICE_STATUS_GET_MESSAGE_TYPE
|
|
1065
|
+
);
|
|
1066
|
+
|
|
1067
|
+
if (runtimeMode === 'bootloader' || runtimeMode === 'romloader') {
|
|
1068
|
+
return this.updateProtocolV2Features(deviceInfo, null, runtimeMode, protocolInfo);
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
if (!deviceStatusSupported) {
|
|
1072
|
+
if (runtimeMode === 'normal') {
|
|
1073
|
+
return this.updateProtocolV2Features(deviceInfo, null, runtimeMode, protocolInfo);
|
|
1074
|
+
}
|
|
1075
|
+
throw ERRORS.TypedError(
|
|
1076
|
+
HardwareErrorCode.DeviceInitializeFailed,
|
|
1077
|
+
`Unknown Protocol V2 build fingerprint without DeviceStatusGet capability: ${protocolInfo.build_fingerprint}`
|
|
1078
|
+
);
|
|
1039
1079
|
}
|
|
1040
|
-
|
|
1080
|
+
|
|
1081
|
+
const deviceStatus = await requestProtocolV2DeviceStatus({
|
|
1082
|
+
commands: this.commands,
|
|
1083
|
+
timeoutMs,
|
|
1084
|
+
});
|
|
1085
|
+
return this.updateProtocolV2Features(deviceInfo, deviceStatus, 'normal', protocolInfo);
|
|
1041
1086
|
}
|
|
1042
1087
|
|
|
1043
1088
|
updateProtocolV2Features(
|
|
1044
1089
|
deviceInfo?: ProtocolV2DeviceInfo,
|
|
1045
1090
|
deviceStatus?: DeviceStatus | null,
|
|
1046
|
-
runtimeMode?: ProtocolV2RuntimeMode
|
|
1091
|
+
runtimeMode?: ProtocolV2RuntimeMode,
|
|
1092
|
+
protocolInfo?: ProtocolInfo
|
|
1047
1093
|
) {
|
|
1048
1094
|
const previousDeviceId = this.getCurrentDeviceId();
|
|
1049
|
-
const resolvedMode =
|
|
1050
|
-
runtimeMode ??
|
|
1051
|
-
(deviceStatus
|
|
1052
|
-
? getProtocolV2RuntimeMode({ deviceInfo, deviceStatusAvailable: true })
|
|
1053
|
-
: this.state?.status.mode);
|
|
1095
|
+
const resolvedMode = runtimeMode ?? (deviceStatus ? 'normal' : this.state?.status.mode);
|
|
1054
1096
|
if (deviceInfo) {
|
|
1055
1097
|
this.updateState(mapProtocolV2DeviceInfoToState(deviceInfo, resolvedMode), 'device-info');
|
|
1056
1098
|
}
|
|
1099
|
+
if (protocolInfo) {
|
|
1100
|
+
this.updateState({ raw: { protocolV2ProtocolInfo: protocolInfo } }, 'device-info');
|
|
1101
|
+
}
|
|
1057
1102
|
if (deviceStatus) {
|
|
1058
1103
|
this.updateState(mapProtocolV2DeviceStatusToState(deviceStatus), 'device-status');
|
|
1059
1104
|
}
|
|
@@ -1122,7 +1167,7 @@ export class Device extends EventEmitter {
|
|
|
1122
1167
|
attachToPinEnabled: null,
|
|
1123
1168
|
unlockedAttachPin: null,
|
|
1124
1169
|
},
|
|
1125
|
-
raw: { protocolV2DeviceStatus: null },
|
|
1170
|
+
raw: { protocolV2ProtocolInfo: null, protocolV2DeviceStatus: null },
|
|
1126
1171
|
},
|
|
1127
1172
|
'transport-reconnect'
|
|
1128
1173
|
);
|
|
@@ -1132,7 +1177,7 @@ export class Device extends EventEmitter {
|
|
|
1132
1177
|
this.updateState(
|
|
1133
1178
|
{
|
|
1134
1179
|
status: { mode: 'normal', unlocked: null },
|
|
1135
|
-
raw: { protocolV2DeviceStatus: null },
|
|
1180
|
+
raw: { protocolV2ProtocolInfo: null, protocolV2DeviceStatus: null },
|
|
1136
1181
|
},
|
|
1137
1182
|
'transport-reconnect'
|
|
1138
1183
|
);
|
|
@@ -1378,7 +1423,16 @@ export class Device extends EventEmitter {
|
|
|
1378
1423
|
|
|
1379
1424
|
isBootloader() {
|
|
1380
1425
|
if (!this.state) return undefined;
|
|
1381
|
-
return this.state.status.mode === 'bootloader'
|
|
1426
|
+
return this.state.status.mode === 'bootloader';
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
isRomloader() {
|
|
1430
|
+
if (!this.state) return undefined;
|
|
1431
|
+
return (
|
|
1432
|
+
this.isProtocolV2() &&
|
|
1433
|
+
this.getCurrentDeviceType() === EDeviceType.Pro2 &&
|
|
1434
|
+
this.state.status.mode === 'romloader'
|
|
1435
|
+
);
|
|
1382
1436
|
}
|
|
1383
1437
|
|
|
1384
1438
|
isInitialized() {
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
type Messages,
|
|
7
7
|
type Transport,
|
|
8
8
|
type TransportCallOptions,
|
|
9
|
+
getSafeTransportLogPayload,
|
|
9
10
|
} from '@onekeyfe/hd-transport';
|
|
10
11
|
|
|
11
12
|
import TransportManager from '../data-manager/TransportManager';
|
|
@@ -282,7 +283,11 @@ export class DeviceCommands {
|
|
|
282
283
|
): Promise<DefaultMessageResponse> {
|
|
283
284
|
const shouldReduceDebug = shouldReduceDebugForCall(type);
|
|
284
285
|
if (!shouldReduceDebug) {
|
|
285
|
-
Log.debug(
|
|
286
|
+
Log.debug(
|
|
287
|
+
'[DeviceCommands] [call] Sending',
|
|
288
|
+
type,
|
|
289
|
+
getSafeTransportLogPayload(msg ?? {}, type)
|
|
290
|
+
);
|
|
286
291
|
}
|
|
287
292
|
|
|
288
293
|
try {
|
|
@@ -290,13 +295,18 @@ export class DeviceCommands {
|
|
|
290
295
|
this.callPromise = promise;
|
|
291
296
|
const res = await promise;
|
|
292
297
|
if (!shouldReduceDebug) {
|
|
293
|
-
LogCore.debug(
|
|
298
|
+
LogCore.debug(
|
|
299
|
+
'[DeviceCommands] [call] Received',
|
|
300
|
+
res.type,
|
|
301
|
+
getSafeTransportLogPayload(res.message, res.type)
|
|
302
|
+
);
|
|
294
303
|
}
|
|
295
304
|
return res;
|
|
296
305
|
} catch (error) {
|
|
297
306
|
LogCore.debug('[DeviceCommands] [call] Received error', {
|
|
298
307
|
request: type,
|
|
299
308
|
errorCode: error?.errorCode,
|
|
309
|
+
response: getSafeTransportLogPayload(error?.response?.data, type),
|
|
300
310
|
});
|
|
301
311
|
if (error.errorCode === HardwareErrorCode.BleDeviceBondError) {
|
|
302
312
|
return {
|
|
@@ -82,9 +82,10 @@ export default class DeviceConnector {
|
|
|
82
82
|
path: string,
|
|
83
83
|
session?: string | null,
|
|
84
84
|
forceCleanRunPromise?: boolean,
|
|
85
|
-
|
|
85
|
+
expectedProtocol?: HardwareConnectProtocol,
|
|
86
|
+
protocolHint?: HardwareConnectProtocol
|
|
86
87
|
) {
|
|
87
|
-
Log.debug('acquire', path, session,
|
|
88
|
+
Log.debug('acquire', path, session, expectedProtocol, protocolHint);
|
|
88
89
|
const env = DataManager.getSettings('env');
|
|
89
90
|
try {
|
|
90
91
|
let res;
|
|
@@ -92,21 +93,23 @@ export default class DeviceConnector {
|
|
|
92
93
|
res = await this.transport.acquire({
|
|
93
94
|
uuid: path,
|
|
94
95
|
forceCleanRunPromise,
|
|
95
|
-
expectedProtocol
|
|
96
|
+
expectedProtocol,
|
|
97
|
+
protocolHint,
|
|
96
98
|
});
|
|
97
99
|
} else {
|
|
98
100
|
res = await this.transport.acquire({
|
|
99
101
|
path,
|
|
100
102
|
previous: session ?? null,
|
|
101
|
-
expectedProtocol
|
|
103
|
+
expectedProtocol,
|
|
104
|
+
protocolHint,
|
|
102
105
|
});
|
|
103
106
|
}
|
|
104
|
-
if (
|
|
107
|
+
if (expectedProtocol) {
|
|
105
108
|
const detectedProtocol = this.transport.getProtocolType(path);
|
|
106
|
-
if (detectedProtocol !==
|
|
109
|
+
if (detectedProtocol !== expectedProtocol) {
|
|
107
110
|
throw ERRORS.TypedError(
|
|
108
111
|
HardwareErrorCode.RuntimeError,
|
|
109
|
-
`Device protocol mismatch: expected ${
|
|
112
|
+
`Device protocol mismatch: expected ${expectedProtocol}, detected ${detectedProtocol}`
|
|
110
113
|
);
|
|
111
114
|
}
|
|
112
115
|
}
|
package/src/device/DevicePool.ts
CHANGED
|
@@ -306,9 +306,11 @@ export class DevicePool extends EventEmitter {
|
|
|
306
306
|
this.disconnectPool = [];
|
|
307
307
|
this.devicesCache = {};
|
|
308
308
|
|
|
309
|
-
// Clear all event listeners but keep the emitter instance
|
|
310
|
-
this.emitter.removeAllListeners();
|
|
311
|
-
|
|
312
309
|
Log.debug('DevicePool state has been reset');
|
|
313
310
|
}
|
|
311
|
+
|
|
312
|
+
static dispose() {
|
|
313
|
+
this.resetState();
|
|
314
|
+
this.emitter.removeAllListeners();
|
|
315
|
+
}
|
|
314
316
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { EFirmwareType } from '@onekeyfe/hd-shared';
|
|
2
2
|
|
|
3
3
|
import { buildProtocolV1FeaturesPayload } from '../deviceProfile/buildDeviceFeatures';
|
|
4
|
+
import { resolveProtocolV2DeviceIdentity } from '../deviceProfile/protocolV2DeviceIdentity';
|
|
4
5
|
import {
|
|
5
6
|
mapLanguageFromProtocolV2,
|
|
6
7
|
mapLanguageToProtocolV2,
|
|
@@ -211,14 +212,15 @@ export const mapProtocolV2DeviceInfoToState = (
|
|
|
211
212
|
mode: DeviceStateMode = 'unknown'
|
|
212
213
|
): DeviceStatePatch => {
|
|
213
214
|
const loader = mode === 'bootloader' || mode === 'romloader';
|
|
215
|
+
const identity = resolveProtocolV2DeviceIdentity(info.hw?.Device_type);
|
|
214
216
|
|
|
215
217
|
return {
|
|
216
218
|
protocol: 'V2',
|
|
217
219
|
protocolVersion: info.protocol_version,
|
|
218
220
|
identity: definedEntries({
|
|
219
|
-
deviceType:
|
|
221
|
+
deviceType: identity.deviceType,
|
|
220
222
|
firmwareType: EFirmwareType.Universal,
|
|
221
|
-
model:
|
|
223
|
+
model: identity.model,
|
|
222
224
|
vendor: 'onekey.so',
|
|
223
225
|
serialNo: info.hw?.serial_no,
|
|
224
226
|
bleName: info.coprocessor?.bt_adv_name,
|
|
@@ -16,12 +16,6 @@ export const projectFeatures = (state: StoredDeviceState): Features => {
|
|
|
16
16
|
delete publicRawFeatures.session_id;
|
|
17
17
|
delete publicRawFeatures.sessionId;
|
|
18
18
|
delete publicRawFeatures.passphraseState;
|
|
19
|
-
const publicRaw = snapshot.raw
|
|
20
|
-
? {
|
|
21
|
-
...snapshot.raw,
|
|
22
|
-
protocolV1Features: publicRawFeatures,
|
|
23
|
-
}
|
|
24
|
-
: undefined;
|
|
25
19
|
const rawOneKeyFeatures = snapshot.raw?.protocolV1OneKeyFeatures ?? {};
|
|
26
20
|
const bootloaderMode =
|
|
27
21
|
snapshot.protocol === 'V1'
|
|
@@ -90,7 +84,6 @@ export const projectFeatures = (state: StoredDeviceState): Features => {
|
|
|
90
84
|
se04BootVersion: snapshot.versions.se04Boot,
|
|
91
85
|
seVersion: snapshot.versions.se ?? null,
|
|
92
86
|
verify: snapshot.verification,
|
|
93
|
-
raw: publicRaw,
|
|
94
87
|
device_id: snapshot.identity.deviceId ?? undefined,
|
|
95
88
|
ble_name: snapshot.identity.bleName ?? undefined,
|
|
96
89
|
passphrase_protection: snapshot.status.passphraseProtection ?? undefined,
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
export class DeviceWalletSessionStore {
|
|
2
2
|
private readonly walletSessions = new Map<string, Map<string, string>>();
|
|
3
3
|
|
|
4
|
+
private readonly standardWalletSessions = new Map<
|
|
5
|
+
string,
|
|
6
|
+
{ passphraseState: string; sessionId: string }
|
|
7
|
+
>();
|
|
8
|
+
|
|
4
9
|
private readonly pendingSessions = new Map<string, string>();
|
|
5
10
|
|
|
6
11
|
get(deviceKey: string, passphraseState?: string) {
|
|
@@ -18,6 +23,17 @@ export class DeviceWalletSessionStore {
|
|
|
18
23
|
deviceSessions.set(passphraseState, sessionId);
|
|
19
24
|
}
|
|
20
25
|
|
|
26
|
+
getStandard(deviceKey: string) {
|
|
27
|
+
if (!deviceKey) return undefined;
|
|
28
|
+
return this.standardWalletSessions.get(deviceKey);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
setStandard(deviceKey: string, passphraseState?: string, sessionId?: string) {
|
|
32
|
+
if (!deviceKey || !passphraseState || !sessionId) return;
|
|
33
|
+
this.set(deviceKey, passphraseState, sessionId);
|
|
34
|
+
this.standardWalletSessions.set(deviceKey, { passphraseState, sessionId });
|
|
35
|
+
}
|
|
36
|
+
|
|
21
37
|
setPending(deviceKey: string, sessionId?: string) {
|
|
22
38
|
if (!deviceKey || !sessionId) return;
|
|
23
39
|
this.pendingSessions.set(deviceKey, sessionId);
|
|
@@ -30,6 +46,10 @@ export class DeviceWalletSessionStore {
|
|
|
30
46
|
|
|
31
47
|
delete(deviceKey: string, passphraseState?: string) {
|
|
32
48
|
if (!deviceKey || !passphraseState) return;
|
|
49
|
+
const standardWalletSession = this.standardWalletSessions.get(deviceKey);
|
|
50
|
+
if (standardWalletSession?.passphraseState === passphraseState) {
|
|
51
|
+
this.standardWalletSessions.delete(deviceKey);
|
|
52
|
+
}
|
|
33
53
|
const deviceSessions = this.walletSessions.get(deviceKey);
|
|
34
54
|
if (!deviceSessions) return;
|
|
35
55
|
deviceSessions.delete(passphraseState);
|
|
@@ -38,6 +58,15 @@ export class DeviceWalletSessionStore {
|
|
|
38
58
|
}
|
|
39
59
|
}
|
|
40
60
|
|
|
61
|
+
deleteStandard(deviceKey: string) {
|
|
62
|
+
if (!deviceKey) return;
|
|
63
|
+
const standardWalletSession = this.standardWalletSessions.get(deviceKey);
|
|
64
|
+
this.standardWalletSessions.delete(deviceKey);
|
|
65
|
+
if (standardWalletSession) {
|
|
66
|
+
this.delete(deviceKey, standardWalletSession.passphraseState);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
41
70
|
deletePending(deviceKey: string) {
|
|
42
71
|
if (!deviceKey) return;
|
|
43
72
|
this.pendingSessions.delete(deviceKey);
|
|
@@ -46,6 +75,7 @@ export class DeviceWalletSessionStore {
|
|
|
46
75
|
deleteDevice(deviceKey: string) {
|
|
47
76
|
if (!deviceKey) return;
|
|
48
77
|
this.walletSessions.delete(deviceKey);
|
|
78
|
+
this.standardWalletSessions.delete(deviceKey);
|
|
49
79
|
this.pendingSessions.delete(deviceKey);
|
|
50
80
|
}
|
|
51
81
|
|
|
@@ -54,16 +84,24 @@ export class DeviceWalletSessionStore {
|
|
|
54
84
|
|
|
55
85
|
const sourceSessions = this.walletSessions.get(from);
|
|
56
86
|
if (sourceSessions) {
|
|
57
|
-
const targetSessions = this.walletSessions.get(to) ?? new Map<string, string>();
|
|
58
|
-
this.walletSessions.set(to, targetSessions);
|
|
59
87
|
sourceSessions.forEach((sessionId, passphraseState) => {
|
|
60
|
-
if (!
|
|
61
|
-
|
|
88
|
+
if (!this.get(to, passphraseState)) {
|
|
89
|
+
this.set(to, passphraseState, sessionId);
|
|
62
90
|
}
|
|
63
91
|
});
|
|
64
92
|
this.walletSessions.delete(from);
|
|
65
93
|
}
|
|
66
94
|
|
|
95
|
+
const standardWalletSession = this.standardWalletSessions.get(from);
|
|
96
|
+
if (
|
|
97
|
+
standardWalletSession &&
|
|
98
|
+
!this.standardWalletSessions.has(to) &&
|
|
99
|
+
this.get(to, standardWalletSession.passphraseState) === standardWalletSession.sessionId
|
|
100
|
+
) {
|
|
101
|
+
this.standardWalletSessions.set(to, standardWalletSession);
|
|
102
|
+
}
|
|
103
|
+
this.standardWalletSessions.delete(from);
|
|
104
|
+
|
|
67
105
|
const pendingSession = this.pendingSessions.get(from);
|
|
68
106
|
if (pendingSession && !this.pendingSessions.has(to)) {
|
|
69
107
|
this.pendingSessions.set(to, pendingSession);
|
|
@@ -98,6 +136,7 @@ export class DeviceWalletSessionStore {
|
|
|
98
136
|
|
|
99
137
|
clear() {
|
|
100
138
|
this.walletSessions.clear();
|
|
139
|
+
this.standardWalletSessions.clear();
|
|
101
140
|
this.pendingSessions.clear();
|
|
102
141
|
}
|
|
103
142
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { EFirmwareType } from '@onekeyfe/hd-shared';
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
resolveDeviceBleFirmwareVersion,
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
resolveDeviceType,
|
|
12
12
|
} from '../utils/deviceFeaturesCompat';
|
|
13
13
|
import { normalizeSafetyCheckLevel } from '../utils/deviceSettings';
|
|
14
|
+
import { resolveProtocolV2DeviceIdentity } from './protocolV2DeviceIdentity';
|
|
14
15
|
|
|
15
16
|
import type {
|
|
16
17
|
DeviceFirmwareImageInfo,
|
|
@@ -224,6 +225,12 @@ export const buildProtocolV2FeaturesPayload = ({
|
|
|
224
225
|
const samePhysicalDevice =
|
|
225
226
|
!incomingSerialNo || !previous?.serialNo || incomingSerialNo === previous.serialNo;
|
|
226
227
|
const cached = samePhysicalDevice ? previous : undefined;
|
|
228
|
+
const incomingDeviceType = info?.hw?.Device_type;
|
|
229
|
+
const resolvedIdentity = resolveProtocolV2DeviceIdentity(incomingDeviceType);
|
|
230
|
+
const cachedIdentity =
|
|
231
|
+
incomingDeviceType === undefined || incomingDeviceType === null ? cached : undefined;
|
|
232
|
+
const deviceType = cachedIdentity ? cachedIdentity.deviceType : resolvedIdentity.deviceType;
|
|
233
|
+
const model = cachedIdentity ? cachedIdentity.model : resolvedIdentity.model;
|
|
227
234
|
|
|
228
235
|
const firmwareVersion = firstMeaningfulVersion(
|
|
229
236
|
getImageVersion(fwApplication),
|
|
@@ -253,7 +260,7 @@ export const buildProtocolV2FeaturesPayload = ({
|
|
|
253
260
|
const attachToPinEnabled = status?.attach_to_pin_enabled ?? cached?.attachToPinEnabled ?? null;
|
|
254
261
|
const unlockedAttachPin =
|
|
255
262
|
status?.unlocked_by_attach_to_pin ?? cached?.unlockedAttachPin ?? undefined;
|
|
256
|
-
const bootloaderMode = runtimeMode === 'bootloader';
|
|
263
|
+
const bootloaderMode = runtimeMode === 'bootloader' || runtimeMode === 'romloader';
|
|
257
264
|
let mode: DeviceFeaturesMode = 'unknown';
|
|
258
265
|
if (runtimeMode) {
|
|
259
266
|
mode = runtimeMode;
|
|
@@ -270,9 +277,9 @@ export const buildProtocolV2FeaturesPayload = ({
|
|
|
270
277
|
return {
|
|
271
278
|
protocol: 'V2',
|
|
272
279
|
protocolVersion: deviceInfo?.protocol_version ?? cached?.protocolVersion ?? null,
|
|
273
|
-
deviceType
|
|
280
|
+
deviceType,
|
|
274
281
|
firmwareType: cached?.firmwareType ?? EFirmwareType.Universal,
|
|
275
|
-
model
|
|
282
|
+
model,
|
|
276
283
|
vendor: 'onekey.so',
|
|
277
284
|
deviceId,
|
|
278
285
|
serialNo,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { EDeviceType } from '@onekeyfe/hd-shared';
|
|
2
|
+
import { DeviceType } from '@onekeyfe/hd-transport';
|
|
3
|
+
|
|
4
|
+
export const resolveProtocolV2DeviceIdentity = (
|
|
5
|
+
deviceType?: DeviceType | keyof typeof DeviceType | null
|
|
6
|
+
): { deviceType: EDeviceType; model: string | null } => {
|
|
7
|
+
switch (deviceType) {
|
|
8
|
+
case DeviceType.CLASSIC1:
|
|
9
|
+
case 'CLASSIC1':
|
|
10
|
+
return { deviceType: EDeviceType.Classic, model: 'classic' };
|
|
11
|
+
case DeviceType.CLASSIC1S:
|
|
12
|
+
case 'CLASSIC1S':
|
|
13
|
+
return { deviceType: EDeviceType.Classic1s, model: 'classic1s' };
|
|
14
|
+
case DeviceType.CLASSIC1S_PURE:
|
|
15
|
+
case 'CLASSIC1S_PURE':
|
|
16
|
+
return { deviceType: EDeviceType.ClassicPure, model: 'classicpure' };
|
|
17
|
+
case DeviceType.MINI:
|
|
18
|
+
case 'MINI':
|
|
19
|
+
return { deviceType: EDeviceType.Mini, model: 'mini' };
|
|
20
|
+
case DeviceType.TOUCH:
|
|
21
|
+
case 'TOUCH':
|
|
22
|
+
return { deviceType: EDeviceType.Touch, model: 'touch' };
|
|
23
|
+
case DeviceType.PRO:
|
|
24
|
+
case 'PRO':
|
|
25
|
+
return { deviceType: EDeviceType.Pro, model: 'pro' };
|
|
26
|
+
case DeviceType.PRO2:
|
|
27
|
+
case 'PRO2':
|
|
28
|
+
return { deviceType: EDeviceType.Pro2, model: 'pro2' };
|
|
29
|
+
default:
|
|
30
|
+
return { deviceType: EDeviceType.Unknown, model: null };
|
|
31
|
+
}
|
|
32
|
+
};
|