@onekeyfe/hd-core 1.2.0-alpha.104 → 1.2.0-alpha.106
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 +100 -28
- package/__tests__/check-all-firmware-release-protocol-v2.test.ts +0 -2
- package/__tests__/device-lifecycle-events.test.ts +113 -2
- package/__tests__/device-pool-state.test.ts +1 -5
- package/__tests__/deviceSettings.test.ts +0 -1
- package/__tests__/firmware-update/firmware-update-v4-install-poll.test.ts +145 -0
- package/__tests__/get-device-state.test.ts +0 -50
- package/__tests__/logBlockEvent.test.ts +13 -1
- package/__tests__/protocol-v2.test.ts +466 -126
- package/__tests__/refresh-device-state.test.ts +0 -1
- package/__tests__/search-devices.test.ts +0 -2
- package/dist/api/FirmwareUpdateV4.d.ts +7 -3
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/GetDeviceState.d.ts.map +1 -1
- package/dist/api/SearchDevices.d.ts.map +1 -1
- package/dist/api/firmware/protocolV2Release.d.ts.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/device/Device.d.ts +1 -3
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/device/DevicePool.d.ts +1 -1
- package/dist/device/DevicePool.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/index.d.ts +1 -6
- package/dist/index.js +260 -196
- package/dist/protocols/protocol-v2/features.d.ts +1 -1
- package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
- package/dist/types/api/getDeviceState.d.ts +0 -1
- package/dist/types/api/getDeviceState.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/FirmwareUpdateV4.ts +262 -172
- package/src/api/GetDeviceState.ts +0 -1
- package/src/api/SearchDevices.ts +0 -2
- package/src/api/firmware/protocolV2Release.ts +0 -1
- package/src/core/index.ts +6 -6
- package/src/device/Device.ts +27 -63
- package/src/device/DeviceCommands.ts +4 -14
- package/src/device/DevicePool.ts +3 -11
- package/src/events/logBlockEvent.ts +14 -1
- package/src/protocols/protocol-v2/features.ts +9 -2
- package/src/types/api/getDeviceState.ts +0 -2
- package/src/utils/deviceSettings.ts +1 -1
- package/__tests__/protocol-v2-legacy-recovery.test.ts +0 -29
- package/dist/core/protocolV2LegacyRecovery.d.ts +0 -5
- package/dist/core/protocolV2LegacyRecovery.d.ts.map +0 -1
- package/src/core/protocolV2LegacyRecovery.ts +0 -12
|
@@ -60,7 +60,6 @@ export async function loadProtocolV2FirmwareReleaseContext({
|
|
|
60
60
|
refreshSections: checkFirmwareHash
|
|
61
61
|
? ['identity', 'versions', 'verification']
|
|
62
62
|
: ['identity', 'versions'],
|
|
63
|
-
allowLegacyProtocolV2ProtocolInfo: true,
|
|
64
63
|
});
|
|
65
64
|
if (state.identity.deviceType !== 'pro2' && state.identity.deviceType !== 'neo') {
|
|
66
65
|
throw ERRORS.TypedError(
|
package/src/core/index.ts
CHANGED
|
@@ -64,7 +64,6 @@ import {
|
|
|
64
64
|
isProtocolV2UiEnabled,
|
|
65
65
|
} from '../protocols/protocol-v2/uiInteraction';
|
|
66
66
|
import { createUiProgressMessageFilter } from '../utils/uiProgressThrottle';
|
|
67
|
-
import { isLegacyProtocolV2FirmwareRecoveryMethod } from './protocolV2LegacyRecovery';
|
|
68
67
|
|
|
69
68
|
import type { ConnectSettings, Features, KnownDevice } from '../types';
|
|
70
69
|
import type { CoreMessage, IFrameCallMessage, UiPromise, UiPromiseResponse } from '../events';
|
|
@@ -110,9 +109,6 @@ const parseInitOptions = (method?: BaseMethod): InitOptions => ({
|
|
|
110
109
|
connectProtocol: method?.payload.connectProtocol,
|
|
111
110
|
forceProtocolDetection: method?.payload.forceProtocolDetection,
|
|
112
111
|
protocolV2DeviceInfoTimeoutMs: method?.payload.protocolV2DeviceInfoTimeoutMs,
|
|
113
|
-
...(isLegacyProtocolV2FirmwareRecoveryMethod(method)
|
|
114
|
-
? { allowLegacyProtocolV2ProtocolInfo: true }
|
|
115
|
-
: {}),
|
|
116
112
|
});
|
|
117
113
|
|
|
118
114
|
let _core: Core | undefined;
|
|
@@ -140,6 +136,9 @@ const toError = (error: unknown): Error | undefined => {
|
|
|
140
136
|
}
|
|
141
137
|
};
|
|
142
138
|
|
|
139
|
+
const isExpectedCompatibilityError = (error: unknown) =>
|
|
140
|
+
error instanceof HardwareError && error.errorCode === HardwareErrorCode.DeviceNotSupportMethod;
|
|
141
|
+
|
|
143
142
|
const updateMethodRequestContext = (method: BaseMethod, updates: any) => {
|
|
144
143
|
if (method.requestContext) {
|
|
145
144
|
updateRequestContext(method.requestContext.responseID, updates);
|
|
@@ -697,7 +696,9 @@ const onCallDevice = async (
|
|
|
697
696
|
try {
|
|
698
697
|
return await task.callPromise.promise;
|
|
699
698
|
} catch (e) {
|
|
700
|
-
|
|
699
|
+
if (!isExpectedCompatibilityError(e)) {
|
|
700
|
+
Log.debug('Device Run Error: ', e);
|
|
701
|
+
}
|
|
701
702
|
completeMethodRequestContext(method, e);
|
|
702
703
|
return createResponseMessage(method.responseID, false, { error: e });
|
|
703
704
|
}
|
|
@@ -1252,7 +1253,6 @@ const cleanup = () => {
|
|
|
1252
1253
|
pendingUiPromises,
|
|
1253
1254
|
ERRORS.TypedError(HardwareErrorCode.ActionCancelled, 'UI request was cancelled')
|
|
1254
1255
|
);
|
|
1255
|
-
Log.debug('Cleanup...');
|
|
1256
1256
|
};
|
|
1257
1257
|
|
|
1258
1258
|
const removeDeviceListener = (device: Device) => {
|
package/src/device/Device.ts
CHANGED
|
@@ -100,8 +100,6 @@ export type InitOptions = {
|
|
|
100
100
|
protocolV2DeviceInfoTimeoutMs?: number;
|
|
101
101
|
/** Refresh Protocol V2 runtime state before returning discovery results. */
|
|
102
102
|
refreshRuntimeState?: boolean;
|
|
103
|
-
/** Recovery-only compatibility used by discovery and Protocol V2 firmware updates. */
|
|
104
|
-
allowLegacyProtocolV2ProtocolInfo?: boolean;
|
|
105
103
|
/**
|
|
106
104
|
* Protocol V1 Initialize response timeout override. Reboot-wait polling passes a
|
|
107
105
|
* short value so an unanswered probe settles before the next poll tick.
|
|
@@ -488,6 +486,10 @@ export class Device extends EventEmitter {
|
|
|
488
486
|
}
|
|
489
487
|
|
|
490
488
|
this.commands = new DeviceCommands(this, this.mainId ?? '');
|
|
489
|
+
// Protocol V2 runtime metadata belongs to one active transport link. A
|
|
490
|
+
// successful acquire creates a fresh link/session, so never carry cached
|
|
491
|
+
// ProtocolInfo or pre-initialize state across that boundary.
|
|
492
|
+
this.invalidateProtocolV2RuntimeState();
|
|
491
493
|
} catch (error) {
|
|
492
494
|
if (options?.forceProtocolDetection) {
|
|
493
495
|
this.originalDescriptor.protocolType = previousProtocol;
|
|
@@ -980,17 +982,7 @@ export class Device extends EventEmitter {
|
|
|
980
982
|
});
|
|
981
983
|
// The default request excludes SE/hash data and therefore uses basic scope.
|
|
982
984
|
// Full version and verification data require getDeviceState({ scope: 'firmware' }).
|
|
983
|
-
|
|
984
|
-
? await this.probeProtocolV2RuntimeState(
|
|
985
|
-
deviceInfo,
|
|
986
|
-
options.protocolV2DeviceInfoTimeoutMs,
|
|
987
|
-
{ allowLegacyProtocolV2ProtocolInfo: true }
|
|
988
|
-
)
|
|
989
|
-
: await this.probeProtocolV2RuntimeState(
|
|
990
|
-
deviceInfo,
|
|
991
|
-
options?.protocolV2DeviceInfoTimeoutMs
|
|
992
|
-
);
|
|
993
|
-
Log.debug('Protocol V2 features:', features);
|
|
985
|
+
await this.probeProtocolV2RuntimeState(deviceInfo, options?.protocolV2DeviceInfoTimeoutMs);
|
|
994
986
|
} catch (error) {
|
|
995
987
|
Log.error('Protocol V2 initialization failed:', error);
|
|
996
988
|
throw error;
|
|
@@ -1026,13 +1018,7 @@ export class Device extends EventEmitter {
|
|
|
1026
1018
|
commands: this.commands,
|
|
1027
1019
|
request: getProtocolV2DeviceInfoRequest(),
|
|
1028
1020
|
});
|
|
1029
|
-
|
|
1030
|
-
await this.probeProtocolV2RuntimeState(deviceInfo, undefined, {
|
|
1031
|
-
allowLegacyProtocolV2ProtocolInfo: true,
|
|
1032
|
-
});
|
|
1033
|
-
} else {
|
|
1034
|
-
await this.probeProtocolV2RuntimeState(deviceInfo);
|
|
1035
|
-
}
|
|
1021
|
+
await this.probeProtocolV2RuntimeState(deviceInfo);
|
|
1036
1022
|
refreshedDeviceInfo = deviceInfo;
|
|
1037
1023
|
initializedWithDeviceInfo = true;
|
|
1038
1024
|
} else {
|
|
@@ -1074,9 +1060,6 @@ export class Device extends EventEmitter {
|
|
|
1074
1060
|
// during an explicit refresh so a device rebooted into application firmware
|
|
1075
1061
|
// can leave the cached loader state.
|
|
1076
1062
|
forceRuntimeContextRefresh: cachedMode === 'bootloader' || cachedMode === 'romloader',
|
|
1077
|
-
...(params.allowLegacyProtocolV2ProtocolInfo
|
|
1078
|
-
? { allowLegacyProtocolV2ProtocolInfo: true }
|
|
1079
|
-
: {}),
|
|
1080
1063
|
});
|
|
1081
1064
|
}
|
|
1082
1065
|
|
|
@@ -1125,9 +1108,10 @@ export class Device extends EventEmitter {
|
|
|
1125
1108
|
source,
|
|
1126
1109
|
changedKeys: result.changedKeys,
|
|
1127
1110
|
};
|
|
1128
|
-
Log.debug('Device state
|
|
1111
|
+
Log.debug('Device state updated', {
|
|
1129
1112
|
source,
|
|
1130
|
-
|
|
1113
|
+
revision: result.revision,
|
|
1114
|
+
changedKeyCount: result.changedKeys.length,
|
|
1131
1115
|
});
|
|
1132
1116
|
this.emit(DEVICE.STATE, this, event);
|
|
1133
1117
|
if (result.state.protocol === 'V1') {
|
|
@@ -1150,23 +1134,8 @@ export class Device extends EventEmitter {
|
|
|
1150
1134
|
|
|
1151
1135
|
async ensureProtocolV2RuntimeContext(
|
|
1152
1136
|
timeoutMs?: number,
|
|
1153
|
-
options?: {
|
|
1154
|
-
forceRefresh?: boolean;
|
|
1155
|
-
allowLegacyProtocolV2ProtocolInfo?: boolean;
|
|
1156
|
-
}
|
|
1137
|
+
options?: { forceRefresh?: boolean }
|
|
1157
1138
|
): Promise<ProtocolInfo> {
|
|
1158
|
-
const assertProtocolInfoAllowed = (protocolInfo: ProtocolInfo) => {
|
|
1159
|
-
if (
|
|
1160
|
-
isLegacyProtocolV2ProtocolInfo(protocolInfo) &&
|
|
1161
|
-
options?.allowLegacyProtocolV2ProtocolInfo !== true
|
|
1162
|
-
) {
|
|
1163
|
-
throw ERRORS.TypedError(
|
|
1164
|
-
HardwareErrorCode.DeviceInitializeFailed,
|
|
1165
|
-
'Legacy Protocol V2 ProtocolInfo is supported only during device discovery and firmware update.'
|
|
1166
|
-
);
|
|
1167
|
-
}
|
|
1168
|
-
return protocolInfo;
|
|
1169
|
-
};
|
|
1170
1139
|
const cachedProtocolInfo =
|
|
1171
1140
|
options?.forceRefresh === true
|
|
1172
1141
|
? undefined
|
|
@@ -1176,11 +1145,11 @@ export class Device extends EventEmitter {
|
|
|
1176
1145
|
: undefined);
|
|
1177
1146
|
if (cachedProtocolInfo) {
|
|
1178
1147
|
this.protocolV2RuntimeContext = cachedProtocolInfo;
|
|
1179
|
-
return
|
|
1148
|
+
return cachedProtocolInfo;
|
|
1180
1149
|
}
|
|
1181
1150
|
|
|
1182
1151
|
if (this.protocolV2RuntimeContextPromise) {
|
|
1183
|
-
return
|
|
1152
|
+
return this.protocolV2RuntimeContextPromise;
|
|
1184
1153
|
}
|
|
1185
1154
|
|
|
1186
1155
|
const requestToken = {};
|
|
@@ -1202,7 +1171,7 @@ export class Device extends EventEmitter {
|
|
|
1202
1171
|
this.protocolV2RuntimeContextPromise = pendingRequest;
|
|
1203
1172
|
|
|
1204
1173
|
try {
|
|
1205
|
-
return
|
|
1174
|
+
return await pendingRequest;
|
|
1206
1175
|
} finally {
|
|
1207
1176
|
if (this.protocolV2RuntimeContextPromise === pendingRequest) {
|
|
1208
1177
|
this.protocolV2RuntimeContextPromise = undefined;
|
|
@@ -1218,16 +1187,14 @@ export class Device extends EventEmitter {
|
|
|
1218
1187
|
timeoutMs?: number,
|
|
1219
1188
|
options?: {
|
|
1220
1189
|
forceRuntimeContextRefresh?: boolean;
|
|
1221
|
-
allowLegacyProtocolV2ProtocolInfo?: boolean;
|
|
1222
1190
|
}
|
|
1223
1191
|
) {
|
|
1224
1192
|
const protocolInfo = await this.ensureProtocolV2RuntimeContext(timeoutMs, {
|
|
1225
1193
|
forceRefresh: options?.forceRuntimeContextRefresh,
|
|
1226
|
-
allowLegacyProtocolV2ProtocolInfo: options?.allowLegacyProtocolV2ProtocolInfo,
|
|
1227
1194
|
});
|
|
1228
|
-
const runtimeMode = getProtocolV2RuntimeMode(protocolInfo);
|
|
1229
|
-
const legacyProtocolInfo = isLegacyProtocolV2ProtocolInfo(protocolInfo);
|
|
1230
1195
|
const runtimeDeviceInfo = deviceInfo ?? this.state?.raw?.protocolV2DeviceInfo;
|
|
1196
|
+
const runtimeMode = getProtocolV2RuntimeMode(protocolInfo, runtimeDeviceInfo);
|
|
1197
|
+
const legacyProtocolInfo = isLegacyProtocolV2ProtocolInfo(protocolInfo);
|
|
1231
1198
|
const protocolV2DeviceType = runtimeDeviceInfo
|
|
1232
1199
|
? resolveProtocolV2DeviceIdentity(runtimeDeviceInfo.hw?.Device_type).deviceType
|
|
1233
1200
|
: this.getCurrentDeviceType();
|
|
@@ -1304,8 +1271,7 @@ export class Device extends EventEmitter {
|
|
|
1304
1271
|
});
|
|
1305
1272
|
}
|
|
1306
1273
|
|
|
1307
|
-
|
|
1308
|
-
this.deviceAcquired = false;
|
|
1274
|
+
private invalidateProtocolV2RuntimeState() {
|
|
1309
1275
|
if (!this.isProtocolV2()) return;
|
|
1310
1276
|
this.protocolV2StateNeedsReload = true;
|
|
1311
1277
|
this.protocolV2RuntimeContext = undefined;
|
|
@@ -1314,6 +1280,11 @@ export class Device extends EventEmitter {
|
|
|
1314
1280
|
this.clearPreInitialized();
|
|
1315
1281
|
}
|
|
1316
1282
|
|
|
1283
|
+
markTransportDisconnected() {
|
|
1284
|
+
this.deviceAcquired = false;
|
|
1285
|
+
this.invalidateProtocolV2RuntimeState();
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1317
1288
|
invalidateAfterWipe() {
|
|
1318
1289
|
const deviceId = this.getCurrentDeviceId();
|
|
1319
1290
|
if (deviceId) {
|
|
@@ -1323,10 +1294,7 @@ export class Device extends EventEmitter {
|
|
|
1323
1294
|
if (this.originalDescriptor.path !== deviceId) {
|
|
1324
1295
|
deviceWalletSessionStore.deleteDevice(this.originalDescriptor.path);
|
|
1325
1296
|
}
|
|
1326
|
-
this.
|
|
1327
|
-
this.protocolV2RuntimeContext = undefined;
|
|
1328
|
-
this.protocolV2RuntimeContextPromise = undefined;
|
|
1329
|
-
this.protocolV2RuntimeContextRequestToken = undefined;
|
|
1297
|
+
this.invalidateProtocolV2RuntimeState();
|
|
1330
1298
|
}
|
|
1331
1299
|
|
|
1332
1300
|
this.passphraseState = undefined;
|
|
@@ -1338,11 +1306,7 @@ export class Device extends EventEmitter {
|
|
|
1338
1306
|
markProtocolV2Reboot(rebootType: DeviceRebootType) {
|
|
1339
1307
|
if (!this.isProtocolV2()) return;
|
|
1340
1308
|
|
|
1341
|
-
this.
|
|
1342
|
-
this.protocolV2RuntimeContext = undefined;
|
|
1343
|
-
this.protocolV2RuntimeContextPromise = undefined;
|
|
1344
|
-
this.protocolV2RuntimeContextRequestToken = undefined;
|
|
1345
|
-
this.clearPreInitialized();
|
|
1309
|
+
this.invalidateProtocolV2RuntimeState();
|
|
1346
1310
|
let loaderMode: 'bootloader' | 'romloader' | undefined;
|
|
1347
1311
|
if (rebootType === DeviceRebootType.Bootloader) {
|
|
1348
1312
|
loaderMode = 'bootloader';
|
|
@@ -1416,6 +1380,10 @@ export class Device extends EventEmitter {
|
|
|
1416
1380
|
if (device.features) {
|
|
1417
1381
|
this._updateFeatures(device.features);
|
|
1418
1382
|
}
|
|
1383
|
+
// Adopting another Device instance's command channel also crosses an active
|
|
1384
|
+
// link boundary. Renegotiate runtime metadata on that channel instead of
|
|
1385
|
+
// retaining ProtocolInfo from the previous instance/session.
|
|
1386
|
+
this.invalidateProtocolV2RuntimeState();
|
|
1419
1387
|
}
|
|
1420
1388
|
|
|
1421
1389
|
async run(fn?: () => Promise<void>, options?: RunOptions) {
|
|
@@ -1545,10 +1513,6 @@ export class Device extends EventEmitter {
|
|
|
1545
1513
|
|
|
1546
1514
|
async interruptionFromUser() {
|
|
1547
1515
|
const error = ERRORS.TypedError(HardwareErrorCode.DeviceInterruptedFromUser);
|
|
1548
|
-
// Cancellation often ends the transport session, especially during firmware
|
|
1549
|
-
// update reboot or exit. Invalidate V2 state before awaiting asynchronous
|
|
1550
|
-
// cancellation callbacks so the next request cannot reuse a stale runtime mode.
|
|
1551
|
-
this.markTransportDisconnected();
|
|
1552
1516
|
await this.cancelableAction?.(error);
|
|
1553
1517
|
await this.commands?.cancel();
|
|
1554
1518
|
|
|
@@ -304,13 +304,6 @@ export class DeviceCommands {
|
|
|
304
304
|
const promise = this.transport.call(this.mainId, type, msg ?? {}, options) as any;
|
|
305
305
|
this.callPromise = promise;
|
|
306
306
|
const res = await promise;
|
|
307
|
-
if (!shouldReduceDebug) {
|
|
308
|
-
LogCore.debug(
|
|
309
|
-
'[DeviceCommands] [call] Received',
|
|
310
|
-
res.type,
|
|
311
|
-
getSafeTransportLogPayload(res.message, res.type)
|
|
312
|
-
);
|
|
313
|
-
}
|
|
314
307
|
return res;
|
|
315
308
|
} catch (error) {
|
|
316
309
|
LogCore.debug('[DeviceCommands] [call] Received error', {
|
|
@@ -445,13 +438,10 @@ export class DeviceCommands {
|
|
|
445
438
|
if (!shouldReduceDebugForCall(callType)) {
|
|
446
439
|
Log.debug('_filterCommonTypes: ', {
|
|
447
440
|
request: callType,
|
|
448
|
-
response:
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
message: getSafeTransportLogPayload(res.message, res.type),
|
|
453
|
-
}
|
|
454
|
-
: res.type,
|
|
441
|
+
response: {
|
|
442
|
+
type: res.type,
|
|
443
|
+
message: getSafeTransportLogPayload(res.message, res.type),
|
|
444
|
+
},
|
|
455
445
|
});
|
|
456
446
|
}
|
|
457
447
|
} catch (error) {
|
package/src/device/DevicePool.ts
CHANGED
|
@@ -182,7 +182,7 @@ export class DevicePool extends EventEmitter {
|
|
|
182
182
|
try {
|
|
183
183
|
await device.initialize(initOptions);
|
|
184
184
|
if (initOptions?.refreshRuntimeState && device.isProtocolV2()) {
|
|
185
|
-
await this._refreshProtocolV2DiscoveryState(device
|
|
185
|
+
await this._refreshProtocolV2DiscoveryState(device);
|
|
186
186
|
}
|
|
187
187
|
} finally {
|
|
188
188
|
await device.release();
|
|
@@ -197,7 +197,7 @@ export class DevicePool extends EventEmitter {
|
|
|
197
197
|
await device.run(
|
|
198
198
|
async () => {
|
|
199
199
|
try {
|
|
200
|
-
await this._refreshProtocolV2DiscoveryState(device
|
|
200
|
+
await this._refreshProtocolV2DiscoveryState(device);
|
|
201
201
|
} catch (error) {
|
|
202
202
|
// Device.run releases after the callback; then propagate the actual read error.
|
|
203
203
|
refreshError = error;
|
|
@@ -206,9 +206,6 @@ export class DevicePool extends EventEmitter {
|
|
|
206
206
|
{
|
|
207
207
|
connectProtocol: initOptions.connectProtocol,
|
|
208
208
|
forceProtocolDetection: initOptions.forceProtocolDetection,
|
|
209
|
-
...(initOptions.allowLegacyProtocolV2ProtocolInfo
|
|
210
|
-
? { allowLegacyProtocolV2ProtocolInfo: true }
|
|
211
|
-
: {}),
|
|
212
209
|
}
|
|
213
210
|
);
|
|
214
211
|
if (refreshError instanceof Error) throw refreshError;
|
|
@@ -220,18 +217,13 @@ export class DevicePool extends EventEmitter {
|
|
|
220
217
|
* error; settings only supplies a label, so its failure retains the existing name.
|
|
221
218
|
* Device.getDeviceState skips unsupported status/settings calls in loader mode.
|
|
222
219
|
*/
|
|
223
|
-
static async _refreshProtocolV2DiscoveryState(device: Device
|
|
224
|
-
const stateReadOptions = initOptions?.allowLegacyProtocolV2ProtocolInfo
|
|
225
|
-
? { allowLegacyProtocolV2ProtocolInfo: true as const }
|
|
226
|
-
: {};
|
|
220
|
+
static async _refreshProtocolV2DiscoveryState(device: Device) {
|
|
227
221
|
await device.getDeviceState({
|
|
228
222
|
refreshSections: ['status'],
|
|
229
|
-
...stateReadOptions,
|
|
230
223
|
});
|
|
231
224
|
try {
|
|
232
225
|
await device.getDeviceState({
|
|
233
226
|
refreshSections: ['settings'],
|
|
234
|
-
...stateReadOptions,
|
|
235
227
|
});
|
|
236
228
|
} catch (error) {
|
|
237
229
|
Log.debug('Unable to refresh Protocol V2 device label during discovery', error);
|
|
@@ -17,6 +17,14 @@ const LogLabelMethod: Set<string> = new Set([
|
|
|
17
17
|
'fileRead',
|
|
18
18
|
]);
|
|
19
19
|
|
|
20
|
+
// 资源上传参数可能包含很大的 Base64 字符串。这里按方法整段跳过,避免日志层
|
|
21
|
+
// 递归复制和序列化这些数据;资源 API 与传输内容本身保持不变。
|
|
22
|
+
const LogPayloadBlockMethod: Set<string> = new Set([
|
|
23
|
+
'deviceUploadNft',
|
|
24
|
+
'deviceUploadWallpaper',
|
|
25
|
+
'uploadPortfolio',
|
|
26
|
+
]);
|
|
27
|
+
|
|
20
28
|
const SensitiveLogKeys: Set<string> = new Set([
|
|
21
29
|
'devicestate',
|
|
22
30
|
'entropy',
|
|
@@ -86,7 +94,12 @@ export function getLogBlockLabel(message: unknown): string | undefined {
|
|
|
86
94
|
}
|
|
87
95
|
|
|
88
96
|
export function getSafeLogPayload(value: unknown, blockLabel?: string): unknown {
|
|
89
|
-
if (
|
|
97
|
+
if (
|
|
98
|
+
blockLabel &&
|
|
99
|
+
(LogBlockEvent.has(blockLabel) ||
|
|
100
|
+
LogPayloadBlockMethod.has(blockLabel) ||
|
|
101
|
+
isSigningMethod(blockLabel))
|
|
102
|
+
) {
|
|
90
103
|
return { method: blockLabel, payload: '[REDACTED]' };
|
|
91
104
|
}
|
|
92
105
|
|
|
@@ -97,11 +97,18 @@ export const parseProtocolV2BuildFingerprint = (
|
|
|
97
97
|
};
|
|
98
98
|
|
|
99
99
|
export const getProtocolV2RuntimeMode = (
|
|
100
|
-
protocolInfo: ProtocolInfo
|
|
100
|
+
protocolInfo: ProtocolInfo,
|
|
101
|
+
deviceInfo?: ProtocolV2DeviceInfo
|
|
101
102
|
): ProtocolV2RuntimeMode | undefined => {
|
|
102
103
|
const binary = parseProtocolV2BuildFingerprint(protocolInfo.build_fingerprint)?.binary;
|
|
103
104
|
if (binary === 'application') return 'normal';
|
|
104
|
-
return binary;
|
|
105
|
+
if (binary) return binary;
|
|
106
|
+
|
|
107
|
+
if (isLegacyProtocolV2ProtocolInfo(protocolInfo) && !deviceInfo?.fw?.application) {
|
|
108
|
+
if (deviceInfo?.fw?.romloader) return 'romloader';
|
|
109
|
+
if (deviceInfo?.fw?.bootloader) return 'bootloader';
|
|
110
|
+
}
|
|
111
|
+
return undefined;
|
|
105
112
|
};
|
|
106
113
|
|
|
107
114
|
// MessageType_DeviceStatusGet in the Protocol V2 protobuf registry.
|
|
@@ -11,8 +11,6 @@ export type GetDeviceStateParams = CommonParams & {
|
|
|
11
11
|
export type DeviceStateReadOptions = {
|
|
12
12
|
refreshSections?: DeviceStateSection[];
|
|
13
13
|
includeRaw?: boolean;
|
|
14
|
-
/** Internal recovery-only compatibility used by discovery and firmware update flows. */
|
|
15
|
-
allowLegacyProtocolV2ProtocolInfo?: boolean;
|
|
16
14
|
};
|
|
17
15
|
|
|
18
16
|
export declare function getDeviceState(
|
|
@@ -200,7 +200,7 @@ export const getAutoShutDownOptions = (
|
|
|
200
200
|
return withNever([60_000, 120_000, 300_000, 600_000], protocol);
|
|
201
201
|
case EDeviceType.Pro2:
|
|
202
202
|
case EDeviceType.Neo:
|
|
203
|
-
return withNever([60_000, 120_000, 300_000, 600_000
|
|
203
|
+
return withNever([60_000, 120_000, 300_000, 600_000], protocol);
|
|
204
204
|
default:
|
|
205
205
|
return [];
|
|
206
206
|
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { isLegacyProtocolV2FirmwareRecoveryMethod } from '../src/core/protocolV2LegacyRecovery';
|
|
2
|
-
|
|
3
|
-
import type { BaseMethod } from '../src/api/BaseMethod';
|
|
4
|
-
|
|
5
|
-
const createMethod = (
|
|
6
|
-
name: string,
|
|
7
|
-
payload: Record<string, unknown>
|
|
8
|
-
): Pick<BaseMethod, 'name' | 'payload'> => ({
|
|
9
|
-
name,
|
|
10
|
-
payload: { method: name, ...payload },
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
describe('Protocol V2 legacy firmware recovery policy', () => {
|
|
14
|
-
test.each([
|
|
15
|
-
['firmware state read', 'getDeviceState', { scope: 'firmware' }],
|
|
16
|
-
['firmware release check', 'checkAllFirmwareRelease', {}],
|
|
17
|
-
['firmware update', 'firmwareUpdateV4', {}],
|
|
18
|
-
])('allows legacy ProtocolInfo for %s', (_label, name, payload) => {
|
|
19
|
-
expect(isLegacyProtocolV2FirmwareRecoveryMethod(createMethod(name, payload))).toBe(true);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
test.each([
|
|
23
|
-
['runtime state read', 'getDeviceState', { scope: 'runtime' }],
|
|
24
|
-
['settings state read', 'getDeviceState', { scope: 'settings' }],
|
|
25
|
-
['ordinary API', 'getFeatures', {}],
|
|
26
|
-
])('rejects legacy ProtocolInfo for %s', (_label, name, payload) => {
|
|
27
|
-
expect(isLegacyProtocolV2FirmwareRecoveryMethod(createMethod(name, payload))).toBe(false);
|
|
28
|
-
});
|
|
29
|
-
});
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { BaseMethod } from '../api/BaseMethod';
|
|
2
|
-
type CoreMethodDescriptor = Pick<BaseMethod, 'name' | 'payload'>;
|
|
3
|
-
export declare const isLegacyProtocolV2FirmwareRecoveryMethod: (method?: CoreMethodDescriptor) => boolean;
|
|
4
|
-
export {};
|
|
5
|
-
//# sourceMappingURL=protocolV2LegacyRecovery.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"protocolV2LegacyRecovery.d.ts","sourceRoot":"","sources":["../../src/core/protocolV2LegacyRecovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,KAAK,oBAAoB,GAAG,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAMjE,eAAO,MAAM,wCAAwC,YAAa,oBAAoB,KAAG,OAGb,CAAC"}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { BaseMethod } from '../api/BaseMethod';
|
|
2
|
-
|
|
3
|
-
type CoreMethodDescriptor = Pick<BaseMethod, 'name' | 'payload'>;
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* TEMPORARY COMPATIBILITY: Legacy ProtocolInfo is accepted only by the
|
|
7
|
-
* firmware recovery entry points used before and during Protocol V2 updates.
|
|
8
|
-
*/
|
|
9
|
-
export const isLegacyProtocolV2FirmwareRecoveryMethod = (method?: CoreMethodDescriptor): boolean =>
|
|
10
|
-
method?.name === 'firmwareUpdateV4' ||
|
|
11
|
-
method?.name === 'checkAllFirmwareRelease' ||
|
|
12
|
-
(method?.name === 'getDeviceState' && method.payload.scope === 'firmware');
|