@onekeyfe/hd-core 1.2.0-alpha.0 → 1.2.0-alpha.2
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__/protocol-v2.test.ts +56 -178
- package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +2 -2
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/GetDeviceInfo.d.ts.map +1 -1
- package/dist/api/GetFeatures.d.ts +1 -1
- package/dist/api/GetOnekeyFeatures.d.ts.map +1 -1
- package/dist/api/device/DeviceUnlock.d.ts +1 -1
- package/dist/api/firmware/bootloaderHelper.d.ts.map +1 -1
- package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
- package/dist/api/tron/TronSignMessage.d.ts +0 -1
- package/dist/api/tron/TronSignMessage.d.ts.map +1 -1
- package/dist/api/tron/TronSignTransaction.d.ts +0 -1
- package/dist/api/tron/TronSignTransaction.d.ts.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/device/Device.d.ts +10 -15
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/deviceProfile/buildDeviceFeatures.d.ts +6 -0
- package/dist/deviceProfile/buildDeviceFeatures.d.ts.map +1 -0
- package/dist/deviceProfile/buildDeviceProfile.d.ts +3 -4
- package/dist/deviceProfile/buildDeviceProfile.d.ts.map +1 -1
- package/dist/deviceProfile/index.d.ts +1 -1
- package/dist/deviceProfile/index.d.ts.map +1 -1
- package/dist/index.d.ts +571 -496
- package/dist/index.js +502 -571
- package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
- package/dist/types/api/getDeviceInfo.d.ts +2 -2
- package/dist/types/api/getDeviceInfo.d.ts.map +1 -1
- package/dist/types/device.d.ts +87 -8
- package/dist/types/device.d.ts.map +1 -1
- package/dist/utils/capabilitieUtils.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
- package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
- package/dist/utils/deviceVersionUtils.d.ts.map +1 -1
- package/dist/utils/findDefectiveBatchDevice.d.ts +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/package.json +4 -4
- package/src/api/FirmwareUpdateV2.ts +9 -2
- package/src/api/FirmwareUpdateV3.ts +2 -1
- package/src/api/FirmwareUpdateV4.ts +24 -31
- package/src/api/GetDeviceInfo.ts +6 -13
- package/src/api/GetOnekeyFeatures.ts +3 -14
- package/src/api/GetPassphraseState.ts +2 -2
- package/src/api/firmware/bootloaderHelper.ts +3 -2
- package/src/api/firmware/getBinary.ts +1 -1
- package/src/api/firmware/releaseHelper.ts +3 -3
- package/src/api/firmware/uploadFirmware.ts +5 -2
- package/src/api/tron/TronSignMessage.ts +0 -1
- package/src/api/tron/TronSignTransaction.ts +0 -1
- package/src/core/index.ts +3 -7
- package/src/data-manager/DataManager.ts +4 -4
- package/src/device/Device.ts +74 -240
- package/src/device/DevicePool.ts +3 -3
- package/src/deviceProfile/buildDeviceFeatures.ts +367 -0
- package/src/deviceProfile/buildDeviceProfile.ts +102 -155
- package/src/deviceProfile/index.ts +4 -1
- package/src/protocols/protocol-v2/features.ts +6 -9
- package/src/types/api/getDeviceInfo.ts +2 -2
- package/src/types/device.ts +97 -34
- package/src/utils/capabilitieUtils.ts +1 -2
- package/src/utils/deviceFeaturesUtils.ts +11 -17
- package/src/utils/deviceInfoUtils.ts +11 -29
- package/src/utils/deviceVersionUtils.ts +7 -25
- package/src/utils/findDefectiveBatchDevice.ts +6 -6
- package/dist/deviceProfile/legacyFeaturesView.d.ts +0 -5
- package/dist/deviceProfile/legacyFeaturesView.d.ts.map +0 -1
- package/src/deviceProfile/legacyFeaturesView.ts +0 -123
package/src/device/Device.ts
CHANGED
|
@@ -40,7 +40,6 @@ import {
|
|
|
40
40
|
type Features,
|
|
41
41
|
type IDeviceModel,
|
|
42
42
|
type IDeviceType,
|
|
43
|
-
type IVersionArray,
|
|
44
43
|
type IVersionRange,
|
|
45
44
|
type SupportFeatureType,
|
|
46
45
|
type UnavailableCapabilities,
|
|
@@ -54,11 +53,7 @@ import {
|
|
|
54
53
|
PROTOCOL_V2_STATUS_DEVICE_INFO_REQUEST,
|
|
55
54
|
requestProtocolV2DeviceInfo,
|
|
56
55
|
} from '../protocols/protocol-v2/features';
|
|
57
|
-
import {
|
|
58
|
-
buildProfileFromProtocolV1,
|
|
59
|
-
buildProfileFromProtocolV2,
|
|
60
|
-
buildProtocolV2GetFeaturesPayload,
|
|
61
|
-
} from '../deviceProfile';
|
|
56
|
+
import { buildProtocolV1FeaturesPayload, buildProtocolV2FeaturesPayload } from '../deviceProfile';
|
|
62
57
|
|
|
63
58
|
import type { PROTO } from '../constants';
|
|
64
59
|
import type {
|
|
@@ -74,7 +69,6 @@ import type {
|
|
|
74
69
|
Success,
|
|
75
70
|
} from '@onekeyfe/hd-transport';
|
|
76
71
|
import type DeviceConnector from './DeviceConnector';
|
|
77
|
-
import type { DeviceProfile } from '../types/api/getDeviceInfo';
|
|
78
72
|
|
|
79
73
|
export type InitOptions = {
|
|
80
74
|
initSession?: boolean;
|
|
@@ -96,11 +90,6 @@ const parseRunOptions = (options?: RunOptions): RunOptions => {
|
|
|
96
90
|
|
|
97
91
|
const Log = getLogger(LoggerNames.Device);
|
|
98
92
|
|
|
99
|
-
const profileVersionToArray = (version?: string | null): IVersionArray | null => {
|
|
100
|
-
if (!version) return null;
|
|
101
|
-
return version.split('.').map(part => Number(part) || 0) as IVersionArray;
|
|
102
|
-
};
|
|
103
|
-
|
|
104
93
|
export interface DeviceEvents {
|
|
105
94
|
[DEVICE.PIN]: [Device, PROTO.PinMatrixRequestType | undefined, (err: any, pin: string) => void];
|
|
106
95
|
[DEVICE.PASSPHRASE_ON_DEVICE]: [Device, ((response: any) => void)?];
|
|
@@ -198,32 +187,12 @@ export class Device extends EventEmitter {
|
|
|
198
187
|
/**
|
|
199
188
|
* 唯一设备状态缓存。
|
|
200
189
|
*
|
|
201
|
-
* V1 直接保存原生 Features;V2 保存由 DevGetDeviceInfo
|
|
202
|
-
*
|
|
203
|
-
*
|
|
190
|
+
* V1 直接保存原生 Features;V2 保存由 DevGetDeviceInfo 映射出的
|
|
191
|
+
* Features 视图。Device 不再保存 profile,结构化 DeviceProfile 只作为
|
|
192
|
+
* getDeviceInfo() 的 API 返回值存在。
|
|
204
193
|
*/
|
|
205
194
|
features: Features | undefined = undefined;
|
|
206
195
|
|
|
207
|
-
private getFeaturesProfile(): DeviceProfile | undefined {
|
|
208
|
-
if (!this.features) return undefined;
|
|
209
|
-
const protocol = this.originalDescriptor.protocolType === 'V2' ? 'V2' : 'V1';
|
|
210
|
-
return buildProfileFromProtocolV1({
|
|
211
|
-
protocol,
|
|
212
|
-
features: this.features,
|
|
213
|
-
onekeyFeatures: this.features as Parameters<typeof buildProfileFromProtocolV1>[0]['onekeyFeatures'],
|
|
214
|
-
sources: ['features'],
|
|
215
|
-
scope: 'verify',
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
get profile(): DeviceProfile | undefined {
|
|
220
|
-
return this.getFeaturesProfile();
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
set profile(profile: DeviceProfile | undefined) {
|
|
224
|
-
this.updateProfile(profile);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
196
|
/**
|
|
228
197
|
* 是否需要更新设备信息。
|
|
229
198
|
*
|
|
@@ -314,8 +283,7 @@ export class Device extends EventEmitter {
|
|
|
314
283
|
label: label || 'OneKey',
|
|
315
284
|
mode: this.getMode(),
|
|
316
285
|
features,
|
|
317
|
-
|
|
318
|
-
sessionId: this.features?.session_id ?? null,
|
|
286
|
+
sessionId: this.features?.sessionId ?? null,
|
|
319
287
|
firmwareVersion: this.getFirmwareVersion(),
|
|
320
288
|
bleFirmwareVersion: this.getBLEFirmwareVersion(),
|
|
321
289
|
unavailableCapabilities: this.unavailableCapabilities,
|
|
@@ -509,9 +477,9 @@ export class Device extends EventEmitter {
|
|
|
509
477
|
* 唯一协议判别器。
|
|
510
478
|
*
|
|
511
479
|
* descriptor.protocolType 是协议探测后的结果;V2 features 由 DevGetDeviceInfo
|
|
512
|
-
*
|
|
480
|
+
* 映射产生。
|
|
513
481
|
* 全 SDK 的协议分支都必须走这里,不要直接读 originalDescriptor.protocolType
|
|
514
|
-
*
|
|
482
|
+
* 或从 features 反推。
|
|
515
483
|
*/
|
|
516
484
|
getProtocol(): 'V1' | 'V2' {
|
|
517
485
|
return this.originalDescriptor.protocolType === 'V2' ? 'V2' : 'V1';
|
|
@@ -522,57 +490,44 @@ export class Device extends EventEmitter {
|
|
|
522
490
|
}
|
|
523
491
|
|
|
524
492
|
getCurrentDeviceType() {
|
|
525
|
-
return
|
|
493
|
+
return getDeviceType(this.features);
|
|
526
494
|
}
|
|
527
495
|
|
|
528
496
|
getCurrentDeviceId() {
|
|
529
|
-
|
|
530
|
-
return this.profile.deviceId || undefined;
|
|
531
|
-
}
|
|
532
|
-
return this.features?.device_id || undefined;
|
|
497
|
+
return this.features?.deviceId || undefined;
|
|
533
498
|
}
|
|
534
499
|
|
|
535
500
|
getCurrentSerialNo() {
|
|
536
|
-
if (this.profile) {
|
|
537
|
-
return this.profile.serialNo || '';
|
|
538
|
-
}
|
|
539
501
|
return this.features ? getDeviceUUID(this.features) : '';
|
|
540
502
|
}
|
|
541
503
|
|
|
542
504
|
getCurrentBleName() {
|
|
543
|
-
|
|
544
|
-
if (this.isProtocolV2()) return this.profile?.bleName ?? null;
|
|
545
|
-
return this.profile?.bleName ?? getDeviceBleName(this.features);
|
|
505
|
+
return getDeviceBleName(this.features);
|
|
546
506
|
}
|
|
547
507
|
|
|
548
508
|
getCurrentLabel() {
|
|
549
|
-
|
|
550
|
-
return this.profile?.label ?? getDeviceLabel(this.features);
|
|
509
|
+
return getDeviceLabel(this.features);
|
|
551
510
|
}
|
|
552
511
|
|
|
553
512
|
getCurrentPassphraseProtection() {
|
|
554
|
-
|
|
555
|
-
return this.profile.status.passphraseProtection;
|
|
556
|
-
}
|
|
557
|
-
return this.features?.passphrase_protection;
|
|
513
|
+
return this.features?.passphraseProtection;
|
|
558
514
|
}
|
|
559
515
|
|
|
560
516
|
getCurrentFirmwareType() {
|
|
561
|
-
return
|
|
517
|
+
return getFirmwareType(this.features);
|
|
562
518
|
}
|
|
563
519
|
|
|
564
520
|
getCurrentFirmwareVersionString() {
|
|
565
|
-
return
|
|
521
|
+
return getDeviceFirmwareVersion(this.features)?.join('.');
|
|
566
522
|
}
|
|
567
523
|
|
|
568
524
|
getCurrentBLEFirmwareVersionString() {
|
|
569
|
-
if (this.profile?.versions.ble) return this.profile.versions.ble;
|
|
570
525
|
if (!this.features) return undefined;
|
|
571
526
|
return getDeviceBLEFirmwareVersion(this.features).join('.');
|
|
572
527
|
}
|
|
573
528
|
|
|
574
529
|
getCurrentSafetyChecks() {
|
|
575
|
-
return this.features?.
|
|
530
|
+
return this.features?.safetyChecks;
|
|
576
531
|
}
|
|
577
532
|
|
|
578
533
|
getCurrentMethodVersionRange(
|
|
@@ -663,17 +618,25 @@ export class Device extends EventEmitter {
|
|
|
663
618
|
return deviceId;
|
|
664
619
|
}
|
|
665
620
|
|
|
621
|
+
private getSessionCacheDeviceKey(_deviceId?: string) {
|
|
622
|
+
const deviceId = _deviceId || this.getCurrentDeviceId();
|
|
623
|
+
if (deviceId) return deviceId;
|
|
624
|
+
if (this.isProtocolV2()) {
|
|
625
|
+
return this.originalDescriptor.path || this.originalDescriptor.id;
|
|
626
|
+
}
|
|
627
|
+
return undefined;
|
|
628
|
+
}
|
|
629
|
+
|
|
666
630
|
getInternalState(_deviceId?: string) {
|
|
667
631
|
Log.debug('getInternalState session cache: ', deviceSessionCache);
|
|
668
632
|
Log.debug(
|
|
669
633
|
'getInternalState session param: ',
|
|
670
634
|
`device_id: ${_deviceId}`,
|
|
671
|
-
`features.
|
|
672
|
-
`profile.deviceId: ${this.profile?.deviceId}`,
|
|
635
|
+
`features.deviceId: ${this.features?.deviceId}`,
|
|
673
636
|
`passphraseState: ${this.passphraseState}`
|
|
674
637
|
);
|
|
675
638
|
|
|
676
|
-
const deviceId =
|
|
639
|
+
const deviceId = this.getSessionCacheDeviceKey(_deviceId);
|
|
677
640
|
if (!deviceId) return undefined;
|
|
678
641
|
// Security invariant: no passphraseState → no session lookup.
|
|
679
642
|
// A previous fallback that scanned `${deviceId}@*` keys could silently
|
|
@@ -691,7 +654,7 @@ export class Device extends EventEmitter {
|
|
|
691
654
|
updateInternalState(
|
|
692
655
|
enablePassphrase: boolean,
|
|
693
656
|
passphraseState: string | undefined,
|
|
694
|
-
deviceId: string,
|
|
657
|
+
deviceId: string | undefined,
|
|
695
658
|
sessionId: string | null = null,
|
|
696
659
|
featuresSessionId: string | null = null
|
|
697
660
|
) {
|
|
@@ -704,17 +667,21 @@ export class Device extends EventEmitter {
|
|
|
704
667
|
`featuresSessionId: ${featuresSessionId}`
|
|
705
668
|
);
|
|
706
669
|
|
|
670
|
+
const cacheDeviceKey = this.getSessionCacheDeviceKey(deviceId);
|
|
671
|
+
if (!cacheDeviceKey) return;
|
|
672
|
+
|
|
707
673
|
if (enablePassphrase) {
|
|
708
674
|
// update the sessionId
|
|
709
675
|
if (sessionId) {
|
|
710
|
-
deviceSessionCache[this.generateStateKey(
|
|
676
|
+
deviceSessionCache[this.generateStateKey(cacheDeviceKey, passphraseState)] = sessionId;
|
|
711
677
|
} else if (featuresSessionId) {
|
|
712
|
-
deviceSessionCache[this.generateStateKey(
|
|
678
|
+
deviceSessionCache[this.generateStateKey(cacheDeviceKey, passphraseState)] =
|
|
679
|
+
featuresSessionId;
|
|
713
680
|
}
|
|
714
681
|
}
|
|
715
682
|
|
|
716
683
|
// delete the old sessionId
|
|
717
|
-
const oldKey = `${
|
|
684
|
+
const oldKey = `${cacheDeviceKey}`;
|
|
718
685
|
if (deviceSessionCache[oldKey]) {
|
|
719
686
|
delete deviceSessionCache[oldKey];
|
|
720
687
|
}
|
|
@@ -727,14 +694,13 @@ export class Device extends EventEmitter {
|
|
|
727
694
|
'setInternalState session param: ',
|
|
728
695
|
`state: ${state}`,
|
|
729
696
|
`initSession: ${initSession}`,
|
|
730
|
-
`
|
|
731
|
-
`profile.deviceId: ${this.profile?.deviceId}`,
|
|
697
|
+
`deviceId: ${this.features?.deviceId}`,
|
|
732
698
|
`passphraseState: ${this.passphraseState}`
|
|
733
699
|
);
|
|
734
700
|
|
|
735
701
|
if (!this.passphraseState && !initSession) return;
|
|
736
702
|
|
|
737
|
-
const deviceId = this.
|
|
703
|
+
const deviceId = this.getSessionCacheDeviceKey();
|
|
738
704
|
if (!deviceId) return;
|
|
739
705
|
|
|
740
706
|
const key = this.generateStateKey(deviceId, this.passphraseState);
|
|
@@ -748,7 +714,7 @@ export class Device extends EventEmitter {
|
|
|
748
714
|
clearInternalState(_deviceId?: string) {
|
|
749
715
|
Log.debug('clearInternalState param: ', _deviceId);
|
|
750
716
|
|
|
751
|
-
const deviceId =
|
|
717
|
+
const deviceId = this.getSessionCacheDeviceKey(_deviceId);
|
|
752
718
|
if (!deviceId) return;
|
|
753
719
|
const key = `${deviceId}`;
|
|
754
720
|
delete deviceSessionCache[key];
|
|
@@ -763,11 +729,10 @@ export class Device extends EventEmitter {
|
|
|
763
729
|
// Protocol V2 不支持传统 Initialize,直接使用协议专用初始化流程。
|
|
764
730
|
if (this.isProtocolV2()) {
|
|
765
731
|
this.passphraseState = options?.passphraseState;
|
|
766
|
-
if (this.
|
|
767
|
-
// 不能直接信任缓存
|
|
768
|
-
//
|
|
769
|
-
//
|
|
770
|
-
// 不会降级已有的 verify / SE versions 数据。
|
|
732
|
+
if (this.features && !this.featuresNeedsReload && !options?.initSession) {
|
|
733
|
+
// 不能直接信任缓存 features:设备端 wipe / 完成初始化 / 改 label 后
|
|
734
|
+
// features 会永久陈旧。每次 run 做一次轻量 status 刷新(不含 fw/SE),
|
|
735
|
+
// 用字段级合并保留已有版本和 SE 信息。
|
|
771
736
|
await this._refreshProtocolV2Status();
|
|
772
737
|
return;
|
|
773
738
|
}
|
|
@@ -821,11 +786,11 @@ export class Device extends EventEmitter {
|
|
|
821
786
|
/**
|
|
822
787
|
* Device initialization over Protocol V2.
|
|
823
788
|
*
|
|
824
|
-
* Protocol V2 不走传统 Initialize/GetFeatures
|
|
825
|
-
*
|
|
789
|
+
* Protocol V2 不走传统 Initialize/GetFeatures;直接用 DevGetDeviceInfo
|
|
790
|
+
* 生成唯一的 features 状态。
|
|
826
791
|
*/
|
|
827
792
|
private async _initializeProtocolV2() {
|
|
828
|
-
Log.debug('Initialize device via Protocol V2
|
|
793
|
+
Log.debug('Initialize device via Protocol V2 features adapter');
|
|
829
794
|
|
|
830
795
|
try {
|
|
831
796
|
// 超时由 requestProtocolV2DeviceInfo 内部的 typedCall timeoutMs(默认 10s)负责,
|
|
@@ -836,16 +801,8 @@ export class Device extends EventEmitter {
|
|
|
836
801
|
});
|
|
837
802
|
// 默认请求不含 SE/hash 数据,scope 如实标注为 basic;
|
|
838
803
|
// 完整数据由 getDeviceInfo(scope:'verify'|'full') 获取。
|
|
839
|
-
const
|
|
840
|
-
|
|
841
|
-
deviceInfo,
|
|
842
|
-
sources: ['deviceInfo'],
|
|
843
|
-
scope: 'basic',
|
|
844
|
-
fallbackSerialNo: this.originalDescriptor?.path,
|
|
845
|
-
}),
|
|
846
|
-
deviceInfo
|
|
847
|
-
);
|
|
848
|
-
Log.debug('Protocol V2 profile:', profile);
|
|
804
|
+
const features = this.updateProtocolV2Features(deviceInfo);
|
|
805
|
+
Log.debug('Protocol V2 features:', features);
|
|
849
806
|
this.featuresNeedsReload = false;
|
|
850
807
|
} catch (error) {
|
|
851
808
|
Log.error('Protocol V2 initialization failed:', error);
|
|
@@ -857,8 +814,7 @@ export class Device extends EventEmitter {
|
|
|
857
814
|
* Protocol V2 的轻量状态刷新(每次 run 前调用)。
|
|
858
815
|
*
|
|
859
816
|
* 请求 hw + bt + status(不含 fw/SE target):status 提供 init_states / label /
|
|
860
|
-
* passphrase_protection 等会在设备端变化的字段;hw/bt 提供 serialNo / bleName
|
|
861
|
-
* 避免 applyProfileUpdate 的顶层字段覆盖把已有身份字段清空。
|
|
817
|
+
* passphrase_protection 等会在设备端变化的字段;hw/bt 提供 serialNo / bleName。
|
|
862
818
|
* versions 为空时按字段级合并保留旧值,verify 数据不会被降级。
|
|
863
819
|
*/
|
|
864
820
|
private async _refreshProtocolV2Status() {
|
|
@@ -867,16 +823,8 @@ export class Device extends EventEmitter {
|
|
|
867
823
|
commands: this.commands,
|
|
868
824
|
request: PROTOCOL_V2_STATUS_DEVICE_INFO_REQUEST,
|
|
869
825
|
});
|
|
870
|
-
const
|
|
871
|
-
|
|
872
|
-
deviceInfo,
|
|
873
|
-
sources: ['deviceInfo'],
|
|
874
|
-
scope: 'basic',
|
|
875
|
-
fallbackSerialNo: this.originalDescriptor?.path,
|
|
876
|
-
}),
|
|
877
|
-
deviceInfo
|
|
878
|
-
);
|
|
879
|
-
Log.debug('Protocol V2 profile (status refresh):', profile);
|
|
826
|
+
const features = this.updateProtocolV2Features(deviceInfo);
|
|
827
|
+
Log.debug('Protocol V2 features (status refresh):', features);
|
|
880
828
|
} catch (error) {
|
|
881
829
|
Log.error('Protocol V2 status refresh failed:', error);
|
|
882
830
|
throw error;
|
|
@@ -888,108 +836,43 @@ export class Device extends EventEmitter {
|
|
|
888
836
|
const deviceInfo = await requestProtocolV2DeviceInfo({
|
|
889
837
|
commands: this.commands,
|
|
890
838
|
});
|
|
891
|
-
|
|
892
|
-
buildProfileFromProtocolV2({
|
|
893
|
-
deviceInfo,
|
|
894
|
-
sources: ['deviceInfo'],
|
|
895
|
-
scope: 'basic',
|
|
896
|
-
fallbackSerialNo: this.originalDescriptor?.path,
|
|
897
|
-
}),
|
|
898
|
-
deviceInfo
|
|
899
|
-
);
|
|
900
|
-
return this.features ?? this.updateProtocolV2Features(profile, deviceInfo);
|
|
839
|
+
return this.updateProtocolV2Features(deviceInfo);
|
|
901
840
|
}
|
|
902
841
|
|
|
903
842
|
const { message } = await this.commands.typedCall('GetFeatures', 'Features', {});
|
|
904
843
|
this._updateFeatures(message);
|
|
905
|
-
return
|
|
844
|
+
return this.features;
|
|
906
845
|
}
|
|
907
846
|
|
|
908
|
-
_updateFeatures(
|
|
847
|
+
_updateFeatures(protoFeatures: PROTO.Features | Features, initSession?: boolean) {
|
|
848
|
+
let feat =
|
|
849
|
+
'protocol' in protoFeatures
|
|
850
|
+
? protoFeatures
|
|
851
|
+
: buildProtocolV1FeaturesPayload(protoFeatures, this.features);
|
|
852
|
+
|
|
909
853
|
// GetFeatures doesn't return 'session_id'
|
|
910
|
-
if (this.features &&
|
|
911
|
-
feat.
|
|
854
|
+
if (this.features?.sessionId && !feat.sessionId) {
|
|
855
|
+
feat.sessionId = this.features.sessionId;
|
|
912
856
|
}
|
|
913
|
-
if (this.getCurrentDeviceId() && feat.
|
|
914
|
-
this.setInternalState(feat.
|
|
857
|
+
if (this.getCurrentDeviceId() && feat.sessionId) {
|
|
858
|
+
this.setInternalState(feat.sessionId, initSession);
|
|
915
859
|
}
|
|
916
860
|
feat.unlocked = feat.unlocked ?? true;
|
|
917
861
|
|
|
918
862
|
feat = fixFeaturesFirmwareVersion(feat);
|
|
919
863
|
|
|
920
864
|
this.features = feat;
|
|
921
|
-
if (!this.isProtocolV2()) {
|
|
922
|
-
this.updateProfile(
|
|
923
|
-
buildProfileFromProtocolV1({
|
|
924
|
-
features: feat,
|
|
925
|
-
sources: ['features'],
|
|
926
|
-
})
|
|
927
|
-
);
|
|
928
|
-
}
|
|
929
865
|
this.featuresNeedsReload = false;
|
|
930
866
|
this.emit(DEVICE.FEATURES, this, feat);
|
|
931
867
|
}
|
|
932
868
|
|
|
933
|
-
|
|
934
|
-
if (!profile) {
|
|
935
|
-
this.features = undefined;
|
|
936
|
-
return;
|
|
937
|
-
}
|
|
938
|
-
if (profile.protocol === 'V2') {
|
|
939
|
-
this.updateProtocolV2Features(profile, profile.raw?.protocolV2DeviceInfo);
|
|
940
|
-
return;
|
|
941
|
-
}
|
|
942
|
-
if (profile.raw?.features) {
|
|
943
|
-
this.features = fixFeaturesFirmwareVersion(profile.raw.features);
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
/**
|
|
948
|
-
* 字段级合并刷新 profile,并返回合并后的结果。
|
|
949
|
-
*
|
|
950
|
-
* basic 范围的刷新(initialize / getFeatures)拿不到 SE 版本和 verify 数据,
|
|
951
|
-
* 不能整体替换掉 getDeviceInfo(scope:'verify'|'full') 建立的完整 profile。
|
|
952
|
-
*/
|
|
953
|
-
applyProfileUpdate(next: DeviceProfile, deviceInfo?: ProtocolV2DeviceInfo): DeviceProfile {
|
|
954
|
-
const prev = this.profile;
|
|
955
|
-
if (!prev || prev.protocol !== next.protocol) {
|
|
956
|
-
this.updateProfile({
|
|
957
|
-
...next,
|
|
958
|
-
raw: {
|
|
959
|
-
...next.raw,
|
|
960
|
-
...(deviceInfo ? { protocolV2DeviceInfo: deviceInfo } : {}),
|
|
961
|
-
},
|
|
962
|
-
});
|
|
963
|
-
return next;
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
const versions = { ...prev.versions };
|
|
967
|
-
for (const [key, value] of Object.entries(next.versions)) {
|
|
968
|
-
if (value != null) {
|
|
969
|
-
(versions as Record<string, string | null | undefined>)[key] = value;
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
const merged: DeviceProfile = {
|
|
974
|
-
...prev,
|
|
975
|
-
...next,
|
|
976
|
-
versions,
|
|
977
|
-
verify: next.verify ?? prev.verify,
|
|
978
|
-
raw: {
|
|
979
|
-
...prev.raw,
|
|
980
|
-
...next.raw,
|
|
981
|
-
...(deviceInfo ? { protocolV2DeviceInfo: deviceInfo } : {}),
|
|
982
|
-
},
|
|
983
|
-
};
|
|
984
|
-
this.updateProfile(merged);
|
|
985
|
-
return merged;
|
|
986
|
-
}
|
|
987
|
-
|
|
988
|
-
private updateProtocolV2Features(profile: DeviceProfile, deviceInfo?: ProtocolV2DeviceInfo) {
|
|
869
|
+
updateProtocolV2Features(deviceInfo?: ProtocolV2DeviceInfo) {
|
|
989
870
|
const features = fixFeaturesFirmwareVersion(
|
|
990
|
-
|
|
871
|
+
buildProtocolV2FeaturesPayload(deviceInfo, this.features)
|
|
991
872
|
);
|
|
992
|
-
this.
|
|
873
|
+
this.features = features;
|
|
874
|
+
this.featuresNeedsReload = false;
|
|
875
|
+
this.emit(DEVICE.FEATURES, this, features);
|
|
993
876
|
return features;
|
|
994
877
|
}
|
|
995
878
|
|
|
@@ -1027,7 +910,6 @@ export class Device extends EventEmitter {
|
|
|
1027
910
|
if (device.features) {
|
|
1028
911
|
this._updateFeatures(device.features);
|
|
1029
912
|
}
|
|
1030
|
-
this.updateProfile(device.profile);
|
|
1031
913
|
}
|
|
1032
914
|
|
|
1033
915
|
async run(fn?: () => Promise<void>, options?: RunOptions) {
|
|
@@ -1160,17 +1042,7 @@ export class Device extends EventEmitter {
|
|
|
1160
1042
|
}
|
|
1161
1043
|
|
|
1162
1044
|
getMode() {
|
|
1163
|
-
if (this.
|
|
1164
|
-
if (this.profile.status.mode === 'bootloader') return EOneKeyDeviceMode.bootloader;
|
|
1165
|
-
if (this.profile.status.mode === 'notInitialized') return EOneKeyDeviceMode.notInitialized;
|
|
1166
|
-
if (this.profile.status.noBackup === true) return EOneKeyDeviceMode.backupMode;
|
|
1167
|
-
if (this.profile.status.mode === 'normal') return EOneKeyDeviceMode.normal;
|
|
1168
|
-
// mode 'unknown'(V2 设备未上报 init_states)保守按未初始化处理,
|
|
1169
|
-
// 与 isInitialized() 的 fail-closed 行为保持一致。
|
|
1170
|
-
if (this.isProtocolV2()) return EOneKeyDeviceMode.notInitialized;
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
if (this.features?.bootloader_mode) {
|
|
1045
|
+
if (this.features?.bootloaderMode) {
|
|
1174
1046
|
// bootloader mode
|
|
1175
1047
|
return EOneKeyDeviceMode.bootloader;
|
|
1176
1048
|
}
|
|
@@ -1180,7 +1052,7 @@ export class Device extends EventEmitter {
|
|
|
1180
1052
|
return EOneKeyDeviceMode.notInitialized;
|
|
1181
1053
|
}
|
|
1182
1054
|
|
|
1183
|
-
if (this.features?.
|
|
1055
|
+
if (this.features?.noBackup) {
|
|
1184
1056
|
// backup mode
|
|
1185
1057
|
return EOneKeyDeviceMode.backupMode;
|
|
1186
1058
|
}
|
|
@@ -1190,17 +1062,11 @@ export class Device extends EventEmitter {
|
|
|
1190
1062
|
}
|
|
1191
1063
|
|
|
1192
1064
|
getFirmwareVersion() {
|
|
1193
|
-
const profileVersion = profileVersionToArray(this.profile?.versions.firmware);
|
|
1194
|
-
if (profileVersion) return profileVersion;
|
|
1195
|
-
if (this.isProtocolV2()) return null;
|
|
1196
1065
|
if (!this.features) return null;
|
|
1197
1066
|
return getDeviceFirmwareVersion(this.features);
|
|
1198
1067
|
}
|
|
1199
1068
|
|
|
1200
1069
|
getBLEFirmwareVersion() {
|
|
1201
|
-
const profileVersion = profileVersionToArray(this.profile?.versions.ble);
|
|
1202
|
-
if (profileVersion) return profileVersion;
|
|
1203
|
-
if (this.isProtocolV2()) return null;
|
|
1204
1070
|
if (!this.features) return null;
|
|
1205
1071
|
return getDeviceBLEFirmwareVersion(this.features);
|
|
1206
1072
|
}
|
|
@@ -1230,37 +1096,19 @@ export class Device extends EventEmitter {
|
|
|
1230
1096
|
}
|
|
1231
1097
|
|
|
1232
1098
|
isBootloader() {
|
|
1233
|
-
|
|
1234
|
-
return (
|
|
1235
|
-
this.profile.status.mode === 'bootloader' || this.profile.status.bootloaderMode === true
|
|
1236
|
-
);
|
|
1237
|
-
}
|
|
1238
|
-
return this.features && !!this.features.bootloader_mode;
|
|
1099
|
+
return this.features && !!this.features.bootloaderMode;
|
|
1239
1100
|
}
|
|
1240
1101
|
|
|
1241
1102
|
isInitialized() {
|
|
1242
|
-
if (this.profile) {
|
|
1243
|
-
if (this.profile.status.initialized != null) return this.profile.status.initialized;
|
|
1244
|
-
if (this.profile.status.mode === 'normal') return true;
|
|
1245
|
-
if (this.profile.status.mode === 'notInitialized') return false;
|
|
1246
|
-
// V2 设备未上报 init_states 时按未初始化处理(fail-closed):
|
|
1247
|
-
// 未知状态放行会让未初始化设备绕过 NOT_INITIALIZE 门禁。
|
|
1248
|
-
if (this.isProtocolV2()) return false;
|
|
1249
|
-
if (this.features) return !!this.features.initialized;
|
|
1250
|
-
return false;
|
|
1251
|
-
}
|
|
1252
1103
|
return this.features && !!this.features.initialized;
|
|
1253
1104
|
}
|
|
1254
1105
|
|
|
1255
1106
|
isSeedless() {
|
|
1256
|
-
|
|
1257
|
-
return this.profile.status.noBackup === true;
|
|
1258
|
-
}
|
|
1259
|
-
return this.features && !!this.features.no_backup;
|
|
1107
|
+
return this.features && !!this.features.noBackup;
|
|
1260
1108
|
}
|
|
1261
1109
|
|
|
1262
1110
|
isUnacquired(): boolean {
|
|
1263
|
-
return this.features === undefined
|
|
1111
|
+
return this.features === undefined;
|
|
1264
1112
|
}
|
|
1265
1113
|
|
|
1266
1114
|
hasUnexpectedMode(allow: string[], require: string[]) {
|
|
@@ -1291,7 +1139,7 @@ export class Device extends EventEmitter {
|
|
|
1291
1139
|
deviceType === EDeviceType.Touch ||
|
|
1292
1140
|
deviceType === EDeviceType.Pro ||
|
|
1293
1141
|
deviceType === EDeviceType.Pro2;
|
|
1294
|
-
const unlocked = this.
|
|
1142
|
+
const unlocked = this.features?.unlocked;
|
|
1295
1143
|
const preCheckTouch = isModeT && unlocked === false;
|
|
1296
1144
|
const passphraseProtection = this.getCurrentPassphraseProtection();
|
|
1297
1145
|
|
|
@@ -1319,7 +1167,6 @@ export class Device extends EventEmitter {
|
|
|
1319
1167
|
|
|
1320
1168
|
async unlockDevice() {
|
|
1321
1169
|
const firmwareVersion = this.getCurrentFirmwareVersionString() ?? '0.0.0';
|
|
1322
|
-
// profile 优先的版本范围解析;features 仅作为 V1 capability 判断来源
|
|
1323
1170
|
const versionRange = this.getCurrentMethodVersionRange(
|
|
1324
1171
|
type => this.supportUnlockVersionRange()[type]
|
|
1325
1172
|
);
|
|
@@ -1338,24 +1185,11 @@ export class Device extends EventEmitter {
|
|
|
1338
1185
|
|
|
1339
1186
|
if (supportUnlock) {
|
|
1340
1187
|
const res = await this.commands.typedCall('UnLockDevice', 'UnLockDeviceResponse');
|
|
1341
|
-
// 解锁结果同步到 profile(标准模型),features 仅在 V1 缓存存在时回写
|
|
1342
|
-
if (this.profile) {
|
|
1343
|
-
this.updateProfile({
|
|
1344
|
-
...this.profile,
|
|
1345
|
-
status: {
|
|
1346
|
-
...this.profile.status,
|
|
1347
|
-
unlocked: res.message.unlocked == null ? null : res.message.unlocked,
|
|
1348
|
-
...(res.message.passphrase_protection != null
|
|
1349
|
-
? { passphraseProtection: res.message.passphrase_protection }
|
|
1350
|
-
: {}),
|
|
1351
|
-
},
|
|
1352
|
-
});
|
|
1353
|
-
}
|
|
1354
1188
|
if (this.features) {
|
|
1355
1189
|
this.features.unlocked = res.message.unlocked == null ? null : res.message.unlocked;
|
|
1356
|
-
this.features.
|
|
1190
|
+
this.features.unlockedAttachPin =
|
|
1357
1191
|
res.message.unlocked_attach_pin == null ? undefined : res.message.unlocked_attach_pin;
|
|
1358
|
-
this.features.
|
|
1192
|
+
this.features.passphraseProtection =
|
|
1359
1193
|
res.message.passphrase_protection == null ? null : res.message.passphrase_protection;
|
|
1360
1194
|
|
|
1361
1195
|
return Promise.resolve(this.features);
|
package/src/device/DevicePool.ts
CHANGED
|
@@ -166,7 +166,7 @@ export class DevicePool extends EventEmitter {
|
|
|
166
166
|
for (let i = this.connectedPool.length - 1; i >= 0; i--) {
|
|
167
167
|
const descriptor = this.connectedPool[i];
|
|
168
168
|
const device = await this._createDevice(descriptor, initOptions);
|
|
169
|
-
Log.debug('emit DEVICE.CONNECT: ', device?.
|
|
169
|
+
Log.debug('emit DEVICE.CONNECT: ', device?.features);
|
|
170
170
|
this.emitter.emit(DEVICE.CONNECT, device);
|
|
171
171
|
this.connectedPool.splice(i, 1);
|
|
172
172
|
}
|
|
@@ -203,7 +203,7 @@ export class DevicePool extends EventEmitter {
|
|
|
203
203
|
this._addConnectedDeviceToPool(d);
|
|
204
204
|
return;
|
|
205
205
|
}
|
|
206
|
-
Log.debug('emit DEVICE.CONNECT: ', device.
|
|
206
|
+
Log.debug('emit DEVICE.CONNECT: ', device.features);
|
|
207
207
|
this.emitter.emit(DEVICE.CONNECT, device);
|
|
208
208
|
});
|
|
209
209
|
|
|
@@ -215,7 +215,7 @@ export class DevicePool extends EventEmitter {
|
|
|
215
215
|
return;
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
-
Log.debug('emit DEVICE.DISCONNECT: ', device.
|
|
218
|
+
Log.debug('emit DEVICE.DISCONNECT: ', device.features);
|
|
219
219
|
this.emitter.emit(DEVICE.DISCONNECT, device);
|
|
220
220
|
});
|
|
221
221
|
}
|