@onekeyfe/hd-core 1.2.0-alpha.33 → 1.2.0-alpha.34
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__/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 +22 -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 +64 -17
- 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 +331 -27
- package/__tests__/pro2Wallpaper.test.ts +1 -1
- package/__tests__/protocol-v2.test.ts +707 -74
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +1 -0
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/GetPassphraseState.d.ts.map +1 -1
- package/dist/api/device/DeviceSettings.d.ts.map +1 -1
- package/dist/api/kaspa/KaspaSignTransaction.d.ts.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/device/Device.d.ts +7 -2
- package/dist/device/Device.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 +8 -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 +19 -7
- package/dist/index.js +455 -221
- package/dist/protocols/protocol-v2/walletSession.d.ts +0 -10
- package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
- package/dist/types/api/openWalletSession.d.ts +1 -1
- package/dist/types/api/openWalletSession.d.ts.map +1 -1
- package/dist/types/device.d.ts +4 -2
- 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/pro2Wallpaper.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/CheckAllFirmwareRelease.ts +11 -81
- package/src/api/FirmwareUpdateV4.ts +33 -17
- package/src/api/GetPassphraseState.ts +1 -3
- package/src/api/OpenWalletSession.ts +3 -3
- package/src/api/device/DeviceSettings.ts +8 -1
- package/src/api/kaspa/KaspaSignTransaction.ts +7 -0
- package/src/core/index.ts +7 -5
- package/src/device/Device.ts +37 -9
- 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 +57 -4
- package/src/deviceProfile/buildDeviceFeatures.ts +10 -3
- 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/walletSession.ts +115 -33
- package/src/types/api/openWalletSession.ts +1 -1
- package/src/types/device.ts +6 -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
|
@@ -280,7 +280,7 @@ export class Device extends EventEmitter {
|
|
|
280
280
|
|
|
281
281
|
// simplified object to pass via postMessage
|
|
282
282
|
toMessageObject(): DeviceTyped | null {
|
|
283
|
-
if (this.isUnacquired()) return null;
|
|
283
|
+
if (this.isUnacquired() || !this.features) return null;
|
|
284
284
|
|
|
285
285
|
const env = DataManager.getSettings('env');
|
|
286
286
|
const deviceType = this.getCurrentDeviceType();
|
|
@@ -297,6 +297,8 @@ export class Device extends EventEmitter {
|
|
|
297
297
|
return {
|
|
298
298
|
/** Android uses a MAC address, while iOS and USB use transport-specific identifiers. */
|
|
299
299
|
connectId: DataManager.isBleConnect(env) ? this.mainId || null : connectId,
|
|
300
|
+
/** Persist this after the first active probe so later calls do not need to guess. */
|
|
301
|
+
connectProtocol: this.originalDescriptor.protocolType,
|
|
300
302
|
/** Stable physical-device identity. */
|
|
301
303
|
serialNo,
|
|
302
304
|
/** @deprecated Use serialNo instead. */
|
|
@@ -364,12 +366,12 @@ export class Device extends EventEmitter {
|
|
|
364
366
|
}
|
|
365
367
|
|
|
366
368
|
async acquire(
|
|
367
|
-
|
|
369
|
+
expectedProtocol?: HardwareConnectProtocol,
|
|
368
370
|
options?: { throwOnRunPromiseError?: boolean }
|
|
369
371
|
) {
|
|
370
372
|
const env = DataManager.getSettings('env');
|
|
371
373
|
const mainIdKey = DataManager.isBleConnect(env) ? 'id' : 'session';
|
|
372
|
-
const
|
|
374
|
+
const protocolHint = expectedProtocol ? undefined : this.originalDescriptor.protocolType;
|
|
373
375
|
try {
|
|
374
376
|
let acquireResult: unknown;
|
|
375
377
|
if (DataManager.isBleConnect(env)) {
|
|
@@ -381,7 +383,8 @@ export class Device extends EventEmitter {
|
|
|
381
383
|
this.originalDescriptor.id,
|
|
382
384
|
undefined,
|
|
383
385
|
true,
|
|
384
|
-
expectedProtocol
|
|
386
|
+
expectedProtocol,
|
|
387
|
+
protocolHint
|
|
385
388
|
);
|
|
386
389
|
this.mainId = (acquireResult as any)?.uuid ?? '';
|
|
387
390
|
Log.debug('Expected uuid:', this.mainId);
|
|
@@ -390,7 +393,8 @@ export class Device extends EventEmitter {
|
|
|
390
393
|
this.originalDescriptor.path,
|
|
391
394
|
this.originalDescriptor.session,
|
|
392
395
|
undefined,
|
|
393
|
-
expectedProtocol
|
|
396
|
+
expectedProtocol,
|
|
397
|
+
protocolHint
|
|
394
398
|
);
|
|
395
399
|
this.mainId = acquireResult as string | undefined;
|
|
396
400
|
Log.debug('Expected session id:', this.mainId);
|
|
@@ -717,13 +721,20 @@ export class Device extends EventEmitter {
|
|
|
717
721
|
return deviceWalletSessionStore.get(deviceId, this.passphraseState);
|
|
718
722
|
}
|
|
719
723
|
|
|
724
|
+
getStandardInternalState(_deviceId?: string) {
|
|
725
|
+
const deviceId = this.getSessionCacheDeviceKey(_deviceId);
|
|
726
|
+
if (!deviceId) return undefined;
|
|
727
|
+
return deviceWalletSessionStore.getStandard(deviceId);
|
|
728
|
+
}
|
|
729
|
+
|
|
720
730
|
// attach to pin to fix internal state
|
|
721
731
|
updateInternalState(
|
|
722
732
|
enablePassphrase: boolean,
|
|
723
733
|
passphraseState: string | undefined,
|
|
724
734
|
deviceId: string | undefined,
|
|
725
735
|
sessionId: string | null = null,
|
|
726
|
-
featuresSessionId: string | null = null
|
|
736
|
+
featuresSessionId: string | null = null,
|
|
737
|
+
walletType: 'standard' | 'hidden' = 'hidden'
|
|
727
738
|
) {
|
|
728
739
|
Log.debug(
|
|
729
740
|
'updateInternalState session param: ',
|
|
@@ -740,7 +751,15 @@ export class Device extends EventEmitter {
|
|
|
740
751
|
if (enablePassphrase) {
|
|
741
752
|
const walletSessionId =
|
|
742
753
|
sessionId || featuresSessionId || deviceWalletSessionStore.getPending(cacheDeviceKey);
|
|
743
|
-
|
|
754
|
+
if (walletType === 'standard') {
|
|
755
|
+
deviceWalletSessionStore.setStandard(
|
|
756
|
+
cacheDeviceKey,
|
|
757
|
+
passphraseState,
|
|
758
|
+
walletSessionId ?? undefined
|
|
759
|
+
);
|
|
760
|
+
} else {
|
|
761
|
+
deviceWalletSessionStore.set(cacheDeviceKey, passphraseState, walletSessionId ?? undefined);
|
|
762
|
+
}
|
|
744
763
|
}
|
|
745
764
|
|
|
746
765
|
deviceWalletSessionStore.deletePending(cacheDeviceKey);
|
|
@@ -779,6 +798,12 @@ export class Device extends EventEmitter {
|
|
|
779
798
|
}
|
|
780
799
|
}
|
|
781
800
|
|
|
801
|
+
clearStandardInternalState(_deviceId?: string) {
|
|
802
|
+
const deviceId = this.getSessionCacheDeviceKey(_deviceId);
|
|
803
|
+
if (!deviceId) return;
|
|
804
|
+
deviceWalletSessionStore.deleteStandard(deviceId);
|
|
805
|
+
}
|
|
806
|
+
|
|
782
807
|
async initialize(options?: InitOptions) {
|
|
783
808
|
// Protocol V2 does not support legacy Initialize; use its dedicated flow.
|
|
784
809
|
if (this.isProtocolV2()) {
|
|
@@ -810,9 +835,12 @@ export class Device extends EventEmitter {
|
|
|
810
835
|
|
|
811
836
|
const expectedDeviceId = options?.deviceId;
|
|
812
837
|
if (expectedDeviceId) {
|
|
813
|
-
//
|
|
838
|
+
// Verify the physical device with a read-only Features request. An
|
|
839
|
+
// empty-context Initialize would invalidate a cached V1 hidden-wallet session.
|
|
814
840
|
this.passphraseState = undefined;
|
|
815
|
-
await
|
|
841
|
+
const { message } = await this.commands.typedCall('GetFeatures', 'Features', {});
|
|
842
|
+
this._updateFeatures(message);
|
|
843
|
+
await TransportManager.reconfigure(this.features);
|
|
816
844
|
if (!this.checkDeviceId(expectedDeviceId)) {
|
|
817
845
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckDeviceIdError);
|
|
818
846
|
}
|
|
@@ -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,13 @@
|
|
|
1
1
|
export class DeviceWalletSessionStore {
|
|
2
|
+
private static readonly MAX_SESSIONS_PER_DEVICE = 3;
|
|
3
|
+
|
|
2
4
|
private readonly walletSessions = new Map<string, Map<string, string>>();
|
|
3
5
|
|
|
6
|
+
private readonly standardWalletSessions = new Map<
|
|
7
|
+
string,
|
|
8
|
+
{ passphraseState: string; sessionId: string }
|
|
9
|
+
>();
|
|
10
|
+
|
|
4
11
|
private readonly pendingSessions = new Map<string, string>();
|
|
5
12
|
|
|
6
13
|
get(deviceKey: string, passphraseState?: string) {
|
|
@@ -15,9 +22,32 @@ export class DeviceWalletSessionStore {
|
|
|
15
22
|
deviceSessions = new Map<string, string>();
|
|
16
23
|
this.walletSessions.set(deviceKey, deviceSessions);
|
|
17
24
|
}
|
|
25
|
+
if (
|
|
26
|
+
!deviceSessions.has(passphraseState) &&
|
|
27
|
+
deviceSessions.size >= DeviceWalletSessionStore.MAX_SESSIONS_PER_DEVICE
|
|
28
|
+
) {
|
|
29
|
+
const oldestPassphraseState = deviceSessions.keys().next().value as string | undefined;
|
|
30
|
+
if (oldestPassphraseState) {
|
|
31
|
+
deviceSessions.delete(oldestPassphraseState);
|
|
32
|
+
if (this.standardWalletSessions.get(deviceKey)?.passphraseState === oldestPassphraseState) {
|
|
33
|
+
this.standardWalletSessions.delete(deviceKey);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
18
37
|
deviceSessions.set(passphraseState, sessionId);
|
|
19
38
|
}
|
|
20
39
|
|
|
40
|
+
getStandard(deviceKey: string) {
|
|
41
|
+
if (!deviceKey) return undefined;
|
|
42
|
+
return this.standardWalletSessions.get(deviceKey);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
setStandard(deviceKey: string, passphraseState?: string, sessionId?: string) {
|
|
46
|
+
if (!deviceKey || !passphraseState || !sessionId) return;
|
|
47
|
+
this.set(deviceKey, passphraseState, sessionId);
|
|
48
|
+
this.standardWalletSessions.set(deviceKey, { passphraseState, sessionId });
|
|
49
|
+
}
|
|
50
|
+
|
|
21
51
|
setPending(deviceKey: string, sessionId?: string) {
|
|
22
52
|
if (!deviceKey || !sessionId) return;
|
|
23
53
|
this.pendingSessions.set(deviceKey, sessionId);
|
|
@@ -30,6 +60,10 @@ export class DeviceWalletSessionStore {
|
|
|
30
60
|
|
|
31
61
|
delete(deviceKey: string, passphraseState?: string) {
|
|
32
62
|
if (!deviceKey || !passphraseState) return;
|
|
63
|
+
const standardWalletSession = this.standardWalletSessions.get(deviceKey);
|
|
64
|
+
if (standardWalletSession?.passphraseState === passphraseState) {
|
|
65
|
+
this.standardWalletSessions.delete(deviceKey);
|
|
66
|
+
}
|
|
33
67
|
const deviceSessions = this.walletSessions.get(deviceKey);
|
|
34
68
|
if (!deviceSessions) return;
|
|
35
69
|
deviceSessions.delete(passphraseState);
|
|
@@ -38,6 +72,15 @@ export class DeviceWalletSessionStore {
|
|
|
38
72
|
}
|
|
39
73
|
}
|
|
40
74
|
|
|
75
|
+
deleteStandard(deviceKey: string) {
|
|
76
|
+
if (!deviceKey) return;
|
|
77
|
+
const standardWalletSession = this.standardWalletSessions.get(deviceKey);
|
|
78
|
+
this.standardWalletSessions.delete(deviceKey);
|
|
79
|
+
if (standardWalletSession) {
|
|
80
|
+
this.delete(deviceKey, standardWalletSession.passphraseState);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
41
84
|
deletePending(deviceKey: string) {
|
|
42
85
|
if (!deviceKey) return;
|
|
43
86
|
this.pendingSessions.delete(deviceKey);
|
|
@@ -46,6 +89,7 @@ export class DeviceWalletSessionStore {
|
|
|
46
89
|
deleteDevice(deviceKey: string) {
|
|
47
90
|
if (!deviceKey) return;
|
|
48
91
|
this.walletSessions.delete(deviceKey);
|
|
92
|
+
this.standardWalletSessions.delete(deviceKey);
|
|
49
93
|
this.pendingSessions.delete(deviceKey);
|
|
50
94
|
}
|
|
51
95
|
|
|
@@ -54,16 +98,24 @@ export class DeviceWalletSessionStore {
|
|
|
54
98
|
|
|
55
99
|
const sourceSessions = this.walletSessions.get(from);
|
|
56
100
|
if (sourceSessions) {
|
|
57
|
-
const targetSessions = this.walletSessions.get(to) ?? new Map<string, string>();
|
|
58
|
-
this.walletSessions.set(to, targetSessions);
|
|
59
101
|
sourceSessions.forEach((sessionId, passphraseState) => {
|
|
60
|
-
if (!
|
|
61
|
-
|
|
102
|
+
if (!this.get(to, passphraseState)) {
|
|
103
|
+
this.set(to, passphraseState, sessionId);
|
|
62
104
|
}
|
|
63
105
|
});
|
|
64
106
|
this.walletSessions.delete(from);
|
|
65
107
|
}
|
|
66
108
|
|
|
109
|
+
const standardWalletSession = this.standardWalletSessions.get(from);
|
|
110
|
+
if (
|
|
111
|
+
standardWalletSession &&
|
|
112
|
+
!this.standardWalletSessions.has(to) &&
|
|
113
|
+
this.get(to, standardWalletSession.passphraseState) === standardWalletSession.sessionId
|
|
114
|
+
) {
|
|
115
|
+
this.standardWalletSessions.set(to, standardWalletSession);
|
|
116
|
+
}
|
|
117
|
+
this.standardWalletSessions.delete(from);
|
|
118
|
+
|
|
67
119
|
const pendingSession = this.pendingSessions.get(from);
|
|
68
120
|
if (pendingSession && !this.pendingSessions.has(to)) {
|
|
69
121
|
this.pendingSessions.set(to, pendingSession);
|
|
@@ -98,6 +150,7 @@ export class DeviceWalletSessionStore {
|
|
|
98
150
|
|
|
99
151
|
clear() {
|
|
100
152
|
this.walletSessions.clear();
|
|
153
|
+
this.standardWalletSessions.clear();
|
|
101
154
|
this.pendingSessions.clear();
|
|
102
155
|
}
|
|
103
156
|
}
|
|
@@ -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),
|
|
@@ -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
|
+
};
|
|
@@ -1,10 +1,68 @@
|
|
|
1
|
+
import { UI_REQUEST } from './ui-request';
|
|
1
2
|
import { UI_RESPONSE } from './ui-response';
|
|
2
3
|
|
|
3
4
|
export const LogBlockEvent: Set<string> = new Set([
|
|
5
|
+
UI_REQUEST.REQUEST_PASSPHRASE,
|
|
6
|
+
UI_REQUEST.REQUEST_PASSPHRASE_ON_DEVICE,
|
|
4
7
|
UI_RESPONSE.RECEIVE_PIN,
|
|
5
8
|
UI_RESPONSE.RECEIVE_PASSPHRASE,
|
|
6
9
|
]);
|
|
7
10
|
|
|
11
|
+
const LogLabelMethod: Set<string> = new Set([
|
|
12
|
+
'openWalletSession',
|
|
13
|
+
'deviceUploadWallpaper',
|
|
14
|
+
'uploadPortfolio',
|
|
15
|
+
'fileWrite',
|
|
16
|
+
'fileRead',
|
|
17
|
+
]);
|
|
18
|
+
|
|
19
|
+
const SensitiveLogKeys: Set<string> = new Set([
|
|
20
|
+
'devicestate',
|
|
21
|
+
'entropy',
|
|
22
|
+
'expectedpassphrasestate',
|
|
23
|
+
'mnemonic',
|
|
24
|
+
'passphrase',
|
|
25
|
+
'passphrasestate',
|
|
26
|
+
'password',
|
|
27
|
+
'pin',
|
|
28
|
+
'privatekey',
|
|
29
|
+
'seed',
|
|
30
|
+
'session',
|
|
31
|
+
'sessionid',
|
|
32
|
+
'walletsessionid',
|
|
33
|
+
'xprv',
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
const normalizeLogKey = (key: string) => key.replace(/[_-]/g, '').toLowerCase();
|
|
37
|
+
|
|
38
|
+
const isSigningMethod = (methodName: string) => /sign/i.test(methodName);
|
|
39
|
+
|
|
40
|
+
const redactLogValue = (value: unknown, seen: WeakSet<object>): unknown => {
|
|
41
|
+
if (ArrayBuffer.isView(value)) {
|
|
42
|
+
return `[BINARY:${value.byteLength}]`;
|
|
43
|
+
}
|
|
44
|
+
if (value instanceof ArrayBuffer) {
|
|
45
|
+
return `[BINARY:${value.byteLength}]`;
|
|
46
|
+
}
|
|
47
|
+
if (Array.isArray(value)) {
|
|
48
|
+
return value.map(item => redactLogValue(item, seen));
|
|
49
|
+
}
|
|
50
|
+
if (!value || typeof value !== 'object') return value;
|
|
51
|
+
if (seen.has(value)) return '[CIRCULAR]';
|
|
52
|
+
|
|
53
|
+
seen.add(value);
|
|
54
|
+
const redacted = Object.fromEntries(
|
|
55
|
+
Object.entries(value as Record<string, unknown>).map(([key, item]) => [
|
|
56
|
+
key,
|
|
57
|
+
SensitiveLogKeys.has(normalizeLogKey(key)) && item !== null && item !== undefined
|
|
58
|
+
? '[REDACTED]'
|
|
59
|
+
: redactLogValue(item, seen),
|
|
60
|
+
])
|
|
61
|
+
);
|
|
62
|
+
seen.delete(value);
|
|
63
|
+
return redacted;
|
|
64
|
+
};
|
|
65
|
+
|
|
8
66
|
export function getLogBlockLabel(message: unknown): string | undefined {
|
|
9
67
|
if (!message || typeof message !== 'object') return undefined;
|
|
10
68
|
|
|
@@ -19,5 +77,30 @@ export function getLogBlockLabel(message: unknown): string | undefined {
|
|
|
19
77
|
}
|
|
20
78
|
|
|
21
79
|
const methodName = method ?? payload?.method;
|
|
22
|
-
|
|
80
|
+
if (methodName && (LogLabelMethod.has(methodName) || isSigningMethod(methodName))) {
|
|
81
|
+
return methodName;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function getSafeLogPayload(value: unknown, blockLabel?: string): unknown {
|
|
88
|
+
if (blockLabel && (LogBlockEvent.has(blockLabel) || isSigningMethod(blockLabel))) {
|
|
89
|
+
return { method: blockLabel, payload: '[REDACTED]' };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const redactedValue = redactLogValue(value, new WeakSet());
|
|
93
|
+
if (
|
|
94
|
+
blockLabel &&
|
|
95
|
+
redactedValue &&
|
|
96
|
+
typeof redactedValue === 'object' &&
|
|
97
|
+
!Array.isArray(redactedValue)
|
|
98
|
+
) {
|
|
99
|
+
return { ...redactedValue, method: blockLabel };
|
|
100
|
+
}
|
|
101
|
+
return redactedValue;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function formatLogMethodLabel(label: string, methodName?: string): string {
|
|
105
|
+
return methodName ? `${label} [${methodName}]` : label;
|
|
23
106
|
}
|