@onekeyfe/hd-core 1.2.0-alpha.22 → 1.2.0-alpha.23
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 +8 -8
- package/__tests__/device-settings.test.ts +1 -1
- package/__tests__/device-wallet-session-store.test.ts +41 -0
- package/__tests__/firmware-update/check-all-firmware-release.test.ts +86 -0
- package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +13 -0
- package/__tests__/logBlockEvent.test.ts +17 -0
- package/__tests__/open-wallet-session.test.ts +90 -31
- package/__tests__/protocol-v2.test.ts +301 -63
- package/dist/api/CheckAllFirmwareRelease.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.map +1 -1
- package/dist/api/GetPassphraseState.d.ts.map +1 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
- package/dist/api/device/DeviceWipe.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareArtifactSource.d.ts +0 -1
- package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +0 -1
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +6 -1
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/device/Device.d.ts +3 -2
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/events/device.d.ts +1 -0
- package/dist/events/device.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/events/ui-request.d.ts +1 -0
- package/dist/events/ui-request.d.ts.map +1 -1
- package/dist/index.d.ts +10 -6
- package/dist/index.js +157 -268
- package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
- package/dist/types/api/getPassphraseState.d.ts.map +1 -1
- package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/CheckAllFirmwareRelease.ts +15 -8
- package/src/api/FirmwareUpdateV2.ts +8 -1
- package/src/api/FirmwareUpdateV3.ts +8 -0
- package/src/api/FirmwareUpdateV4.ts +21 -19
- package/src/api/GetPassphraseState.ts +11 -5
- package/src/api/device/DeviceUpdateBootloader.ts +9 -1
- package/src/api/device/DeviceWipe.ts +2 -0
- package/src/api/firmware/FirmwareArtifactSource.ts +1 -1
- package/src/api/firmware/FirmwareUpdatePlan.ts +1 -1
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +15 -1
- package/src/core/index.ts +1 -0
- package/src/data/messages/messages-protocol-v2.json +18 -57
- package/src/device/Device.ts +30 -7
- package/src/device/DeviceCommands.ts +24 -151
- package/src/events/device.ts +1 -0
- package/src/events/logBlockEvent.ts +1 -15
- package/src/events/ui-request.ts +1 -0
- package/src/protocols/protocol-v2/deviceSession.ts +1 -1
- package/src/protocols/protocol-v2/settingsUnlockPolicy.ts +0 -1
- package/src/protocols/protocol-v2/walletSession.ts +41 -20
- package/src/types/api/getPassphraseState.ts +4 -3
- package/src/utils/deviceInfoUtils.ts +3 -16
|
@@ -11,7 +11,11 @@ import { DataManager } from '../../data-manager';
|
|
|
11
11
|
import { checkBootloaderLength, checkBootloaderSourceLength } from '../firmware/updateBootloader';
|
|
12
12
|
import { openFirmwareByteSource } from '../firmware/FirmwareArtifactSource';
|
|
13
13
|
import { resolveFirmwareUpdateHostBinding } from '../firmware/FirmwareHostBinding';
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
assertFirmwareUpdatePreparedPlanBinding,
|
|
16
|
+
assertFirmwareUpdatePreparedPlanDeviceIdentity,
|
|
17
|
+
} from '../firmware/FirmwareUpdatePreparedPlan';
|
|
18
|
+
import { getDeviceUUID } from '../../utils';
|
|
15
19
|
|
|
16
20
|
import type { DeviceUpdateBootloaderParams } from '../../types/api/deviceUpdateBootloader';
|
|
17
21
|
import type { EFirmwareType } from '@onekeyfe/hd-shared';
|
|
@@ -160,6 +164,10 @@ export default class DeviceUpdateBootloader extends FirmwareUpdateBaseMethod<any
|
|
|
160
164
|
artifactReader: hostBinding?.artifactReader ?? payload.artifactReader,
|
|
161
165
|
};
|
|
162
166
|
if (payload.artifact) {
|
|
167
|
+
assertFirmwareUpdatePreparedPlanDeviceIdentity({
|
|
168
|
+
preparedPlan: payload.preparedPlan,
|
|
169
|
+
deviceIdentity: getDeviceUUID(features) || undefined,
|
|
170
|
+
});
|
|
163
171
|
assertFirmwareUpdatePreparedPlanBinding({
|
|
164
172
|
preparedPlan: payload.preparedPlan,
|
|
165
173
|
executor: 'v2',
|
|
@@ -24,10 +24,12 @@ export default class DeviceWipe extends BaseMethod<WipeDevice> {
|
|
|
24
24
|
const res = await this.device.commands.typedCall('DeviceSettingsPageShow', 'Success', {
|
|
25
25
|
page: DeviceSettingsPage.DeviceReset,
|
|
26
26
|
});
|
|
27
|
+
this.device.invalidateAfterWipe();
|
|
27
28
|
return Promise.resolve(res.message);
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
const res = await this.device.commands.typedCall('WipeDevice', 'Success');
|
|
32
|
+
this.device.invalidateAfterWipe();
|
|
31
33
|
|
|
32
34
|
return Promise.resolve(res.message);
|
|
33
35
|
}
|
|
@@ -58,7 +58,7 @@ export const assertFirmwareArtifactReference = (
|
|
|
58
58
|
return artifact;
|
|
59
59
|
};
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
const assertFirmwareArtifactRead = (size: number, offset: number, length: number) => {
|
|
62
62
|
if (
|
|
63
63
|
!Number.isSafeInteger(offset) ||
|
|
64
64
|
offset < 0 ||
|
|
@@ -149,7 +149,7 @@ export const digestFirmwareUpdateContract = (value: unknown): string =>
|
|
|
149
149
|
sha256(new TextEncoder().encode(JSON.stringify(canonicalizeFirmwareUpdateContract(value))))
|
|
150
150
|
);
|
|
151
151
|
|
|
152
|
-
|
|
152
|
+
const digestFirmwareUpdatePlan = (plan: Omit<FirmwareUpdatePlan, 'planDigest'>): string =>
|
|
153
153
|
digestFirmwareUpdateContract(plan);
|
|
154
154
|
|
|
155
155
|
const planError = (message: string): never => {
|
|
@@ -295,7 +295,21 @@ export const validateFirmwareUpdatePreparedPlan = (value: unknown): FirmwareUpda
|
|
|
295
295
|
return preparedPlan;
|
|
296
296
|
};
|
|
297
297
|
|
|
298
|
-
export
|
|
298
|
+
export const assertFirmwareUpdatePreparedPlanDeviceIdentity = ({
|
|
299
|
+
preparedPlan: value,
|
|
300
|
+
deviceIdentity,
|
|
301
|
+
}: {
|
|
302
|
+
preparedPlan: unknown;
|
|
303
|
+
deviceIdentity: string | undefined;
|
|
304
|
+
}): FirmwareUpdatePreparedPlan => {
|
|
305
|
+
const preparedPlan = validateFirmwareUpdatePreparedPlan(value);
|
|
306
|
+
if (!deviceIdentity || preparedPlan.deviceIdentity !== deviceIdentity) {
|
|
307
|
+
throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckDeviceIdError);
|
|
308
|
+
}
|
|
309
|
+
return preparedPlan;
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
type FirmwareUpdatePreparedBinding = {
|
|
299
313
|
target: FirmwareUpdatePlan['targetsToUpdate'][number];
|
|
300
314
|
artifact: FirmwareArtifactReference;
|
|
301
315
|
logicalName?: string;
|
package/src/core/index.ts
CHANGED
|
@@ -1262,6 +1262,7 @@ const onDevicePassphraseHandler = async (
|
|
|
1262
1262
|
device: device.toMessageObject() as KnownDevice,
|
|
1263
1263
|
passphraseState: device.passphraseState,
|
|
1264
1264
|
existsAttachPinUser: requestPayload.existsAttachPinUser,
|
|
1265
|
+
deviceOnly: requestPayload.deviceOnly,
|
|
1265
1266
|
source: requestPayload.source,
|
|
1266
1267
|
reason: requestPayload.reason,
|
|
1267
1268
|
expectedPassphraseState: requestPayload.expectedPassphraseState,
|
|
@@ -482,9 +482,10 @@
|
|
|
482
482
|
"MessageType_DeviceStatus": 60603,
|
|
483
483
|
"MessageType_DevGetOnboardingStatus": 60604,
|
|
484
484
|
"MessageType_DevOnboardingStatus": 60605,
|
|
485
|
+
"MessageType_DeviceSessionGet": 60606,
|
|
485
486
|
"MessageType_DeviceSession": 60607,
|
|
486
487
|
"MessageType_DeviceSessionAskPin": 60608,
|
|
487
|
-
"
|
|
488
|
+
"MessageType_DeviceSessionAskPassphrase": 60609,
|
|
488
489
|
"MessageType_FilesystemPermissionFix": 60800,
|
|
489
490
|
"MessageType_FilesystemPathInfo": 60801,
|
|
490
491
|
"MessageType_FilesystemPathInfoQuery": 60802,
|
|
@@ -506,8 +507,7 @@
|
|
|
506
507
|
[90, 92],
|
|
507
508
|
[114, 122],
|
|
508
509
|
[300, 304],
|
|
509
|
-
[309, 312]
|
|
510
|
-
[60606, 60606]
|
|
510
|
+
[309, 312]
|
|
511
511
|
]
|
|
512
512
|
},
|
|
513
513
|
"AlephiumGetAddress": {
|
|
@@ -12446,81 +12446,42 @@
|
|
|
12446
12446
|
"DeviceSessionError_Busy": 5
|
|
12447
12447
|
}
|
|
12448
12448
|
},
|
|
12449
|
-
"
|
|
12449
|
+
"DeviceSessionGet": {
|
|
12450
12450
|
"fields": {
|
|
12451
12451
|
"session_id": {
|
|
12452
|
-
"rule": "required",
|
|
12453
12452
|
"type": "bytes",
|
|
12454
12453
|
"id": 1
|
|
12455
12454
|
}
|
|
12456
12455
|
}
|
|
12457
12456
|
},
|
|
12458
|
-
"
|
|
12459
|
-
"fields": {
|
|
12460
|
-
"passphrase": {
|
|
12461
|
-
"rule": "required",
|
|
12462
|
-
"type": "string",
|
|
12463
|
-
"id": 1
|
|
12464
|
-
}
|
|
12465
|
-
}
|
|
12466
|
-
},
|
|
12467
|
-
"DeviceSessionPassphraseOnDevice": {
|
|
12468
|
-
"fields": {}
|
|
12469
|
-
},
|
|
12470
|
-
"DeviceSessionAttachPinOnDevice": {
|
|
12471
|
-
"fields": {}
|
|
12472
|
-
},
|
|
12473
|
-
"DeviceSessionSelect": {
|
|
12474
|
-
"oneofs": {
|
|
12475
|
-
"access": {
|
|
12476
|
-
"oneof": ["host_passphrase", "passphrase_on_device", "attach_pin_on_device"]
|
|
12477
|
-
}
|
|
12478
|
-
},
|
|
12457
|
+
"DeviceSession": {
|
|
12479
12458
|
"fields": {
|
|
12480
|
-
"
|
|
12481
|
-
"type": "
|
|
12459
|
+
"session_id": {
|
|
12460
|
+
"type": "bytes",
|
|
12482
12461
|
"id": 1
|
|
12483
12462
|
},
|
|
12484
|
-
"
|
|
12485
|
-
"type": "
|
|
12463
|
+
"btc_test_address": {
|
|
12464
|
+
"type": "string",
|
|
12486
12465
|
"id": 2
|
|
12487
|
-
},
|
|
12488
|
-
"attach_pin_on_device": {
|
|
12489
|
-
"type": "DeviceSessionAttachPinOnDevice",
|
|
12490
|
-
"id": 3
|
|
12491
12466
|
}
|
|
12492
12467
|
}
|
|
12493
12468
|
},
|
|
12494
|
-
"
|
|
12495
|
-
"
|
|
12496
|
-
"
|
|
12497
|
-
|
|
12498
|
-
|
|
12499
|
-
},
|
|
12500
|
-
"fields": {
|
|
12501
|
-
"resume": {
|
|
12502
|
-
"type": "DeviceSessionResume",
|
|
12503
|
-
"id": 1
|
|
12504
|
-
},
|
|
12505
|
-
"select": {
|
|
12506
|
-
"type": "DeviceSessionSelect",
|
|
12507
|
-
"id": 2
|
|
12508
|
-
}
|
|
12469
|
+
"DeviceSessionPinType": {
|
|
12470
|
+
"values": {
|
|
12471
|
+
"Any": 1,
|
|
12472
|
+
"Main": 2,
|
|
12473
|
+
"AttachToPin": 3
|
|
12509
12474
|
}
|
|
12510
12475
|
},
|
|
12511
|
-
"
|
|
12476
|
+
"DeviceSessionAskPin": {
|
|
12512
12477
|
"fields": {
|
|
12513
|
-
"
|
|
12514
|
-
"type": "
|
|
12478
|
+
"type": {
|
|
12479
|
+
"type": "DeviceSessionPinType",
|
|
12515
12480
|
"id": 1
|
|
12516
|
-
},
|
|
12517
|
-
"btc_test_address": {
|
|
12518
|
-
"type": "string",
|
|
12519
|
-
"id": 2
|
|
12520
12481
|
}
|
|
12521
12482
|
}
|
|
12522
12483
|
},
|
|
12523
|
-
"
|
|
12484
|
+
"DeviceSessionAskPassphrase": {
|
|
12524
12485
|
"fields": {}
|
|
12525
12486
|
},
|
|
12526
12487
|
"DeviceSessionAskPin_FailureSubCodes": {
|
package/src/device/Device.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import EventEmitter from 'events';
|
|
2
2
|
import semver from 'semver';
|
|
3
|
-
import { DeviceRebootType, Enum_Capability } from '@onekeyfe/hd-transport';
|
|
3
|
+
import { DeviceRebootType, DeviceSessionPinType, Enum_Capability } from '@onekeyfe/hd-transport';
|
|
4
4
|
import {
|
|
5
5
|
EDeviceType,
|
|
6
6
|
ERRORS,
|
|
@@ -322,8 +322,10 @@ export class Device extends EventEmitter {
|
|
|
322
322
|
deviceId,
|
|
323
323
|
path: this.originalDescriptor?.path,
|
|
324
324
|
bleName,
|
|
325
|
-
name:
|
|
326
|
-
|
|
325
|
+
name: label || bleName || `OneKey ${deviceType?.toUpperCase()}`,
|
|
326
|
+
// Keep the legacy top-level field string-compatible while preserving
|
|
327
|
+
// the canonical nullable value at state.identity.label.
|
|
328
|
+
label: label ?? '',
|
|
327
329
|
mode: this.getMode(),
|
|
328
330
|
features,
|
|
329
331
|
state,
|
|
@@ -1068,6 +1070,22 @@ export class Device extends EventEmitter {
|
|
|
1068
1070
|
this.clearPreInitialized();
|
|
1069
1071
|
}
|
|
1070
1072
|
|
|
1073
|
+
invalidateAfterWipe() {
|
|
1074
|
+
const deviceId = this.getCurrentDeviceId();
|
|
1075
|
+
if (deviceId) {
|
|
1076
|
+
deviceWalletSessionStore.deleteDevice(deviceId);
|
|
1077
|
+
}
|
|
1078
|
+
if (this.isProtocolV2() && this.originalDescriptor.path !== deviceId) {
|
|
1079
|
+
deviceWalletSessionStore.deleteDevice(this.originalDescriptor.path);
|
|
1080
|
+
this.protocolV2StateNeedsReload = true;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
this.passphraseState = undefined;
|
|
1084
|
+
this.stateStore = new DeviceStateStore();
|
|
1085
|
+
this.clearPreInitialized();
|
|
1086
|
+
this.needReloadDevice = true;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1071
1089
|
markProtocolV2Reboot(rebootType: DeviceRebootType) {
|
|
1072
1090
|
if (!this.isProtocolV2()) return;
|
|
1073
1091
|
|
|
@@ -1418,12 +1436,17 @@ export class Device extends EventEmitter {
|
|
|
1418
1436
|
};
|
|
1419
1437
|
}
|
|
1420
1438
|
|
|
1421
|
-
async unlockDevice() {
|
|
1439
|
+
async unlockDevice(pinType: DeviceSessionPinType = DeviceSessionPinType.Main) {
|
|
1422
1440
|
if (this.isProtocolV2()) {
|
|
1423
1441
|
try {
|
|
1424
|
-
await this.commands.typedCall(
|
|
1425
|
-
|
|
1426
|
-
|
|
1442
|
+
await this.commands.typedCall(
|
|
1443
|
+
'DeviceSessionAskPin',
|
|
1444
|
+
'Success',
|
|
1445
|
+
{ type: pinType },
|
|
1446
|
+
{
|
|
1447
|
+
timeoutMs: 120_000,
|
|
1448
|
+
}
|
|
1449
|
+
);
|
|
1427
1450
|
} catch (error) {
|
|
1428
1451
|
const errorText =
|
|
1429
1452
|
error instanceof Error
|
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
} from '@onekeyfe/hd-transport';
|
|
10
10
|
|
|
11
11
|
import TransportManager from '../data-manager/TransportManager';
|
|
12
|
-
import DataManager from '../data-manager/DataManager';
|
|
13
12
|
import { LoggerNames, getLogger, patchFeatures } from '../utils';
|
|
14
13
|
import { DEVICE, type PassphraseRequestPayload } from '../events';
|
|
15
14
|
import { DeviceModelToTypes } from '../types';
|
|
@@ -39,10 +38,6 @@ type TypedCallResponseMap = {
|
|
|
39
38
|
};
|
|
40
39
|
export type DefaultMessageResponse = TypedCallResponseMap[MessageKey];
|
|
41
40
|
|
|
42
|
-
const MAX_DEBUG_ARRAY_ITEMS = 20;
|
|
43
|
-
const MAX_DEBUG_OBJECT_KEYS = 40;
|
|
44
|
-
const MAX_DEBUG_STRING_LENGTH = 512;
|
|
45
|
-
const MAX_DEBUG_DEPTH = 4;
|
|
46
41
|
const HIGH_VOLUME_DEBUG_CALLS = new Set([
|
|
47
42
|
'FilesystemFileRead',
|
|
48
43
|
'FilesystemFileWrite',
|
|
@@ -53,106 +48,16 @@ const HIGH_VOLUME_DEBUG_CALLS = new Set([
|
|
|
53
48
|
'FirmwareUpload',
|
|
54
49
|
'ResourceAck',
|
|
55
50
|
]);
|
|
56
|
-
const
|
|
51
|
+
const DEVICE_SESSION_CALLS = new Set([
|
|
52
|
+
'DeviceSessionGet',
|
|
53
|
+
'DeviceSessionAskPin',
|
|
54
|
+
'DeviceSessionAskPassphrase',
|
|
55
|
+
]);
|
|
57
56
|
|
|
58
57
|
function shouldReduceDebugForCall(type: string) {
|
|
59
58
|
return HIGH_VOLUME_DEBUG_CALLS.has(type);
|
|
60
59
|
}
|
|
61
60
|
|
|
62
|
-
function shouldBlockDebugForCall(type: string) {
|
|
63
|
-
return SENSITIVE_DEBUG_CALLS.has(type);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function getBinaryByteLength(value: unknown): number | undefined {
|
|
67
|
-
if (value instanceof ArrayBuffer) {
|
|
68
|
-
return value.byteLength;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (ArrayBuffer.isView(value)) {
|
|
72
|
-
return value.byteLength;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (typeof Blob !== 'undefined' && value instanceof Blob) {
|
|
76
|
-
return value.size;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return undefined;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function summarizeRedactedData(value: unknown): string {
|
|
83
|
-
const byteLength = getBinaryByteLength(value);
|
|
84
|
-
if (byteLength !== undefined) {
|
|
85
|
-
return `[redacted data: ${byteLength} bytes]`;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (typeof value === 'string') {
|
|
89
|
-
return `[redacted data: string length=${value.length}]`;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (Array.isArray(value)) {
|
|
93
|
-
return `[redacted data: array length=${value.length}]`;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (value && typeof value === 'object') {
|
|
97
|
-
return `[redacted data: object keys=${Object.keys(value).length}]`;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return `[redacted data: ${typeof value}]`;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function sanitizeDebugPayload(value: unknown, key = '', depth = 0): unknown {
|
|
104
|
-
if (key === 'data' && value !== null && value !== undefined) {
|
|
105
|
-
return summarizeRedactedData(value);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Redact passphrase-bearing keys as defense in depth so wallet identifiers and
|
|
109
|
-
// host passphrases cannot reach diagnostic logs through a future call path.
|
|
110
|
-
if (key && /passphrase/i.test(key)) {
|
|
111
|
-
return '[redacted passphrase]';
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const byteLength = getBinaryByteLength(value);
|
|
115
|
-
if (byteLength !== undefined) {
|
|
116
|
-
return `[binary: ${byteLength} bytes]`;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (typeof value === 'string') {
|
|
120
|
-
return value.length > MAX_DEBUG_STRING_LENGTH
|
|
121
|
-
? `${value.slice(0, MAX_DEBUG_STRING_LENGTH)}... (len=${value.length})`
|
|
122
|
-
: value;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (!value || typeof value !== 'object') {
|
|
126
|
-
return value;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (depth >= MAX_DEBUG_DEPTH) {
|
|
130
|
-
return Array.isArray(value)
|
|
131
|
-
? `[array length=${value.length}]`
|
|
132
|
-
: `[object keys=${Object.keys(value).length}]`;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (Array.isArray(value)) {
|
|
136
|
-
const items = value
|
|
137
|
-
.slice(0, MAX_DEBUG_ARRAY_ITEMS)
|
|
138
|
-
.map(item => sanitizeDebugPayload(item, key, depth + 1));
|
|
139
|
-
if (value.length > MAX_DEBUG_ARRAY_ITEMS) {
|
|
140
|
-
items.push(`... (${value.length - MAX_DEBUG_ARRAY_ITEMS} more)`);
|
|
141
|
-
}
|
|
142
|
-
return items;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const entries = Object.entries(value).slice(0, MAX_DEBUG_OBJECT_KEYS);
|
|
146
|
-
const sanitized: Record<string, unknown> = {};
|
|
147
|
-
entries.forEach(([entryKey, entryValue]) => {
|
|
148
|
-
sanitized[entryKey] = sanitizeDebugPayload(entryValue, entryKey, depth + 1);
|
|
149
|
-
});
|
|
150
|
-
if (Object.keys(value).length > MAX_DEBUG_OBJECT_KEYS) {
|
|
151
|
-
sanitized.__truncated__ = `${Object.keys(value).length - MAX_DEBUG_OBJECT_KEYS} more keys`;
|
|
152
|
-
}
|
|
153
|
-
return sanitized;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
61
|
/**
|
|
157
62
|
* Interactive acknowledgements must not inherit timeoutMs from the original call.
|
|
158
63
|
* User confirmation and PIN/passphrase entry have unbounded think time. Preserve only
|
|
@@ -377,14 +282,15 @@ export class DeviceCommands {
|
|
|
377
282
|
const promise = this.transport.call(this.mainId, type, msg ?? {}, options) as any;
|
|
378
283
|
this.callPromise = promise;
|
|
379
284
|
const res = await promise;
|
|
380
|
-
if (
|
|
381
|
-
LogCore.debug('[DeviceCommands] [call] Received', res.type, res.message);
|
|
382
|
-
} else if (!shouldReduceDebug) {
|
|
285
|
+
if (!shouldReduceDebug) {
|
|
383
286
|
LogCore.debug('[DeviceCommands] [call] Received', res.type);
|
|
384
287
|
}
|
|
385
288
|
return res;
|
|
386
289
|
} catch (error) {
|
|
387
|
-
LogCore.debug('[DeviceCommands] [call] Received error',
|
|
290
|
+
LogCore.debug('[DeviceCommands] [call] Received error', {
|
|
291
|
+
request: type,
|
|
292
|
+
errorCode: error?.errorCode,
|
|
293
|
+
});
|
|
388
294
|
if (error.errorCode === HardwareErrorCode.BleDeviceBondError) {
|
|
389
295
|
return {
|
|
390
296
|
type: 'BleDeviceBondError',
|
|
@@ -405,9 +311,6 @@ export class DeviceCommands {
|
|
|
405
311
|
}
|
|
406
312
|
}
|
|
407
313
|
|
|
408
|
-
if (responseData) {
|
|
409
|
-
Log.debug('error response', responseData);
|
|
410
|
-
}
|
|
411
314
|
if (responseError === 'device disconnected during action') {
|
|
412
315
|
return { type: 'BridgeDeviceDisconnected', message: { error: responseError } } as any;
|
|
413
316
|
}
|
|
@@ -452,32 +355,6 @@ export class DeviceCommands {
|
|
|
452
355
|
);
|
|
453
356
|
}
|
|
454
357
|
|
|
455
|
-
// Structured log of actual outgoing payloads (skip acks)
|
|
456
|
-
try {
|
|
457
|
-
const skipTypes: MessageKey[] = [
|
|
458
|
-
'ButtonAck',
|
|
459
|
-
'PinMatrixAck',
|
|
460
|
-
'PassphraseAck',
|
|
461
|
-
'Cancel',
|
|
462
|
-
'DeviceSessionOpen',
|
|
463
|
-
'BixinPinInputOnDevice',
|
|
464
|
-
'FilesystemFileRead',
|
|
465
|
-
'FilesystemFileWrite',
|
|
466
|
-
'FileRead',
|
|
467
|
-
'FileWrite',
|
|
468
|
-
'EmmcFileRead',
|
|
469
|
-
'EmmcFileWrite',
|
|
470
|
-
'FirmwareUpload',
|
|
471
|
-
'ResourceAck',
|
|
472
|
-
] as any;
|
|
473
|
-
if (!skipTypes.includes(type) && !shouldBlockDebugForCall(type) && msg) {
|
|
474
|
-
// Use debug channel to avoid noise escalation
|
|
475
|
-
Log.debug('[DeviceCommands] [typedCall] Sending payload', type, sanitizeDebugPayload(msg));
|
|
476
|
-
}
|
|
477
|
-
} catch (e) {
|
|
478
|
-
// ignore logging errors
|
|
479
|
-
}
|
|
480
|
-
|
|
481
358
|
const expectedTypes = Array.isArray(resType) ? resType : resType.split('|');
|
|
482
359
|
const response = await this._commonCall(type, msg, {
|
|
483
360
|
...options,
|
|
@@ -495,14 +372,11 @@ export class DeviceCommands {
|
|
|
495
372
|
// throw bridge network error
|
|
496
373
|
if (error instanceof HardwareError) {
|
|
497
374
|
if (error.errorCode === HardwareErrorCode.ResponseUnexpectTypeError) {
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
response: sanitizeDebugPayload(response.message),
|
|
504
|
-
});
|
|
505
|
-
}
|
|
375
|
+
Log.debug('[DeviceCommands] [typedCall] Unexpected response type', {
|
|
376
|
+
request: type,
|
|
377
|
+
expected: resType,
|
|
378
|
+
received: response.type,
|
|
379
|
+
});
|
|
506
380
|
// Do not intercept CallMethodError
|
|
507
381
|
// Do not intercept “assertType: Response of unexpected type” error
|
|
508
382
|
// Blocking the above two messages will not know what the specific error message is, and the specific error should be handled by the subsequent business logic.
|
|
@@ -541,12 +415,11 @@ export class DeviceCommands {
|
|
|
541
415
|
options?: TransportCallOptions
|
|
542
416
|
): Promise<DefaultMessageResponse> {
|
|
543
417
|
try {
|
|
544
|
-
if (shouldReduceDebugForCall(callType)
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
Log.debug('_filterCommonTypes: ', sanitizeDebugPayload(res));
|
|
418
|
+
if (!shouldReduceDebugForCall(callType)) {
|
|
419
|
+
Log.debug('_filterCommonTypes: ', {
|
|
420
|
+
request: callType,
|
|
421
|
+
response: res.type,
|
|
422
|
+
});
|
|
550
423
|
}
|
|
551
424
|
} catch (error) {
|
|
552
425
|
// ignore
|
|
@@ -607,7 +480,7 @@ export class DeviceCommands {
|
|
|
607
480
|
const isLegacyProtocolV2LockedFailure =
|
|
608
481
|
this.device.isProtocolV2() && /^device (?:is )?locked$/i.test(normalizedMessage);
|
|
609
482
|
if (
|
|
610
|
-
callType
|
|
483
|
+
DEVICE_SESSION_CALLS.has(callType) &&
|
|
611
484
|
subcode === DeviceSessionErrorCode.DeviceSessionError_InvalidSession
|
|
612
485
|
) {
|
|
613
486
|
error = ERRORS.TypedError(HardwareErrorCode.WalletSessionInvalid, message, {
|
|
@@ -616,7 +489,7 @@ export class DeviceCommands {
|
|
|
616
489
|
firmwareMessage: message,
|
|
617
490
|
});
|
|
618
491
|
} else if (
|
|
619
|
-
callType
|
|
492
|
+
DEVICE_SESSION_CALLS.has(callType) &&
|
|
620
493
|
subcode === DeviceSessionErrorCode.DeviceSessionError_UserCancelled
|
|
621
494
|
) {
|
|
622
495
|
error = ERRORS.TypedError(HardwareErrorCode.ActionCancelled, message, {
|
|
@@ -625,7 +498,7 @@ export class DeviceCommands {
|
|
|
625
498
|
firmwareMessage: message,
|
|
626
499
|
});
|
|
627
500
|
} else if (
|
|
628
|
-
callType
|
|
501
|
+
DEVICE_SESSION_CALLS.has(callType) &&
|
|
629
502
|
subcode === DeviceSessionErrorCode.DeviceSessionError_AttachPinUnavailable
|
|
630
503
|
) {
|
|
631
504
|
error = ERRORS.TypedError(HardwareErrorCode.DeviceCheckUnlockTypeError, message, {
|
|
@@ -634,7 +507,7 @@ export class DeviceCommands {
|
|
|
634
507
|
firmwareMessage: message,
|
|
635
508
|
});
|
|
636
509
|
} else if (
|
|
637
|
-
callType
|
|
510
|
+
DEVICE_SESSION_CALLS.has(callType) &&
|
|
638
511
|
subcode === DeviceSessionErrorCode.DeviceSessionError_PassphraseDisabled
|
|
639
512
|
) {
|
|
640
513
|
error = ERRORS.TypedError(HardwareErrorCode.DeviceNotOpenedPassphrase, message, {
|
package/src/events/device.ts
CHANGED
|
@@ -54,6 +54,7 @@ export interface DeviceButtonRequestPayload extends Omit<PROTO.ButtonRequest, 'c
|
|
|
54
54
|
|
|
55
55
|
export type PassphraseRequestPayload = {
|
|
56
56
|
existsAttachPinUser?: boolean;
|
|
57
|
+
deviceOnly?: boolean;
|
|
57
58
|
source?: 'wallet-session-coordinator';
|
|
58
59
|
reason?: 'open-wallet' | 'session-recovery';
|
|
59
60
|
expectedPassphraseState?: string;
|
|
@@ -5,16 +5,6 @@ export const LogBlockEvent: Set<string> = new Set([
|
|
|
5
5
|
UI_RESPONSE.RECEIVE_PASSPHRASE,
|
|
6
6
|
]);
|
|
7
7
|
|
|
8
|
-
const LogBlockMethod: Set<string> = new Set([
|
|
9
|
-
'evmSignTypedData',
|
|
10
|
-
'openWalletSession',
|
|
11
|
-
'DeviceSessionOpen',
|
|
12
|
-
'deviceUploadWallpaper',
|
|
13
|
-
'uploadPortfolio',
|
|
14
|
-
'fileWrite',
|
|
15
|
-
'fileRead',
|
|
16
|
-
]);
|
|
17
|
-
|
|
18
8
|
export function getLogBlockLabel(message: unknown): string | undefined {
|
|
19
9
|
if (!message || typeof message !== 'object') return undefined;
|
|
20
10
|
|
|
@@ -29,9 +19,5 @@ export function getLogBlockLabel(message: unknown): string | undefined {
|
|
|
29
19
|
}
|
|
30
20
|
|
|
31
21
|
const methodName = method ?? payload?.method;
|
|
32
|
-
|
|
33
|
-
return methodName;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return undefined;
|
|
22
|
+
return methodName;
|
|
37
23
|
}
|
package/src/events/ui-request.ts
CHANGED
|
@@ -107,6 +107,7 @@ export interface UiRequestPassphrase {
|
|
|
107
107
|
device: Device;
|
|
108
108
|
passphraseState?: string;
|
|
109
109
|
existsAttachPinUser?: boolean;
|
|
110
|
+
deviceOnly?: boolean;
|
|
110
111
|
source?: 'wallet-session-coordinator';
|
|
111
112
|
reason?: 'open-wallet' | 'session-recovery';
|
|
112
113
|
expectedPassphraseState?: string;
|
|
@@ -18,7 +18,7 @@ export function assertCompleteDeviceSession(
|
|
|
18
18
|
) {
|
|
19
19
|
throw ERRORS.TypedError(
|
|
20
20
|
HardwareErrorCode.RuntimeError,
|
|
21
|
-
'
|
|
21
|
+
'DeviceSessionGet returned an incomplete DeviceSession response.'
|
|
22
22
|
);
|
|
23
23
|
}
|
|
24
24
|
}
|