@onekeyfe/hd-core 1.2.0-alpha.22 → 1.2.0-alpha.24
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 +43 -8
- package/__tests__/connectSettings.test.ts +5 -47
- package/__tests__/device-lifecycle-events.test.ts +59 -0
- package/__tests__/device-settings.test.ts +1 -1
- package/__tests__/device-wallet-session-store.test.ts +41 -0
- package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +30 -39
- package/__tests__/logBlockEvent.test.ts +17 -0
- package/__tests__/open-wallet-session.test.ts +233 -111
- package/__tests__/protocol-v2-ping.test.ts +28 -0
- package/__tests__/protocol-v2.test.ts +513 -313
- package/__tests__/public-pro2-api-boundary.test.ts +22 -0
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV2.d.ts +0 -11
- package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts +3 -7
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +5 -21
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/GetPassphraseState.d.ts.map +1 -1
- package/dist/api/OpenWalletSession.d.ts +1 -8
- package/dist/api/OpenWalletSession.d.ts.map +1 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts +1 -5
- package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
- package/dist/api/device/DeviceWipe.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +0 -7
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
- package/dist/api/firmware/getBinary.d.ts +0 -7
- package/dist/api/firmware/getBinary.d.ts.map +1 -1
- package/dist/api/firmware/updateBootloader.d.ts +0 -2
- package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/uploadFirmware.d.ts +1 -9
- package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/protocol-v2/Ping.d.ts +2 -0
- package/dist/api/protocol-v2/Ping.d.ts.map +1 -1
- package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/data-manager/DataManager.d.ts +0 -1
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/data-manager/connectSettings.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 +98 -278
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +876 -2647
- package/dist/inject.d.ts.map +1 -1
- package/dist/lowLevelInject.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockRetry.d.ts +2 -3
- package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/walletSession.d.ts +12 -0
- package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
- package/dist/topLevelInject.d.ts.map +1 -1
- package/dist/types/api/checkAllFirmwareRelease.d.ts +0 -3
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/deviceUpdateBootloader.d.ts +0 -6
- package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
- package/dist/types/api/export.d.ts +1 -4
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdate.d.ts +0 -69
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/dist/types/api/getPassphraseState.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +4 -10
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/openWalletSession.d.ts +0 -12
- package/dist/types/api/openWalletSession.d.ts.map +1 -1
- package/dist/types/api/protocolV2.d.ts +4 -0
- package/dist/types/api/protocolV2.d.ts.map +1 -1
- package/dist/types/settings.d.ts +0 -13
- package/dist/types/settings.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 +3 -16
- package/src/api/FirmwareUpdateV2.ts +119 -284
- package/src/api/FirmwareUpdateV3.ts +55 -248
- package/src/api/FirmwareUpdateV4.ts +293 -751
- package/src/api/GetPassphraseState.ts +11 -5
- package/src/api/OpenWalletSession.ts +23 -86
- package/src/api/device/DeviceUpdateBootloader.ts +6 -114
- package/src/api/device/DeviceWipe.ts +2 -0
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +0 -50
- package/src/api/firmware/updateBootloader.ts +4 -19
- package/src/api/firmware/uploadFirmware.ts +22 -140
- package/src/api/index.ts +1 -0
- package/src/api/protocol-v2/Ping.ts +32 -1
- package/src/core/index.ts +40 -7
- package/src/data/messages/messages-protocol-v2.json +49 -56
- package/src/data-manager/DataManager.ts +33 -33
- package/src/data-manager/connectSettings.ts +0 -11
- package/src/device/Device.ts +29 -8
- package/src/device/DeviceCommands.ts +43 -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/index.ts +0 -5
- package/src/inject.ts +4 -22
- package/src/lowLevelInject.ts +1 -5
- package/src/protocols/protocol-v2/deviceSession.ts +1 -1
- package/src/protocols/protocol-v2/settingsUnlockPolicy.ts +0 -1
- package/src/protocols/protocol-v2/unlockRetry.ts +20 -3
- package/src/protocols/protocol-v2/walletSession.ts +57 -18
- package/src/topLevelInject.ts +1 -5
- package/src/types/api/checkAllFirmwareRelease.ts +0 -3
- package/src/types/api/deviceUpdateBootloader.ts +0 -6
- package/src/types/api/export.ts +0 -18
- package/src/types/api/firmwareUpdate.ts +0 -76
- package/src/types/api/getPassphraseState.ts +4 -3
- package/src/types/api/index.ts +3 -14
- package/src/types/api/openWalletSession.ts +0 -19
- package/src/types/api/protocolV2.ts +10 -0
- package/src/types/settings.ts +0 -13
- package/src/utils/deviceInfoUtils.ts +2 -3
- package/__tests__/firmware-update/firmware-artifact-source.test.ts +0 -119
- package/__tests__/firmware-update/firmware-host-binding.test.ts +0 -70
- package/__tests__/firmware-update/firmware-update-capabilities.test.ts +0 -13
- package/__tests__/firmware-update/firmware-update-plan.test.ts +0 -326
- package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +0 -200
- package/__tests__/firmware-update/firmware-upload-source.test.ts +0 -70
- package/dist/api/firmware/FirmwareArtifactSource.d.ts +0 -26
- package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareHostBinding.d.ts +0 -6
- package/dist/api/firmware/FirmwareHostBinding.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +0 -3
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +0 -24
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +0 -25
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdateCapabilities.d.ts +0 -9
- package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdatePlan.d.ts +0 -27
- package/dist/types/api/firmwareUpdatePlan.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +0 -42
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +0 -1
- package/src/api/firmware/FirmwareArtifactSource.ts +0 -278
- package/src/api/firmware/FirmwareHostBinding.ts +0 -100
- package/src/api/firmware/FirmwareUpdateCapabilities.ts +0 -9
- package/src/api/firmware/FirmwareUpdatePlan.ts +0 -621
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +0 -378
- package/src/types/api/firmwareUpdateCapabilities.ts +0 -9
- package/src/types/api/firmwareUpdatePlan.ts +0 -36
- package/src/types/api/firmwareUpdatePreparedPlan.ts +0 -53
|
@@ -399,17 +399,7 @@ export default class DataManager {
|
|
|
399
399
|
|
|
400
400
|
static async load(settings: ConnectSettings) {
|
|
401
401
|
this.settings = settings;
|
|
402
|
-
|
|
403
|
-
settings.firmwareManifestMode ?? (settings.fetchConfig ? 'sdk-managed' : undefined);
|
|
404
|
-
if (settings.preloadedConfig) {
|
|
405
|
-
this.applyRemoteConfig(settings.preloadedConfig);
|
|
406
|
-
Log.log('[DataConfig] Preloaded firmware config loaded');
|
|
407
|
-
return;
|
|
408
|
-
}
|
|
409
|
-
if (manifestMode === 'external-only') {
|
|
410
|
-
throw new Error('External firmware config snapshot is required');
|
|
411
|
-
}
|
|
412
|
-
if (manifestMode !== 'sdk-managed') {
|
|
402
|
+
if (!settings.fetchConfig) {
|
|
413
403
|
return;
|
|
414
404
|
}
|
|
415
405
|
|
|
@@ -419,50 +409,60 @@ export default class DataManager {
|
|
|
419
409
|
|
|
420
410
|
const urlWithCache = `${url}?noCache=${getTimeStamp()}`;
|
|
421
411
|
let data: RemoteConfigResponse | null = null;
|
|
412
|
+
let fetchMethod: 'configFetcher' | 'axios' | 'none' = 'none';
|
|
413
|
+
|
|
414
|
+
// 1. Try custom configFetcher first (client-side IP direct connection support)
|
|
422
415
|
if (settings.configFetcher) {
|
|
423
|
-
Log.debug('[DataConfig] Trying client
|
|
416
|
+
Log.debug('[DataConfig] Trying configFetcher (client-side fetcher)...');
|
|
424
417
|
try {
|
|
425
418
|
data = await settings.configFetcher(urlWithCache);
|
|
419
|
+
if (data) {
|
|
420
|
+
fetchMethod = 'configFetcher';
|
|
421
|
+
Log.log('[DataConfig] ConfigFetcher success');
|
|
422
|
+
} else {
|
|
423
|
+
Log.debug('[DataConfig] ConfigFetcher returned null, will fallback to axios');
|
|
424
|
+
}
|
|
426
425
|
} catch (e) {
|
|
427
|
-
Log.warn('[DataConfig]
|
|
426
|
+
Log.warn('[DataConfig] ConfigFetcher error, will fallback to axios:', e);
|
|
428
427
|
}
|
|
429
428
|
}
|
|
429
|
+
|
|
430
|
+
// 2. Fallback to default axios request
|
|
430
431
|
if (!data) {
|
|
431
|
-
Log.debug('[DataConfig] Trying SDK
|
|
432
|
+
Log.debug('[DataConfig] Trying axios (SDK default fetcher)...');
|
|
432
433
|
try {
|
|
433
434
|
const response = await axios.get<RemoteConfigResponse>(urlWithCache, {
|
|
434
435
|
// because of iframe timeout is 10000
|
|
435
436
|
timeout: 7000,
|
|
436
437
|
});
|
|
437
438
|
data = response.data;
|
|
438
|
-
|
|
439
|
+
fetchMethod = 'axios';
|
|
440
|
+
Log.log('[DataConfig] Axios fetch success');
|
|
439
441
|
} catch (e) {
|
|
440
|
-
Log.warn('[DataConfig]
|
|
442
|
+
Log.warn('[DataConfig] Axios fetch error:', e);
|
|
441
443
|
}
|
|
442
444
|
}
|
|
443
445
|
|
|
446
|
+
// 3. Apply config if available
|
|
444
447
|
if (data) {
|
|
445
|
-
|
|
448
|
+
Log.log(`[DataConfig] Config loaded successfully via [${fetchMethod}]`);
|
|
449
|
+
this.deviceMap = {
|
|
450
|
+
[EDeviceType.Classic]: this.enrichFirmwareReleaseInfo(data.classic),
|
|
451
|
+
[EDeviceType.Classic1s]: this.enrichFirmwareReleaseInfo(data.classic1s),
|
|
452
|
+
[EDeviceType.ClassicPure]: this.enrichFirmwareReleaseInfo(data.classicpure),
|
|
453
|
+
[EDeviceType.Mini]: this.enrichFirmwareReleaseInfo(data.mini),
|
|
454
|
+
[EDeviceType.Touch]: this.enrichFirmwareReleaseInfo(data.touch),
|
|
455
|
+
[EDeviceType.Pro]: this.enrichFirmwareReleaseInfo(data.pro),
|
|
456
|
+
[EDeviceType.Pro2]: this.enrichFirmwareReleaseInfo(data.pro2),
|
|
457
|
+
};
|
|
458
|
+
this.assets = {
|
|
459
|
+
bridge: data.bridge,
|
|
460
|
+
};
|
|
446
461
|
} else {
|
|
447
|
-
Log.warn('[DataConfig]
|
|
462
|
+
Log.warn('[DataConfig] All fetch methods failed, using built-in default config');
|
|
448
463
|
}
|
|
449
464
|
}
|
|
450
465
|
|
|
451
|
-
private static applyRemoteConfig(data: RemoteConfigResponse) {
|
|
452
|
-
this.deviceMap = {
|
|
453
|
-
[EDeviceType.Classic]: this.enrichFirmwareReleaseInfo(data.classic),
|
|
454
|
-
[EDeviceType.Classic1s]: this.enrichFirmwareReleaseInfo(data.classic1s),
|
|
455
|
-
[EDeviceType.ClassicPure]: this.enrichFirmwareReleaseInfo(data.classicpure),
|
|
456
|
-
[EDeviceType.Mini]: this.enrichFirmwareReleaseInfo(data.mini),
|
|
457
|
-
[EDeviceType.Touch]: this.enrichFirmwareReleaseInfo(data.touch),
|
|
458
|
-
[EDeviceType.Pro]: this.enrichFirmwareReleaseInfo(data.pro),
|
|
459
|
-
[EDeviceType.Pro2]: this.enrichFirmwareReleaseInfo(data.pro2),
|
|
460
|
-
};
|
|
461
|
-
this.assets = {
|
|
462
|
-
bridge: data.bridge,
|
|
463
|
-
};
|
|
464
|
-
}
|
|
465
|
-
|
|
466
466
|
static updateEnv(newEnv: ConnectSettings['env']) {
|
|
467
467
|
if (this.settings) {
|
|
468
468
|
const prevEnv = this.settings.env;
|
|
@@ -115,21 +115,10 @@ export const parseConnectSettings = (input: Partial<ConnectSettings> = {}) => {
|
|
|
115
115
|
settings.fetchConfig = input.fetchConfig;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
if (
|
|
119
|
-
input.firmwareManifestMode === 'sdk-managed' ||
|
|
120
|
-
input.firmwareManifestMode === 'external-only'
|
|
121
|
-
) {
|
|
122
|
-
settings.firmwareManifestMode = input.firmwareManifestMode;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
118
|
if (input.configFetcher) {
|
|
126
119
|
settings.configFetcher = input.configFetcher;
|
|
127
120
|
}
|
|
128
121
|
|
|
129
|
-
if (input.preloadedConfig) {
|
|
130
|
-
settings.preloadedConfig = input.preloadedConfig;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
122
|
return settings;
|
|
134
123
|
};
|
|
135
124
|
|
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,
|
|
@@ -342,6 +344,10 @@ export class Device extends EventEmitter {
|
|
|
342
344
|
// eslint-disable-next-line no-async-promise-executor
|
|
343
345
|
return new Promise<boolean>(async (resolve, reject) => {
|
|
344
346
|
if (DataManager.isBleConnect(env)) {
|
|
347
|
+
if (this.hasDeviceAcquire() && this.commands && !this.commands.disposed) {
|
|
348
|
+
resolve(true);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
345
351
|
try {
|
|
346
352
|
await this.acquire(connectProtocol);
|
|
347
353
|
resolve(true);
|
|
@@ -1063,11 +1069,28 @@ export class Device extends EventEmitter {
|
|
|
1063
1069
|
}
|
|
1064
1070
|
|
|
1065
1071
|
markTransportDisconnected() {
|
|
1072
|
+
this.deviceAcquired = false;
|
|
1066
1073
|
if (!this.isProtocolV2()) return;
|
|
1067
1074
|
this.protocolV2StateNeedsReload = true;
|
|
1068
1075
|
this.clearPreInitialized();
|
|
1069
1076
|
}
|
|
1070
1077
|
|
|
1078
|
+
invalidateAfterWipe() {
|
|
1079
|
+
const deviceId = this.getCurrentDeviceId();
|
|
1080
|
+
if (deviceId) {
|
|
1081
|
+
deviceWalletSessionStore.deleteDevice(deviceId);
|
|
1082
|
+
}
|
|
1083
|
+
if (this.isProtocolV2() && this.originalDescriptor.path !== deviceId) {
|
|
1084
|
+
deviceWalletSessionStore.deleteDevice(this.originalDescriptor.path);
|
|
1085
|
+
this.protocolV2StateNeedsReload = true;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
this.passphraseState = undefined;
|
|
1089
|
+
this.stateStore = new DeviceStateStore();
|
|
1090
|
+
this.clearPreInitialized();
|
|
1091
|
+
this.needReloadDevice = true;
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1071
1094
|
markProtocolV2Reboot(rebootType: DeviceRebootType) {
|
|
1072
1095
|
if (!this.isProtocolV2()) return;
|
|
1073
1096
|
|
|
@@ -1339,7 +1362,7 @@ export class Device extends EventEmitter {
|
|
|
1339
1362
|
isUsedHere() {
|
|
1340
1363
|
const env = DataManager.getSettings('env');
|
|
1341
1364
|
if (DataManager.isBleConnect(env)) {
|
|
1342
|
-
return
|
|
1365
|
+
return this.deviceAcquired;
|
|
1343
1366
|
}
|
|
1344
1367
|
return this.isUsed() && this.originalDescriptor.session === this.mainId;
|
|
1345
1368
|
}
|
|
@@ -1418,12 +1441,10 @@ export class Device extends EventEmitter {
|
|
|
1418
1441
|
};
|
|
1419
1442
|
}
|
|
1420
1443
|
|
|
1421
|
-
async unlockDevice() {
|
|
1444
|
+
async unlockDevice(pinType: DeviceSessionPinType = DeviceSessionPinType.Main) {
|
|
1422
1445
|
if (this.isProtocolV2()) {
|
|
1423
1446
|
try {
|
|
1424
|
-
await this.commands.typedCall('DeviceSessionAskPin', 'Success',
|
|
1425
|
-
timeoutMs: 120_000,
|
|
1426
|
-
});
|
|
1447
|
+
await this.commands.typedCall('DeviceSessionAskPin', 'Success', { type: pinType });
|
|
1427
1448
|
} catch (error) {
|
|
1428
1449
|
const errorText =
|
|
1429
1450
|
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, {
|
|
@@ -642,6 +515,25 @@ export class DeviceCommands {
|
|
|
642
515
|
subcode,
|
|
643
516
|
firmwareMessage: message,
|
|
644
517
|
});
|
|
518
|
+
} else if (
|
|
519
|
+
DEVICE_SESSION_CALLS.has(callType) &&
|
|
520
|
+
(subcode === DeviceSessionErrorCode.DeviceSessionError_Busy ||
|
|
521
|
+
/^(?:busy|another flow in progress)$/i.test(normalizedMessage))
|
|
522
|
+
) {
|
|
523
|
+
error = ERRORS.TypedError(HardwareErrorCode.DeviceBusy, message, {
|
|
524
|
+
failureCode: code,
|
|
525
|
+
subcode,
|
|
526
|
+
firmwareMessage: message,
|
|
527
|
+
});
|
|
528
|
+
} else if (
|
|
529
|
+
callType === 'DeviceSessionAskPin' &&
|
|
530
|
+
/^passphrase disabled$/i.test(normalizedMessage)
|
|
531
|
+
) {
|
|
532
|
+
error = ERRORS.TypedError(HardwareErrorCode.DeviceNotOpenedPassphrase, message, {
|
|
533
|
+
failureCode: code,
|
|
534
|
+
subcode,
|
|
535
|
+
firmwareMessage: message,
|
|
536
|
+
});
|
|
645
537
|
} else if (
|
|
646
538
|
subcode === DeviceErrorCode.DeviceError_ActionCancelled ||
|
|
647
539
|
isLegacyProtocolV2ActionCancelledFailure
|
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;
|
package/src/index.ts
CHANGED
|
@@ -19,11 +19,6 @@ export * from './types';
|
|
|
19
19
|
export { whitelist, whitelistExtension } from './data/config';
|
|
20
20
|
export { executeCallback, cleanupCallback };
|
|
21
21
|
export { preloadSessionCache } from './device/Device';
|
|
22
|
-
export {
|
|
23
|
-
getFirmwareUpdateHostBindingGeneration,
|
|
24
|
-
registerFirmwareUpdateHostBinding,
|
|
25
|
-
unregisterFirmwareUpdateHostBinding,
|
|
26
|
-
} from './api/firmware/FirmwareHostBinding';
|
|
27
22
|
|
|
28
23
|
const HardwareSdk = ({
|
|
29
24
|
init,
|
package/src/inject.ts
CHANGED
|
@@ -1,17 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
prepareFirmwareUpdatePlan,
|
|
4
|
-
validateFirmwareUpdatePreparedPlan,
|
|
5
|
-
} from './api/firmware/FirmwareUpdatePreparedPlan';
|
|
6
|
-
import {
|
|
7
|
-
getFirmwareUpdateHostBindingGeneration,
|
|
8
|
-
registerFirmwareUpdateHostBinding,
|
|
9
|
-
unregisterFirmwareUpdateHostBinding,
|
|
10
|
-
} from './api/firmware/FirmwareHostBinding';
|
|
11
|
-
|
|
1
|
+
import type { Unsuccessful } from './types';
|
|
12
2
|
import type { EventEmitter } from 'events';
|
|
13
3
|
import type { CallMethod } from './events';
|
|
14
|
-
import type { Unsuccessful } from './types';
|
|
15
4
|
import type { CoreApi } from './types/api';
|
|
16
5
|
import type { AllNetworkAddress } from './types/api/allNetworkGetAddress';
|
|
17
6
|
|
|
@@ -79,10 +68,7 @@ export const inject = ({
|
|
|
79
68
|
|
|
80
69
|
call,
|
|
81
70
|
|
|
82
|
-
dispose
|
|
83
|
-
unregisterFirmwareUpdateHostBinding();
|
|
84
|
-
await dispose();
|
|
85
|
-
},
|
|
71
|
+
dispose,
|
|
86
72
|
|
|
87
73
|
uiResponse,
|
|
88
74
|
|
|
@@ -113,12 +99,6 @@ export const createCoreApi = (
|
|
|
113
99
|
| 'updateSettings'
|
|
114
100
|
| 'switchTransport'
|
|
115
101
|
> => ({
|
|
116
|
-
getFirmwareUpdateCapabilities,
|
|
117
|
-
registerFirmwareUpdateHostBinding,
|
|
118
|
-
unregisterFirmwareUpdateHostBinding,
|
|
119
|
-
getFirmwareUpdateHostBindingGeneration,
|
|
120
|
-
prepareFirmwareUpdatePlan,
|
|
121
|
-
validateFirmwareUpdatePreparedPlan,
|
|
122
102
|
getLogs: () => call({ method: 'getLogs' }),
|
|
123
103
|
clearSessionCache: params => call({ ...params, method: 'clearSessionCache' }),
|
|
124
104
|
/**
|
|
@@ -167,6 +147,8 @@ export const createCoreApi = (
|
|
|
167
147
|
|
|
168
148
|
testInitializeDeviceDuration: (connectId, params) =>
|
|
169
149
|
call({ ...params, connectId, method: 'testInitializeDeviceDuration' }),
|
|
150
|
+
testProtocolV2Ping: (connectId, params) =>
|
|
151
|
+
call({ ...params, connectId, method: 'testProtocolV2Ping' }),
|
|
170
152
|
preInitialize: (connectId, params) => call({ ...params, connectId, method: 'preInitialize' }),
|
|
171
153
|
deviceBackup: connectId => call({ connectId, method: 'deviceBackup' }),
|
|
172
154
|
deviceChangePin: (connectId, params) => call({ ...params, connectId, method: 'deviceChangePin' }),
|
package/src/lowLevelInject.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { createCoreApi } from './inject';
|
|
2
|
-
import { unregisterFirmwareUpdateHostBinding } from './api/firmware/FirmwareHostBinding';
|
|
3
2
|
|
|
4
3
|
import type { EventEmitter } from 'events';
|
|
5
4
|
import type { CallMethod, CoreMessage } from './events';
|
|
@@ -44,10 +43,7 @@ export const lowLevelInject = ({
|
|
|
44
43
|
|
|
45
44
|
call,
|
|
46
45
|
|
|
47
|
-
dispose
|
|
48
|
-
unregisterFirmwareUpdateHostBinding();
|
|
49
|
-
await dispose();
|
|
50
|
-
},
|
|
46
|
+
dispose,
|
|
51
47
|
|
|
52
48
|
uiResponse,
|
|
53
49
|
|
|
@@ -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
|
}
|